Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
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     /* If this is a new record and not the first one, then we need to
0457      * update the next pointer of the previous entry
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     /* When the record continues to exist we only need to invalidate
0487      * the requested entry
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     /* If the record needs to be deleted, but it is not the first,
0496      * then we need to make sure that the previous record no longer
0497      * points to it. Remove deleted record from the list to reflect
0498      * that and then re-add it at the end, so that it could be
0499      * properly removed by the record destruction code
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     /* If the first record needs to be deleted, but the list is not
0513      * singular, then the second record needs to be written in the
0514      * first record's address, as this address is stored as a property
0515      * of the FID
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     /* This is the last case where the last remaining record needs to
0529      * be deleted. Simply delete the entry
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     /* The address of the first record in the list is a property of
0601      * the FID and we never change it. It only needs to be set when
0602      * a new list is created
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     /* The address of the first record needs to be invalidated only when
0620      * the last record is about to be removed
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     /* Iterate over inner ECN values */
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     /* Iterate over inner ECN values */
1074     for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
1075         int j;
1076 
1077         /* Iterate over outer ECN values */
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 }