LCOV - code coverage report
Current view: top level - vnet/dpo - mpls_disposition.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 172 177 97.2 %
Date: 2023-10-26 01:39:38 Functions: 37 50 74.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             : #include <vnet/ip/ip4_input.h>
      17             : #include <vnet/ip/ip6_input.h>
      18             : #include <vnet/dpo/mpls_disposition.h>
      19             : #include <vnet/mpls/mpls.h>
      20             : 
      21             : #ifndef CLIB_MARCH_VARIANT
      22             : /*
      23             :  * pool of all MPLS Label DPOs
      24             :  */
      25             : mpls_disp_dpo_t *mpls_disp_dpo_pool;
      26             : 
      27             : static mpls_disp_dpo_t *
      28          90 : mpls_disp_dpo_alloc (void)
      29             : {
      30             :     mpls_disp_dpo_t *mdd;
      31             : 
      32          90 :     pool_get_aligned(mpls_disp_dpo_pool, mdd, CLIB_CACHE_LINE_BYTES);
      33          90 :     clib_memset(mdd, 0, sizeof(*mdd));
      34             : 
      35          90 :     dpo_reset(&mdd->mdd_dpo);
      36             : 
      37          90 :     return (mdd);
      38             : }
      39             : 
      40             : static index_t
      41          90 : mpls_disp_dpo_get_index (mpls_disp_dpo_t *mdd)
      42             : {
      43          90 :     return (mdd - mpls_disp_dpo_pool);
      44             : }
      45             : 
      46             : void
      47          90 : mpls_disp_dpo_create (dpo_proto_t payload_proto,
      48             :                       fib_rpf_id_t rpf_id,
      49             :                       fib_mpls_lsp_mode_t mode,
      50             :                       const dpo_id_t *parent,
      51             :                       dpo_id_t *dpo)
      52             : {
      53             :     mpls_disp_dpo_t *mdd;
      54             :     dpo_type_t dtype;
      55             : 
      56          90 :     mdd = mpls_disp_dpo_alloc();
      57             : 
      58          90 :     mdd->mdd_payload_proto = payload_proto;
      59          90 :     mdd->mdd_rpf_id = rpf_id;
      60          90 :     mdd->mdd_mode = mode;
      61          90 :     dtype = (FIB_MPLS_LSP_MODE_PIPE == mode ?
      62          90 :              DPO_MPLS_DISPOSITION_PIPE :
      63             :              DPO_MPLS_DISPOSITION_UNIFORM);
      64             : 
      65             :     /*
      66             :      * stack this disposition object on the parent given
      67             :      */
      68          90 :     dpo_stack(dtype,
      69          90 :               mdd->mdd_payload_proto,
      70             :               &mdd->mdd_dpo,
      71             :               parent);
      72             : 
      73             :     /*
      74             :      * set up the return DPO to refer to this object
      75             :      */
      76          90 :     dpo_set(dpo,
      77             :             dtype,
      78             :             payload_proto,
      79             :             mpls_disp_dpo_get_index(mdd));
      80          90 : }
      81             : 
      82             : u8*
      83         865 : format_mpls_disp_dpo (u8 *s, va_list *args)
      84             : {
      85         865 :     index_t index = va_arg(*args, index_t);
      86         865 :     u32 indent = va_arg(*args, u32);
      87             :     mpls_disp_dpo_t *mdd;
      88             : 
      89         865 :     mdd = mpls_disp_dpo_get(index);
      90             : 
      91         865 :     s = format(s, "mpls-disposition:[%d]:[", index);
      92             : 
      93         865 :     if (0 != mdd->mdd_rpf_id)
      94         865 :         s = format(s, "rpf-id:%d ", mdd->mdd_rpf_id);
      95             : 
      96         865 :     s = format(s, "%U, %U]",
      97         865 :                format_dpo_proto, mdd->mdd_payload_proto,
      98         865 :                format_fib_mpls_lsp_mode, mdd->mdd_mode);
      99             : 
     100         865 :     s = format(s, "\n%U", format_white_space, indent);
     101         865 :     s = format(s, "%U", format_dpo_id, &mdd->mdd_dpo, indent+2);
     102             : 
     103         865 :     return (s);
     104             : }
     105             : 
     106             : static void
     107         318 : mpls_disp_dpo_lock (dpo_id_t *dpo)
     108             : {
     109             :     mpls_disp_dpo_t *mdd;
     110             : 
     111         318 :     mdd = mpls_disp_dpo_get(dpo->dpoi_index);
     112             : 
     113         318 :     mdd->mdd_locks++;
     114         318 : }
     115             : 
     116             : static void
     117         318 : mpls_disp_dpo_unlock (dpo_id_t *dpo)
     118             : {
     119             :     mpls_disp_dpo_t *mdd;
     120             : 
     121         318 :     mdd = mpls_disp_dpo_get(dpo->dpoi_index);
     122             : 
     123         318 :     mdd->mdd_locks--;
     124             : 
     125         318 :     if (0 == mdd->mdd_locks)
     126             :     {
     127          90 :         dpo_reset(&mdd->mdd_dpo);
     128          90 :         pool_put(mpls_disp_dpo_pool, mdd);
     129             :     }
     130         318 : }
     131             : #endif /* CLIB_MARCH_VARIANT */
     132             : 
     133             : /**
     134             :  * @brief A struct to hold tracing information for the MPLS label disposition
     135             :  * node.
     136             :  */
     137             : typedef struct mpls_label_disposition_trace_t_
     138             : {
     139             :     dpo_proto_t mddt_payload_proto;
     140             :     fib_rpf_id_t mddt_rpf_id;
     141             :     fib_mpls_lsp_mode_t mddt_mode;
     142             : } mpls_label_disposition_trace_t;
     143             : 
     144             : extern vlib_node_registration_t ip4_mpls_label_disposition_pipe_node;
     145             : extern vlib_node_registration_t ip6_mpls_label_disposition_pipe_node;
     146             : extern vlib_node_registration_t ip4_mpls_label_disposition_uniform_node;
     147             : extern vlib_node_registration_t ip6_mpls_label_disposition_uniform_node;
     148             : 
     149             : always_inline uword
     150          61 : mpls_label_disposition_inline (vlib_main_t * vm,
     151             :                                vlib_node_runtime_t * node,
     152             :                                vlib_frame_t * from_frame,
     153             :                                u8 payload_is_ip4,
     154             :                                u8 payload_is_ip6,
     155             :                                fib_mpls_lsp_mode_t mode)
     156             : {
     157             :     u32 n_left_from, next_index, * from, * to_next;
     158             :     vlib_node_runtime_t *error_node;
     159             : 
     160          61 :     if (payload_is_ip4)
     161             :     {
     162          31 :         if (FIB_MPLS_LSP_MODE_PIPE == mode)
     163             :             error_node =
     164          27 :                 vlib_node_get_runtime(vm, ip4_mpls_label_disposition_pipe_node.index);
     165             :         else
     166             :             error_node =
     167           4 :                 vlib_node_get_runtime(vm, ip4_mpls_label_disposition_uniform_node.index);
     168             :     }
     169             :     else
     170             :     {
     171          30 :         if (FIB_MPLS_LSP_MODE_PIPE == mode)
     172             :             error_node =
     173          28 :                 vlib_node_get_runtime(vm, ip6_mpls_label_disposition_pipe_node.index);
     174             :         else
     175             :             error_node =
     176           2 :                 vlib_node_get_runtime(vm, ip6_mpls_label_disposition_uniform_node.index);
     177             :     }
     178          61 :     from = vlib_frame_vector_args(from_frame);
     179          61 :     n_left_from = from_frame->n_vectors;
     180             : 
     181          61 :     next_index = node->cached_next_index;
     182             : 
     183         122 :     while (n_left_from > 0)
     184             :     {
     185             :         u32 n_left_to_next;
     186             : 
     187          61 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     188             : 
     189        3169 :         while (n_left_from >= 4 && n_left_to_next >= 2)
     190             :         {
     191             :             mpls_disp_dpo_t *mdd0, *mdd1;
     192             :             u32 bi0, mddi0, bi1, mddi1;
     193             :             vlib_buffer_t * b0, *b1;
     194             :             u32 next0, next1;
     195             : 
     196        3108 :             bi0 = to_next[0] = from[0];
     197        3108 :             bi1 = to_next[1] = from[1];
     198             : 
     199             :             /* Prefetch next iteration. */
     200             :             {
     201             :                 vlib_buffer_t * p2, * p3;
     202             : 
     203        3108 :                 p2 = vlib_get_buffer(vm, from[2]);
     204        3108 :                 p3 = vlib_get_buffer(vm, from[3]);
     205             : 
     206        3108 :                 vlib_prefetch_buffer_header(p2, STORE);
     207        3108 :                 vlib_prefetch_buffer_header(p3, STORE);
     208             : 
     209        3108 :                 CLIB_PREFETCH(p2->data, sizeof(ip6_header_t), STORE);
     210        3108 :                 CLIB_PREFETCH(p3->data, sizeof(ip6_header_t), STORE);
     211             :             }
     212             : 
     213        3108 :             from += 2;
     214        3108 :             to_next += 2;
     215        3108 :             n_left_from -= 2;
     216        3108 :             n_left_to_next -= 2;
     217             : 
     218        3108 :             b0 = vlib_get_buffer(vm, bi0);
     219        3108 :             b1 = vlib_get_buffer(vm, bi1);
     220             : 
     221             :             /* dst lookup was done by ip4 lookup */
     222        3108 :             mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     223        3108 :             mddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     224        3108 :             mdd0 = mpls_disp_dpo_get(mddi0);
     225        3108 :             mdd1 = mpls_disp_dpo_get(mddi1);
     226             : 
     227        3108 :             next0 = mdd0->mdd_dpo.dpoi_next_node;
     228        3108 :             next1 = mdd1->mdd_dpo.dpoi_next_node;
     229             : 
     230        3108 :             if (payload_is_ip4)
     231             :             {
     232             :                 ip4_header_t *ip0, *ip1;
     233             : 
     234        1490 :                 ip0 = vlib_buffer_get_current(b0);
     235        1490 :                 ip1 = vlib_buffer_get_current(b1);
     236             : 
     237             :                 /*
     238             :                  * IPv4 input checks on the exposed IP header
     239             :                  * including checksum
     240             :                  */
     241        1490 :                 ip4_input_check_x2(vm, error_node,
     242             :                                    b0, b1, ip0, ip1,
     243             :                                    &next0, &next1, 1);
     244             : 
     245        1490 :                 if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
     246             :                 {
     247             :                     /*
     248             :                      * Copy the TTL from the MPLS packet into the
     249             :                      * exposed IP. recalc the chksum
     250             :                      */
     251         254 :                     ip0->ttl = vnet_buffer(b0)->mpls.ttl;
     252         254 :                     ip1->ttl = vnet_buffer(b1)->mpls.ttl;
     253         254 :                     ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp);
     254         254 :                     ip1->tos = mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp);
     255             : 
     256         254 :                     ip0->checksum = ip4_header_checksum(ip0);
     257         254 :                     ip1->checksum = ip4_header_checksum(ip1);
     258             :                 }
     259             :             }
     260        1618 :             else if (payload_is_ip6)
     261             :             {
     262             :                 ip6_header_t *ip0, *ip1;
     263             : 
     264        1618 :                 ip0 = vlib_buffer_get_current(b0);
     265        1618 :                 ip1 = vlib_buffer_get_current(b1);
     266             : 
     267             :                 /*
     268             :                  * IPv6 input checks on the exposed IP header
     269             :                  */
     270        1618 :                 ip6_input_check_x2(vm, error_node,
     271             :                                    b0, b1, ip0, ip1,
     272             :                                    &next0, &next1);
     273             : 
     274        1618 :                 if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
     275             :                 {
     276             :                     /*
     277             :                      * Copy the TTL from the MPLS packet into the
     278             :                      * exposed IP
     279             :                      */
     280         127 :                     ip0->hop_limit = vnet_buffer(b0)->mpls.ttl;
     281         127 :                     ip1->hop_limit = vnet_buffer(b1)->mpls.ttl;
     282             : 
     283         127 :                     ip6_set_traffic_class_network_order(
     284             :                         ip0,
     285         127 :                         mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp));
     286         127 :                     ip6_set_traffic_class_network_order(
     287             :                         ip1,
     288         127 :                         mpls_exp_to_ip_dscp(vnet_buffer(b1)->mpls.exp));
     289             :                 }
     290             :             }
     291             : 
     292        3108 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
     293        3108 :             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mdd1->mdd_dpo.dpoi_index;
     294        3108 :             vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
     295        3108 :             vnet_buffer(b1)->ip.rpf_id = mdd1->mdd_rpf_id;
     296             : 
     297        3108 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     298             :             {
     299             :                 mpls_label_disposition_trace_t *tr =
     300        3108 :                     vlib_add_trace(vm, node, b0, sizeof(*tr));
     301             : 
     302        3108 :                 tr->mddt_payload_proto = mdd0->mdd_payload_proto;
     303        3108 :                 tr->mddt_rpf_id = mdd0->mdd_rpf_id;
     304        3108 :                 tr->mddt_mode = mdd0->mdd_mode;
     305             :             }
     306        3108 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     307             :             {
     308             :                 mpls_label_disposition_trace_t *tr =
     309        3108 :                     vlib_add_trace(vm, node, b1, sizeof(*tr));
     310        3108 :                 tr->mddt_payload_proto = mdd1->mdd_payload_proto;
     311        3108 :                 tr->mddt_rpf_id = mdd1->mdd_rpf_id;
     312        3108 :                 tr->mddt_mode = mdd1->mdd_mode;
     313             :             }
     314             : 
     315        3108 :             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
     316             :                                             n_left_to_next,
     317             :                                             bi0, bi1, next0, next1);
     318             :         }
     319             : 
     320         188 :         while (n_left_from > 0 && n_left_to_next > 0)
     321             :         {
     322             :             mpls_disp_dpo_t *mdd0;
     323             :             vlib_buffer_t * b0;
     324             :             u32 bi0, mddi0;
     325             :             u32 next0;
     326             : 
     327         127 :             bi0 = from[0];
     328         127 :             to_next[0] = bi0;
     329         127 :             from += 1;
     330         127 :             to_next += 1;
     331         127 :             n_left_from -= 1;
     332         127 :             n_left_to_next -= 1;
     333             : 
     334         127 :             b0 = vlib_get_buffer(vm, bi0);
     335             : 
     336             :             /* dst lookup was done by ip4 lookup */
     337         127 :             mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     338         127 :             mdd0 = mpls_disp_dpo_get(mddi0);
     339         127 :             next0 = mdd0->mdd_dpo.dpoi_next_node;
     340             : 
     341         127 :             if (payload_is_ip4)
     342             :             {
     343             :                 ip4_header_t *ip0;
     344             : 
     345          67 :                 ip0 = vlib_buffer_get_current(b0);
     346             : 
     347             :                 /*
     348             :                  * IPv4 input checks on the exposed IP header
     349             :                  * including checksum
     350             :                  */
     351          67 :                 ip4_input_check_x1(vm, error_node, b0, ip0, &next0, 1);
     352             : 
     353          67 :                 if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
     354             :                 {
     355             :                     /*
     356             :                      * Copy the TTL from the MPLS packet into the
     357             :                      * exposed IP. recalc the chksum
     358             :                      */
     359           6 :                     ip0->ttl = vnet_buffer(b0)->mpls.ttl;
     360           6 :                     ip0->tos = mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp);
     361           6 :                     ip0->checksum = ip4_header_checksum(ip0);
     362             :                 }
     363             :             }
     364          60 :             else if (payload_is_ip6)
     365             :             {
     366             :                 ip6_header_t *ip0;
     367             : 
     368          60 :                 ip0 = vlib_buffer_get_current(b0);
     369             : 
     370             :                 /*
     371             :                  * IPv6 input checks on the exposed IP header
     372             :                  */
     373          60 :                 ip6_input_check_x1(vm, error_node, b0, ip0, &next0);
     374             : 
     375          60 :                 if (FIB_MPLS_LSP_MODE_UNIFORM == mode)
     376             :                 {
     377             :                     /*
     378             :                      * Copy the TTL from the MPLS packet into the
     379             :                      * exposed IP
     380             :                      */
     381           3 :                     ip0->hop_limit = vnet_buffer(b0)->mpls.ttl;
     382             : 
     383           3 :                     ip6_set_traffic_class_network_order(
     384             :                         ip0,
     385           3 :                         mpls_exp_to_ip_dscp(vnet_buffer(b0)->mpls.exp));
     386             :                 }
     387             :             }
     388             : 
     389         127 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
     390         127 :             vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
     391             : 
     392         127 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     393             :             {
     394             :                 mpls_label_disposition_trace_t *tr =
     395         127 :                     vlib_add_trace(vm, node, b0, sizeof(*tr));
     396         127 :                 tr->mddt_payload_proto = mdd0->mdd_payload_proto;
     397         127 :                 tr->mddt_rpf_id = mdd0->mdd_rpf_id;
     398         127 :                 tr->mddt_mode = mdd0->mdd_mode;
     399             :             }
     400             : 
     401         127 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     402             :                                             n_left_to_next, bi0, next0);
     403             :         }
     404          61 :         vlib_put_next_frame(vm, node, next_index, n_left_to_next);
     405             :     }
     406          61 :     return from_frame->n_vectors;
     407             : }
     408             : 
     409             : static u8 *
     410        2803 : format_mpls_label_disposition_trace (u8 * s, va_list * args)
     411             : {
     412        2803 :     CLIB_UNUSED(vlib_main_t * vm) = va_arg(*args, vlib_main_t *);
     413        2803 :     CLIB_UNUSED(vlib_node_t * node) = va_arg(*args, vlib_node_t *);
     414             :     CLIB_UNUSED(mpls_label_disposition_trace_t * t);
     415             : 
     416        2803 :     t = va_arg(*args, mpls_label_disposition_trace_t *);
     417             : 
     418        2803 :     s = format(s, "rpf-id:%d %U, %U",
     419             :                t->mddt_rpf_id,
     420        2803 :                format_dpo_proto, t->mddt_payload_proto,
     421        2803 :                format_fib_mpls_lsp_mode, t->mddt_mode);
     422             : 
     423        2803 :     return (s);
     424             : }
     425             : 
     426        2327 : VLIB_NODE_FN (ip4_mpls_label_disposition_pipe_node) (vlib_main_t * vm,
     427             :                                  vlib_node_runtime_t * node,
     428             :                                  vlib_frame_t * frame)
     429             : {
     430          27 :     return (mpls_label_disposition_inline(vm, node, frame, 1, 0,
     431             :                                           FIB_MPLS_LSP_MODE_PIPE));
     432             : }
     433             : 
     434      183788 : VLIB_REGISTER_NODE (ip4_mpls_label_disposition_pipe_node) = {
     435             :   .name = "ip4-mpls-label-disposition-pipe",
     436             :   .vector_size = sizeof (u32),
     437             : 
     438             :   .format_trace = format_mpls_label_disposition_trace,
     439             :   .sibling_of = "ip4-input",
     440             :   .n_errors = IP4_N_ERROR,
     441             :   .error_counters = ip4_error_counters,
     442             : };
     443             : 
     444        2328 : VLIB_NODE_FN (ip6_mpls_label_disposition_pipe_node) (vlib_main_t * vm,
     445             :                                  vlib_node_runtime_t * node,
     446             :                                  vlib_frame_t * frame)
     447             : {
     448          28 :     return (mpls_label_disposition_inline(vm, node, frame, 0, 1,
     449             :                                           FIB_MPLS_LSP_MODE_PIPE));
     450             : }
     451             : 
     452      183788 : VLIB_REGISTER_NODE (ip6_mpls_label_disposition_pipe_node) = {
     453             :   .name = "ip6-mpls-label-disposition-pipe",
     454             :   .vector_size = sizeof (u32),
     455             : 
     456             :   .format_trace = format_mpls_label_disposition_trace,
     457             :   .sibling_of = "ip6-input",
     458             :   .n_errors = IP6_N_ERROR,
     459             :   .error_counters = ip6_error_counters,
     460             : };
     461             : 
     462        2304 : VLIB_NODE_FN (ip4_mpls_label_disposition_uniform_node) (vlib_main_t * vm,
     463             :                                  vlib_node_runtime_t * node,
     464             :                                  vlib_frame_t * frame)
     465             : {
     466           4 :     return (mpls_label_disposition_inline(vm, node, frame, 1, 0,
     467             :                                           FIB_MPLS_LSP_MODE_UNIFORM));
     468             : }
     469             : 
     470      183788 : VLIB_REGISTER_NODE (ip4_mpls_label_disposition_uniform_node) = {
     471             :   .name = "ip4-mpls-label-disposition-uniform",
     472             :   .vector_size = sizeof (u32),
     473             : 
     474             :   .format_trace = format_mpls_label_disposition_trace,
     475             :   .sibling_of = "ip4-input",
     476             :   .n_errors = IP4_N_ERROR,
     477             :   .error_counters = ip4_error_counters,
     478             : };
     479             : 
     480        2302 : VLIB_NODE_FN (ip6_mpls_label_disposition_uniform_node) (vlib_main_t * vm,
     481             :                                     vlib_node_runtime_t * node,
     482             :                                     vlib_frame_t * frame)
     483             : {
     484           2 :     return (mpls_label_disposition_inline(vm, node, frame, 0, 1,
     485             :                                           FIB_MPLS_LSP_MODE_UNIFORM));
     486             : }
     487             : 
     488      183788 : VLIB_REGISTER_NODE (ip6_mpls_label_disposition_uniform_node) = {
     489             :   .name = "ip6-mpls-label-disposition-uniform",
     490             :   .vector_size = sizeof (u32),
     491             : 
     492             :   .format_trace = format_mpls_label_disposition_trace,
     493             :   .sibling_of = "ip6-input",
     494             :   .n_errors = IP6_N_ERROR,
     495             :   .error_counters = ip6_error_counters,
     496             : };
     497             : 
     498             : #ifndef CLIB_MARCH_VARIANT
     499             : static void
     500           0 : mpls_disp_dpo_mem_show (void)
     501             : {
     502           0 :     fib_show_memory_usage("MPLS label",
     503           0 :                           pool_elts(mpls_disp_dpo_pool),
     504           0 :                           pool_len(mpls_disp_dpo_pool),
     505             :                           sizeof(mpls_disp_dpo_t));
     506           0 : }
     507             : 
     508             : const static dpo_vft_t mdd_vft = {
     509             :     .dv_lock = mpls_disp_dpo_lock,
     510             :     .dv_unlock = mpls_disp_dpo_unlock,
     511             :     .dv_format = format_mpls_disp_dpo,
     512             :     .dv_mem_show = mpls_disp_dpo_mem_show,
     513             : };
     514             : 
     515             : const static char* const mpls_label_disp_pipe_ip4_nodes[] =
     516             : {
     517             :     "ip4-mpls-label-disposition-pipe",
     518             :     NULL,
     519             : };
     520             : const static char* const mpls_label_disp_pipe_ip6_nodes[] =
     521             : {
     522             :     "ip6-mpls-label-disposition-pipe",
     523             :     NULL,
     524             : };
     525             : const static char* const * const mpls_label_disp_pipe_nodes[DPO_PROTO_NUM] =
     526             : {
     527             :     [DPO_PROTO_IP4]  = mpls_label_disp_pipe_ip4_nodes,
     528             :     [DPO_PROTO_IP6]  = mpls_label_disp_pipe_ip6_nodes,
     529             : };
     530             : 
     531             : const static char* const mpls_label_disp_uniform_ip4_nodes[] =
     532             : {
     533             :     "ip4-mpls-label-disposition-uniform",
     534             :     NULL,
     535             : };
     536             : const static char* const mpls_label_disp_uniform_ip6_nodes[] =
     537             : {
     538             :     "ip6-mpls-label-disposition-uniform",
     539             :     NULL,
     540             : };
     541             : const static char* const * const mpls_label_disp_uniform_nodes[DPO_PROTO_NUM] =
     542             : {
     543             :     [DPO_PROTO_IP4]  = mpls_label_disp_uniform_ip4_nodes,
     544             :     [DPO_PROTO_IP6]  = mpls_label_disp_uniform_ip6_nodes,
     545             : };
     546             : 
     547             : 
     548             : void
     549         575 : mpls_disp_dpo_module_init(void)
     550             : {
     551         575 :     dpo_register(DPO_MPLS_DISPOSITION_PIPE, &mdd_vft,
     552             :                  mpls_label_disp_pipe_nodes);
     553         575 :     dpo_register(DPO_MPLS_DISPOSITION_UNIFORM, &mdd_vft,
     554             :                  mpls_label_disp_uniform_nodes);
     555         575 : }
     556             : #endif /* CLIB_MARCH_VARIANT */

Generated by: LCOV version 1.14