LCOV - code coverage report
Current view: top level - vnet/dpo - pw_cw.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 101 107 94.4 %
Date: 2023-07-05 22:20:52 Functions: 13 14 92.9 %

          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/pw_cw.h>
      17             : #include <vnet/fib/fib_node.h>
      18             : 
      19             : #ifndef CLIB_MARCH_VARIANT
      20             : 
      21             : /*
      22             :  * pool of all MPLS Label DPOs
      23             :  */
      24             : pw_cw_dpo_t *pw_cw_dpo_pool;
      25             : 
      26             : static pw_cw_dpo_t *
      27           1 : pw_cw_dpo_alloc (void)
      28             : {
      29             :     pw_cw_dpo_t *pwcw;
      30             : 
      31           1 :     pool_get_aligned_zero(pw_cw_dpo_pool, pwcw, 8);
      32             : 
      33           1 :     return (pwcw);
      34             : }
      35             : 
      36             : static index_t
      37           1 : pw_cw_dpo_get_index (pw_cw_dpo_t *pwcw)
      38             : {
      39           1 :     return (pwcw - pw_cw_dpo_pool);
      40             : }
      41             : 
      42             : void
      43           1 : pw_cw_dpo_create (const dpo_id_t *parent,
      44             :                   dpo_id_t *dpo)
      45             : {
      46             :     pw_cw_dpo_t *pwcw;
      47             : 
      48           1 :     pwcw = pw_cw_dpo_alloc();
      49             : 
      50             :     /*
      51             :      * stack this disposition object on the parent given
      52             :      */
      53           1 :     dpo_stack(DPO_PW_CW,
      54           1 :               parent->dpoi_proto,
      55             :               &pwcw->pwcw_parent,
      56             :               parent);
      57             : 
      58             :     /*
      59             :      * set up the return DPO to refer to this object
      60             :      */
      61           1 :     dpo_set(dpo,
      62             :             DPO_PW_CW,
      63           1 :             parent->dpoi_proto,
      64             :             pw_cw_dpo_get_index(pwcw));
      65           1 : }
      66             : 
      67             : u8*
      68           1 : format_pw_cw_dpo (u8 *s, va_list *args)
      69             : {
      70           1 :     index_t pwcwi = va_arg (*args, index_t);
      71           1 :     u32 indent = va_arg (*args, u32);
      72             :     pw_cw_dpo_t *pwcw;
      73             : 
      74           1 :     if (pool_is_free_index(pw_cw_dpo_pool, pwcwi))
      75             :     {
      76             :         /*
      77             :          * the packet trace can be printed after the DPO has been deleted
      78             :          */
      79           0 :         return (format(s, "pw-cw[???,%d]:", pwcwi));
      80             :     }
      81             : 
      82           1 :     pwcw = pw_cw_dpo_get(pwcwi);
      83           1 :     s = format(s, "pw-cw[%d]:", pwcwi);
      84             : 
      85           1 :     s = format(s, "\n%U", format_white_space, indent);
      86           1 :     s = format(s, "%U", format_dpo_id, &pwcw->pwcw_parent, indent+2);
      87             : 
      88           1 :     return (s);
      89             : }
      90             : 
      91             : static void
      92           3 : pw_cw_dpo_lock (dpo_id_t *dpo)
      93             : {
      94             :     pw_cw_dpo_t *pwcw;
      95             : 
      96           3 :     pwcw = pw_cw_dpo_get(dpo->dpoi_index);
      97             : 
      98           3 :     pwcw->pwcw_locks++;
      99           3 : }
     100             : 
     101             : static void
     102           3 : pw_cw_dpo_unlock (dpo_id_t *dpo)
     103             : {
     104             :     pw_cw_dpo_t *pwcw;
     105             : 
     106           3 :     pwcw = pw_cw_dpo_get(dpo->dpoi_index);
     107             : 
     108           3 :     pwcw->pwcw_locks--;
     109             : 
     110           3 :     if (0 == pwcw->pwcw_locks)
     111             :     {
     112           1 :         dpo_reset(&pwcw->pwcw_parent);
     113           1 :         pool_put(pw_cw_dpo_pool, pwcw);
     114             :     }
     115           3 : }
     116             : #endif /* CLIB_MARCH_VARIANT */
     117             : 
     118             : /**
     119             :  * @brief A struct to hold tracing information for the MPLS label imposition
     120             :  * node.
     121             :  */
     122             : typedef struct pw_cw_trace_t_
     123             : {
     124             :     /**
     125             :      * The CW popped
     126             :      */
     127             :     u32 cw;
     128             : } pw_cw_trace_t;
     129             : 
     130             : always_inline uword
     131           2 : pw_cw_pop_inline (vlib_main_t * vm,
     132             :                   vlib_node_runtime_t * node,
     133             :                   vlib_frame_t * from_frame)
     134             : {
     135             :     u32 n_left_from, next_index, * from, * to_next;
     136             : 
     137           2 :     from = vlib_frame_vector_args(from_frame);
     138           2 :     n_left_from = from_frame->n_vectors;
     139           2 :     next_index = node->cached_next_index;
     140             : 
     141           4 :     while (n_left_from > 0)
     142             :     {
     143             :         u32 n_left_to_next;
     144             : 
     145           2 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     146             : 
     147          34 :         while (n_left_from >= 4 && n_left_to_next >= 2)
     148             :         {
     149             :             pw_cw_dpo_t *pwcw0, *pwcw1;
     150             :             u32 bi0, pwcwi0, bi1, pwcwi1;
     151             :             vlib_buffer_t * b0, *b1;
     152             :             u32 next0, next1;
     153             : 
     154          32 :             bi0 = to_next[0] = from[0];
     155          32 :             bi1 = to_next[1] = from[1];
     156             : 
     157             :             /* Prefetch next iteration. */
     158             :             {
     159             :                 vlib_buffer_t * p2, * p3;
     160             : 
     161          32 :                 p2 = vlib_get_buffer(vm, from[2]);
     162          32 :                 p3 = vlib_get_buffer(vm, from[3]);
     163             : 
     164          32 :                 vlib_prefetch_buffer_header(p2, STORE);
     165          32 :                 vlib_prefetch_buffer_header(p3, STORE);
     166             : 
     167          32 :                 CLIB_PREFETCH(p2->data, sizeof(pw_cw_t), STORE);
     168          32 :                 CLIB_PREFETCH(p3->data, sizeof(pw_cw_t), STORE);
     169             :             }
     170             : 
     171          32 :             from += 2;
     172          32 :             to_next += 2;
     173          32 :             n_left_from -= 2;
     174          32 :             n_left_to_next -= 2;
     175             : 
     176          32 :             b0 = vlib_get_buffer(vm, bi0);
     177          32 :             b1 = vlib_get_buffer(vm, bi1);
     178             : 
     179             :             /* get the next parent DPO for the next pop */
     180          32 :             pwcwi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     181          32 :             pwcwi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     182          32 :             pwcw0 = pw_cw_dpo_get(pwcwi0);
     183          32 :             pwcw1 = pw_cw_dpo_get(pwcwi1);
     184             : 
     185          32 :             next0 = pwcw0->pwcw_parent.dpoi_next_node;
     186          32 :             next1 = pwcw1->pwcw_parent.dpoi_next_node;
     187             : 
     188          32 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = pwcw0->pwcw_parent.dpoi_index;
     189          32 :             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = pwcw1->pwcw_parent.dpoi_index;
     190             : 
     191          32 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     192             :             {
     193          32 :                 pw_cw_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
     194             : 
     195          32 :                 tr->cw = *((pw_cw_t*) vlib_buffer_get_current(b0));
     196             :             }
     197          32 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     198             :             {
     199          32 :                 pw_cw_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
     200             : 
     201          32 :                 tr->cw = *((pw_cw_t*) vlib_buffer_get_current(b1));
     202             :             }
     203             : 
     204             :             /* pop the PW CW */
     205          32 :             vlib_buffer_advance (b0, sizeof(pw_cw_t));
     206          32 :             vlib_buffer_advance (b1, sizeof(pw_cw_t));
     207             : 
     208          32 :             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
     209             :                                             n_left_to_next,
     210             :                                             bi0, bi1, next0, next1);
     211             :         }
     212             : 
     213           6 :         while (n_left_from > 0 && n_left_to_next > 0)
     214             :         {
     215             :             pw_cw_dpo_t *pwcw0;
     216             :             vlib_buffer_t * b0;
     217             :             u32 bi0, pwcwi0;
     218             :             u32 next0;
     219             : 
     220           4 :             bi0 = from[0];
     221           4 :             to_next[0] = bi0;
     222           4 :             from += 1;
     223           4 :             to_next += 1;
     224           4 :             n_left_from -= 1;
     225           4 :             n_left_to_next -= 1;
     226             : 
     227           4 :             b0 = vlib_get_buffer(vm, bi0);
     228             : 
     229           4 :             pwcwi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     230           4 :             pwcw0 = pw_cw_dpo_get(pwcwi0);
     231           4 :             next0 = pwcw0->pwcw_parent.dpoi_next_node;
     232           4 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = pwcw0->pwcw_parent.dpoi_index;
     233             : 
     234           4 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     235             :             {
     236           4 :                 pw_cw_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
     237             : 
     238           4 :                 tr->cw = *((pw_cw_t*) vlib_buffer_get_current(b0));
     239             :             }
     240             : 
     241           4 :             vlib_buffer_advance (b0, sizeof(pw_cw_t));
     242             : 
     243           4 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     244             :                                             n_left_to_next, bi0, next0);
     245             :         }
     246           2 :         vlib_put_next_frame(vm, node, next_index, n_left_to_next);
     247             :     }
     248           2 :     return from_frame->n_vectors;
     249             : }
     250             : 
     251             : static u8 *
     252         118 : format_pw_cw_trace (u8 * s, va_list * args)
     253             : {
     254         118 :     CLIB_UNUSED(vlib_main_t * vm) = va_arg(*args, vlib_main_t *);
     255         118 :     CLIB_UNUSED(vlib_node_t * node) = va_arg(*args, vlib_node_t *);
     256             :     CLIB_UNUSED(pw_cw_trace_t * t);
     257             : 
     258         118 :     t = va_arg(*args, pw_cw_trace_t *);
     259             : 
     260         118 :     s = format(s, "cw:0x%x", t->cw);
     261             : 
     262         118 :     return (s);
     263             : }
     264             : 
     265         561 : VLIB_NODE_FN (pw_cw_node) (vlib_main_t * vm,
     266             :                            vlib_node_runtime_t * node,
     267             :                            vlib_frame_t * frame)
     268             : {
     269           2 :     return (pw_cw_pop_inline(vm, node, frame));
     270             : }
     271             : 
     272      178120 : VLIB_REGISTER_NODE(pw_cw_node) = {
     273             :     .name = "pw-cw-pop",
     274             :     .vector_size = sizeof(u32),
     275             :     .format_trace = format_pw_cw_trace,
     276             : };
     277             : 
     278             : #ifndef CLIB_MARCH_VARIANT
     279             : static void
     280           0 : pw_cw_dpo_mem_show (void)
     281             : {
     282           0 :     fib_show_memory_usage("PW-CW",
     283           0 :                           pool_elts(pw_cw_dpo_pool),
     284           0 :                           pool_len(pw_cw_dpo_pool),
     285             :                           sizeof(pw_cw_dpo_t));
     286           0 : }
     287             : 
     288             : const static dpo_vft_t pwcw_vft = {
     289             :     .dv_lock = pw_cw_dpo_lock,
     290             :     .dv_unlock = pw_cw_dpo_unlock,
     291             :     .dv_format = format_pw_cw_dpo,
     292             :     .dv_mem_show = pw_cw_dpo_mem_show,
     293             : };
     294             : 
     295             : const static char* const pw_cw_proto_nodes[] =
     296             : {
     297             :     "pw-cw-pop",
     298             :     NULL,
     299             : };
     300             : 
     301             : const static char* const * const pw_cw_nodes[DPO_PROTO_NUM] =
     302             : {
     303             :     [DPO_PROTO_IP4]  = pw_cw_proto_nodes,
     304             :     [DPO_PROTO_IP6]  = pw_cw_proto_nodes,
     305             :     [DPO_PROTO_MPLS] = pw_cw_proto_nodes,
     306             :     [DPO_PROTO_ETHERNET] = pw_cw_proto_nodes,
     307             : };
     308             : 
     309             : void
     310         559 : pw_cw_dpo_module_init (void)
     311             : {
     312         559 :     dpo_register(DPO_PW_CW, &pwcw_vft, pw_cw_nodes);
     313         559 : }
     314             : 
     315             : #endif /* CLIB_MARCH_VARIANT */

Generated by: LCOV version 1.14