LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk/n3k - vr_dpdk_n3k_config.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 54 182 29.7 %
Date: 2026-08-03 02:19:58 Functions: 8 28 28.6 %
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 <errno.h>
      10             : #include <getopt.h>
      11             : #include <stdbool.h>
      12             : #include <sys/queue.h>
      13             : 
      14             : #include <rte_eal.h>
      15             : #include <rte_dev.h>
      16             : #include <string.h>
      17             : 
      18             : #include "vr_dpdk.h"
      19             : #include "vr_dpdk_n3k_config.h"
      20             : #include "vr_dpdk_n3k_service_core.h"
      21             : 
      22             : #define VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER(match, routine)                 \
      23             :     {                                                                          \
      24             :         .match_str = (match), .handler_routine = (routine)                     \
      25             :     }
      26             : 
      27             : #define REPRESENTORS_MAX_NUMBER 2
      28             : 
      29             : struct vr_dpdk_n3k_eal_opt {
      30             :     STAILQ_ENTRY(vr_dpdk_n3k_eal_opt) next;
      31             : 
      32             :     char *opt;
      33             :     char *value;
      34             : };
      35             : 
      36             : STAILQ_HEAD(vr_dpdk_n3k_eal_opts, vr_dpdk_n3k_eal_opt);
      37             : 
      38             : struct vr_dpdk_n3k_config {
      39             :     char phy_representor_name[REPRESENTORS_MAX_NUMBER][RTE_DEV_NAME_MAX_LEN];
      40             :     size_t phy_representor_name_nbr;
      41             :     bool drop_offload_enabled;
      42             :     bool aging_service_core_enabled;
      43             :     bool force_vdpa_mapping;
      44             :     bool multihoming_enabled;
      45             :     struct vr_dpdk_n3k_eal_opts eal_opts;
      46             : };
      47             : 
      48             : struct vr_dpdk_n3k_config n3k_config = { .phy_representor_name_nbr = 0,
      49             :                                          .drop_offload_enabled = true,
      50             :                                          .aging_service_core_enabled = false,
      51             :                                          .force_vdpa_mapping = false,
      52             :                                          .multihoming_enabled = false,
      53             :                                          .eal_opts = STAILQ_HEAD_INITIALIZER(
      54             :                                            n3k_config.eal_opts) };
      55             : 
      56             : typedef int (*option_handler_t)(struct vr_dpdk_n3k_config *, size_t, char **);
      57             : 
      58             : struct vr_dpdk_n3k_option_handler {
      59             :     const char *match_str;
      60             :     option_handler_t handler_routine;
      61             : };
      62             : 
      63             : static size_t
      64           0 : get_argv_last_filled_pos(size_t argv_sz, char **argv)
      65             : {
      66           0 :     size_t last_filled_pos = 0;
      67           0 :     for (; last_filled_pos < argv_sz; ++last_filled_pos) {
      68           0 :         if (argv[last_filled_pos] == NULL) {
      69           0 :             break;
      70             :         }
      71             :     }
      72             : 
      73           0 :     return --last_filled_pos;
      74             : }
      75             : 
      76             : static size_t
      77           0 : get_n3k_eal_argc(struct vr_dpdk_n3k_config *cfg, size_t vr_eal_argc)
      78             : {
      79             :     struct vr_dpdk_n3k_eal_opt *opt;
      80           0 :     size_t n3k_eal_param_cnt = 0;
      81             : 
      82           0 :     STAILQ_FOREACH(opt, &cfg->eal_opts, next)
      83             :     {
      84           0 :         n3k_eal_param_cnt++;
      85           0 :         if (opt->value != NULL) {
      86           0 :             n3k_eal_param_cnt++;
      87             :         }
      88             :     }
      89             : 
      90           0 :     return vr_eal_argc + n3k_eal_param_cnt;
      91             : }
      92             : 
      93             : static void
      94           0 : free_eal_opts(struct vr_dpdk_n3k_config *cfg)
      95             : {
      96             :     struct vr_dpdk_n3k_eal_opt *opt;
      97             : 
      98           0 :     while (!STAILQ_EMPTY(&cfg->eal_opts)) {
      99           0 :         opt = STAILQ_FIRST(&cfg->eal_opts);
     100           0 :         STAILQ_REMOVE_HEAD(&cfg->eal_opts, next);
     101           0 :         free(opt);
     102             :     }
     103           0 : }
     104             : 
     105             : static int
     106           0 : new_eal_opt(struct vr_dpdk_n3k_config *cfg, char *opt, char *value)
     107             : {
     108           0 :     struct vr_dpdk_n3k_eal_opt *eal_opt = malloc(sizeof(*eal_opt));
     109           0 :     if (!eal_opt) {
     110           0 :         RTE_LOG(
     111             :           ERR, VROUTER, "N3K config: Allocating memory for eal opt failed\n");
     112           0 :         return -ENOMEM;
     113             :     }
     114             : 
     115           0 :     RTE_LOG(INFO,
     116             :             VROUTER,
     117             :             "Passing %s%s%s to EAL\n",
     118             :             opt,
     119             :             value == NULL ? "" : " with value: ",
     120             :             value == NULL ? "" : value);
     121             : 
     122           0 :     eal_opt->opt = opt;
     123           0 :     eal_opt->value = value;
     124             : 
     125           0 :     STAILQ_INSERT_TAIL(&cfg->eal_opts, eal_opt, next);
     126             : 
     127           0 :     return 0;
     128             : }
     129             : 
     130             : static void
     131           0 : append_opts_to_eal_args(struct vr_dpdk_n3k_config *cfg,
     132             :                         size_t arg_pos,
     133             :                         char **argv)
     134             : {
     135             :     struct vr_dpdk_n3k_eal_opt *opt;
     136             : 
     137           0 :     STAILQ_FOREACH(opt, &cfg->eal_opts, next)
     138             :     {
     139           0 :         argv[arg_pos++] = opt->opt;
     140           0 :         if (opt->value) {
     141           0 :             argv[arg_pos++] = opt->value;
     142             :         }
     143             :     }
     144           0 : }
     145             : 
     146             : static char *
     147           1 : get_provided_opt(char **argv)
     148             : {
     149           1 :     return argv[optind - 1];
     150             : }
     151             : 
     152             : static char *
     153           1 : get_provided_opt_value(size_t argc, char **argv)
     154             : {
     155           1 :     bool option_has_value = (optind < argc) && (*argv[optind] != '-');
     156             : 
     157           1 :     return option_has_value ? argv[optind++] : NULL;
     158             : }
     159             : 
     160             : static int
     161           0 : handle_opt_eal(struct vr_dpdk_n3k_config *cfg, size_t vr_argc, char **vr_argv)
     162             : {
     163           0 :     if (optind >= vr_argc) {
     164           0 :         RTE_LOG(ERR, VROUTER, "N3K Config: Expected EAL opt, got nothing\n");
     165           0 :         return -EINVAL;
     166             :     }
     167             : 
     168             :     // Skip '--eal'
     169           0 :     optind++;
     170             : 
     171           0 :     char *opt = get_provided_opt(vr_argv);
     172             : 
     173           0 :     if (*opt != '-') {
     174           0 :         RTE_LOG(ERR, VROUTER, "N3K Config: Expected EAL option, got %s\n", opt);
     175           0 :         return -EINVAL;
     176             :     }
     177             : 
     178           0 :     char *value = get_provided_opt_value(vr_argc, vr_argv);
     179             : 
     180           0 :     return new_eal_opt(cfg, opt, value);
     181             : }
     182             : 
     183             : static int
     184           0 : handle_opt_whitelist(struct vr_dpdk_n3k_config *cfg,
     185             :                      size_t vr_argc,
     186             :                      char **vr_argv)
     187             : {
     188             :     static char whitelist_eal_opt[] = "--pci-whitelist";
     189           0 :     char *value = get_provided_opt_value(vr_argc, vr_argv);
     190             : 
     191           0 :     if (!value) {
     192           0 :         RTE_LOG(ERR, VROUTER, "N3K Config: Expected whitelist parameter\n");
     193           0 :         return -EINVAL;
     194             :     }
     195             : 
     196           0 :     if (strstr(value, "insert_type=flr-sim") != NULL) {
     197           0 :         vr_dpdk_n3k_service_core_flr_sim_enable();
     198             :     }
     199             : 
     200           0 :     return new_eal_opt(cfg, whitelist_eal_opt, value);
     201             : }
     202             : 
     203             : static unsigned int
     204           2 : get_subarg_len(char *ptrStr,
     205             :                unsigned int idx)
     206             : {
     207           2 :     unsigned int i = 0;
     208           2 :     char *strTmp = NULL;
     209             : 
     210           2 :     for(i=0; ptrStr; i++) {
     211           2 :         strTmp = strstr(ptrStr, ",");
     212           2 :         if(i == idx) {
     213           1 :             if(!strTmp) return strlen(ptrStr);
     214             :             else {
     215           0 :                 return strTmp - ptrStr;
     216             :             }
     217             :         }
     218           1 :         if(!strTmp) break;
     219             : 
     220           0 :         ptrStr = strTmp + 1;
     221             :     }
     222             : 
     223           1 :     return 0;
     224             : }
     225             : 
     226             : static char*
     227           1 : get_subarg_val(char *ptrStr,
     228             :                unsigned int idx)
     229             : {
     230           1 :     unsigned int i = 0;
     231           1 :     char *strTmp = NULL;
     232             : 
     233           1 :     for(i=0; ptrStr; i++) {
     234           1 :         strTmp = strstr(ptrStr, ",");
     235           1 :         if(i == idx) {
     236           1 :             return ptrStr;
     237             :         }
     238           0 :         if(!strTmp) break;
     239             : 
     240           0 :         ptrStr = strTmp + 1;
     241             :     }
     242             : 
     243           0 :     return NULL;
     244             : }
     245             : 
     246             : static int
     247           1 : handle_opt_enable_n3k(struct vr_dpdk_n3k_config *cfg,
     248             :                       size_t vr_argc,
     249             :                       char **vr_argv)
     250             : {
     251             :     int i;
     252           1 :     unsigned int subLen = 0;
     253           1 :     char *tmpStr = get_provided_opt_value(vr_argc, vr_argv);
     254             : 
     255           1 :     if(!tmpStr) {
     256           0 :         RTE_LOG(ERR, VROUTER, "N3K Config: Missing representor name\n");
     257           0 :         return -EINVAL;
     258             :     }
     259             : 
     260           1 :     RTE_LOG(INFO, VROUTER, "N3K Config: Enabling N3K offloads\n");
     261             : 
     262           1 :     cfg->phy_representor_name_nbr = 0;
     263           2 :     for(i=0; i<REPRESENTORS_MAX_NUMBER; i++) {
     264           2 :         subLen = get_subarg_len(tmpStr, i);
     265           2 :         if(subLen) {
     266           1 :             subLen = (subLen>(RTE_DEV_NAME_MAX_LEN-1))?RTE_DEV_NAME_MAX_LEN-1:subLen;
     267           1 :             strncpy(cfg->phy_representor_name[i], get_subarg_val(tmpStr, i), subLen);
     268           1 :             cfg->phy_representor_name[i][subLen] = 0;
     269           1 :             cfg->phy_representor_name_nbr++;
     270             :         } else {
     271           1 :             break;
     272             :         }
     273           1 :         RTE_LOG(INFO, VROUTER, "N3K Config: Representor[%d]: %s\n", i, cfg->phy_representor_name[i]);
     274             :     }
     275             : 
     276           1 :     if(!strcmp("l3mh", cfg->phy_representor_name[0])) {
     277           0 :         cfg->multihoming_enabled = true;
     278           0 :         for(i=0; i<REPRESENTORS_MAX_NUMBER; i++) {
     279           0 :             snprintf(cfg->phy_representor_name[i], RTE_DEV_NAME_MAX_LEN, "net_n3k0_phy%d", i);
     280             :         }
     281           0 :         RTE_LOG(INFO, VROUTER, "N3K Config: Multihomming enabled\n");
     282             :     }
     283             : 
     284           1 :     return 0;
     285             : }
     286             : 
     287             : static int
     288           0 : handle_opt_no_drop_offload(struct vr_dpdk_n3k_config *cfg,
     289             :    __attribute__((unused)) size_t vr_argc,
     290             :    __attribute__((unused)) char **vr_argv)
     291             : {
     292           0 :     cfg->drop_offload_enabled = false;
     293             : 
     294           0 :     RTE_LOG(INFO, VROUTER, "N3K Config: Disabling drop offload\n");
     295             : 
     296           0 :     return 0;
     297             : }
     298             : 
     299             : static int
     300           0 : handle_opt_aging_lcore(struct vr_dpdk_n3k_config *cfg,
     301             :   __attribute__((unused)) size_t vr_argc,
     302             :   __attribute__((unused)) char **vr_argv)
     303             : {
     304           0 :     cfg->aging_service_core_enabled = true;
     305             : 
     306           0 :     RTE_LOG(INFO, VROUTER, "N3K Config: Enabling aging lcore\n");
     307             : 
     308           0 :     return 0;
     309             : }
     310             : 
     311             : static int
     312           0 : handle_opt_force_vdpa_mapping(struct vr_dpdk_n3k_config *cfg,
     313             :   __attribute__((unused)) size_t vr_argc,
     314             :   __attribute__((unused)) char **vr_argv)
     315             : {
     316           0 :     cfg->force_vdpa_mapping = true;
     317             : 
     318           0 :     RTE_LOG(INFO, VROUTER, "N3K Config: Forcing vDPA mapping\n");
     319             : 
     320           0 :     return 0;
     321             : }
     322             : 
     323             : struct vr_dpdk_n3k_option_handler n3k_options[] = {
     324             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--enable_n3k",
     325             :                                            handle_opt_enable_n3k),
     326             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--no_drop_offload",
     327             :                                            handle_opt_no_drop_offload),
     328             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--aging_lcore",
     329             :                                            handle_opt_aging_lcore),
     330             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--eal", handle_opt_eal),
     331             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--whitelist", handle_opt_whitelist),
     332             :     VR_DPDK_N3K_OPTION_HANDLER_INITIALIZER("--force_vdpa_mapping",
     333             :                                            handle_opt_force_vdpa_mapping),
     334             : };
     335             : 
     336             : int
     337           1 : vr_dpdk_n3k_config_parse_opt(size_t vr_argc, char **vr_argv, char vr_opt)
     338             : {
     339           1 :     struct vr_dpdk_n3k_config *cfg = &n3k_config;
     340           1 :     int i = 0;
     341           1 :     char *opt_provided = get_provided_opt(vr_argv);
     342             : 
     343           1 :     for (; i < RTE_DIM(n3k_options); ++i) {
     344           1 :         struct vr_dpdk_n3k_option_handler *curr_opt = &n3k_options[i];
     345           1 :         bool opt_matched = strcmp(opt_provided, curr_opt->match_str) == 0;
     346             : 
     347           1 :         if (opt_matched) {
     348           1 :             return curr_opt->handler_routine(cfg, vr_argc, vr_argv);
     349             :         }
     350             :     }
     351             : 
     352           0 :     return -EINVAL;
     353             : }
     354             : 
     355             : int
     356           0 : vr_dpdk_n3k_config_get_updated_eal_args(
     357             :   size_t argc,
     358             :   char **argv,
     359             :   struct vr_dpdk_n3k_config_eal_args *updated_args)
     360             : {
     361           0 :     struct vr_dpdk_n3k_config *cfg = &n3k_config;
     362           0 :     size_t vr_eal_argc = get_argv_last_filled_pos(argc, argv) + 1;
     363           0 :     size_t new_size = get_n3k_eal_argc(cfg, vr_eal_argc);
     364             :     // Freed by caller
     365           0 :     char **updated_argv = malloc(sizeof(*updated_argv) * new_size);
     366           0 :     if (!updated_argv) {
     367           0 :         RTE_LOG(ERR,
     368             :                 VROUTER,
     369             :                 "N3K config: Allocating memory for updated eal args failed\n");
     370           0 :         return -ENOMEM;
     371             :     }
     372             : 
     373           0 :     memcpy(updated_argv, argv, vr_eal_argc * sizeof(*argv));
     374             : 
     375           0 :     append_opts_to_eal_args(cfg, vr_eal_argc, updated_argv);
     376             : 
     377           0 :     updated_args->argc = new_size;
     378           0 :     updated_args->argv = updated_argv;
     379             : 
     380           0 :     return 0;
     381             : }
     382             : 
     383             : static void
     384           0 : n3k_usage(void)
     385             : {
     386           0 :     RTE_LOG(
     387             :       INFO,
     388             :       VROUTER,
     389             :       "\n"
     390             :       "    --whitelist NAME            Add pci address to a PCI whitelist\n"
     391             :       "                                To use the device in vDPA mode: "
     392             :       "--whitelist <PCI>,vdpa=1\n"
     393             :       "                                equivalent of --eal --pci-whitelist "
     394             :       "...\n"
     395             :       "    --enable_n3k NAME           Use n3k specific callbacks\n"
     396             :       "                                it is needed to specify physical "
     397             :       "representor name here\n"
     398             :       "    --no_drop_offload           Do not offload drop flows to HW\n"
     399             :       "    --aging_lcore               Enable N3000 aging lcore\n"
     400             :       "    --eal                       Options for EAL must begin with --eal "
     401             :       "opt, e.g.\n"
     402             :       "                                --eal --log-level lib.eal:8\n"
     403             :       "   --force_vdpa_mapping         Assign random n3k VF for all vifs");
     404           0 : }
     405             : 
     406             : void
     407           0 : vr_dpdk_n3k_config_print_usage(void)
     408             : {
     409           0 :     n3k_usage();
     410           0 : }
     411             : 
     412             : void
     413           0 : vr_dpdk_n3k_config_init(void)
     414             : {
     415           0 :     return;
     416             : }
     417             : 
     418             : void
     419           0 : vr_dpdk_n3k_config_exit(void)
     420             : {
     421           0 :     struct vr_dpdk_n3k_config *cfg = &n3k_config;
     422             : 
     423           0 :     free_eal_opts(cfg);
     424           0 : }
     425             : 
     426             : bool
     427           0 : vr_dpdk_n3k_config_is_aging_service_core_enabled(void)
     428             : {
     429           0 :     return n3k_config.aging_service_core_enabled;
     430             : }
     431             : 
     432             : bool
     433           2 : vr_dpdk_n3k_config_is_n3k_enabled(void)
     434             : {
     435           2 :     return n3k_config.phy_representor_name_nbr != 0;
     436             : }
     437             : 
     438             : bool
     439           0 : vr_dpdk_n3k_config_is_drop_offload_enabled(void)
     440             : {
     441           0 :     return n3k_config.drop_offload_enabled;
     442             : }
     443             : 
     444             : bool
     445           0 : vr_dpdk_n3k_config_vdpa_mapping_enabled(void)
     446             : {
     447           0 :     return n3k_config.force_vdpa_mapping;
     448             : }
     449             : 
     450           0 : static int get_mac_by_name(const char *ptr_name, struct rte_ether_addr *ptr_mac_addr)
     451             : {
     452           0 :     int rc = -1;
     453           0 :     uint16_t port_id = 0;
     454             : 
     455           0 :     rc = rte_eth_dev_get_port_by_name(ptr_name, &port_id);
     456           0 :     if (!rc) {
     457           0 :         rc = rte_eth_macaddr_get(port_id, ptr_mac_addr);
     458             :     }
     459             : 
     460           0 :     return rc;
     461             : }
     462             : 
     463           0 : static const char* get_multihoming_representor(struct vr_interface *vif)
     464             : {
     465             :     int i;
     466           0 :     const char *representor_name = NULL;
     467             :     struct rte_ether_addr mac_addr;
     468             : 
     469           0 :     if( !vif ) {
     470           0 :         return NULL;
     471             :     }
     472             : 
     473           0 :     for(i=0; i<REPRESENTORS_MAX_NUMBER; i++) {
     474           0 :         if( !get_mac_by_name(n3k_config.phy_representor_name[i], &mac_addr) ) {
     475           0 :             if(!memcmp(vif->vif_mac, mac_addr.addr_bytes, sizeof(vif->vif_mac))) {
     476           0 :                 representor_name = n3k_config.phy_representor_name[i];
     477           0 :                 RTE_LOG(INFO, VROUTER, "Vif <%s> match to representor <%s>\n", vif->vif_name, representor_name);
     478           0 :                 break;
     479             :             }
     480             :         }
     481             :     }
     482             : 
     483           0 :     return representor_name;
     484             : }
     485             : 
     486             : const char *
     487           2 : vr_dpdk_n3k_config_get_phy_repr_name(struct vr_interface *vif)
     488             : {
     489           2 :     const char *representor_name = NULL;
     490             : 
     491           2 :     if( n3k_config.multihoming_enabled ) {
     492           0 :         representor_name = get_multihoming_representor(vif);
     493             :     }
     494             :     else {
     495           2 :        representor_name = n3k_config.phy_representor_name[0];
     496             :     }
     497             : 
     498           2 :     return representor_name;
     499             : }

Generated by: LCOV version 1.14