1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 // Copyright (c) 2021 Mellanox Technologies. 3 4 #include "eswitch.h" 5 6 /* This struct is used as a key to the hash table and we need it to be packed 7 * so hash result is consistent 8 */ 9 struct mlx5_vport_key { 10 u32 chain; 11 u16 prio; 12 u16 vport; 13 u16 vhca_id; 14 const struct esw_vport_tbl_namespace *vport_ns; 15 } __packed; 16 17 struct mlx5_vport_table { 18 struct hlist_node hlist; 19 struct mlx5_flow_table *fdb; 20 u32 num_rules; 21 struct mlx5_vport_key key; 22 }; 23 24 static struct mlx5_flow_table * 25 esw_vport_tbl_create(struct mlx5_eswitch *esw, struct mlx5_flow_namespace *ns, 26 const struct esw_vport_tbl_namespace *vport_ns) 27 { 28 struct mlx5_flow_table_attr ft_attr = {}; 29 struct mlx5_flow_table *fdb; 30 31 if (vport_ns->max_num_groups) 32 ft_attr.autogroup.max_num_groups = vport_ns->max_num_groups; 33 else 34 ft_attr.autogroup.max_num_groups = esw->params.large_group_num; 35 ft_attr.max_fte = vport_ns->max_fte; 36 ft_attr.prio = FDB_PER_VPORT; 37 ft_attr.flags = vport_ns->flags; 38 fdb = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); 39 if (IS_ERR(fdb)) { 40 esw_warn(esw->dev, "Failed to create per vport FDB Table err %ld\n", 41 PTR_ERR(fdb)); 42 } 43 44 return fdb; 45 } 46 47 static u32 flow_attr_to_vport_key(struct mlx5_eswitch *esw, 48 struct mlx5_vport_tbl_attr *attr, 49 struct mlx5_vport_key *key) 50 { 51 key->vport = attr->vport; 52 key->chain = attr->chain; 53 key->prio = attr->prio; 54 key->vhca_id = MLX5_CAP_GEN(esw->dev, vhca_id); 55 key->vport_ns = attr->vport_ns; 56 return jhash(key, sizeof(*key), 0); 57 } 58 59 /* caller must hold vports.lock */ 60 static struct mlx5_vport_table * 61 esw_vport_tbl_lookup(struct mlx5_eswitch *esw, struct mlx5_vport_key *skey, u32 key) 62 { 63 struct mlx5_vport_table *e; 64 65 hash_for_each_possible(esw->fdb_table.offloads.vports.table, e, hlist, key) 66 if (!memcmp(&e->key, skey, sizeof(*skey))) 67 return e; 68 69 return NULL; 70 } 71 72 struct mlx5_flow_table * 73 mlx5_esw_vporttbl_get(struct mlx5_eswitch *esw, struct mlx5_vport_tbl_attr *attr) 74 { 75 struct mlx5_core_dev *dev = esw->dev; 76 struct mlx5_flow_namespace *ns; 77 struct mlx5_flow_table *fdb; 78 struct mlx5_vport_table *e; 79 struct mlx5_vport_key skey; 80 u32 hkey; 81 82 mutex_lock(&esw->fdb_table.offloads.vports.lock); 83 hkey = flow_attr_to_vport_key(esw, attr, &skey); 84 e = esw_vport_tbl_lookup(esw, &skey, hkey); 85 if (e) { 86 e->num_rules++; 87 goto out; 88 } 89 90 e = kzalloc(sizeof(*e), GFP_KERNEL); 91 if (!e) { 92 fdb = ERR_PTR(-ENOMEM); 93 goto err_alloc; 94 } 95 96 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); 97 if (!ns) { 98 esw_warn(dev, "Failed to get FDB namespace\n"); 99 fdb = ERR_PTR(-ENOENT); 100 goto err_ns; 101 } 102 103 fdb = esw_vport_tbl_create(esw, ns, attr->vport_ns); 104 if (IS_ERR(fdb)) 105 goto err_ns; 106 107 e->fdb = fdb; 108 e->num_rules = 1; 109 e->key = skey; 110 hash_add(esw->fdb_table.offloads.vports.table, &e->hlist, hkey); 111 out: 112 mutex_unlock(&esw->fdb_table.offloads.vports.lock); 113 return e->fdb; 114 115 err_ns: 116 kfree(e); 117 err_alloc: 118 mutex_unlock(&esw->fdb_table.offloads.vports.lock); 119 return fdb; 120 } 121 122 void 123 mlx5_esw_vporttbl_put(struct mlx5_eswitch *esw, struct mlx5_vport_tbl_attr *attr) 124 { 125 struct mlx5_vport_table *e; 126 struct mlx5_vport_key key; 127 u32 hkey; 128 129 mutex_lock(&esw->fdb_table.offloads.vports.lock); 130 hkey = flow_attr_to_vport_key(esw, attr, &key); 131 e = esw_vport_tbl_lookup(esw, &key, hkey); 132 if (!e || --e->num_rules) 133 goto out; 134 135 hash_del(&e->hlist); 136 mlx5_destroy_flow_table(e->fdb); 137 kfree(e); 138 out: 139 mutex_unlock(&esw->fdb_table.offloads.vports.lock); 140 } 141