LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk/n3k - vr_dpdk_n3k_mpls.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 42 99 42.4 %
Date: 2026-08-03 02:19:58 Functions: 6 10 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* SPDX-License-Identifier: BSD-2-Clause
       2             :  * Copyright(c) HCL TECHNOLOGIES LTD
       3             :  * Submitted on behalf of a third-party: Intel Corporation, a
       4             :  * Delaware corporation, having its principal place of business
       5             :  * at 2200 Mission College Boulevard,
       6             :  * Santa Clara, California 95052, USA
       7             :  */
       8             : 
       9             : #include "vr_dpdk_n3k_mpls.h"
      10             : 
      11             : #include <assert.h>
      12             : #include <string.h>
      13             : #include <sys/queue.h>
      14             : 
      15             : #include <rte_log.h>
      16             : #include <rte_malloc.h>
      17             : #include <rte_spinlock.h>
      18             : 
      19             : #include "vr_dpdk.h"
      20             : 
      21             : enum { N3K_OFFLOAD_MPLS_LABEL_COUNT = 1 << 20 };
      22             : 
      23             : #define EMPTY_LABEL UINT32_MAX
      24             : 
      25             : struct vr_n3k_offload_mpls_entry {
      26             :     struct vr_n3k_offload_mpls value;
      27             :     STAILQ_ENTRY(vr_n3k_offload_mpls_entry) entries;
      28             : };
      29             : 
      30           8 : static bool entry_is_empty(const struct vr_n3k_offload_mpls_entry *entry) {
      31           8 :     return entry->value.label == EMPTY_LABEL;
      32             : }
      33             : 
      34             : STAILQ_HEAD(vr_n3k_nh_to_labels_list, vr_n3k_offload_mpls_entry);
      35             : 
      36             : struct vr_n3k_nh_to_labels {
      37             :     struct vr_n3k_nh_to_labels_list list;
      38             :     size_t count;
      39             : };
      40             : 
      41             : static uint32_t nexthops_count;
      42             : 
      43             : /* Invariant: !entry_is_empty(&label_to_nh[label]) iff.
      44             :  *     nh_to_labels[label_to_nh[label].value.nexthop_id].list contains &label_to_nh[label] */
      45             : static struct vr_n3k_offload_mpls_entry *label_to_nh;
      46             : static struct vr_n3k_nh_to_labels *nh_to_labels;
      47             : 
      48             : static rte_rwlock_t mpls_lock __rte_cache_aligned;
      49             : 
      50             : int
      51          12 : vr_dpdk_n3k_offload_mpls_init(uint32_t nh_count)
      52             : {
      53             :     int idx;
      54             : 
      55          12 :     rte_rwlock_init(&mpls_lock);
      56             : 
      57          12 :     label_to_nh = rte_malloc("n3k_offload_mpls",
      58             :             N3K_OFFLOAD_MPLS_LABEL_COUNT * sizeof(*label_to_nh), 0);
      59          12 :     if (label_to_nh == NULL)
      60           0 :         return -ENOMEM;
      61             : 
      62             :     /* set label_to_nh[*].value.label = EMPTY_LABEL */
      63          12 :     memset(label_to_nh, 0xff, N3K_OFFLOAD_MPLS_LABEL_COUNT * sizeof(*label_to_nh));
      64             : 
      65          12 :     nh_to_labels = rte_zmalloc(
      66             :         "n3k_offload_mpls", nh_count * sizeof(*nh_to_labels), 0);
      67          12 :     if (nh_to_labels == NULL) {
      68           0 :         rte_free(label_to_nh);
      69           0 :         return -ENOMEM;
      70             :     }
      71             : 
      72        1212 :     for (idx = 0; idx < nh_count; ++idx) {
      73        1200 :         STAILQ_INIT(&nh_to_labels[idx].list);
      74             :     }
      75             : 
      76          12 :     nexthops_count = nh_count;
      77             : 
      78          12 :     return 0;
      79             : }
      80             : 
      81             : static void
      82           4 : vr_dpdk_n3k_offload_mpls_insert(struct vr_n3k_offload_mpls mpls)
      83             : {
      84           4 :     struct vr_n3k_offload_mpls_entry *entry = &label_to_nh[mpls.label];
      85           4 :     assert(entry_is_empty(entry));
      86             : 
      87           4 :     entry->value = mpls;
      88             : 
      89           4 :     struct vr_n3k_nh_to_labels *labels = &nh_to_labels[mpls.nexthop_id];
      90           4 :     STAILQ_INSERT_HEAD(&labels->list, entry, entries);
      91           4 :     labels->count++;
      92           4 : }
      93             : 
      94             : int
      95           4 : vr_dpdk_n3k_offload_mpls_insert_copy_for_test(struct vr_n3k_offload_mpls mpls)
      96             : {
      97           4 :     if (!entry_is_empty(&label_to_nh[mpls.label]))
      98           0 :         return -EEXIST;
      99             : 
     100           4 :     rte_rwlock_write_lock(&mpls_lock);
     101           4 :     vr_dpdk_n3k_offload_mpls_insert(mpls);
     102           4 :     rte_rwlock_write_unlock(&mpls_lock);
     103             : 
     104           4 :     return 0;
     105             : }
     106             : 
     107             : /* Removes mapping, if exists.
     108             :  * @returns
     109             :  *     true if mapping existed and had been removed,
     110             :  *     false is mapping did not exist */
     111             : static bool
     112           0 : vr_dpdk_n3k_offload_mpls_remove_mapping(int label)
     113             : {
     114           0 :     struct vr_n3k_offload_mpls_entry *entry = &label_to_nh[label];
     115           0 :     if (entry_is_empty(entry)) {
     116           0 :         return false;
     117             :     }
     118             : 
     119           0 :     struct vr_n3k_nh_to_labels *labels = &nh_to_labels[entry->value.nexthop_id];
     120           0 :     STAILQ_REMOVE(&labels->list, entry, vr_n3k_offload_mpls_entry, entries);
     121           0 :     labels->count--;
     122             : 
     123           0 :     label_to_nh[label].value.label = EMPTY_LABEL;
     124             : 
     125           0 :     return true;
     126             : }
     127             : 
     128             : void
     129          12 : vr_dpdk_n3k_offload_mpls_exit(void)
     130             : {
     131          12 :     rte_free(nh_to_labels);
     132          12 :     nh_to_labels = NULL;
     133             : 
     134          12 :     rte_free(label_to_nh);
     135          12 :     label_to_nh = NULL;
     136          12 : }
     137             : 
     138             : extern int __attribute__((weak))
     139             :    vr_dpdk_n3k_offload_mpls_get_by_label(uint32_t label, struct vr_n3k_offload_mpls *);
     140             : 
     141             : int
     142           0 : vr_dpdk_n3k_offload_mpls_get_by_label(uint32_t label, struct vr_n3k_offload_mpls * out)
     143             : {
     144           0 :     if (label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
     145           0 :         return -EINVAL;
     146             : 
     147           0 :     rte_rwlock_read_lock(&mpls_lock);
     148             : 
     149           0 :     if (label_to_nh[label].value.label == EMPTY_LABEL) {
     150           0 :         rte_rwlock_read_unlock(&mpls_lock);
     151           0 :         return -ENOENT;
     152             :     }
     153           0 :     *out = label_to_nh[label].value;
     154             : 
     155           0 :     rte_rwlock_read_unlock(&mpls_lock);
     156             : 
     157           0 :     return 0;
     158             : }
     159             : 
     160             : int
     161           4 : vr_dpdk_n3k_offload_mpls_get_by_nh(uint32_t nh_id, struct vr_n3k_offload_mpls * out)
     162             : {
     163           4 :     if (nh_id >= nexthops_count)
     164           0 :         return -EINVAL;
     165             : 
     166           4 :     rte_rwlock_read_lock(&mpls_lock);
     167           4 :     struct vr_n3k_nh_to_labels *labels = &nh_to_labels[nh_id];
     168           4 :     if (labels->count == 0) {
     169           0 :         rte_rwlock_read_unlock(&mpls_lock);
     170           0 :         return -ENOENT;
     171             :     }
     172             : 
     173           4 :     if (labels->count != 1) {
     174           0 :         rte_rwlock_read_unlock(&mpls_lock);
     175           0 :         RTE_LOG(WARNING, VROUTER,
     176             :             "%s(): Multiple MPLS labels found for nh=%d\n", __func__, nh_id);
     177           0 :         return -ENOTSUP;
     178             :     }
     179             : 
     180           4 :     *out = STAILQ_FIRST(&labels->list)->value;
     181           4 :     rte_rwlock_read_unlock(&mpls_lock);
     182             : 
     183           4 :     return 0;
     184             : }
     185             : 
     186             : int
     187           0 : vr_dpdk_n3k_offload_mpls_add(struct vr_nexthop *nh, int label)
     188             : {
     189           0 :     if(nh == NULL) {
     190           0 :         RTE_LOG(DEBUG, VROUTER, "%s() called; nh=NULL\n", __func__);
     191           0 :         return -EINVAL;
     192             :     }
     193             : 
     194           0 :     RTE_LOG(
     195             :         DEBUG, VROUTER,
     196             :         "%s() called; nh=%p; nh_id=%d; nh_type=%d; label=%d;\n",
     197             :         __func__, nh, nh->nh_id, nh->nh_type, label
     198             :     );
     199             : 
     200           0 :     if (nh->nh_id >= nexthops_count)
     201           0 :         return -EINVAL;
     202             : 
     203             :     /* TODO(n3k): Handle multiple routers */
     204           0 :     if (nh->nh_rid != 0)
     205           0 :         return -EINVAL;
     206             : 
     207           0 :     if (label < 0 || label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
     208           0 :         return -EINVAL;
     209             : 
     210           0 :     rte_rwlock_write_lock(&mpls_lock);
     211             : 
     212           0 :     uint32_t old_nh_id = label_to_nh[label].value.nexthop_id;
     213           0 :     bool mapping_removed = vr_dpdk_n3k_offload_mpls_remove_mapping(label);
     214             : 
     215           0 :     vr_dpdk_n3k_offload_mpls_insert((struct vr_n3k_offload_mpls) {
     216             :             .label = label,
     217           0 :             .nexthop_id = nh->nh_id,
     218             :     });
     219             : 
     220           0 :     rte_rwlock_write_unlock(&mpls_lock);
     221             : 
     222           0 :     if (mapping_removed) {
     223           0 :         RTE_LOG(
     224             :             WARNING, VROUTER,
     225             :             "%s(): nh=%p; nh_id=%u; label=%d; "
     226             :             "WARNING, label already offloaded; previous entry: nh_id=%u;\n",
     227             :             __func__, nh, nh->nh_id, label, old_nh_id
     228             :         );
     229             :     }
     230             : 
     231           0 :     return 0;
     232             : }
     233             : 
     234             : int
     235           0 : vr_dpdk_n3k_offload_mpls_del(int label)
     236             : {
     237           0 :     RTE_LOG(DEBUG, VROUTER, "%s() called; label=%d\n", __func__, label);
     238             : 
     239           0 :     if (label < 0 || label >= N3K_OFFLOAD_MPLS_LABEL_COUNT)
     240           0 :         return -EINVAL;
     241             : 
     242           0 :     rte_rwlock_write_lock(&mpls_lock);
     243           0 :     vr_dpdk_n3k_offload_mpls_remove_mapping(label);
     244           0 :     rte_rwlock_write_unlock(&mpls_lock);
     245             : 
     246           0 :     return 0;
     247             : }

Generated by: LCOV version 1.14