LCOV - code coverage report
Current view: top level - vnet/dpo - dpo.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 194 235 82.6 %
Date: 2023-10-26 01:39:38 Functions: 27 30 90.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /**
      16             :  * @brief
      17             :  * A Data-Path Object is an object that represents actions that are
      18             :  * applied to packets are they are switched through VPP.
      19             :  *
      20             :  * The DPO is a base class that is specialised by other objects to provide
      21             :  * concrete actions
      22             :  *
      23             :  * The VLIB graph nodes are graph of types, the DPO graph is a graph of instances.
      24             :  */
      25             : 
      26             : // clang-format off
      27             : 
      28             : #include <vnet/dpo/dpo.h>
      29             : #include <vnet/ip/lookup.h>
      30             : #include <vnet/ip/format.h>
      31             : #include <vnet/adj/adj.h>
      32             : 
      33             : #include <vnet/dpo/load_balance.h>
      34             : #include <vnet/dpo/mpls_label_dpo.h>
      35             : #include <vnet/dpo/lookup_dpo.h>
      36             : #include <vnet/dpo/drop_dpo.h>
      37             : #include <vnet/dpo/receive_dpo.h>
      38             : #include <vnet/dpo/punt_dpo.h>
      39             : #include <vnet/dpo/classify_dpo.h>
      40             : #include <vnet/dpo/ip_null_dpo.h>
      41             : #include <vnet/dpo/replicate_dpo.h>
      42             : #include <vnet/dpo/interface_rx_dpo.h>
      43             : #include <vnet/dpo/interface_tx_dpo.h>
      44             : #include <vnet/dpo/mpls_disposition.h>
      45             : #include <vnet/dpo/dvr_dpo.h>
      46             : #include <vnet/dpo/l3_proxy_dpo.h>
      47             : #include <vnet/dpo/ip6_ll_dpo.h>
      48             : #include <vnet/dpo/pw_cw.h>
      49             : 
      50             : /**
      51             :  * Array of char* names for the DPO types and protos
      52             :  */
      53             : static const char* dpo_type_names[] = DPO_TYPES;
      54             : static const char* dpo_proto_names[] = DPO_PROTOS;
      55             : 
      56             : /**
      57             :  * @brief Vector of virtual function tables for the DPO types
      58             :  *
      59             :  * This is a vector so we can dynamically register new DPO types in plugins.
      60             :  */
      61             : static dpo_vft_t *dpo_vfts;
      62             : 
      63             : /**
      64             :  * @brief vector of graph node names associated with each DPO type and protocol.
      65             :  *
      66             :  *   dpo_nodes[child_type][child_proto][node_X] = node_name;
      67             :  * i.e.
      68             :  *   dpo_node[DPO_LOAD_BALANCE][DPO_PROTO_IP4][0] = "ip4-lookup"
      69             :  *   dpo_node[DPO_LOAD_BALANCE][DPO_PROTO_IP4][1] = "ip4-load-balance"
      70             :  *
      71             :  * This is a vector so we can dynamically register new DPO types in plugins.
      72             :  */
      73             : static const char* const * const ** dpo_nodes;
      74             : 
      75             : /**
      76             :  * @brief Vector of edge indicies from parent DPO nodes to child
      77             :  *
      78             :  * dpo_edges[child_type][child_proto][parent_type][parent_proto] = edge_index
      79             :  *
      80             :  * This array is derived at init time from the dpo_nodes above. Note that
      81             :  * the third dimension in dpo_nodes is lost, hence, the edge index from each
      82             :  * node MUST be the same.
      83             :  * Including both the child and parent protocol is required to support the
      84             :  * case where it changes as the graph is traversed, most notably when an
      85             :  * MPLS label is popped.
      86             :  *
      87             :  * Note that this array is child type specific, not child instance specific.
      88             :  */
      89             : static u32 ****dpo_edges;
      90             : 
      91             : /**
      92             :  * @brief The DPO type value that can be assigned to the next dynamic
      93             :  *        type registration.
      94             :  */
      95             : static dpo_type_t dpo_dynamic = DPO_LAST;
      96             : 
      97             : dpo_proto_t
      98       54900 : vnet_link_to_dpo_proto (vnet_link_t linkt)
      99             : {
     100       54900 :     switch (linkt)
     101             :     {
     102       20979 :     case VNET_LINK_IP6:
     103       20979 :         return (DPO_PROTO_IP6);
     104       32803 :     case VNET_LINK_IP4:
     105       32803 :         return (DPO_PROTO_IP4);
     106        1006 :     case VNET_LINK_MPLS:
     107        1006 :         return (DPO_PROTO_MPLS);
     108         112 :     case VNET_LINK_ETHERNET:
     109         112 :         return (DPO_PROTO_ETHERNET);
     110           0 :     case VNET_LINK_NSH:
     111           0 :         return (DPO_PROTO_NSH);
     112           0 :     case VNET_LINK_ARP:
     113           0 :         break;
     114             :     }
     115           0 :     ASSERT(0);
     116           0 :     return (0);
     117             : }
     118             : 
     119             : vnet_link_t
     120       52965 : dpo_proto_to_link (dpo_proto_t dp)
     121             : {
     122       52965 :     switch (dp)
     123             :     {
     124       20712 :     case DPO_PROTO_IP6:
     125       20712 :         return (VNET_LINK_IP6);
     126       32253 :     case DPO_PROTO_IP4:
     127       32253 :         return (VNET_LINK_IP4);
     128           0 :     case DPO_PROTO_MPLS:
     129             :     case DPO_PROTO_BIER:
     130           0 :         return (VNET_LINK_MPLS);
     131           0 :     case DPO_PROTO_ETHERNET:
     132           0 :         return (VNET_LINK_ETHERNET);
     133           0 :     case DPO_PROTO_NSH:
     134           0 :         return (VNET_LINK_NSH);
     135             :     }
     136           0 :     return (~0);
     137             : }
     138             : 
     139             : u8 *
     140       10157 : format_dpo_type (u8 * s, va_list * args)
     141             : {
     142       10157 :     dpo_type_t type = va_arg (*args, int);
     143             : 
     144       10157 :     s = format(s, "%s", dpo_type_names[type]);
     145             : 
     146       10157 :     return (s);
     147             : }
     148             : 
     149             : u8 *
     150       69872 : format_dpo_id (u8 * s, va_list * args)
     151             : {
     152       69872 :     dpo_id_t *dpo = va_arg (*args, dpo_id_t*);
     153       69872 :     u32 indent = va_arg (*args, u32);
     154             : 
     155       69872 :     s = format(s, "[@%d]: ", dpo->dpoi_next_node);
     156             : 
     157       69872 :     if (NULL != dpo_vfts[dpo->dpoi_type].dv_format)
     158             :     {
     159       69872 :         s = format(s, "%U",
     160       69872 :                    dpo_vfts[dpo->dpoi_type].dv_format,
     161             :                    dpo->dpoi_index,
     162             :                    indent);
     163             :     }
     164             :     else
     165             :     {
     166           0 :         switch (dpo->dpoi_type)
     167             :         {
     168           0 :         case DPO_FIRST:
     169           0 :             s = format(s, "unset");
     170           0 :             break;
     171           0 :         default:
     172           0 :             s = format(s, "unknown");
     173           0 :             break;
     174             :         }
     175             :     }
     176       69872 :     return (s);
     177             : }
     178             : 
     179             : u8 *
     180       23901 : format_dpo_proto (u8 * s, va_list * args)
     181             : {
     182       23901 :     dpo_proto_t proto = va_arg (*args, int);
     183             : 
     184       23901 :     return (format(s, "%s", dpo_proto_names[proto]));
     185             : }
     186             : 
     187             : void
     188     1285000 : dpo_set (dpo_id_t *dpo,
     189             :          dpo_type_t type,
     190             :          dpo_proto_t proto,
     191             :          index_t index)
     192             : {
     193     1285000 :     dpo_id_t tmp = *dpo;
     194             : 
     195     1285000 :     dpo->dpoi_type = type;
     196     1285000 :     dpo->dpoi_proto = proto,
     197     1285000 :     dpo->dpoi_index = index;
     198             : 
     199     1285000 :     if (DPO_ADJACENCY == type)
     200             :     {
     201             :         /*
     202             :          * set the adj subtype
     203             :          */
     204             :         ip_adjacency_t *adj;
     205             : 
     206       21841 :         adj = adj_get(index);
     207             : 
     208       21841 :         switch (adj->lookup_next_index)
     209             :         {
     210        6059 :         case IP_LOOKUP_NEXT_ARP:
     211        6059 :             dpo->dpoi_type = DPO_ADJACENCY_INCOMPLETE;
     212        6059 :             break;
     213        1492 :         case IP_LOOKUP_NEXT_MIDCHAIN:
     214        1492 :             dpo->dpoi_type = DPO_ADJACENCY_MIDCHAIN;
     215        1492 :             break;
     216           0 :         case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     217           0 :             dpo->dpoi_type = DPO_ADJACENCY_MCAST_MIDCHAIN;
     218           0 :             break;
     219        3078 :         case IP_LOOKUP_NEXT_MCAST:
     220        3078 :             dpo->dpoi_type = DPO_ADJACENCY_MCAST;
     221        3078 :             break;
     222           0 :         case IP_LOOKUP_NEXT_GLEAN:
     223           0 :             dpo->dpoi_type = DPO_ADJACENCY_GLEAN;
     224           0 :             break;
     225       11212 :         default:
     226       11212 :             break;
     227             :         }
     228     1263160 :     }
     229     1285000 :     dpo_lock(dpo);
     230     1285000 :     dpo_unlock(&tmp);
     231     1285000 : }
     232             : 
     233             : void
     234     1884900 : dpo_reset (dpo_id_t *dpo)
     235             : {
     236     1884900 :     dpo_id_t tmp = DPO_INVALID;
     237             : 
     238             :     /*
     239             :      * use the atomic copy operation.
     240             :      */
     241     1884900 :     dpo_copy(dpo, &tmp);
     242     1884900 : }
     243             : 
     244             : /**
     245             :  * \brief
     246             :  * Compare two Data-path objects
     247             :  *
     248             :  * like memcmp, return 0 is matching, !0 otherwise.
     249             :  */
     250             : int
     251          55 : dpo_cmp (const dpo_id_t *dpo1,
     252             :          const dpo_id_t *dpo2)
     253             : {
     254             :     int res;
     255             : 
     256          55 :     res = dpo1->dpoi_type - dpo2->dpoi_type;
     257             : 
     258          55 :     if (0 != res) return (res);
     259             : 
     260          49 :     return (dpo1->dpoi_index - dpo2->dpoi_index);
     261             : }
     262             : 
     263             : void
     264     4737100 : dpo_copy (dpo_id_t *dst,
     265             :           const dpo_id_t *src)
     266             : {
     267     4737100 :     dpo_id_t tmp = {
     268     4737100 :         .as_u64 = dst->as_u64
     269             :     };
     270             : 
     271             :     /*
     272             :      * the destination is written in a single u64 write - hence atomically w.r.t
     273             :      * any packets inflight.
     274             :      */
     275     4737100 :     dst->as_u64 = src->as_u64;
     276             : 
     277     4737100 :     dpo_lock(dst);
     278     4737100 :     dpo_unlock(&tmp);
     279     4737100 : }
     280             : 
     281             : int
     282      177770 : dpo_is_adj (const dpo_id_t *dpo)
     283             : {
     284      326851 :     return ((dpo->dpoi_type == DPO_ADJACENCY) ||
     285      149081 :             (dpo->dpoi_type == DPO_ADJACENCY_INCOMPLETE) ||
     286      132306 :             (dpo->dpoi_type == DPO_ADJACENCY_GLEAN) ||
     287       20695 :             (dpo->dpoi_type == DPO_ADJACENCY_MCAST) ||
     288       20695 :             (dpo->dpoi_type == DPO_ADJACENCY_MCAST_MIDCHAIN) ||
     289      342333 :             (dpo->dpoi_type == DPO_ADJACENCY_MIDCHAIN) ||
     290       15482 :             (dpo->dpoi_type == DPO_ADJACENCY_GLEAN));
     291             : }
     292             : 
     293             : static u32 *
     294     1066670 : dpo_default_get_next_node (const dpo_id_t *dpo)
     295             : {
     296     1066670 :     u32 *node_indices = NULL;
     297             :     const char *node_name;
     298     1066670 :     u32 ii = 0;
     299             : 
     300     1066670 :     node_name = dpo_nodes[dpo->dpoi_type][dpo->dpoi_proto][ii];
     301     2133340 :     while (NULL != node_name)
     302             :     {
     303             :         vlib_node_t *node;
     304             : 
     305     1066670 :         node = vlib_get_node_by_name(vlib_get_main(), (u8*) node_name);
     306     1066670 :         ASSERT(NULL != node);
     307     1066670 :         vec_add1(node_indices, node->index);
     308             : 
     309     1066670 :         ++ii;
     310     1066670 :         node_name = dpo_nodes[dpo->dpoi_type][dpo->dpoi_proto][ii];
     311             :     }
     312             : 
     313     1066670 :     return (node_indices);
     314             : }
     315             : 
     316             : /**
     317             :  * A default variant of the make interpose function that just returns
     318             :  * the original
     319             :  */
     320             : static void
     321           0 : dpo_default_mk_interpose (const dpo_id_t *original,
     322             :                           const dpo_id_t *parent,
     323             :                           dpo_id_t *clone)
     324             : {
     325           0 :     dpo_copy(clone, original);
     326           0 : }
     327             : 
     328             : void
     329       41975 : dpo_register (dpo_type_t type,
     330             :               const dpo_vft_t *vft,
     331             :               const char * const * const * nodes)
     332             : {
     333       41975 :     vec_validate(dpo_vfts, type);
     334       41975 :     dpo_vfts[type] = *vft;
     335       41975 :     if (NULL == dpo_vfts[type].dv_get_next_node)
     336             :     {
     337       41400 :         dpo_vfts[type].dv_get_next_node = dpo_default_get_next_node;
     338             :     }
     339       41975 :     if (NULL == dpo_vfts[type].dv_mk_interpose)
     340             :     {
     341       38525 :         dpo_vfts[type].dv_mk_interpose = dpo_default_mk_interpose;
     342             :     }
     343             : 
     344       41975 :     vec_validate(dpo_nodes, type);
     345       41975 :     dpo_nodes[type] = nodes;
     346       41975 : }
     347             : 
     348             : dpo_type_t
     349       25300 : dpo_register_new_type (const dpo_vft_t *vft,
     350             :                        const char * const * const * nodes)
     351             : {
     352       25300 :     dpo_type_t type = dpo_dynamic++;
     353             : 
     354       25300 :     dpo_register(type, vft, nodes);
     355             : 
     356       25300 :     return (type);
     357             : }
     358             : 
     359             : void
     360          47 : dpo_mk_interpose (const dpo_id_t *original,
     361             :                   const dpo_id_t *parent,
     362             :                   dpo_id_t *clone)
     363             : {
     364          47 :     if (!dpo_id_is_valid(original))
     365           0 :         return;
     366             : 
     367          47 :     dpo_vfts[original->dpoi_type].dv_mk_interpose(original, parent, clone);
     368             : }
     369             : 
     370             : void
     371     6022100 : dpo_lock (dpo_id_t *dpo)
     372             : {
     373     6022100 :     if (!dpo_id_is_valid(dpo))
     374     1896480 :         return;
     375             : 
     376     4125620 :     dpo_vfts[dpo->dpoi_type].dv_lock(dpo);
     377             : }
     378             : 
     379             : void
     380     6040410 : dpo_unlock (dpo_id_t *dpo)
     381             : {
     382     6040410 :     if (!dpo_id_is_valid(dpo))
     383     3024860 :         return;
     384             : 
     385     3015550 :     dpo_vfts[dpo->dpoi_type].dv_unlock(dpo);
     386             : }
     387             : 
     388             : u32
     389       25124 : dpo_get_urpf(const dpo_id_t *dpo)
     390             : {
     391       25124 :     if (dpo_id_is_valid(dpo) &&
     392       25124 :         (NULL != dpo_vfts[dpo->dpoi_type].dv_get_urpf))
     393             :     {
     394          16 :         return (dpo_vfts[dpo->dpoi_type].dv_get_urpf(dpo));
     395             :     }
     396             : 
     397       25108 :     return (~0);
     398             : }
     399             : 
     400             : u16
     401          14 : dpo_get_mtu(const dpo_id_t *dpo)
     402             : {
     403          14 :     if (dpo_id_is_valid(dpo) &&
     404          14 :         (NULL != dpo_vfts[dpo->dpoi_type].dv_get_mtu))
     405             :     {
     406          14 :         return (dpo_vfts[dpo->dpoi_type].dv_get_mtu(dpo));
     407             :     }
     408             : 
     409           0 :     return (0xffff);
     410             : }
     411             : 
     412             : static u32
     413      211175 : dpo_get_next_node (dpo_type_t child_type,
     414             :                    dpo_proto_t child_proto,
     415             :                    const dpo_id_t *parent_dpo)
     416             : {
     417             :     dpo_proto_t parent_proto;
     418             :     dpo_type_t parent_type;
     419             : 
     420      211175 :     parent_type = parent_dpo->dpoi_type;
     421      211175 :     parent_proto = parent_dpo->dpoi_proto;
     422             : 
     423      211175 :     vec_validate(dpo_edges, child_type);
     424      211175 :     vec_validate(dpo_edges[child_type], child_proto);
     425      211175 :     vec_validate(dpo_edges[child_type][child_proto], parent_type);
     426      226904 :     vec_validate_init_empty(
     427             :         dpo_edges[child_type][child_proto][parent_type],
     428             :         parent_proto, ~0);
     429             : 
     430             :     /*
     431             :      * if the edge index has not yet been created for this node to node transition
     432             :      */
     433      211175 :     if (~0 == dpo_edges[child_type][child_proto][parent_type][parent_proto])
     434             :     {
     435             :         vlib_node_t *child_node;
     436             :         u32 *parent_indices;
     437             :         vlib_main_t *vm;
     438             :         u32 edge, *pi, cc;
     439             : 
     440        9269 :         vm = vlib_get_main();
     441             : 
     442        9269 :         ASSERT(NULL != dpo_vfts[parent_type].dv_get_next_node);
     443        9269 :         ASSERT(NULL != dpo_nodes[child_type]);
     444        9269 :         ASSERT(NULL != dpo_nodes[child_type][child_proto]);
     445             : 
     446        9269 :         cc = 0;
     447        9269 :         parent_indices = dpo_vfts[parent_type].dv_get_next_node(parent_dpo);
     448             : 
     449        9269 :         vlib_worker_thread_barrier_sync(vm);
     450             : 
     451             :         /*
     452             :          * create a graph arc from each of the child's registered node types,
     453             :          * to each of the parent's.
     454             :          */
     455       18538 :         while (NULL != dpo_nodes[child_type][child_proto][cc])
     456             :         {
     457             :             child_node =
     458        9269 :                 vlib_get_node_by_name(vm,
     459        9269 :                                       (u8*) dpo_nodes[child_type][child_proto][cc]);
     460             : 
     461       18538 :             vec_foreach(pi, parent_indices)
     462             :             {
     463        9269 :                 edge = vlib_node_add_next(vm, child_node->index, *pi);
     464             : 
     465        9269 :                 if (~0 == dpo_edges[child_type][child_proto][parent_type][parent_proto])
     466             :                 {
     467        9269 :                     dpo_edges[child_type][child_proto][parent_type][parent_proto] = edge;
     468             :                 }
     469             :                 else
     470             :                 {
     471           0 :                     ASSERT(dpo_edges[child_type][child_proto][parent_type][parent_proto] == edge);
     472             :                 }
     473             :             }
     474        9269 :             cc++;
     475             :         }
     476             : 
     477        9269 :         vlib_worker_thread_barrier_release(vm);
     478        9269 :         vec_free(parent_indices);
     479             :     }
     480             : 
     481      211175 :     return (dpo_edges[child_type][child_proto][parent_type][parent_proto]);
     482             : }
     483             : 
     484             : /**
     485             :  * @brief return already stacked up next node index for a given
     486             :  * child_type/child_proto and parent_type/patent_proto.
     487             :  * The VLIB graph arc used is taken from the parent and child types
     488             :  * passed.
     489             :  */
     490             : u32
     491           0 : dpo_get_next_node_by_type_and_proto (dpo_type_t   child_type,
     492             :                                      dpo_proto_t  child_proto,
     493             :                                      dpo_type_t   parent_type,
     494             :                                      dpo_proto_t  parent_proto)
     495             : {
     496           0 :    return (dpo_edges[child_type][child_proto][parent_type][parent_proto]);
     497             : }
     498             : 
     499             : /**
     500             :  * @brief Stack one DPO object on another, and thus establish a child parent
     501             :  * relationship. The VLIB graph arc used is taken from the parent and child types
     502             :  * passed.
     503             :  */
     504             : static void
     505     1268580 : dpo_stack_i (u32 edge,
     506             :              dpo_id_t *dpo,
     507             :              const dpo_id_t *parent)
     508             : {
     509             :     /*
     510             :      * in order to get an atomic update of the parent we create a temporary,
     511             :      * from a copy of the child, and add the next_node. then we copy to the parent
     512             :      */
     513     1268580 :     dpo_id_t tmp = DPO_INVALID;
     514     1268580 :     dpo_copy(&tmp, parent);
     515             : 
     516             :     /*
     517             :      * get the edge index for the parent to child VLIB graph transition
     518             :      */
     519     1268580 :     tmp.dpoi_next_node = edge;
     520             : 
     521             :     /*
     522             :      * this update is atomic.
     523             :      */
     524     1268580 :     dpo_copy(dpo, &tmp);
     525             : 
     526     1268580 :     dpo_reset(&tmp);
     527     1268580 : }
     528             : 
     529             : /**
     530             :  * @brief Stack one DPO object on another, and thus establish a child-parent
     531             :  * relationship. The VLIB graph arc used is taken from the parent and child types
     532             :  * passed.
     533             :  */
     534             : void
     535      211175 : dpo_stack (dpo_type_t child_type,
     536             :            dpo_proto_t child_proto,
     537             :            dpo_id_t *dpo,
     538             :            const dpo_id_t *parent)
     539             : {
     540      211175 :     dpo_stack_i(dpo_get_next_node(child_type, child_proto, parent), dpo, parent);
     541      211175 : }
     542             : 
     543             : /**
     544             :  * @brief Stack one DPO object on another, and thus establish a child parent
     545             :  * relationship. A new VLIB graph arc is created from the child node passed
     546             :  * to the nodes registered by the parent. The VLIB infra will ensure this arc
     547             :  * is added only once.
     548             :  */
     549             : void
     550     1057410 : dpo_stack_from_node (u32 child_node_index,
     551             :                      dpo_id_t *dpo,
     552             :                      const dpo_id_t *parent)
     553             : {
     554             :     dpo_type_t parent_type;
     555             :     u32 *parent_indices;
     556             :     vlib_main_t *vm;
     557             :     u32 edge, *pi;
     558             : 
     559     1057410 :     edge = 0;
     560     1057410 :     parent_type = parent->dpoi_type;
     561     1057410 :     vm = vlib_get_main();
     562             : 
     563     1057410 :     ASSERT(NULL != dpo_vfts[parent_type].dv_get_next_node);
     564     1057410 :     parent_indices = dpo_vfts[parent_type].dv_get_next_node(parent);
     565     1057410 :     ASSERT(parent_indices);
     566             : 
     567             :     /*
     568             :      * This loop is purposefully written with the worker thread lock in the
     569             :      * inner loop because;
     570             :      *  1) the likelihood that the edge does not exist is smaller
     571             :      *  2) the likelihood there is more than one node is even smaller
     572             :      * so we are optimising for not need to take the lock
     573             :      */
     574     2114820 :     vec_foreach(pi, parent_indices)
     575             :     {
     576     1057410 :         edge = vlib_node_get_next(vm, child_node_index, *pi);
     577             : 
     578     1057410 :         if (~0 == edge)
     579             :         {
     580         599 :             vlib_worker_thread_barrier_sync(vm);
     581             : 
     582         599 :             edge = vlib_node_add_next(vm, child_node_index, *pi);
     583             : 
     584         599 :             vlib_worker_thread_barrier_release(vm);
     585             :         }
     586             :     }
     587     1057410 :     dpo_stack_i(edge, dpo, parent);
     588             : 
     589             :     /* should free this local vector to avoid memory leak */
     590     1057410 :     vec_free(parent_indices);
     591     1057410 : }
     592             : 
     593             : static clib_error_t *
     594         575 : dpo_module_init (vlib_main_t * vm)
     595             : {
     596         575 :     drop_dpo_module_init();
     597         575 :     punt_dpo_module_init();
     598         575 :     receive_dpo_module_init();
     599         575 :     load_balance_module_init();
     600         575 :     mpls_label_dpo_module_init();
     601         575 :     classify_dpo_module_init();
     602         575 :     lookup_dpo_module_init();
     603         575 :     ip_null_dpo_module_init();
     604         575 :     ip6_ll_dpo_module_init();
     605         575 :     replicate_module_init();
     606         575 :     interface_rx_dpo_module_init();
     607         575 :     interface_tx_dpo_module_init();
     608         575 :     mpls_disp_dpo_module_init();
     609         575 :     dvr_dpo_module_init();
     610         575 :     l3_proxy_dpo_module_init();
     611         575 :     pw_cw_dpo_module_init();
     612             : 
     613         575 :     return (NULL);
     614             : }
     615             : 
     616             : /* *INDENT-OFF* */
     617       13247 : VLIB_INIT_FUNCTION(dpo_module_init) =
     618             : {
     619             :     .runs_before = VLIB_INITS ("ip_main_init"),
     620             : };
     621             : /* *INDENT-ON* */
     622             : 
     623             : static clib_error_t *
     624           0 : dpo_memory_show (vlib_main_t * vm,
     625             :                  unformat_input_t * input,
     626             :                  vlib_cli_command_t * cmd)
     627             : {
     628             :     dpo_vft_t *vft;
     629             : 
     630           0 :     vlib_cli_output (vm, "DPO memory");
     631           0 :     vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s   totals",
     632             :                      "Name","Size", "in-use", "allocated");
     633             : 
     634           0 :     vec_foreach(vft, dpo_vfts)
     635             :     {
     636           0 :         if (NULL != vft->dv_mem_show)
     637           0 :             vft->dv_mem_show();
     638             :     }
     639             : 
     640           0 :     return (NULL);
     641             : }
     642             : 
     643             : /* *INDENT-OFF* */
     644             : /*?
     645             :  * The '<em>sh dpo memory </em>' command displays the memory usage for each
     646             :  * data-plane object type.
     647             :  *
     648             :  * @cliexpar
     649             :  * @cliexstart{show dpo memory}
     650             :  * DPO memory
     651             :  *             Name               Size  in-use /allocated   totals
     652             :  *         load-balance            64     12   /    12      768/768
     653             :  *           Adjacency            256      1   /    1       256/256
     654             :  *            Receive              24      5   /    5       120/120
     655             :  *            Lookup               12      0   /    0       0/0
     656             :  *           Classify              12      0   /    0       0/0
     657             :  *          MPLS label             24      0   /    0       0/0
     658             :  * @cliexend
     659             : ?*/
     660      285289 : VLIB_CLI_COMMAND (show_fib_memory, static) = {
     661             :     .path = "show dpo memory",
     662             :     .function = dpo_memory_show,
     663             :     .short_help = "show dpo memory",
     664             : };
     665             : /* *INDENT-ON* */
     666             : 
     667             : // clang-format on

Generated by: LCOV version 1.14