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 *
esw_vport_tbl_create(struct mlx5_eswitch * esw,struct mlx5_flow_namespace * ns,const struct esw_vport_tbl_namespace * vport_ns)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
flow_attr_to_vport_key(struct mlx5_eswitch * esw,struct mlx5_vport_tbl_attr * attr,struct mlx5_vport_key * key)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 *
esw_vport_tbl_lookup(struct mlx5_eswitch * esw,struct mlx5_vport_key * skey,u32 key)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 *
mlx5_esw_vporttbl_get(struct mlx5_eswitch * esw,struct mlx5_vport_tbl_attr * attr)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
mlx5_esw_vporttbl_put(struct mlx5_eswitch * esw,struct mlx5_vport_tbl_attr * attr)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