LCOV - code coverage report
Current view: top level - vnet/osi - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 24 120 20.0 %
Date: 2023-10-26 01:39:38 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             :  * osi_node.c: osi packet processing
      17             :  *
      18             :  * Copyright (c) 2010 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vlib/vlib.h>
      41             : #include <vnet/pg/pg.h>
      42             : #include <vnet/osi/osi.h>
      43             : #include <vnet/ppp/ppp.h>
      44             : #include <vnet/hdlc/hdlc.h>
      45             : #include <vnet/llc/llc.h>
      46             : 
      47             : #define foreach_osi_input_next                  \
      48             :   _ (PUNT, "error-punt")                      \
      49             :   _ (DROP, "error-drop")
      50             : 
      51             : typedef enum
      52             : {
      53             : #define _(s,n) OSI_INPUT_NEXT_##s,
      54             :   foreach_osi_input_next
      55             : #undef _
      56             :     OSI_INPUT_N_NEXT,
      57             : } osi_input_next_t;
      58             : 
      59             : typedef struct
      60             : {
      61             :   u8 packet_data[32];
      62             : } osi_input_trace_t;
      63             : 
      64             : static u8 *
      65           0 : format_osi_input_trace (u8 * s, va_list * va)
      66             : {
      67           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      68           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      69           0 :   osi_input_trace_t *t = va_arg (*va, osi_input_trace_t *);
      70             : 
      71           0 :   s = format (s, "%U", format_osi_header, t->packet_data);
      72             : 
      73           0 :   return s;
      74             : }
      75             : 
      76             : static uword
      77           0 : osi_input (vlib_main_t * vm,
      78             :            vlib_node_runtime_t * node, vlib_frame_t * from_frame)
      79             : {
      80           0 :   osi_main_t *lm = &osi_main;
      81             :   u32 n_left_from, next_index, *from, *to_next;
      82             : 
      83           0 :   from = vlib_frame_vector_args (from_frame);
      84           0 :   n_left_from = from_frame->n_vectors;
      85             : 
      86           0 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
      87           0 :     vlib_trace_frame_buffers_only (vm, node,
      88             :                                    from,
      89             :                                    n_left_from,
      90             :                                    sizeof (from[0]),
      91             :                                    sizeof (osi_input_trace_t));
      92             : 
      93           0 :   next_index = node->cached_next_index;
      94             : 
      95           0 :   while (n_left_from > 0)
      96             :     {
      97             :       u32 n_left_to_next;
      98             : 
      99           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     100             : 
     101           0 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     102             :         {
     103             :           u32 bi0, bi1;
     104             :           vlib_buffer_t *b0, *b1;
     105             :           osi_header_t *h0, *h1;
     106             :           u8 next0, next1, enqueue_code;
     107             : 
     108             :           /* Prefetch next iteration. */
     109             :           {
     110             :             vlib_buffer_t *b2, *b3;
     111             : 
     112           0 :             b2 = vlib_get_buffer (vm, from[2]);
     113           0 :             b3 = vlib_get_buffer (vm, from[3]);
     114             : 
     115           0 :             vlib_prefetch_buffer_header (b2, LOAD);
     116           0 :             vlib_prefetch_buffer_header (b3, LOAD);
     117             : 
     118           0 :             CLIB_PREFETCH (b2->data, sizeof (h0[0]), LOAD);
     119           0 :             CLIB_PREFETCH (b3->data, sizeof (h1[0]), LOAD);
     120             :           }
     121             : 
     122           0 :           bi0 = from[0];
     123           0 :           bi1 = from[1];
     124           0 :           to_next[0] = bi0;
     125           0 :           to_next[1] = bi1;
     126           0 :           from += 2;
     127           0 :           to_next += 2;
     128           0 :           n_left_to_next -= 2;
     129           0 :           n_left_from -= 2;
     130             : 
     131           0 :           b0 = vlib_get_buffer (vm, bi0);
     132           0 :           b1 = vlib_get_buffer (vm, bi1);
     133             : 
     134           0 :           h0 = vlib_buffer_get_current (b0);
     135           0 :           h1 = vlib_buffer_get_current (b1);
     136             : 
     137           0 :           next0 = lm->input_next_by_protocol[h0->protocol];
     138           0 :           next1 = lm->input_next_by_protocol[h1->protocol];
     139             : 
     140           0 :           b0->error =
     141           0 :             node->errors[next0 ==
     142             :                          OSI_INPUT_NEXT_DROP ? OSI_ERROR_UNKNOWN_PROTOCOL :
     143             :                          OSI_ERROR_NONE];
     144           0 :           b1->error =
     145           0 :             node->errors[next1 ==
     146             :                          OSI_INPUT_NEXT_DROP ? OSI_ERROR_UNKNOWN_PROTOCOL :
     147             :                          OSI_ERROR_NONE];
     148             : 
     149           0 :           enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
     150             : 
     151           0 :           if (PREDICT_FALSE (enqueue_code != 0))
     152             :             {
     153           0 :               switch (enqueue_code)
     154             :                 {
     155           0 :                 case 1:
     156             :                   /* A B A */
     157           0 :                   to_next[-2] = bi1;
     158           0 :                   to_next -= 1;
     159           0 :                   n_left_to_next += 1;
     160           0 :                   vlib_set_next_frame_buffer (vm, node, next0, bi0);
     161           0 :                   break;
     162             : 
     163           0 :                 case 2:
     164             :                   /* A A B */
     165           0 :                   to_next -= 1;
     166           0 :                   n_left_to_next += 1;
     167           0 :                   vlib_set_next_frame_buffer (vm, node, next1, bi1);
     168           0 :                   break;
     169             : 
     170           0 :                 case 3:
     171             :                   /* A B B or A B C */
     172           0 :                   to_next -= 2;
     173           0 :                   n_left_to_next += 2;
     174           0 :                   vlib_set_next_frame_buffer (vm, node, next0, bi0);
     175           0 :                   vlib_set_next_frame_buffer (vm, node, next1, bi1);
     176           0 :                   if (next0 == next1)
     177             :                     {
     178           0 :                       vlib_put_next_frame (vm, node, next_index,
     179             :                                            n_left_to_next);
     180           0 :                       next_index = next1;
     181           0 :                       vlib_get_next_frame (vm, node, next_index, to_next,
     182             :                                            n_left_to_next);
     183             :                     }
     184             :                 }
     185             :             }
     186             :         }
     187             : 
     188           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     189             :         {
     190             :           u32 bi0;
     191             :           vlib_buffer_t *b0;
     192             :           osi_header_t *h0;
     193             :           u8 next0;
     194             : 
     195           0 :           bi0 = from[0];
     196           0 :           to_next[0] = bi0;
     197           0 :           from += 1;
     198           0 :           to_next += 1;
     199           0 :           n_left_from -= 1;
     200           0 :           n_left_to_next -= 1;
     201             : 
     202           0 :           b0 = vlib_get_buffer (vm, bi0);
     203             : 
     204           0 :           h0 = vlib_buffer_get_current (b0);
     205             : 
     206           0 :           next0 = lm->input_next_by_protocol[h0->protocol];
     207             : 
     208           0 :           b0->error =
     209           0 :             node->errors[next0 ==
     210             :                          OSI_INPUT_NEXT_DROP ? OSI_ERROR_UNKNOWN_PROTOCOL :
     211             :                          OSI_ERROR_NONE];
     212             : 
     213             :           /* Sent packet to wrong next? */
     214           0 :           if (PREDICT_FALSE (next0 != next_index))
     215             :             {
     216             :               /* Return old frame; remove incorrectly enqueued packet. */
     217           0 :               vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);
     218             : 
     219             :               /* Send to correct next. */
     220           0 :               next_index = next0;
     221           0 :               vlib_get_next_frame (vm, node, next_index, to_next,
     222             :                                    n_left_to_next);
     223             : 
     224           0 :               to_next[0] = bi0;
     225           0 :               to_next += 1;
     226           0 :               n_left_to_next -= 1;
     227             :             }
     228             :         }
     229             : 
     230           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     231             :     }
     232             : 
     233           0 :   return from_frame->n_vectors;
     234             : }
     235             : 
     236             : static char *osi_error_strings[] = {
     237             : #define _(f,s) s,
     238             :   foreach_osi_error
     239             : #undef _
     240             : };
     241             : 
     242             : /* *INDENT-OFF* */
     243      183788 : VLIB_REGISTER_NODE (osi_input_node) = {
     244             :   .function = osi_input,
     245             :   .name = "osi-input",
     246             :   /* Takes a vector of packets. */
     247             :   .vector_size = sizeof (u32),
     248             : 
     249             :   .n_errors = OSI_N_ERROR,
     250             :   .error_strings = osi_error_strings,
     251             : 
     252             :   .n_next_nodes = OSI_INPUT_N_NEXT,
     253             :   .next_nodes = {
     254             : #define _(s,n) [OSI_INPUT_NEXT_##s] = n,
     255             :     foreach_osi_input_next
     256             : #undef _
     257             :   },
     258             : 
     259             :   .format_buffer = format_osi_header_with_length,
     260             :   .format_trace = format_osi_input_trace,
     261             :   .unformat_buffer = unformat_osi_header,
     262             : };
     263             : /* *INDENT-ON* */
     264             : 
     265             : static void
     266         575 : osi_setup_node (vlib_main_t *vm, u32 node_index)
     267             : {
     268         575 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     269         575 :   pg_node_t *pn = pg_get_node (node_index);
     270             : 
     271         575 :   n->format_buffer = format_osi_header_with_length;
     272         575 :   n->unformat_buffer = unformat_osi_header;
     273         575 :   pn->unformat_edit = unformat_pg_osi_header;
     274         575 : }
     275             : 
     276             : static clib_error_t *
     277         575 : osi_input_init (vlib_main_t * vm)
     278             : {
     279         575 :   clib_error_t *error = 0;
     280         575 :   osi_main_t *lm = &osi_main;
     281             : 
     282         575 :   if ((error = vlib_call_init_function (vm, osi_init)))
     283           0 :     return error;
     284             : 
     285         575 :   osi_setup_node (vm, osi_input_node.index);
     286             : 
     287             :   {
     288             :     int i;
     289      147775 :     for (i = 0; i < ARRAY_LEN (lm->input_next_by_protocol); i++)
     290      147200 :       lm->input_next_by_protocol[i] = OSI_INPUT_NEXT_DROP;
     291             :   }
     292             : 
     293         575 :   ppp_register_input_protocol (vm, PPP_PROTOCOL_osi, osi_input_node.index);
     294         575 :   hdlc_register_input_protocol (vm, HDLC_PROTOCOL_osi, osi_input_node.index);
     295         575 :   llc_register_input_protocol (vm, LLC_PROTOCOL_osi_layer1,
     296             :                                osi_input_node.index);
     297         575 :   llc_register_input_protocol (vm, LLC_PROTOCOL_osi_layer2,
     298             :                                osi_input_node.index);
     299         575 :   llc_register_input_protocol (vm, LLC_PROTOCOL_osi_layer3,
     300             :                                osi_input_node.index);
     301         575 :   llc_register_input_protocol (vm, LLC_PROTOCOL_osi_layer4,
     302             :                                osi_input_node.index);
     303         575 :   llc_register_input_protocol (vm, LLC_PROTOCOL_osi_layer5,
     304             :                                osi_input_node.index);
     305             : 
     306         575 :   return 0;
     307             : }
     308             : 
     309       57023 : VLIB_INIT_FUNCTION (osi_input_init);
     310             : 
     311             : void
     312           0 : osi_register_input_protocol (osi_protocol_t protocol, u32 node_index)
     313             : {
     314           0 :   osi_main_t *lm = &osi_main;
     315           0 :   vlib_main_t *vm = lm->vlib_main;
     316             :   osi_protocol_info_t *pi;
     317             : 
     318             :   {
     319           0 :     clib_error_t *error = vlib_call_init_function (vm, osi_input_init);
     320           0 :     if (error)
     321           0 :       clib_error_report (error);
     322             :   }
     323             : 
     324           0 :   pi = osi_get_protocol_info (lm, protocol);
     325           0 :   pi->node_index = node_index;
     326           0 :   pi->next_index = vlib_node_add_next (vm, osi_input_node.index, node_index);
     327             : 
     328           0 :   lm->input_next_by_protocol[protocol] = pi->next_index;
     329           0 : }
     330             : 
     331             : /*
     332             :  * fd.io coding-style-patch-verification: ON
     333             :  *
     334             :  * Local Variables:
     335             :  * eval: (c-set-style "gnu")
     336             :  * End:
     337             :  */

Generated by: LCOV version 1.14