.. | .. |
---|
6 | 6 | #include <linux/if_vlan.h> |
---|
7 | 7 | #include <linux/if_bridge.h> |
---|
8 | 8 | #include <linux/netdevice.h> |
---|
| 9 | +#include <linux/rhashtable.h> |
---|
9 | 10 | #include <linux/rtnetlink.h> |
---|
| 11 | +#include <linux/refcount.h> |
---|
10 | 12 | |
---|
11 | 13 | #include "spectrum.h" |
---|
12 | 14 | #include "reg.h" |
---|
.. | .. |
---|
14 | 16 | struct mlxsw_sp_fid_family; |
---|
15 | 17 | |
---|
16 | 18 | struct mlxsw_sp_fid_core { |
---|
| 19 | + struct rhashtable fid_ht; |
---|
| 20 | + struct rhashtable vni_ht; |
---|
17 | 21 | struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; |
---|
18 | 22 | unsigned int *port_fid_mappings; |
---|
19 | 23 | }; |
---|
.. | .. |
---|
21 | 25 | struct mlxsw_sp_fid { |
---|
22 | 26 | struct list_head list; |
---|
23 | 27 | struct mlxsw_sp_rif *rif; |
---|
24 | | - unsigned int ref_count; |
---|
| 28 | + refcount_t ref_count; |
---|
25 | 29 | u16 fid_index; |
---|
26 | 30 | struct mlxsw_sp_fid_family *fid_family; |
---|
| 31 | + struct rhash_head ht_node; |
---|
| 32 | + |
---|
| 33 | + struct rhash_head vni_ht_node; |
---|
| 34 | + enum mlxsw_sp_nve_type nve_type; |
---|
| 35 | + __be32 vni; |
---|
| 36 | + u32 nve_flood_index; |
---|
| 37 | + int nve_ifindex; |
---|
| 38 | + u8 vni_valid:1, |
---|
| 39 | + nve_flood_index_valid:1; |
---|
27 | 40 | }; |
---|
28 | 41 | |
---|
29 | 42 | struct mlxsw_sp_fid_8021q { |
---|
.. | .. |
---|
34 | 47 | struct mlxsw_sp_fid_8021d { |
---|
35 | 48 | struct mlxsw_sp_fid common; |
---|
36 | 49 | int br_ifindex; |
---|
| 50 | +}; |
---|
| 51 | + |
---|
| 52 | +static const struct rhashtable_params mlxsw_sp_fid_ht_params = { |
---|
| 53 | + .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index), |
---|
| 54 | + .key_offset = offsetof(struct mlxsw_sp_fid, fid_index), |
---|
| 55 | + .head_offset = offsetof(struct mlxsw_sp_fid, ht_node), |
---|
| 56 | +}; |
---|
| 57 | + |
---|
| 58 | +static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { |
---|
| 59 | + .key_len = sizeof_field(struct mlxsw_sp_fid, vni), |
---|
| 60 | + .key_offset = offsetof(struct mlxsw_sp_fid, vni), |
---|
| 61 | + .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node), |
---|
37 | 62 | }; |
---|
38 | 63 | |
---|
39 | 64 | struct mlxsw_sp_flood_table { |
---|
.. | .. |
---|
56 | 81 | struct mlxsw_sp_port *port, u16 vid); |
---|
57 | 82 | void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, |
---|
58 | 83 | struct mlxsw_sp_port *port, u16 vid); |
---|
| 84 | + int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni); |
---|
| 85 | + void (*vni_clear)(struct mlxsw_sp_fid *fid); |
---|
| 86 | + int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid, |
---|
| 87 | + u32 nve_flood_index); |
---|
| 88 | + void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid); |
---|
| 89 | + void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid, |
---|
| 90 | + const struct net_device *nve_dev); |
---|
59 | 91 | }; |
---|
60 | 92 | |
---|
61 | 93 | struct mlxsw_sp_fid_family { |
---|
.. | .. |
---|
70 | 102 | enum mlxsw_sp_rif_type rif_type; |
---|
71 | 103 | const struct mlxsw_sp_fid_ops *ops; |
---|
72 | 104 | struct mlxsw_sp *mlxsw_sp; |
---|
| 105 | + u8 lag_vid_valid:1; |
---|
73 | 106 | }; |
---|
74 | 107 | |
---|
75 | 108 | static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { |
---|
.. | .. |
---|
93 | 126 | [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, |
---|
94 | 127 | [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, |
---|
95 | 128 | }; |
---|
| 129 | + |
---|
| 130 | +bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index) |
---|
| 131 | +{ |
---|
| 132 | + enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY; |
---|
| 133 | + struct mlxsw_sp_fid_family *fid_family; |
---|
| 134 | + |
---|
| 135 | + fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type]; |
---|
| 136 | + |
---|
| 137 | + return fid_family->start_index == fid_index; |
---|
| 138 | +} |
---|
| 139 | + |
---|
| 140 | +bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid) |
---|
| 141 | +{ |
---|
| 142 | + return fid->fid_family->lag_vid_valid; |
---|
| 143 | +} |
---|
| 144 | + |
---|
| 145 | +struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, |
---|
| 146 | + u16 fid_index) |
---|
| 147 | +{ |
---|
| 148 | + struct mlxsw_sp_fid *fid; |
---|
| 149 | + |
---|
| 150 | + fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index, |
---|
| 151 | + mlxsw_sp_fid_ht_params); |
---|
| 152 | + if (fid) |
---|
| 153 | + refcount_inc(&fid->ref_count); |
---|
| 154 | + |
---|
| 155 | + return fid; |
---|
| 156 | +} |
---|
| 157 | + |
---|
| 158 | +int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex) |
---|
| 159 | +{ |
---|
| 160 | + if (!fid->vni_valid) |
---|
| 161 | + return -EINVAL; |
---|
| 162 | + |
---|
| 163 | + *nve_ifindex = fid->nve_ifindex; |
---|
| 164 | + |
---|
| 165 | + return 0; |
---|
| 166 | +} |
---|
| 167 | + |
---|
| 168 | +int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid, |
---|
| 169 | + enum mlxsw_sp_nve_type *p_type) |
---|
| 170 | +{ |
---|
| 171 | + if (!fid->vni_valid) |
---|
| 172 | + return -EINVAL; |
---|
| 173 | + |
---|
| 174 | + *p_type = fid->nve_type; |
---|
| 175 | + |
---|
| 176 | + return 0; |
---|
| 177 | +} |
---|
| 178 | + |
---|
| 179 | +struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, |
---|
| 180 | + __be32 vni) |
---|
| 181 | +{ |
---|
| 182 | + struct mlxsw_sp_fid *fid; |
---|
| 183 | + |
---|
| 184 | + fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, |
---|
| 185 | + mlxsw_sp_fid_vni_ht_params); |
---|
| 186 | + if (fid) |
---|
| 187 | + refcount_inc(&fid->ref_count); |
---|
| 188 | + |
---|
| 189 | + return fid; |
---|
| 190 | +} |
---|
| 191 | + |
---|
| 192 | +int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) |
---|
| 193 | +{ |
---|
| 194 | + if (!fid->vni_valid) |
---|
| 195 | + return -EINVAL; |
---|
| 196 | + |
---|
| 197 | + *vni = fid->vni; |
---|
| 198 | + |
---|
| 199 | + return 0; |
---|
| 200 | +} |
---|
| 201 | + |
---|
| 202 | +int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, |
---|
| 203 | + u32 nve_flood_index) |
---|
| 204 | +{ |
---|
| 205 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 206 | + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; |
---|
| 207 | + int err; |
---|
| 208 | + |
---|
| 209 | + if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid)) |
---|
| 210 | + return -EINVAL; |
---|
| 211 | + |
---|
| 212 | + err = ops->nve_flood_index_set(fid, nve_flood_index); |
---|
| 213 | + if (err) |
---|
| 214 | + return err; |
---|
| 215 | + |
---|
| 216 | + fid->nve_flood_index = nve_flood_index; |
---|
| 217 | + fid->nve_flood_index_valid = true; |
---|
| 218 | + |
---|
| 219 | + return 0; |
---|
| 220 | +} |
---|
| 221 | + |
---|
| 222 | +void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) |
---|
| 223 | +{ |
---|
| 224 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 225 | + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; |
---|
| 226 | + |
---|
| 227 | + if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid)) |
---|
| 228 | + return; |
---|
| 229 | + |
---|
| 230 | + fid->nve_flood_index_valid = false; |
---|
| 231 | + ops->nve_flood_index_clear(fid); |
---|
| 232 | +} |
---|
| 233 | + |
---|
| 234 | +bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid) |
---|
| 235 | +{ |
---|
| 236 | + return fid->nve_flood_index_valid; |
---|
| 237 | +} |
---|
| 238 | + |
---|
| 239 | +int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type, |
---|
| 240 | + __be32 vni, int nve_ifindex) |
---|
| 241 | +{ |
---|
| 242 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 243 | + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; |
---|
| 244 | + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; |
---|
| 245 | + int err; |
---|
| 246 | + |
---|
| 247 | + if (WARN_ON(!ops->vni_set || fid->vni_valid)) |
---|
| 248 | + return -EINVAL; |
---|
| 249 | + |
---|
| 250 | + fid->nve_type = type; |
---|
| 251 | + fid->nve_ifindex = nve_ifindex; |
---|
| 252 | + fid->vni = vni; |
---|
| 253 | + err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht, |
---|
| 254 | + &fid->vni_ht_node, |
---|
| 255 | + mlxsw_sp_fid_vni_ht_params); |
---|
| 256 | + if (err) |
---|
| 257 | + return err; |
---|
| 258 | + |
---|
| 259 | + err = ops->vni_set(fid, vni); |
---|
| 260 | + if (err) |
---|
| 261 | + goto err_vni_set; |
---|
| 262 | + |
---|
| 263 | + fid->vni_valid = true; |
---|
| 264 | + |
---|
| 265 | + return 0; |
---|
| 266 | + |
---|
| 267 | +err_vni_set: |
---|
| 268 | + rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, |
---|
| 269 | + mlxsw_sp_fid_vni_ht_params); |
---|
| 270 | + return err; |
---|
| 271 | +} |
---|
| 272 | + |
---|
| 273 | +void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid) |
---|
| 274 | +{ |
---|
| 275 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 276 | + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; |
---|
| 277 | + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; |
---|
| 278 | + |
---|
| 279 | + if (WARN_ON(!ops->vni_clear || !fid->vni_valid)) |
---|
| 280 | + return; |
---|
| 281 | + |
---|
| 282 | + fid->vni_valid = false; |
---|
| 283 | + ops->vni_clear(fid); |
---|
| 284 | + rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, |
---|
| 285 | + mlxsw_sp_fid_vni_ht_params); |
---|
| 286 | +} |
---|
| 287 | + |
---|
| 288 | +bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid) |
---|
| 289 | +{ |
---|
| 290 | + return fid->vni_valid; |
---|
| 291 | +} |
---|
| 292 | + |
---|
| 293 | +void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid, |
---|
| 294 | + const struct net_device *nve_dev) |
---|
| 295 | +{ |
---|
| 296 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 297 | + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; |
---|
| 298 | + |
---|
| 299 | + if (ops->fdb_clear_offload) |
---|
| 300 | + ops->fdb_clear_offload(fid, nve_dev); |
---|
| 301 | +} |
---|
96 | 302 | |
---|
97 | 303 | static const struct mlxsw_sp_flood_table * |
---|
98 | 304 | mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, |
---|
.. | .. |
---|
154 | 360 | fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); |
---|
155 | 361 | } |
---|
156 | 362 | |
---|
157 | | -enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid) |
---|
158 | | -{ |
---|
159 | | - return fid->fid_family->rif_type; |
---|
160 | | -} |
---|
161 | | - |
---|
162 | 363 | u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) |
---|
163 | 364 | { |
---|
164 | 365 | return fid->fid_index; |
---|
.. | .. |
---|
172 | 373 | void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) |
---|
173 | 374 | { |
---|
174 | 375 | fid->rif = rif; |
---|
| 376 | +} |
---|
| 377 | + |
---|
| 378 | +struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid) |
---|
| 379 | +{ |
---|
| 380 | + return fid->rif; |
---|
175 | 381 | } |
---|
176 | 382 | |
---|
177 | 383 | enum mlxsw_sp_rif_type |
---|
.. | .. |
---|
217 | 423 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); |
---|
218 | 424 | } |
---|
219 | 425 | |
---|
220 | | -static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, |
---|
221 | | - u16 vid, bool valid) |
---|
| 426 | +static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, |
---|
| 427 | + __be32 vni, bool vni_valid, u32 nve_flood_index, |
---|
| 428 | + bool nve_flood_index_valid) |
---|
222 | 429 | { |
---|
223 | | - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; |
---|
224 | | - char svfa_pl[MLXSW_REG_SVFA_LEN]; |
---|
| 430 | + char sfmr_pl[MLXSW_REG_SFMR_LEN]; |
---|
225 | 431 | |
---|
226 | | - mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid); |
---|
227 | | - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); |
---|
| 432 | + mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index, |
---|
| 433 | + 0); |
---|
| 434 | + mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid); |
---|
| 435 | + mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni)); |
---|
| 436 | + mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid); |
---|
| 437 | + mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index); |
---|
| 438 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); |
---|
228 | 439 | } |
---|
229 | 440 | |
---|
230 | 441 | static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, |
---|
.. | .. |
---|
236 | 447 | mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); |
---|
237 | 448 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); |
---|
238 | 449 | } |
---|
239 | | - |
---|
240 | | -static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) |
---|
241 | | -{ |
---|
242 | | - struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; |
---|
243 | | - struct mlxsw_sp_fid_8021q *fid_8021q; |
---|
244 | | - int err; |
---|
245 | | - |
---|
246 | | - err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true); |
---|
247 | | - if (err) |
---|
248 | | - return err; |
---|
249 | | - |
---|
250 | | - fid_8021q = mlxsw_sp_fid_8021q_fid(fid); |
---|
251 | | - err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, |
---|
252 | | - true); |
---|
253 | | - if (err) |
---|
254 | | - goto err_fid_map; |
---|
255 | | - |
---|
256 | | - return 0; |
---|
257 | | - |
---|
258 | | -err_fid_map: |
---|
259 | | - mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); |
---|
260 | | - return err; |
---|
261 | | -} |
---|
262 | | - |
---|
263 | | -static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) |
---|
264 | | -{ |
---|
265 | | - struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; |
---|
266 | | - struct mlxsw_sp_fid_8021q *fid_8021q; |
---|
267 | | - |
---|
268 | | - fid_8021q = mlxsw_sp_fid_8021q_fid(fid); |
---|
269 | | - mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false); |
---|
270 | | - mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); |
---|
271 | | -} |
---|
272 | | - |
---|
273 | | -static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid, |
---|
274 | | - const void *arg, u16 *p_fid_index) |
---|
275 | | -{ |
---|
276 | | - struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
277 | | - u16 vid = *(u16 *) arg; |
---|
278 | | - |
---|
279 | | - /* Use 1:1 mapping for simplicity although not a must */ |
---|
280 | | - if (vid < fid_family->start_index || vid > fid_family->end_index) |
---|
281 | | - return -EINVAL; |
---|
282 | | - *p_fid_index = vid; |
---|
283 | | - |
---|
284 | | - return 0; |
---|
285 | | -} |
---|
286 | | - |
---|
287 | | -static bool |
---|
288 | | -mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) |
---|
289 | | -{ |
---|
290 | | - u16 vid = *(u16 *) arg; |
---|
291 | | - |
---|
292 | | - return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; |
---|
293 | | -} |
---|
294 | | - |
---|
295 | | -static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid) |
---|
296 | | -{ |
---|
297 | | - return fid->fid_index; |
---|
298 | | -} |
---|
299 | | - |
---|
300 | | -static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, |
---|
301 | | - struct mlxsw_sp_port *mlxsw_sp_port, |
---|
302 | | - u16 vid) |
---|
303 | | -{ |
---|
304 | | - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
---|
305 | | - u8 local_port = mlxsw_sp_port->local_port; |
---|
306 | | - |
---|
307 | | - /* In case there are no {Port, VID} => FID mappings on the port, |
---|
308 | | - * we can use the global VID => FID mapping we created when the |
---|
309 | | - * FID was configured. |
---|
310 | | - */ |
---|
311 | | - if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) |
---|
312 | | - return 0; |
---|
313 | | - return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, |
---|
314 | | - vid, true); |
---|
315 | | -} |
---|
316 | | - |
---|
317 | | -static void |
---|
318 | | -mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, |
---|
319 | | - struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) |
---|
320 | | -{ |
---|
321 | | - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
---|
322 | | - u8 local_port = mlxsw_sp_port->local_port; |
---|
323 | | - |
---|
324 | | - if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) |
---|
325 | | - return; |
---|
326 | | - __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid, |
---|
327 | | - false); |
---|
328 | | -} |
---|
329 | | - |
---|
330 | | -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { |
---|
331 | | - .setup = mlxsw_sp_fid_8021q_setup, |
---|
332 | | - .configure = mlxsw_sp_fid_8021q_configure, |
---|
333 | | - .deconfigure = mlxsw_sp_fid_8021q_deconfigure, |
---|
334 | | - .index_alloc = mlxsw_sp_fid_8021q_index_alloc, |
---|
335 | | - .compare = mlxsw_sp_fid_8021q_compare, |
---|
336 | | - .flood_index = mlxsw_sp_fid_8021q_flood_index, |
---|
337 | | - .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, |
---|
338 | | - .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, |
---|
339 | | -}; |
---|
340 | | - |
---|
341 | | -static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { |
---|
342 | | - { |
---|
343 | | - .packet_type = MLXSW_SP_FLOOD_TYPE_UC, |
---|
344 | | - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, |
---|
345 | | - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, |
---|
346 | | - .table_index = 0, |
---|
347 | | - }, |
---|
348 | | - { |
---|
349 | | - .packet_type = MLXSW_SP_FLOOD_TYPE_MC, |
---|
350 | | - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, |
---|
351 | | - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, |
---|
352 | | - .table_index = 1, |
---|
353 | | - }, |
---|
354 | | - { |
---|
355 | | - .packet_type = MLXSW_SP_FLOOD_TYPE_BC, |
---|
356 | | - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, |
---|
357 | | - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, |
---|
358 | | - .table_index = 2, |
---|
359 | | - }, |
---|
360 | | -}; |
---|
361 | | - |
---|
362 | | -/* Range and flood configuration must match mlxsw_config_profile */ |
---|
363 | | -static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = { |
---|
364 | | - .type = MLXSW_SP_FID_TYPE_8021Q, |
---|
365 | | - .fid_size = sizeof(struct mlxsw_sp_fid_8021q), |
---|
366 | | - .start_index = 1, |
---|
367 | | - .end_index = VLAN_VID_MASK, |
---|
368 | | - .flood_tables = mlxsw_sp_fid_8021q_flood_tables, |
---|
369 | | - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables), |
---|
370 | | - .rif_type = MLXSW_SP_RIF_TYPE_VLAN, |
---|
371 | | - .ops = &mlxsw_sp_fid_8021q_ops, |
---|
372 | | -}; |
---|
373 | 450 | |
---|
374 | 451 | static struct mlxsw_sp_fid_8021d * |
---|
375 | 452 | mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) |
---|
.. | .. |
---|
393 | 470 | |
---|
394 | 471 | static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) |
---|
395 | 472 | { |
---|
| 473 | + if (fid->vni_valid) |
---|
| 474 | + mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); |
---|
396 | 475 | mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); |
---|
397 | 476 | } |
---|
398 | 477 | |
---|
.. | .. |
---|
421 | 500 | |
---|
422 | 501 | static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) |
---|
423 | 502 | { |
---|
424 | | - return fid->fid_index - fid->fid_family->start_index; |
---|
| 503 | + return fid->fid_index - VLAN_N_VID; |
---|
425 | 504 | } |
---|
426 | 505 | |
---|
427 | 506 | static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) |
---|
.. | .. |
---|
531 | 610 | mlxsw_sp_port->local_port, vid, false); |
---|
532 | 611 | } |
---|
533 | 612 | |
---|
| 613 | +static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) |
---|
| 614 | +{ |
---|
| 615 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 616 | + |
---|
| 617 | + return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni, |
---|
| 618 | + true, fid->nve_flood_index, |
---|
| 619 | + fid->nve_flood_index_valid); |
---|
| 620 | +} |
---|
| 621 | + |
---|
| 622 | +static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid) |
---|
| 623 | +{ |
---|
| 624 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 625 | + |
---|
| 626 | + mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false, |
---|
| 627 | + fid->nve_flood_index, fid->nve_flood_index_valid); |
---|
| 628 | +} |
---|
| 629 | + |
---|
| 630 | +static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid, |
---|
| 631 | + u32 nve_flood_index) |
---|
| 632 | +{ |
---|
| 633 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 634 | + |
---|
| 635 | + return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, |
---|
| 636 | + fid->vni, fid->vni_valid, nve_flood_index, |
---|
| 637 | + true); |
---|
| 638 | +} |
---|
| 639 | + |
---|
| 640 | +static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid) |
---|
| 641 | +{ |
---|
| 642 | + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 643 | + |
---|
| 644 | + mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni, |
---|
| 645 | + fid->vni_valid, 0, false); |
---|
| 646 | +} |
---|
| 647 | + |
---|
| 648 | +static void |
---|
| 649 | +mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid, |
---|
| 650 | + const struct net_device *nve_dev) |
---|
| 651 | +{ |
---|
| 652 | + br_fdb_clear_offload(nve_dev, 0); |
---|
| 653 | +} |
---|
| 654 | + |
---|
534 | 655 | static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { |
---|
535 | 656 | .setup = mlxsw_sp_fid_8021d_setup, |
---|
536 | 657 | .configure = mlxsw_sp_fid_8021d_configure, |
---|
.. | .. |
---|
540 | 661 | .flood_index = mlxsw_sp_fid_8021d_flood_index, |
---|
541 | 662 | .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, |
---|
542 | 663 | .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, |
---|
| 664 | + .vni_set = mlxsw_sp_fid_8021d_vni_set, |
---|
| 665 | + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, |
---|
| 666 | + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, |
---|
| 667 | + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, |
---|
| 668 | + .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, |
---|
543 | 669 | }; |
---|
544 | 670 | |
---|
545 | 671 | static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { |
---|
.. | .. |
---|
573 | 699 | .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), |
---|
574 | 700 | .rif_type = MLXSW_SP_RIF_TYPE_FID, |
---|
575 | 701 | .ops = &mlxsw_sp_fid_8021d_ops, |
---|
| 702 | + .lag_vid_valid = 1, |
---|
| 703 | +}; |
---|
| 704 | + |
---|
| 705 | +static bool |
---|
| 706 | +mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) |
---|
| 707 | +{ |
---|
| 708 | + u16 vid = *(u16 *) arg; |
---|
| 709 | + |
---|
| 710 | + return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; |
---|
| 711 | +} |
---|
| 712 | + |
---|
| 713 | +static void |
---|
| 714 | +mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, |
---|
| 715 | + const struct net_device *nve_dev) |
---|
| 716 | +{ |
---|
| 717 | + br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); |
---|
| 718 | +} |
---|
| 719 | + |
---|
| 720 | +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = { |
---|
| 721 | + .setup = mlxsw_sp_fid_8021q_setup, |
---|
| 722 | + .configure = mlxsw_sp_fid_8021d_configure, |
---|
| 723 | + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, |
---|
| 724 | + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, |
---|
| 725 | + .compare = mlxsw_sp_fid_8021q_compare, |
---|
| 726 | + .flood_index = mlxsw_sp_fid_8021d_flood_index, |
---|
| 727 | + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, |
---|
| 728 | + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, |
---|
| 729 | + .vni_set = mlxsw_sp_fid_8021d_vni_set, |
---|
| 730 | + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, |
---|
| 731 | + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, |
---|
| 732 | + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, |
---|
| 733 | + .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, |
---|
| 734 | +}; |
---|
| 735 | + |
---|
| 736 | +/* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */ |
---|
| 737 | +#define MLXSW_SP_FID_8021Q_EMU_START (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX) |
---|
| 738 | +#define MLXSW_SP_FID_8021Q_EMU_END (MLXSW_SP_FID_8021Q_EMU_START + \ |
---|
| 739 | + VLAN_VID_MASK - 2) |
---|
| 740 | + |
---|
| 741 | +/* Range and flood configuration must match mlxsw_config_profile */ |
---|
| 742 | +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { |
---|
| 743 | + .type = MLXSW_SP_FID_TYPE_8021Q, |
---|
| 744 | + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), |
---|
| 745 | + .start_index = MLXSW_SP_FID_8021Q_EMU_START, |
---|
| 746 | + .end_index = MLXSW_SP_FID_8021Q_EMU_END, |
---|
| 747 | + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, |
---|
| 748 | + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), |
---|
| 749 | + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, |
---|
| 750 | + .ops = &mlxsw_sp_fid_8021q_emu_ops, |
---|
| 751 | + .lag_vid_valid = 1, |
---|
576 | 752 | }; |
---|
577 | 753 | |
---|
578 | 754 | static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) |
---|
.. | .. |
---|
702 | 878 | }; |
---|
703 | 879 | |
---|
704 | 880 | static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { |
---|
705 | | - [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family, |
---|
| 881 | + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_emu_family, |
---|
706 | 882 | [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, |
---|
707 | 883 | [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, |
---|
708 | 884 | [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, |
---|
709 | 885 | }; |
---|
| 886 | + |
---|
| 887 | +static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, |
---|
| 888 | + enum mlxsw_sp_fid_type type, |
---|
| 889 | + const void *arg) |
---|
| 890 | +{ |
---|
| 891 | + struct mlxsw_sp_fid_family *fid_family; |
---|
| 892 | + struct mlxsw_sp_fid *fid; |
---|
| 893 | + |
---|
| 894 | + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; |
---|
| 895 | + list_for_each_entry(fid, &fid_family->fids_list, list) { |
---|
| 896 | + if (!fid->fid_family->ops->compare(fid, arg)) |
---|
| 897 | + continue; |
---|
| 898 | + refcount_inc(&fid->ref_count); |
---|
| 899 | + return fid; |
---|
| 900 | + } |
---|
| 901 | + |
---|
| 902 | + return NULL; |
---|
| 903 | +} |
---|
710 | 904 | |
---|
711 | 905 | static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, |
---|
712 | 906 | enum mlxsw_sp_fid_type type, |
---|
.. | .. |
---|
717 | 911 | u16 fid_index; |
---|
718 | 912 | int err; |
---|
719 | 913 | |
---|
720 | | - fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; |
---|
721 | | - list_for_each_entry(fid, &fid_family->fids_list, list) { |
---|
722 | | - if (!fid->fid_family->ops->compare(fid, arg)) |
---|
723 | | - continue; |
---|
724 | | - fid->ref_count++; |
---|
| 914 | + fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg); |
---|
| 915 | + if (fid) |
---|
725 | 916 | return fid; |
---|
726 | | - } |
---|
727 | 917 | |
---|
| 918 | + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; |
---|
728 | 919 | fid = kzalloc(fid_family->fid_size, GFP_KERNEL); |
---|
729 | 920 | if (!fid) |
---|
730 | 921 | return ERR_PTR(-ENOMEM); |
---|
.. | .. |
---|
743 | 934 | if (err) |
---|
744 | 935 | goto err_configure; |
---|
745 | 936 | |
---|
| 937 | + err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node, |
---|
| 938 | + mlxsw_sp_fid_ht_params); |
---|
| 939 | + if (err) |
---|
| 940 | + goto err_rhashtable_insert; |
---|
| 941 | + |
---|
746 | 942 | list_add(&fid->list, &fid_family->fids_list); |
---|
747 | | - fid->ref_count++; |
---|
| 943 | + refcount_set(&fid->ref_count, 1); |
---|
748 | 944 | return fid; |
---|
749 | 945 | |
---|
| 946 | +err_rhashtable_insert: |
---|
| 947 | + fid->fid_family->ops->deconfigure(fid); |
---|
750 | 948 | err_configure: |
---|
751 | 949 | __clear_bit(fid_index - fid_family->start_index, |
---|
752 | 950 | fid_family->fids_bitmap); |
---|
.. | .. |
---|
758 | 956 | void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) |
---|
759 | 957 | { |
---|
760 | 958 | struct mlxsw_sp_fid_family *fid_family = fid->fid_family; |
---|
| 959 | + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; |
---|
761 | 960 | |
---|
762 | | - if (--fid->ref_count == 1 && fid->rif) { |
---|
763 | | - /* Destroy the associated RIF and let it drop the last |
---|
764 | | - * reference on the FID. |
---|
765 | | - */ |
---|
766 | | - return mlxsw_sp_rif_destroy(fid->rif); |
---|
767 | | - } else if (fid->ref_count == 0) { |
---|
768 | | - list_del(&fid->list); |
---|
769 | | - fid->fid_family->ops->deconfigure(fid); |
---|
770 | | - __clear_bit(fid->fid_index - fid_family->start_index, |
---|
771 | | - fid_family->fids_bitmap); |
---|
772 | | - kfree(fid); |
---|
773 | | - } |
---|
| 961 | + if (!refcount_dec_and_test(&fid->ref_count)) |
---|
| 962 | + return; |
---|
| 963 | + |
---|
| 964 | + list_del(&fid->list); |
---|
| 965 | + rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht, |
---|
| 966 | + &fid->ht_node, mlxsw_sp_fid_ht_params); |
---|
| 967 | + fid->fid_family->ops->deconfigure(fid); |
---|
| 968 | + __clear_bit(fid->fid_index - fid_family->start_index, |
---|
| 969 | + fid_family->fids_bitmap); |
---|
| 970 | + kfree(fid); |
---|
774 | 971 | } |
---|
775 | 972 | |
---|
776 | 973 | struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) |
---|
.. | .. |
---|
782 | 979 | int br_ifindex) |
---|
783 | 980 | { |
---|
784 | 981 | return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); |
---|
| 982 | +} |
---|
| 983 | + |
---|
| 984 | +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, |
---|
| 985 | + u16 vid) |
---|
| 986 | +{ |
---|
| 987 | + return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); |
---|
| 988 | +} |
---|
| 989 | + |
---|
| 990 | +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, |
---|
| 991 | + int br_ifindex) |
---|
| 992 | +{ |
---|
| 993 | + return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, |
---|
| 994 | + &br_ifindex); |
---|
785 | 995 | } |
---|
786 | 996 | |
---|
787 | 997 | struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
853 | 1063 | |
---|
854 | 1064 | fid_family->mlxsw_sp = mlxsw_sp; |
---|
855 | 1065 | INIT_LIST_HEAD(&fid_family->fids_list); |
---|
856 | | - fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids), |
---|
857 | | - sizeof(unsigned long), GFP_KERNEL); |
---|
| 1066 | + fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL); |
---|
858 | 1067 | if (!fid_family->fids_bitmap) { |
---|
859 | 1068 | err = -ENOMEM; |
---|
860 | 1069 | goto err_alloc_fids_bitmap; |
---|
.. | .. |
---|
871 | 1080 | return 0; |
---|
872 | 1081 | |
---|
873 | 1082 | err_fid_flood_tables_init: |
---|
874 | | - kfree(fid_family->fids_bitmap); |
---|
| 1083 | + bitmap_free(fid_family->fids_bitmap); |
---|
875 | 1084 | err_alloc_fids_bitmap: |
---|
876 | 1085 | kfree(fid_family); |
---|
877 | 1086 | return err; |
---|
.. | .. |
---|
882 | 1091 | struct mlxsw_sp_fid_family *fid_family) |
---|
883 | 1092 | { |
---|
884 | 1093 | mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; |
---|
885 | | - kfree(fid_family->fids_bitmap); |
---|
| 1094 | + bitmap_free(fid_family->fids_bitmap); |
---|
886 | 1095 | WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); |
---|
887 | 1096 | kfree(fid_family); |
---|
888 | 1097 | } |
---|
.. | .. |
---|
918 | 1127 | return -ENOMEM; |
---|
919 | 1128 | mlxsw_sp->fid_core = fid_core; |
---|
920 | 1129 | |
---|
| 1130 | + err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params); |
---|
| 1131 | + if (err) |
---|
| 1132 | + goto err_rhashtable_fid_init; |
---|
| 1133 | + |
---|
| 1134 | + err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params); |
---|
| 1135 | + if (err) |
---|
| 1136 | + goto err_rhashtable_vni_init; |
---|
| 1137 | + |
---|
921 | 1138 | fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), |
---|
922 | 1139 | GFP_KERNEL); |
---|
923 | 1140 | if (!fid_core->port_fid_mappings) { |
---|
.. | .. |
---|
944 | 1161 | } |
---|
945 | 1162 | kfree(fid_core->port_fid_mappings); |
---|
946 | 1163 | err_alloc_port_fid_mappings: |
---|
| 1164 | + rhashtable_destroy(&fid_core->vni_ht); |
---|
| 1165 | +err_rhashtable_vni_init: |
---|
| 1166 | + rhashtable_destroy(&fid_core->fid_ht); |
---|
| 1167 | +err_rhashtable_fid_init: |
---|
947 | 1168 | kfree(fid_core); |
---|
948 | 1169 | return err; |
---|
949 | 1170 | } |
---|
.. | .. |
---|
957 | 1178 | mlxsw_sp_fid_family_unregister(mlxsw_sp, |
---|
958 | 1179 | fid_core->fid_family_arr[i]); |
---|
959 | 1180 | kfree(fid_core->port_fid_mappings); |
---|
| 1181 | + rhashtable_destroy(&fid_core->vni_ht); |
---|
| 1182 | + rhashtable_destroy(&fid_core->fid_ht); |
---|
960 | 1183 | kfree(fid_core); |
---|
961 | 1184 | } |
---|