0001
0002
0003
0004 #include <linux/err.h>
0005 #include <linux/gfp.h>
0006 #include <linux/kernel.h>
0007 #include <linux/list.h>
0008 #include <linux/netlink.h>
0009 #include <linux/rtnetlink.h>
0010 #include <linux/slab.h>
0011 #include <net/inet_ecn.h>
0012 #include <net/ipv6.h>
0013
0014 #include "reg.h"
0015 #include "spectrum.h"
0016 #include "spectrum_nve.h"
0017
0018 const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[] = {
0019 [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp1_nve_vxlan_ops,
0020 };
0021
0022 const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[] = {
0023 [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp2_nve_vxlan_ops,
0024 };
0025
0026 struct mlxsw_sp_nve_mc_entry;
0027 struct mlxsw_sp_nve_mc_record;
0028 struct mlxsw_sp_nve_mc_list;
0029
0030 struct mlxsw_sp_nve_mc_record_ops {
0031 enum mlxsw_reg_tnumt_record_type type;
0032 int (*entry_add)(struct mlxsw_sp_nve_mc_record *mc_record,
0033 struct mlxsw_sp_nve_mc_entry *mc_entry,
0034 const union mlxsw_sp_l3addr *addr);
0035 void (*entry_del)(const struct mlxsw_sp_nve_mc_record *mc_record,
0036 const struct mlxsw_sp_nve_mc_entry *mc_entry);
0037 void (*entry_set)(const struct mlxsw_sp_nve_mc_record *mc_record,
0038 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0039 char *tnumt_pl, unsigned int entry_index);
0040 bool (*entry_compare)(const struct mlxsw_sp_nve_mc_record *mc_record,
0041 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0042 const union mlxsw_sp_l3addr *addr);
0043 };
0044
0045 struct mlxsw_sp_nve_mc_list_key {
0046 u16 fid_index;
0047 };
0048
0049 struct mlxsw_sp_nve_mc_ipv6_entry {
0050 struct in6_addr addr6;
0051 u32 addr6_kvdl_index;
0052 };
0053
0054 struct mlxsw_sp_nve_mc_entry {
0055 union {
0056 __be32 addr4;
0057 struct mlxsw_sp_nve_mc_ipv6_entry ipv6_entry;
0058 };
0059 u8 valid:1;
0060 };
0061
0062 struct mlxsw_sp_nve_mc_record {
0063 struct list_head list;
0064 enum mlxsw_sp_l3proto proto;
0065 unsigned int num_entries;
0066 struct mlxsw_sp *mlxsw_sp;
0067 struct mlxsw_sp_nve_mc_list *mc_list;
0068 const struct mlxsw_sp_nve_mc_record_ops *ops;
0069 u32 kvdl_index;
0070 struct mlxsw_sp_nve_mc_entry entries[];
0071 };
0072
0073 struct mlxsw_sp_nve_mc_list {
0074 struct list_head records_list;
0075 struct rhash_head ht_node;
0076 struct mlxsw_sp_nve_mc_list_key key;
0077 };
0078
0079 static const struct rhashtable_params mlxsw_sp_nve_mc_list_ht_params = {
0080 .key_len = sizeof(struct mlxsw_sp_nve_mc_list_key),
0081 .key_offset = offsetof(struct mlxsw_sp_nve_mc_list, key),
0082 .head_offset = offsetof(struct mlxsw_sp_nve_mc_list, ht_node),
0083 };
0084
0085 static int
0086 mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
0087 struct mlxsw_sp_nve_mc_entry *mc_entry,
0088 const union mlxsw_sp_l3addr *addr)
0089 {
0090 mc_entry->addr4 = addr->addr4;
0091
0092 return 0;
0093 }
0094
0095 static void
0096 mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
0097 const struct mlxsw_sp_nve_mc_entry *mc_entry)
0098 {
0099 }
0100
0101 static void
0102 mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
0103 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0104 char *tnumt_pl, unsigned int entry_index)
0105 {
0106 u32 udip = be32_to_cpu(mc_entry->addr4);
0107
0108 mlxsw_reg_tnumt_udip_set(tnumt_pl, entry_index, udip);
0109 }
0110
0111 static bool
0112 mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
0113 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0114 const union mlxsw_sp_l3addr *addr)
0115 {
0116 return mc_entry->addr4 == addr->addr4;
0117 }
0118
0119 static const struct mlxsw_sp_nve_mc_record_ops
0120 mlxsw_sp_nve_mc_record_ipv4_ops = {
0121 .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV4,
0122 .entry_add = &mlxsw_sp_nve_mc_record_ipv4_entry_add,
0123 .entry_del = &mlxsw_sp_nve_mc_record_ipv4_entry_del,
0124 .entry_set = &mlxsw_sp_nve_mc_record_ipv4_entry_set,
0125 .entry_compare = &mlxsw_sp_nve_mc_record_ipv4_entry_compare,
0126 };
0127
0128 static int
0129 mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
0130 struct mlxsw_sp_nve_mc_entry *mc_entry,
0131 const union mlxsw_sp_l3addr *addr)
0132 {
0133 u32 kvdl_index;
0134 int err;
0135
0136 err = mlxsw_sp_ipv6_addr_kvdl_index_get(mc_record->mlxsw_sp,
0137 &addr->addr6, &kvdl_index);
0138 if (err)
0139 return err;
0140
0141 mc_entry->ipv6_entry.addr6 = addr->addr6;
0142 mc_entry->ipv6_entry.addr6_kvdl_index = kvdl_index;
0143 return 0;
0144 }
0145
0146 static void
0147 mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
0148 const struct mlxsw_sp_nve_mc_entry *mc_entry)
0149 {
0150 mlxsw_sp_ipv6_addr_put(mc_record->mlxsw_sp,
0151 &mc_entry->ipv6_entry.addr6);
0152 }
0153
0154 static void
0155 mlxsw_sp_nve_mc_record_ipv6_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
0156 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0157 char *tnumt_pl, unsigned int entry_index)
0158 {
0159 u32 udip_ptr = mc_entry->ipv6_entry.addr6_kvdl_index;
0160
0161 mlxsw_reg_tnumt_udip_ptr_set(tnumt_pl, entry_index, udip_ptr);
0162 }
0163
0164 static bool
0165 mlxsw_sp_nve_mc_record_ipv6_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
0166 const struct mlxsw_sp_nve_mc_entry *mc_entry,
0167 const union mlxsw_sp_l3addr *addr)
0168 {
0169 return ipv6_addr_equal(&mc_entry->ipv6_entry.addr6, &addr->addr6);
0170 }
0171
0172 static const struct mlxsw_sp_nve_mc_record_ops
0173 mlxsw_sp_nve_mc_record_ipv6_ops = {
0174 .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV6,
0175 .entry_add = &mlxsw_sp_nve_mc_record_ipv6_entry_add,
0176 .entry_del = &mlxsw_sp_nve_mc_record_ipv6_entry_del,
0177 .entry_set = &mlxsw_sp_nve_mc_record_ipv6_entry_set,
0178 .entry_compare = &mlxsw_sp_nve_mc_record_ipv6_entry_compare,
0179 };
0180
0181 static const struct mlxsw_sp_nve_mc_record_ops *
0182 mlxsw_sp_nve_mc_record_ops_arr[] = {
0183 [MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_nve_mc_record_ipv4_ops,
0184 [MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_nve_mc_record_ipv6_ops,
0185 };
0186
0187 int mlxsw_sp_nve_learned_ip_resolve(struct mlxsw_sp *mlxsw_sp, u32 uip,
0188 enum mlxsw_sp_l3proto proto,
0189 union mlxsw_sp_l3addr *addr)
0190 {
0191 switch (proto) {
0192 case MLXSW_SP_L3_PROTO_IPV4:
0193 addr->addr4 = cpu_to_be32(uip);
0194 return 0;
0195 default:
0196 WARN_ON(1);
0197 return -EINVAL;
0198 }
0199 }
0200
0201 static struct mlxsw_sp_nve_mc_list *
0202 mlxsw_sp_nve_mc_list_find(struct mlxsw_sp *mlxsw_sp,
0203 const struct mlxsw_sp_nve_mc_list_key *key)
0204 {
0205 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0206
0207 return rhashtable_lookup_fast(&nve->mc_list_ht, key,
0208 mlxsw_sp_nve_mc_list_ht_params);
0209 }
0210
0211 static struct mlxsw_sp_nve_mc_list *
0212 mlxsw_sp_nve_mc_list_create(struct mlxsw_sp *mlxsw_sp,
0213 const struct mlxsw_sp_nve_mc_list_key *key)
0214 {
0215 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0216 struct mlxsw_sp_nve_mc_list *mc_list;
0217 int err;
0218
0219 mc_list = kmalloc(sizeof(*mc_list), GFP_KERNEL);
0220 if (!mc_list)
0221 return ERR_PTR(-ENOMEM);
0222
0223 INIT_LIST_HEAD(&mc_list->records_list);
0224 mc_list->key = *key;
0225
0226 err = rhashtable_insert_fast(&nve->mc_list_ht, &mc_list->ht_node,
0227 mlxsw_sp_nve_mc_list_ht_params);
0228 if (err)
0229 goto err_rhashtable_insert;
0230
0231 return mc_list;
0232
0233 err_rhashtable_insert:
0234 kfree(mc_list);
0235 return ERR_PTR(err);
0236 }
0237
0238 static void mlxsw_sp_nve_mc_list_destroy(struct mlxsw_sp *mlxsw_sp,
0239 struct mlxsw_sp_nve_mc_list *mc_list)
0240 {
0241 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0242
0243 rhashtable_remove_fast(&nve->mc_list_ht, &mc_list->ht_node,
0244 mlxsw_sp_nve_mc_list_ht_params);
0245 WARN_ON(!list_empty(&mc_list->records_list));
0246 kfree(mc_list);
0247 }
0248
0249 static struct mlxsw_sp_nve_mc_list *
0250 mlxsw_sp_nve_mc_list_get(struct mlxsw_sp *mlxsw_sp,
0251 const struct mlxsw_sp_nve_mc_list_key *key)
0252 {
0253 struct mlxsw_sp_nve_mc_list *mc_list;
0254
0255 mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, key);
0256 if (mc_list)
0257 return mc_list;
0258
0259 return mlxsw_sp_nve_mc_list_create(mlxsw_sp, key);
0260 }
0261
0262 static void
0263 mlxsw_sp_nve_mc_list_put(struct mlxsw_sp *mlxsw_sp,
0264 struct mlxsw_sp_nve_mc_list *mc_list)
0265 {
0266 if (!list_empty(&mc_list->records_list))
0267 return;
0268 mlxsw_sp_nve_mc_list_destroy(mlxsw_sp, mc_list);
0269 }
0270
0271 static struct mlxsw_sp_nve_mc_record *
0272 mlxsw_sp_nve_mc_record_create(struct mlxsw_sp *mlxsw_sp,
0273 struct mlxsw_sp_nve_mc_list *mc_list,
0274 enum mlxsw_sp_l3proto proto)
0275 {
0276 unsigned int num_max_entries = mlxsw_sp->nve->num_max_mc_entries[proto];
0277 struct mlxsw_sp_nve_mc_record *mc_record;
0278 int err;
0279
0280 mc_record = kzalloc(struct_size(mc_record, entries, num_max_entries),
0281 GFP_KERNEL);
0282 if (!mc_record)
0283 return ERR_PTR(-ENOMEM);
0284
0285 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
0286 &mc_record->kvdl_index);
0287 if (err)
0288 goto err_kvdl_alloc;
0289
0290 mc_record->ops = mlxsw_sp_nve_mc_record_ops_arr[proto];
0291 mc_record->mlxsw_sp = mlxsw_sp;
0292 mc_record->mc_list = mc_list;
0293 mc_record->proto = proto;
0294 list_add_tail(&mc_record->list, &mc_list->records_list);
0295
0296 return mc_record;
0297
0298 err_kvdl_alloc:
0299 kfree(mc_record);
0300 return ERR_PTR(err);
0301 }
0302
0303 static void
0304 mlxsw_sp_nve_mc_record_destroy(struct mlxsw_sp_nve_mc_record *mc_record)
0305 {
0306 struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
0307
0308 list_del(&mc_record->list);
0309 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
0310 mc_record->kvdl_index);
0311 WARN_ON(mc_record->num_entries);
0312 kfree(mc_record);
0313 }
0314
0315 static struct mlxsw_sp_nve_mc_record *
0316 mlxsw_sp_nve_mc_record_get(struct mlxsw_sp *mlxsw_sp,
0317 struct mlxsw_sp_nve_mc_list *mc_list,
0318 enum mlxsw_sp_l3proto proto)
0319 {
0320 struct mlxsw_sp_nve_mc_record *mc_record;
0321
0322 list_for_each_entry_reverse(mc_record, &mc_list->records_list, list) {
0323 unsigned int num_entries = mc_record->num_entries;
0324 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0325
0326 if (mc_record->proto == proto &&
0327 num_entries < nve->num_max_mc_entries[proto])
0328 return mc_record;
0329 }
0330
0331 return mlxsw_sp_nve_mc_record_create(mlxsw_sp, mc_list, proto);
0332 }
0333
0334 static void
0335 mlxsw_sp_nve_mc_record_put(struct mlxsw_sp_nve_mc_record *mc_record)
0336 {
0337 if (mc_record->num_entries != 0)
0338 return;
0339
0340 mlxsw_sp_nve_mc_record_destroy(mc_record);
0341 }
0342
0343 static struct mlxsw_sp_nve_mc_entry *
0344 mlxsw_sp_nve_mc_free_entry_find(struct mlxsw_sp_nve_mc_record *mc_record)
0345 {
0346 struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
0347 unsigned int num_max_entries;
0348 int i;
0349
0350 num_max_entries = nve->num_max_mc_entries[mc_record->proto];
0351 for (i = 0; i < num_max_entries; i++) {
0352 if (mc_record->entries[i].valid)
0353 continue;
0354 return &mc_record->entries[i];
0355 }
0356
0357 return NULL;
0358 }
0359
0360 static int
0361 mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record)
0362 {
0363 enum mlxsw_reg_tnumt_record_type type = mc_record->ops->type;
0364 struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
0365 struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
0366 char tnumt_pl[MLXSW_REG_TNUMT_LEN];
0367 unsigned int num_max_entries;
0368 unsigned int num_entries = 0;
0369 u32 next_kvdl_index = 0;
0370 bool next_valid = false;
0371 int i;
0372
0373 if (!list_is_last(&mc_record->list, &mc_list->records_list)) {
0374 struct mlxsw_sp_nve_mc_record *next_record;
0375
0376 next_record = list_next_entry(mc_record, list);
0377 next_kvdl_index = next_record->kvdl_index;
0378 next_valid = true;
0379 }
0380
0381 mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TUNNEL_PORT_NVE,
0382 mc_record->kvdl_index, next_valid,
0383 next_kvdl_index, mc_record->num_entries);
0384
0385 num_max_entries = mlxsw_sp->nve->num_max_mc_entries[mc_record->proto];
0386 for (i = 0; i < num_max_entries; i++) {
0387 struct mlxsw_sp_nve_mc_entry *mc_entry;
0388
0389 mc_entry = &mc_record->entries[i];
0390 if (!mc_entry->valid)
0391 continue;
0392 mc_record->ops->entry_set(mc_record, mc_entry, tnumt_pl,
0393 num_entries++);
0394 }
0395
0396 WARN_ON(num_entries != mc_record->num_entries);
0397
0398 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnumt), tnumt_pl);
0399 }
0400
0401 static bool
0402 mlxsw_sp_nve_mc_record_is_first(struct mlxsw_sp_nve_mc_record *mc_record)
0403 {
0404 struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
0405 struct mlxsw_sp_nve_mc_record *first_record;
0406
0407 first_record = list_first_entry(&mc_list->records_list,
0408 struct mlxsw_sp_nve_mc_record, list);
0409
0410 return mc_record == first_record;
0411 }
0412
0413 static struct mlxsw_sp_nve_mc_entry *
0414 mlxsw_sp_nve_mc_entry_find(struct mlxsw_sp_nve_mc_record *mc_record,
0415 union mlxsw_sp_l3addr *addr)
0416 {
0417 struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
0418 unsigned int num_max_entries;
0419 int i;
0420
0421 num_max_entries = nve->num_max_mc_entries[mc_record->proto];
0422 for (i = 0; i < num_max_entries; i++) {
0423 struct mlxsw_sp_nve_mc_entry *mc_entry;
0424
0425 mc_entry = &mc_record->entries[i];
0426 if (!mc_entry->valid)
0427 continue;
0428 if (mc_record->ops->entry_compare(mc_record, mc_entry, addr))
0429 return mc_entry;
0430 }
0431
0432 return NULL;
0433 }
0434
0435 static int
0436 mlxsw_sp_nve_mc_record_ip_add(struct mlxsw_sp_nve_mc_record *mc_record,
0437 union mlxsw_sp_l3addr *addr)
0438 {
0439 struct mlxsw_sp_nve_mc_entry *mc_entry = NULL;
0440 int err;
0441
0442 mc_entry = mlxsw_sp_nve_mc_free_entry_find(mc_record);
0443 if (WARN_ON(!mc_entry))
0444 return -EINVAL;
0445
0446 err = mc_record->ops->entry_add(mc_record, mc_entry, addr);
0447 if (err)
0448 return err;
0449 mc_record->num_entries++;
0450 mc_entry->valid = true;
0451
0452 err = mlxsw_sp_nve_mc_record_refresh(mc_record);
0453 if (err)
0454 goto err_record_refresh;
0455
0456
0457
0458
0459 if (mc_record->num_entries != 1 ||
0460 mlxsw_sp_nve_mc_record_is_first(mc_record))
0461 return 0;
0462
0463 err = mlxsw_sp_nve_mc_record_refresh(list_prev_entry(mc_record, list));
0464 if (err)
0465 goto err_prev_record_refresh;
0466
0467 return 0;
0468
0469 err_prev_record_refresh:
0470 err_record_refresh:
0471 mc_entry->valid = false;
0472 mc_record->num_entries--;
0473 mc_record->ops->entry_del(mc_record, mc_entry);
0474 return err;
0475 }
0476
0477 static void
0478 mlxsw_sp_nve_mc_record_entry_del(struct mlxsw_sp_nve_mc_record *mc_record,
0479 struct mlxsw_sp_nve_mc_entry *mc_entry)
0480 {
0481 struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
0482
0483 mc_entry->valid = false;
0484 mc_record->num_entries--;
0485
0486
0487
0488
0489 if (mc_record->num_entries != 0) {
0490 mlxsw_sp_nve_mc_record_refresh(mc_record);
0491 mc_record->ops->entry_del(mc_record, mc_entry);
0492 return;
0493 }
0494
0495
0496
0497
0498
0499
0500
0501 if (!mlxsw_sp_nve_mc_record_is_first(mc_record)) {
0502 struct mlxsw_sp_nve_mc_record *prev_record;
0503
0504 prev_record = list_prev_entry(mc_record, list);
0505 list_del(&mc_record->list);
0506 mlxsw_sp_nve_mc_record_refresh(prev_record);
0507 list_add_tail(&mc_record->list, &mc_list->records_list);
0508 mc_record->ops->entry_del(mc_record, mc_entry);
0509 return;
0510 }
0511
0512
0513
0514
0515
0516
0517 if (mlxsw_sp_nve_mc_record_is_first(mc_record) &&
0518 !list_is_singular(&mc_list->records_list)) {
0519 struct mlxsw_sp_nve_mc_record *next_record;
0520
0521 next_record = list_next_entry(mc_record, list);
0522 swap(mc_record->kvdl_index, next_record->kvdl_index);
0523 mlxsw_sp_nve_mc_record_refresh(next_record);
0524 mc_record->ops->entry_del(mc_record, mc_entry);
0525 return;
0526 }
0527
0528
0529
0530
0531 mc_record->ops->entry_del(mc_record, mc_entry);
0532 }
0533
0534 static struct mlxsw_sp_nve_mc_record *
0535 mlxsw_sp_nve_mc_record_find(struct mlxsw_sp_nve_mc_list *mc_list,
0536 enum mlxsw_sp_l3proto proto,
0537 union mlxsw_sp_l3addr *addr,
0538 struct mlxsw_sp_nve_mc_entry **mc_entry)
0539 {
0540 struct mlxsw_sp_nve_mc_record *mc_record;
0541
0542 list_for_each_entry(mc_record, &mc_list->records_list, list) {
0543 if (mc_record->proto != proto)
0544 continue;
0545
0546 *mc_entry = mlxsw_sp_nve_mc_entry_find(mc_record, addr);
0547 if (*mc_entry)
0548 return mc_record;
0549 }
0550
0551 return NULL;
0552 }
0553
0554 static int mlxsw_sp_nve_mc_list_ip_add(struct mlxsw_sp *mlxsw_sp,
0555 struct mlxsw_sp_nve_mc_list *mc_list,
0556 enum mlxsw_sp_l3proto proto,
0557 union mlxsw_sp_l3addr *addr)
0558 {
0559 struct mlxsw_sp_nve_mc_record *mc_record;
0560 int err;
0561
0562 mc_record = mlxsw_sp_nve_mc_record_get(mlxsw_sp, mc_list, proto);
0563 if (IS_ERR(mc_record))
0564 return PTR_ERR(mc_record);
0565
0566 err = mlxsw_sp_nve_mc_record_ip_add(mc_record, addr);
0567 if (err)
0568 goto err_ip_add;
0569
0570 return 0;
0571
0572 err_ip_add:
0573 mlxsw_sp_nve_mc_record_put(mc_record);
0574 return err;
0575 }
0576
0577 static void mlxsw_sp_nve_mc_list_ip_del(struct mlxsw_sp *mlxsw_sp,
0578 struct mlxsw_sp_nve_mc_list *mc_list,
0579 enum mlxsw_sp_l3proto proto,
0580 union mlxsw_sp_l3addr *addr)
0581 {
0582 struct mlxsw_sp_nve_mc_record *mc_record;
0583 struct mlxsw_sp_nve_mc_entry *mc_entry;
0584
0585 mc_record = mlxsw_sp_nve_mc_record_find(mc_list, proto, addr,
0586 &mc_entry);
0587 if (!mc_record)
0588 return;
0589
0590 mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
0591 mlxsw_sp_nve_mc_record_put(mc_record);
0592 }
0593
0594 static int
0595 mlxsw_sp_nve_fid_flood_index_set(struct mlxsw_sp_fid *fid,
0596 struct mlxsw_sp_nve_mc_list *mc_list)
0597 {
0598 struct mlxsw_sp_nve_mc_record *mc_record;
0599
0600
0601
0602
0603
0604 if (mlxsw_sp_fid_nve_flood_index_is_set(fid))
0605 return 0;
0606
0607 mc_record = list_first_entry(&mc_list->records_list,
0608 struct mlxsw_sp_nve_mc_record, list);
0609
0610 return mlxsw_sp_fid_nve_flood_index_set(fid, mc_record->kvdl_index);
0611 }
0612
0613 static void
0614 mlxsw_sp_nve_fid_flood_index_clear(struct mlxsw_sp_fid *fid,
0615 struct mlxsw_sp_nve_mc_list *mc_list)
0616 {
0617 struct mlxsw_sp_nve_mc_record *mc_record;
0618
0619
0620
0621
0622 if (!list_is_singular(&mc_list->records_list))
0623 return;
0624
0625 mc_record = list_first_entry(&mc_list->records_list,
0626 struct mlxsw_sp_nve_mc_record, list);
0627 if (mc_record->num_entries != 1)
0628 return;
0629
0630 return mlxsw_sp_fid_nve_flood_index_clear(fid);
0631 }
0632
0633 int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp,
0634 struct mlxsw_sp_fid *fid,
0635 enum mlxsw_sp_l3proto proto,
0636 union mlxsw_sp_l3addr *addr)
0637 {
0638 struct mlxsw_sp_nve_mc_list_key key = { 0 };
0639 struct mlxsw_sp_nve_mc_list *mc_list;
0640 int err;
0641
0642 key.fid_index = mlxsw_sp_fid_index(fid);
0643 mc_list = mlxsw_sp_nve_mc_list_get(mlxsw_sp, &key);
0644 if (IS_ERR(mc_list))
0645 return PTR_ERR(mc_list);
0646
0647 err = mlxsw_sp_nve_mc_list_ip_add(mlxsw_sp, mc_list, proto, addr);
0648 if (err)
0649 goto err_add_ip;
0650
0651 err = mlxsw_sp_nve_fid_flood_index_set(fid, mc_list);
0652 if (err)
0653 goto err_fid_flood_index_set;
0654
0655 return 0;
0656
0657 err_fid_flood_index_set:
0658 mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
0659 err_add_ip:
0660 mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
0661 return err;
0662 }
0663
0664 void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp,
0665 struct mlxsw_sp_fid *fid,
0666 enum mlxsw_sp_l3proto proto,
0667 union mlxsw_sp_l3addr *addr)
0668 {
0669 struct mlxsw_sp_nve_mc_list_key key = { 0 };
0670 struct mlxsw_sp_nve_mc_list *mc_list;
0671
0672 key.fid_index = mlxsw_sp_fid_index(fid);
0673 mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
0674 if (!mc_list)
0675 return;
0676
0677 mlxsw_sp_nve_fid_flood_index_clear(fid, mc_list);
0678 mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
0679 mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
0680 }
0681
0682 static void
0683 mlxsw_sp_nve_mc_record_delete(struct mlxsw_sp_nve_mc_record *mc_record)
0684 {
0685 struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
0686 unsigned int num_max_entries;
0687 int i;
0688
0689 num_max_entries = nve->num_max_mc_entries[mc_record->proto];
0690 for (i = 0; i < num_max_entries; i++) {
0691 struct mlxsw_sp_nve_mc_entry *mc_entry = &mc_record->entries[i];
0692
0693 if (!mc_entry->valid)
0694 continue;
0695 mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
0696 }
0697
0698 WARN_ON(mc_record->num_entries);
0699 mlxsw_sp_nve_mc_record_put(mc_record);
0700 }
0701
0702 static void mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp *mlxsw_sp,
0703 struct mlxsw_sp_fid *fid)
0704 {
0705 struct mlxsw_sp_nve_mc_record *mc_record, *tmp;
0706 struct mlxsw_sp_nve_mc_list_key key = { 0 };
0707 struct mlxsw_sp_nve_mc_list *mc_list;
0708
0709 if (!mlxsw_sp_fid_nve_flood_index_is_set(fid))
0710 return;
0711
0712 mlxsw_sp_fid_nve_flood_index_clear(fid);
0713
0714 key.fid_index = mlxsw_sp_fid_index(fid);
0715 mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
0716 if (WARN_ON(!mc_list))
0717 return;
0718
0719 list_for_each_entry_safe(mc_record, tmp, &mc_list->records_list, list)
0720 mlxsw_sp_nve_mc_record_delete(mc_record);
0721
0722 WARN_ON(!list_empty(&mc_list->records_list));
0723 mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
0724 }
0725
0726 static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp,
0727 struct mlxsw_sp_nve_config *config)
0728 {
0729 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0730 const struct mlxsw_sp_nve_ops *ops;
0731 int err;
0732
0733 if (nve->num_nve_tunnels++ != 0)
0734 return 0;
0735
0736 nve->config = *config;
0737
0738 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
0739 &nve->tunnel_index);
0740 if (err)
0741 goto err_kvdl_alloc;
0742
0743 ops = nve->nve_ops_arr[config->type];
0744 err = ops->init(nve, config);
0745 if (err)
0746 goto err_ops_init;
0747
0748 return 0;
0749
0750 err_ops_init:
0751 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
0752 nve->tunnel_index);
0753 err_kvdl_alloc:
0754 memset(&nve->config, 0, sizeof(nve->config));
0755 nve->num_nve_tunnels--;
0756 return err;
0757 }
0758
0759 static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp)
0760 {
0761 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0762 const struct mlxsw_sp_nve_ops *ops;
0763
0764 ops = nve->nve_ops_arr[nve->config.type];
0765
0766 if (mlxsw_sp->nve->num_nve_tunnels == 1) {
0767 ops->fini(nve);
0768 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
0769 nve->tunnel_index);
0770 memset(&nve->config, 0, sizeof(nve->config));
0771 }
0772 nve->num_nve_tunnels--;
0773 }
0774
0775 static void mlxsw_sp_nve_fdb_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
0776 u16 fid_index)
0777 {
0778 char sfdf_pl[MLXSW_REG_SFDF_LEN];
0779
0780 mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID);
0781 mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
0782 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
0783 }
0784
0785 static void mlxsw_sp_nve_fdb_clear_offload(struct mlxsw_sp *mlxsw_sp,
0786 const struct mlxsw_sp_fid *fid,
0787 const struct net_device *nve_dev,
0788 __be32 vni)
0789 {
0790 const struct mlxsw_sp_nve_ops *ops;
0791 enum mlxsw_sp_nve_type type;
0792
0793 if (WARN_ON(mlxsw_sp_fid_nve_type(fid, &type)))
0794 return;
0795
0796 ops = mlxsw_sp->nve->nve_ops_arr[type];
0797 ops->fdb_clear_offload(nve_dev, vni);
0798 }
0799
0800 struct mlxsw_sp_nve_ipv6_ht_key {
0801 u8 mac[ETH_ALEN];
0802 u16 fid_index;
0803 };
0804
0805 struct mlxsw_sp_nve_ipv6_ht_node {
0806 struct rhash_head ht_node;
0807 struct list_head list;
0808 struct mlxsw_sp_nve_ipv6_ht_key key;
0809 struct in6_addr addr6;
0810 };
0811
0812 static const struct rhashtable_params mlxsw_sp_nve_ipv6_ht_params = {
0813 .key_len = sizeof(struct mlxsw_sp_nve_ipv6_ht_key),
0814 .key_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, key),
0815 .head_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, ht_node),
0816 };
0817
0818 int mlxsw_sp_nve_ipv6_addr_kvdl_set(struct mlxsw_sp *mlxsw_sp,
0819 const struct in6_addr *addr6,
0820 u32 *p_kvdl_index)
0821 {
0822 return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, addr6, p_kvdl_index);
0823 }
0824
0825 void mlxsw_sp_nve_ipv6_addr_kvdl_unset(struct mlxsw_sp *mlxsw_sp,
0826 const struct in6_addr *addr6)
0827 {
0828 mlxsw_sp_ipv6_addr_put(mlxsw_sp, addr6);
0829 }
0830
0831 static struct mlxsw_sp_nve_ipv6_ht_node *
0832 mlxsw_sp_nve_ipv6_ht_node_lookup(struct mlxsw_sp *mlxsw_sp, const char *mac,
0833 u16 fid_index)
0834 {
0835 struct mlxsw_sp_nve_ipv6_ht_key key = {};
0836
0837 ether_addr_copy(key.mac, mac);
0838 key.fid_index = fid_index;
0839 return rhashtable_lookup_fast(&mlxsw_sp->nve->ipv6_ht, &key,
0840 mlxsw_sp_nve_ipv6_ht_params);
0841 }
0842
0843 static int mlxsw_sp_nve_ipv6_ht_insert(struct mlxsw_sp *mlxsw_sp,
0844 const char *mac, u16 fid_index,
0845 const struct in6_addr *addr6)
0846 {
0847 struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
0848 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0849 int err;
0850
0851 ipv6_ht_node = kzalloc(sizeof(*ipv6_ht_node), GFP_KERNEL);
0852 if (!ipv6_ht_node)
0853 return -ENOMEM;
0854
0855 ether_addr_copy(ipv6_ht_node->key.mac, mac);
0856 ipv6_ht_node->key.fid_index = fid_index;
0857 ipv6_ht_node->addr6 = *addr6;
0858
0859 err = rhashtable_insert_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
0860 mlxsw_sp_nve_ipv6_ht_params);
0861 if (err)
0862 goto err_rhashtable_insert;
0863
0864 list_add(&ipv6_ht_node->list, &nve->ipv6_addr_list);
0865
0866 return 0;
0867
0868 err_rhashtable_insert:
0869 kfree(ipv6_ht_node);
0870 return err;
0871 }
0872
0873 static void
0874 mlxsw_sp_nve_ipv6_ht_remove(struct mlxsw_sp *mlxsw_sp,
0875 struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node)
0876 {
0877 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0878
0879 list_del(&ipv6_ht_node->list);
0880 rhashtable_remove_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
0881 mlxsw_sp_nve_ipv6_ht_params);
0882 kfree(ipv6_ht_node);
0883 }
0884
0885 int
0886 mlxsw_sp_nve_ipv6_addr_map_replace(struct mlxsw_sp *mlxsw_sp, const char *mac,
0887 u16 fid_index,
0888 const struct in6_addr *new_addr6)
0889 {
0890 struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
0891
0892 ASSERT_RTNL();
0893
0894 ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
0895 fid_index);
0896 if (!ipv6_ht_node)
0897 return mlxsw_sp_nve_ipv6_ht_insert(mlxsw_sp, mac, fid_index,
0898 new_addr6);
0899
0900 mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
0901 ipv6_ht_node->addr6 = *new_addr6;
0902 return 0;
0903 }
0904
0905 void mlxsw_sp_nve_ipv6_addr_map_del(struct mlxsw_sp *mlxsw_sp, const char *mac,
0906 u16 fid_index)
0907 {
0908 struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
0909
0910 ASSERT_RTNL();
0911
0912 ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
0913 fid_index);
0914 if (WARN_ON(!ipv6_ht_node))
0915 return;
0916
0917 mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
0918 }
0919
0920 static void mlxsw_sp_nve_ipv6_addr_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
0921 u16 fid_index)
0922 {
0923 struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node, *tmp;
0924 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0925
0926 list_for_each_entry_safe(ipv6_ht_node, tmp, &nve->ipv6_addr_list,
0927 list) {
0928 if (ipv6_ht_node->key.fid_index != fid_index)
0929 continue;
0930
0931 mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
0932 mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
0933 }
0934 }
0935
0936 int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
0937 struct mlxsw_sp_nve_params *params,
0938 struct netlink_ext_ack *extack)
0939 {
0940 struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
0941 const struct mlxsw_sp_nve_ops *ops;
0942 struct mlxsw_sp_nve_config config;
0943 int err;
0944
0945 ops = nve->nve_ops_arr[params->type];
0946
0947 if (!ops->can_offload(nve, params, extack))
0948 return -EINVAL;
0949
0950 memset(&config, 0, sizeof(config));
0951 ops->nve_config(nve, params, &config);
0952 if (nve->num_nve_tunnels &&
0953 memcmp(&config, &nve->config, sizeof(config))) {
0954 NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration");
0955 return -EINVAL;
0956 }
0957
0958 err = mlxsw_sp_nve_tunnel_init(mlxsw_sp, &config);
0959 if (err) {
0960 NL_SET_ERR_MSG_MOD(extack, "Failed to initialize NVE tunnel");
0961 return err;
0962 }
0963
0964 err = mlxsw_sp_fid_vni_set(fid, params->type, params->vni,
0965 params->dev->ifindex);
0966 if (err) {
0967 NL_SET_ERR_MSG_MOD(extack, "Failed to set VNI on FID");
0968 goto err_fid_vni_set;
0969 }
0970
0971 err = ops->fdb_replay(params->dev, params->vni, extack);
0972 if (err)
0973 goto err_fdb_replay;
0974
0975 return 0;
0976
0977 err_fdb_replay:
0978 mlxsw_sp_fid_vni_clear(fid);
0979 err_fid_vni_set:
0980 mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
0981 return err;
0982 }
0983
0984 void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
0985 struct mlxsw_sp_fid *fid)
0986 {
0987 u16 fid_index = mlxsw_sp_fid_index(fid);
0988 struct net_device *nve_dev;
0989 int nve_ifindex;
0990 __be32 vni;
0991
0992 mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
0993 mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
0994 mlxsw_sp_nve_ipv6_addr_flush_by_fid(mlxsw_sp, fid_index);
0995
0996 if (WARN_ON(mlxsw_sp_fid_nve_ifindex(fid, &nve_ifindex) ||
0997 mlxsw_sp_fid_vni(fid, &vni)))
0998 goto out;
0999
1000 nve_dev = dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex);
1001 if (!nve_dev)
1002 goto out;
1003
1004 mlxsw_sp_nve_fdb_clear_offload(mlxsw_sp, fid, nve_dev, vni);
1005 mlxsw_sp_fid_fdb_clear_offload(fid, nve_dev);
1006
1007 dev_put(nve_dev);
1008
1009 out:
1010 mlxsw_sp_fid_vni_clear(fid);
1011 mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
1012 }
1013
1014 int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port)
1015 {
1016 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1017 char tnqdr_pl[MLXSW_REG_TNQDR_LEN];
1018
1019 mlxsw_reg_tnqdr_pack(tnqdr_pl, mlxsw_sp_port->local_port);
1020 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqdr), tnqdr_pl);
1021 }
1022
1023 void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1024 {
1025 }
1026
1027 static int mlxsw_sp_nve_qos_init(struct mlxsw_sp *mlxsw_sp)
1028 {
1029 char tnqcr_pl[MLXSW_REG_TNQCR_LEN];
1030
1031 mlxsw_reg_tnqcr_pack(tnqcr_pl);
1032 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqcr), tnqcr_pl);
1033 }
1034
1035 static int mlxsw_sp_nve_ecn_encap_init(struct mlxsw_sp *mlxsw_sp)
1036 {
1037 int i;
1038
1039
1040 for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
1041 u8 outer_ecn = INET_ECN_encapsulate(0, i);
1042 char tneem_pl[MLXSW_REG_TNEEM_LEN];
1043 int err;
1044
1045 mlxsw_reg_tneem_pack(tneem_pl, i, outer_ecn);
1046 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tneem),
1047 tneem_pl);
1048 if (err)
1049 return err;
1050 }
1051
1052 return 0;
1053 }
1054
1055 static int __mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp,
1056 u8 inner_ecn, u8 outer_ecn)
1057 {
1058 char tndem_pl[MLXSW_REG_TNDEM_LEN];
1059 u8 new_inner_ecn;
1060 bool trap_en;
1061
1062 new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn,
1063 &trap_en);
1064 mlxsw_reg_tndem_pack(tndem_pl, outer_ecn, inner_ecn, new_inner_ecn,
1065 trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
1066 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tndem), tndem_pl);
1067 }
1068
1069 static int mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
1070 {
1071 int i;
1072
1073
1074 for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
1075 int j;
1076
1077
1078 for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) {
1079 int err;
1080
1081 err = __mlxsw_sp_nve_ecn_decap_init(mlxsw_sp, i, j);
1082 if (err)
1083 return err;
1084 }
1085 }
1086
1087 return 0;
1088 }
1089
1090 static int mlxsw_sp_nve_ecn_init(struct mlxsw_sp *mlxsw_sp)
1091 {
1092 int err;
1093
1094 err = mlxsw_sp_nve_ecn_encap_init(mlxsw_sp);
1095 if (err)
1096 return err;
1097
1098 return mlxsw_sp_nve_ecn_decap_init(mlxsw_sp);
1099 }
1100
1101 static int mlxsw_sp_nve_resources_query(struct mlxsw_sp *mlxsw_sp)
1102 {
1103 unsigned int max;
1104
1105 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4) ||
1106 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6))
1107 return -EIO;
1108 max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4);
1109 mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV4] = max;
1110 max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6);
1111 mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV6] = max;
1112
1113 return 0;
1114 }
1115
1116 int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
1117 {
1118 struct mlxsw_sp_nve *nve;
1119 int err;
1120
1121 nve = kzalloc(sizeof(*mlxsw_sp->nve), GFP_KERNEL);
1122 if (!nve)
1123 return -ENOMEM;
1124 mlxsw_sp->nve = nve;
1125 nve->mlxsw_sp = mlxsw_sp;
1126 nve->nve_ops_arr = mlxsw_sp->nve_ops_arr;
1127
1128 err = rhashtable_init(&nve->mc_list_ht,
1129 &mlxsw_sp_nve_mc_list_ht_params);
1130 if (err)
1131 goto err_mc_rhashtable_init;
1132
1133 err = rhashtable_init(&nve->ipv6_ht, &mlxsw_sp_nve_ipv6_ht_params);
1134 if (err)
1135 goto err_ipv6_rhashtable_init;
1136
1137 INIT_LIST_HEAD(&nve->ipv6_addr_list);
1138
1139 err = mlxsw_sp_nve_qos_init(mlxsw_sp);
1140 if (err)
1141 goto err_nve_qos_init;
1142
1143 err = mlxsw_sp_nve_ecn_init(mlxsw_sp);
1144 if (err)
1145 goto err_nve_ecn_init;
1146
1147 err = mlxsw_sp_nve_resources_query(mlxsw_sp);
1148 if (err)
1149 goto err_nve_resources_query;
1150
1151 return 0;
1152
1153 err_nve_resources_query:
1154 err_nve_ecn_init:
1155 err_nve_qos_init:
1156 rhashtable_destroy(&nve->ipv6_ht);
1157 err_ipv6_rhashtable_init:
1158 rhashtable_destroy(&nve->mc_list_ht);
1159 err_mc_rhashtable_init:
1160 mlxsw_sp->nve = NULL;
1161 kfree(nve);
1162 return err;
1163 }
1164
1165 void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
1166 {
1167 WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
1168 WARN_ON(!list_empty(&mlxsw_sp->nve->ipv6_addr_list));
1169 rhashtable_destroy(&mlxsw_sp->nve->ipv6_ht);
1170 rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
1171 kfree(mlxsw_sp->nve);
1172 mlxsw_sp->nve = NULL;
1173 }