LCOV - code coverage report
Current view: top level - vnet/dpo - dvr_dpo.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 197 226 87.2 %
Date: 2023-10-26 01:39:38 Functions: 49 66 74.2 %

          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/dpo/dvr_dpo.h>
      17             : #include <vnet/fib/fib_node.h>
      18             : #include <vnet/ip/ip.h>
      19             : #include <vnet/ethernet/ethernet.h>
      20             : #include <vnet/l2/l2_input.h>
      21             : 
      22             : #ifndef CLIB_MARCH_VARIANT
      23             : dvr_dpo_t *dvr_dpo_pool;
      24             : 
      25             : /**
      26             :  * The 'DB' of DVR DPOs.
      27             :  * There is one per-interface per-L3 proto, so this is a per-interface vector
      28             :  */
      29             : static index_t *dvr_dpo_db[DPO_PROTO_NUM];
      30             : 
      31             : static dvr_dpo_t *
      32           7 : dvr_dpo_alloc (void)
      33             : {
      34             :     dvr_dpo_t *dd;
      35             : 
      36           7 :     pool_get(dvr_dpo_pool, dd);
      37             : 
      38           7 :     return (dd);
      39             : }
      40             : 
      41             : static inline dvr_dpo_t *
      42          82 : dvr_dpo_get_from_dpo (const dpo_id_t *dpo)
      43             : {
      44          82 :     ASSERT(DPO_DVR == dpo->dpoi_type);
      45             : 
      46          82 :     return (dvr_dpo_get(dpo->dpoi_index));
      47             : }
      48             : 
      49             : static inline index_t
      50          15 : dvr_dpo_get_index (dvr_dpo_t *dd)
      51             : {
      52          15 :     return (dd - dvr_dpo_pool);
      53             : }
      54             : 
      55             : static void
      56          41 : dvr_dpo_lock (dpo_id_t *dpo)
      57             : {
      58             :     dvr_dpo_t *dd;
      59             : 
      60          41 :     dd = dvr_dpo_get_from_dpo(dpo);
      61          41 :     dd->dd_locks++;
      62          41 : }
      63             : 
      64             : static void
      65          41 : dvr_dpo_unlock (dpo_id_t *dpo)
      66             : {
      67             :     dvr_dpo_t *dd;
      68             : 
      69          41 :     dd = dvr_dpo_get_from_dpo(dpo);
      70          41 :     dd->dd_locks--;
      71             : 
      72          41 :     if (0 == dd->dd_locks)
      73             :     {
      74           7 :         if (DPO_PROTO_IP4 == dd->dd_proto)
      75             :         {
      76           5 :             vnet_feature_enable_disable ("ip4-output", "ip4-dvr-reinject",
      77             :                                          dd->dd_sw_if_index, 0, 0, 0);
      78             :         }
      79             :         else
      80             :         {
      81           2 :             vnet_feature_enable_disable ("ip6-output", "ip6-dvr-reinject",
      82             :                                          dd->dd_sw_if_index, 0, 0, 0);
      83             :         }
      84             : 
      85           7 :         dvr_dpo_db[dd->dd_proto][dd->dd_sw_if_index] = INDEX_INVALID;
      86           7 :         pool_put(dvr_dpo_pool, dd);
      87             :     }
      88          41 : }
      89             : 
      90             : void
      91           8 : dvr_dpo_add_or_lock (u32 sw_if_index,
      92             :                      dpo_proto_t dproto,
      93             :                      dpo_id_t *dpo)
      94             : {
      95             :     l2_input_config_t *config;
      96             :     dvr_dpo_t *dd;
      97             : 
      98          24 :     vec_validate_init_empty(dvr_dpo_db[dproto],
      99             :                             sw_if_index,
     100             :                             INDEX_INVALID);
     101             : 
     102           8 :     if (INDEX_INVALID == dvr_dpo_db[dproto][sw_if_index])
     103             :     {
     104           7 :         dd = dvr_dpo_alloc();
     105             : 
     106           7 :         dd->dd_sw_if_index = sw_if_index;
     107           7 :         dd->dd_proto = dproto;
     108             : 
     109           7 :         dvr_dpo_db[dproto][sw_if_index] = dvr_dpo_get_index(dd);
     110             : 
     111           7 :         config = l2input_intf_config (sw_if_index);
     112             : 
     113          12 :         if (l2_input_is_bridge(config) ||
     114           5 :             l2_input_is_xconnect(config))
     115             :         {
     116           2 :             dd->dd_reinject = DVR_REINJECT_L2;
     117             :         }
     118             :         else
     119             :         {
     120           5 :             dd->dd_reinject = DVR_REINJECT_L3;
     121             :         }
     122             : 
     123             :         /*
     124             :          * enable the reinject into L2 path feature on the interface
     125             :          */
     126           7 :         if (DPO_PROTO_IP4 == dproto)
     127           5 :             vnet_feature_enable_disable ("ip4-output", "ip4-dvr-reinject",
     128             :                                          dd->dd_sw_if_index, 1, 0, 0);
     129           2 :         else if (DPO_PROTO_IP6 == dproto)
     130           2 :             vnet_feature_enable_disable ("ip6-output", "ip6-dvr-reinject",
     131             :                                          dd->dd_sw_if_index, 1, 0, 0);
     132             :         else
     133           0 :             ASSERT(0);
     134             :     }
     135             :     else
     136             :     {
     137           1 :         dd = dvr_dpo_get(dvr_dpo_db[dproto][sw_if_index]);
     138             :     }
     139             : 
     140           8 :     dpo_set(dpo, DPO_DVR, dproto, dvr_dpo_get_index(dd));
     141           8 : }
     142             : #endif /* CLIB_MARCH_VARIANT */
     143             : 
     144             : 
     145             : static clib_error_t *
     146       13514 : dvr_dpo_interface_state_change (vnet_main_t * vnm,
     147             :                                       u32 sw_if_index,
     148             :                                       u32 flags)
     149             : {
     150             :     /*
     151             :      */
     152       13514 :     return (NULL);
     153             : }
     154             : 
     155        2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
     156             :     dvr_dpo_interface_state_change);
     157             : 
     158             : /**
     159             :  * @brief Registered callback for HW interface state changes
     160             :  */
     161             : static clib_error_t *
     162       13336 : dvr_dpo_hw_interface_state_change (vnet_main_t * vnm,
     163             :                                          u32 hw_if_index,
     164             :                                          u32 flags)
     165             : {
     166       13336 :     return (NULL);
     167             : }
     168             : 
     169        2881 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
     170             :     dvr_dpo_hw_interface_state_change);
     171             : 
     172             : static clib_error_t *
     173       11798 : dvr_dpo_interface_delete (vnet_main_t * vnm,
     174             :                                 u32 sw_if_index,
     175             :                                 u32 is_add)
     176             : {
     177       11798 :     return (NULL);
     178             : }
     179             : 
     180        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
     181             :     dvr_dpo_interface_delete);
     182             : 
     183             : #ifndef CLIB_MARCH_VARIANT
     184             : static u8*
     185           0 : format_dvr_reinject (u8* s, va_list *ap)
     186             : {
     187           0 :     dvr_dpo_reinject_t ddr = va_arg(*ap, int);
     188             : 
     189           0 :     switch (ddr)
     190             :     {
     191           0 :     case DVR_REINJECT_L2:
     192           0 :         s = format (s, "l2");
     193           0 :         break;
     194           0 :     case DVR_REINJECT_L3:
     195           0 :         s = format (s, "l3");
     196           0 :         break;
     197             :     }
     198           0 :     return (s);
     199             : }
     200             : 
     201             : static u8*
     202           0 : format_dvr_dpo (u8* s, va_list *ap)
     203             : {
     204           0 :     index_t index = va_arg(*ap, index_t);
     205           0 :     CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
     206           0 :     vnet_main_t * vnm = vnet_get_main();
     207           0 :     dvr_dpo_t *dd = dvr_dpo_get(index);
     208             : 
     209           0 :     return (format(s, "%U-dvr-%U-dpo %U",
     210           0 :                    format_dpo_proto, dd->dd_proto,
     211             :                    format_vnet_sw_interface_name,
     212             :                    vnm,
     213             :                    vnet_get_sw_interface(vnm, dd->dd_sw_if_index),
     214           0 :                    format_dvr_reinject, dd->dd_reinject));
     215             : }
     216             : 
     217             : static void
     218           0 : dvr_dpo_mem_show (void)
     219             : {
     220           0 :     fib_show_memory_usage("DVR",
     221           0 :                           pool_elts(dvr_dpo_pool),
     222           0 :                           pool_len(dvr_dpo_pool),
     223             :                           sizeof(dvr_dpo_t));
     224           0 : }
     225             : 
     226             : 
     227             : const static dpo_vft_t dvr_dpo_vft = {
     228             :     .dv_lock = dvr_dpo_lock,
     229             :     .dv_unlock = dvr_dpo_unlock,
     230             :     .dv_format = format_dvr_dpo,
     231             :     .dv_mem_show = dvr_dpo_mem_show,
     232             : };
     233             : 
     234             : /**
     235             :  * @brief The per-protocol VLIB graph nodes that are assigned to a glean
     236             :  *        object.
     237             :  *
     238             :  * this means that these graph nodes are ones from which a glean is the
     239             :  * parent object in the DPO-graph.
     240             :  */
     241             : const static char* const dvr_dpo_ip4_nodes[] =
     242             : {
     243             :     "ip4-dvr-dpo",
     244             :     NULL,
     245             : };
     246             : const static char* const dvr_dpo_ip6_nodes[] =
     247             : {
     248             :     "ip6-dvr-dpo",
     249             :     NULL,
     250             : };
     251             : 
     252             : const static char* const * const dvr_dpo_nodes[DPO_PROTO_NUM] =
     253             : {
     254             :     [DPO_PROTO_IP4]  = dvr_dpo_ip4_nodes,
     255             :     [DPO_PROTO_IP6]  = dvr_dpo_ip6_nodes,
     256             : };
     257             : 
     258             : void
     259         575 : dvr_dpo_module_init (void)
     260             : {
     261         575 :     dpo_register(DPO_DVR,
     262             :                  &dvr_dpo_vft,
     263             :                  dvr_dpo_nodes);
     264         575 : }
     265             : #endif /* CLIB_MARCH_VARIANT */
     266             : 
     267             : /**
     268             :  * @brief Interface DPO trace data
     269             :  */
     270             : typedef struct dvr_dpo_trace_t_
     271             : {
     272             :     u32 sw_if_index;
     273             : } dvr_dpo_trace_t;
     274             : 
     275             : always_inline uword
     276          13 : dvr_dpo_inline (vlib_main_t * vm,
     277             :                 vlib_node_runtime_t * node,
     278             :                 vlib_frame_t * from_frame,
     279             :                 u8 is_ip6)
     280             : {
     281             :     u32 n_left_from, next_index, * from, * to_next;
     282          13 :     ip_lookup_main_t *lm = (is_ip6?
     283          13 :                             &ip6_main.lookup_main:
     284             :                             &ip4_main.lookup_main);
     285             : 
     286          13 :     from = vlib_frame_vector_args (from_frame);
     287          13 :     n_left_from = from_frame->n_vectors;
     288             : 
     289          13 :     next_index = node->cached_next_index;
     290             : 
     291          26 :     while (n_left_from > 0)
     292             :     {
     293             :         u32 n_left_to_next;
     294             : 
     295          13 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     296             : 
     297         173 :         while (n_left_from >= 4 && n_left_to_next > 2)
     298             :         {
     299             :             const dvr_dpo_t *dd0, *dd1;
     300             :             u32 bi0, ddi0, bi1, ddi1;
     301             :             vlib_buffer_t *b0, *b1;
     302             :             u32 next0, next1;
     303             :             u8 len0, len1;
     304             : 
     305         160 :             bi0 = from[0];
     306         160 :             to_next[0] = bi0;
     307         160 :             bi1 = from[1];
     308         160 :             to_next[1] = bi1;
     309         160 :             from += 2;
     310         160 :             to_next += 2;
     311         160 :             n_left_from -= 2;
     312         160 :             n_left_to_next -= 2;
     313         160 :             next0 = next1 = 0;
     314             : 
     315         160 :             b0 = vlib_get_buffer (vm, bi0);
     316         160 :             b1 = vlib_get_buffer (vm, bi1);
     317             : 
     318         160 :             ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     319         160 :             ddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     320         160 :             dd0 = dvr_dpo_get(ddi0);
     321         160 :             dd1 = dvr_dpo_get(ddi1);
     322             : 
     323         160 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = dd0->dd_sw_if_index;
     324         160 :             vnet_buffer(b1)->sw_if_index[VLIB_TX] = dd1->dd_sw_if_index;
     325             : 
     326         160 :             len0 = ((u8*)vlib_buffer_get_current(b0) -
     327         160 :                     (u8*)ethernet_buffer_get_header(b0));
     328         160 :             len1 = ((u8*)vlib_buffer_get_current(b1) -
     329         160 :                     (u8*)ethernet_buffer_get_header(b1));
     330         160 :             vnet_buffer(b0)->l2.l2_len =
     331         160 :                 vnet_buffer(b0)->ip.save_rewrite_length =
     332             :                    len0;
     333         160 :             vnet_buffer(b1)->l2.l2_len =
     334         160 :                 vnet_buffer(b1)->ip.save_rewrite_length =
     335             :                     len1;
     336             : 
     337         160 :             b0->flags |= VNET_BUFFER_F_IS_DVR;
     338         160 :             b1->flags |= VNET_BUFFER_F_IS_DVR;
     339             : 
     340         160 :             vlib_buffer_advance(b0, -len0);
     341         160 :             vlib_buffer_advance(b1, -len1);
     342             : 
     343         160 :             vnet_feature_arc_start (lm->output_feature_arc_index,
     344             :                                     dd0->dd_sw_if_index, &next0, b0);
     345         160 :             vnet_feature_arc_start (lm->output_feature_arc_index,
     346             :                                     dd1->dd_sw_if_index, &next1, b1);
     347             : 
     348         160 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     349             :             {
     350             :                 dvr_dpo_trace_t *tr0;
     351             : 
     352         160 :                 tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
     353         160 :                 tr0->sw_if_index = dd0->dd_sw_if_index;
     354             :             }
     355         160 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     356             :             {
     357             :                 dvr_dpo_trace_t *tr1;
     358             : 
     359         160 :                 tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
     360         160 :                 tr1->sw_if_index = dd1->dd_sw_if_index;
     361             :             }
     362             : 
     363         160 :             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
     364             :                                             n_left_to_next, bi0, bi1,
     365             :                                             next0, next1);
     366             :         }
     367             : 
     368          36 :         while (n_left_from > 0 && n_left_to_next > 0)
     369             :         {
     370             :             const dvr_dpo_t * dd0;
     371             :             vlib_buffer_t * b0;
     372             :             u32 bi0, ddi0;
     373             :             u32 next0;
     374             :             u8 len0;
     375             : 
     376          23 :             bi0 = from[0];
     377          23 :             to_next[0] = bi0;
     378          23 :             from += 1;
     379          23 :             to_next += 1;
     380          23 :             n_left_from -= 1;
     381          23 :             n_left_to_next -= 1;
     382          23 :             next0 = 0;
     383             : 
     384          23 :             b0 = vlib_get_buffer (vm, bi0);
     385             : 
     386          23 :             ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     387          23 :             dd0 = dvr_dpo_get(ddi0);
     388             : 
     389          23 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = dd0->dd_sw_if_index;
     390             : 
     391             :             /*
     392             :              * take that, rewind it back...
     393             :              */
     394          23 :             len0 = ((u8*)vlib_buffer_get_current(b0) -
     395          23 :                     (u8*)ethernet_buffer_get_header(b0));
     396          23 :             vnet_buffer(b0)->l2.l2_len =
     397          23 :                 vnet_buffer(b0)->ip.save_rewrite_length =
     398             :                     len0;
     399          23 :             b0->flags |= VNET_BUFFER_F_IS_DVR;
     400          23 :             vlib_buffer_advance(b0, -len0);
     401             : 
     402             :             /*
     403             :              * start processing the ipX output features
     404             :              */
     405          23 :             vnet_feature_arc_start(lm->output_feature_arc_index,
     406             :                                    dd0->dd_sw_if_index, &next0, b0);
     407             : 
     408          23 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     409             :             {
     410             :                 dvr_dpo_trace_t *tr;
     411             : 
     412          23 :                 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
     413          23 :                 tr->sw_if_index = dd0->dd_sw_if_index;
     414             :             }
     415             : 
     416          23 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     417             :                                             n_left_to_next, bi0,
     418             :                                             next0);
     419             :         }
     420          13 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     421             :     }
     422          13 :     return from_frame->n_vectors;
     423             : }
     424             : 
     425             : static u8 *
     426         533 : format_dvr_dpo_trace (u8 * s, va_list * args)
     427             : {
     428         533 :     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     429         533 :     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     430         533 :     dvr_dpo_trace_t * t = va_arg (*args, dvr_dpo_trace_t *);
     431         533 :     u32 indent = format_get_indent (s);
     432         533 :     s = format (s, "%U sw_if_index:%d",
     433             :                 format_white_space, indent,
     434             :                 t->sw_if_index);
     435         533 :     return s;
     436             : }
     437             : 
     438        2313 : VLIB_NODE_FN (ip4_dvr_dpo_node) (vlib_main_t * vm,
     439             :              vlib_node_runtime_t * node,
     440             :              vlib_frame_t * from_frame)
     441             : {
     442          13 :     return (dvr_dpo_inline(vm, node, from_frame, 0));
     443             : }
     444             : 
     445        2300 : VLIB_NODE_FN (ip6_dvr_dpo_node) (vlib_main_t * vm,
     446             :              vlib_node_runtime_t * node,
     447             :              vlib_frame_t * from_frame)
     448             : {
     449           0 :     return (dvr_dpo_inline(vm, node, from_frame, 1));
     450             : }
     451             : 
     452      183788 : VLIB_REGISTER_NODE (ip4_dvr_dpo_node) = {
     453             :     .name = "ip4-dvr-dpo",
     454             :     .vector_size = sizeof (u32),
     455             :     .format_trace = format_dvr_dpo_trace,
     456             :     .sibling_of = "ip4-rewrite",
     457             : };
     458      183788 : VLIB_REGISTER_NODE (ip6_dvr_dpo_node) = {
     459             :     .name = "ip6-dvr-dpo",
     460             :     .vector_size = sizeof (u32),
     461             :     .format_trace = format_dvr_dpo_trace,
     462             :     .sibling_of = "ip6-rewrite",
     463             : };
     464             : 
     465             : typedef enum dvr_reinject_next_t_
     466             : {
     467             :     DVR_REINJECT_NEXT_L2,
     468             :     DVR_REINJECT_NEXT_L3,
     469             : } dvr_reinject_next_t;
     470             : 
     471             : always_inline uword
     472          12 : dvr_reinject_inline (vlib_main_t * vm,
     473             :                      vlib_node_runtime_t * node,
     474             :                      vlib_frame_t * from_frame)
     475             : {
     476             :     u32 n_left_from, next_index, * from, * to_next;
     477             : 
     478          12 :     from = vlib_frame_vector_args (from_frame);
     479          12 :     n_left_from = from_frame->n_vectors;
     480             : 
     481          12 :     next_index = node->cached_next_index;
     482             : 
     483          24 :     while (n_left_from > 0)
     484             :     {
     485             :         u32 n_left_to_next;
     486             : 
     487          12 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     488             : 
     489         140 :         while (n_left_from >= 4 && n_left_to_next > 2)
     490             :         {
     491             :             dvr_reinject_next_t next0, next1;
     492             :             const dvr_dpo_t *dd0, *dd1;
     493             :             u32 bi0, bi1, ddi0, ddi1;
     494             :             vlib_buffer_t *b0, *b1;
     495             : 
     496         128 :             bi0 = from[0];
     497         128 :             to_next[0] = bi0;
     498         128 :             bi1 = from[1];
     499         128 :             to_next[1] = bi1;
     500         128 :             from += 2;
     501         128 :             to_next += 2;
     502         128 :             n_left_from -= 2;
     503         128 :             n_left_to_next -= 2;
     504             : 
     505         128 :             b0 = vlib_get_buffer (vm, bi0);
     506         128 :             b1 = vlib_get_buffer (vm, bi1);
     507             : 
     508         128 :             if (b0->flags & VNET_BUFFER_F_IS_DVR)
     509             :             {
     510         128 :                 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     511         128 :                 dd0 = dvr_dpo_get(ddi0);
     512         128 :                 next0 = (dd0->dd_reinject == DVR_REINJECT_L2 ?
     513         128 :                          DVR_REINJECT_NEXT_L2 :
     514             :                          DVR_REINJECT_NEXT_L3);
     515             :             }
     516             :             else
     517           0 :                 vnet_feature_next( &next0, b0);
     518             : 
     519         128 :             if (b1->flags & VNET_BUFFER_F_IS_DVR)
     520             :             {
     521         128 :                 ddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     522         128 :                 dd1 = dvr_dpo_get(ddi1);
     523         128 :                 next1 = (dd1->dd_reinject == DVR_REINJECT_L2 ?
     524         128 :                          DVR_REINJECT_NEXT_L2 :
     525             :                          DVR_REINJECT_NEXT_L3);
     526             :             }
     527             :             else
     528           0 :                 vnet_feature_next( &next1, b1);
     529             : 
     530         128 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     531             :             {
     532             :                 dvr_dpo_trace_t *tr0;
     533             : 
     534         128 :                 tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
     535         128 :                 tr0->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_TX];
     536             :             }
     537         128 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     538             :             {
     539             :                 dvr_dpo_trace_t *tr1;
     540             : 
     541         128 :                 tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
     542         128 :                 tr1->sw_if_index = vnet_buffer(b1)->sw_if_index[VLIB_TX];
     543             :             }
     544             : 
     545         128 :             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
     546             :                                             n_left_to_next, bi0, bi1,
     547             :                                             next0, next1);
     548             :         }
     549             : 
     550          32 :         while (n_left_from > 0 && n_left_to_next > 0)
     551             :         {
     552             :             dvr_reinject_next_t next0;
     553             :             const dvr_dpo_t *dd0;
     554             :             vlib_buffer_t * b0;
     555             :             u32 bi0, ddi0;
     556             : 
     557          20 :             bi0 = from[0];
     558          20 :             to_next[0] = bi0;
     559          20 :             from += 1;
     560          20 :             to_next += 1;
     561          20 :             n_left_from -= 1;
     562          20 :             n_left_to_next -= 1;
     563             : 
     564          20 :             b0 = vlib_get_buffer (vm, bi0);
     565             : 
     566          20 :             if (b0->flags & VNET_BUFFER_F_IS_DVR)
     567             :             {
     568          20 :                 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     569          20 :                 dd0 = dvr_dpo_get(ddi0);
     570          20 :                 next0 = (dd0->dd_reinject == DVR_REINJECT_L2 ?
     571          20 :                          DVR_REINJECT_NEXT_L2 :
     572             :                          DVR_REINJECT_NEXT_L3);
     573             :             }
     574             :             else
     575           0 :                 vnet_feature_next( &next0, b0);
     576             : 
     577          20 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     578             :             {
     579             :                 dvr_dpo_trace_t *tr;
     580             : 
     581          20 :                 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
     582          20 :                 tr->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_TX];
     583             :             }
     584             : 
     585          20 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     586             :                                             n_left_to_next, bi0, next0);
     587             :         }
     588          12 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     589             :     }
     590          12 :     return from_frame->n_vectors;
     591             : }
     592             : 
     593        2312 : VLIB_NODE_FN (ip4_dvr_reinject_node) (vlib_main_t * vm,
     594             :                   vlib_node_runtime_t * node,
     595             :                   vlib_frame_t * from_frame)
     596             : {
     597          12 :     return (dvr_reinject_inline(vm, node, from_frame));
     598             : }
     599             : 
     600        2300 : VLIB_NODE_FN (ip6_dvr_reinject_node) (vlib_main_t * vm,
     601             :                   vlib_node_runtime_t * node,
     602             :                   vlib_frame_t * from_frame)
     603             : {
     604           0 :     return (dvr_reinject_inline(vm, node, from_frame));
     605             : }
     606             : 
     607      183788 : VLIB_REGISTER_NODE (ip4_dvr_reinject_node) = {
     608             :     .name = "ip4-dvr-reinject",
     609             :     .vector_size = sizeof (u32),
     610             :     .format_trace = format_dvr_dpo_trace,
     611             : 
     612             :     .n_next_nodes = 1,
     613             :     .next_nodes = {
     614             :         [DVR_REINJECT_NEXT_L2] = "l2-output",
     615             :         [DVR_REINJECT_NEXT_L3] = "interface-output",
     616             :     },
     617             : };
     618             : 
     619      183788 : VLIB_REGISTER_NODE (ip6_dvr_reinject_node) = {
     620             :     .name = "ip6-dvr-reinject",
     621             :     .vector_size = sizeof (u32),
     622             :     .format_trace = format_dvr_dpo_trace,
     623             : 
     624             :     .n_next_nodes = 1,
     625             :     .next_nodes = {
     626             :         [DVR_REINJECT_NEXT_L2] = "l2-output",
     627             :         [DVR_REINJECT_NEXT_L3] = "interface-output",
     628             :     },
     629             : };
     630             : 
     631       76635 : VNET_FEATURE_INIT (ip4_dvr_reinject_feat_node, static) =
     632             : {
     633             :   .arc_name = "ip4-output",
     634             :   .node_name = "ip4-dvr-reinject",
     635             : };
     636       76635 : VNET_FEATURE_INIT (ip6_dvr_reinject_feat_node, static) =
     637             : {
     638             :   .arc_name = "ip6-output",
     639             :   .node_name = "ip6-dvr-reinject",
     640             : };
     641             : 

Generated by: LCOV version 1.14