LCOV - code coverage report
Current view: top level - vnet/snap - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 75 135 55.6 %
Date: 2023-07-05 22:20:52 Functions: 9 9 100.0 %

          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             :  * snap_node.c: snap 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/llc/llc.h>
      43             : #include <vnet/snap/snap.h>
      44             : 
      45             : typedef enum
      46             : {
      47             :   SNAP_INPUT_NEXT_DROP,
      48             :   SNAP_INPUT_NEXT_PUNT,
      49             :   SNAP_INPUT_NEXT_ETHERNET_TYPE,
      50             :   SNAP_INPUT_N_NEXT,
      51             : } snap_input_next_t;
      52             : 
      53             : typedef struct
      54             : {
      55             :   u8 packet_data[32];
      56             : } snap_input_trace_t;
      57             : 
      58             : static u8 *
      59           3 : format_snap_input_trace (u8 * s, va_list * va)
      60             : {
      61           3 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
      62           3 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
      63           3 :   snap_input_trace_t *t = va_arg (*va, snap_input_trace_t *);
      64             : 
      65           3 :   s = format (s, "%U", format_snap_header, t->packet_data);
      66             : 
      67           3 :   return s;
      68             : }
      69             : 
      70             : static uword
      71           3 : snap_input (vlib_main_t * vm,
      72             :             vlib_node_runtime_t * node, vlib_frame_t * from_frame)
      73             : {
      74           3 :   snap_main_t *sm = &snap_main;
      75             :   u32 n_left_from, next_index, *from, *to_next;
      76             : 
      77           3 :   from = vlib_frame_vector_args (from_frame);
      78           3 :   n_left_from = from_frame->n_vectors;
      79             : 
      80           3 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
      81           3 :     vlib_trace_frame_buffers_only (vm, node,
      82             :                                    from,
      83             :                                    n_left_from,
      84             :                                    sizeof (from[0]),
      85             :                                    sizeof (snap_input_trace_t));
      86             : 
      87           3 :   next_index = node->cached_next_index;
      88             : 
      89           6 :   while (n_left_from > 0)
      90             :     {
      91             :       u32 n_left_to_next;
      92             : 
      93           3 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
      94             : 
      95           3 :       while (n_left_from >= 4 && n_left_to_next >= 2)
      96             :         {
      97             :           u32 bi0, bi1;
      98             :           vlib_buffer_t *b0, *b1;
      99             :           snap_header_t *h0, *h1;
     100             :           snap_protocol_info_t *pi0, *pi1;
     101             :           u8 next0, next1, is_ethernet0, is_ethernet1, len0, len1,
     102             :             enqueue_code;
     103             :           u32 oui0, oui1;
     104             : 
     105             :           /* Prefetch next iteration. */
     106             :           {
     107             :             vlib_buffer_t *b2, *b3;
     108             : 
     109           0 :             b2 = vlib_get_buffer (vm, from[2]);
     110           0 :             b3 = vlib_get_buffer (vm, from[3]);
     111             : 
     112           0 :             vlib_prefetch_buffer_header (b2, LOAD);
     113           0 :             vlib_prefetch_buffer_header (b3, LOAD);
     114             : 
     115           0 :             CLIB_PREFETCH (b2->data, sizeof (h0[0]), LOAD);
     116           0 :             CLIB_PREFETCH (b3->data, sizeof (h1[0]), LOAD);
     117             :           }
     118             : 
     119           0 :           bi0 = from[0];
     120           0 :           bi1 = from[1];
     121           0 :           to_next[0] = bi0;
     122           0 :           to_next[1] = bi1;
     123           0 :           from += 2;
     124           0 :           to_next += 2;
     125           0 :           n_left_to_next -= 2;
     126           0 :           n_left_from -= 2;
     127             : 
     128           0 :           b0 = vlib_get_buffer (vm, bi0);
     129           0 :           b1 = vlib_get_buffer (vm, bi1);
     130             : 
     131           0 :           h0 = vlib_buffer_get_current (b0);
     132           0 :           h1 = vlib_buffer_get_current (b1);
     133             : 
     134           0 :           oui0 = snap_header_get_oui (h0);
     135           0 :           oui1 = snap_header_get_oui (h1);
     136             : 
     137           0 :           is_ethernet0 = oui0 == IEEE_OUI_ethernet;
     138           0 :           is_ethernet1 = oui1 == IEEE_OUI_ethernet;
     139             : 
     140           0 :           len0 = sizeof (h0[0]) - (is_ethernet0 ? sizeof (h0->protocol) : 0);
     141           0 :           len1 = sizeof (h1[0]) - (is_ethernet1 ? sizeof (h1->protocol) : 0);
     142             : 
     143           0 :           vlib_buffer_advance (b0, len0);
     144           0 :           vlib_buffer_advance (b1, len1);
     145             : 
     146           0 :           pi0 = snap_get_protocol_info (sm, h0);
     147           0 :           pi1 = snap_get_protocol_info (sm, h1);
     148             : 
     149           0 :           next0 = pi0 ? pi0->next_index : SNAP_INPUT_NEXT_DROP;
     150           0 :           next1 = pi1 ? pi1->next_index : SNAP_INPUT_NEXT_DROP;
     151             : 
     152           0 :           next0 = is_ethernet0 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next0;
     153           0 :           next1 = is_ethernet1 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next1;
     154             : 
     155             :           /* In case of error. */
     156           0 :           b0->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
     157           0 :           b1->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
     158             : 
     159           0 :           enqueue_code = (next0 != next_index) + 2 * (next1 != next_index);
     160             : 
     161           0 :           if (PREDICT_FALSE (enqueue_code != 0))
     162             :             {
     163           0 :               switch (enqueue_code)
     164             :                 {
     165           0 :                 case 1:
     166             :                   /* A B A */
     167           0 :                   to_next[-2] = bi1;
     168           0 :                   to_next -= 1;
     169           0 :                   n_left_to_next += 1;
     170           0 :                   vlib_set_next_frame_buffer (vm, node, next0, bi0);
     171           0 :                   break;
     172             : 
     173           0 :                 case 2:
     174             :                   /* A A B */
     175           0 :                   to_next -= 1;
     176           0 :                   n_left_to_next += 1;
     177           0 :                   vlib_set_next_frame_buffer (vm, node, next1, bi1);
     178           0 :                   break;
     179             : 
     180           0 :                 case 3:
     181             :                   /* A B B or A B C */
     182           0 :                   to_next -= 2;
     183           0 :                   n_left_to_next += 2;
     184           0 :                   vlib_set_next_frame_buffer (vm, node, next0, bi0);
     185           0 :                   vlib_set_next_frame_buffer (vm, node, next1, bi1);
     186           0 :                   if (next0 == next1)
     187             :                     {
     188           0 :                       vlib_put_next_frame (vm, node, next_index,
     189             :                                            n_left_to_next);
     190           0 :                       next_index = next1;
     191           0 :                       vlib_get_next_frame (vm, node, next_index, to_next,
     192             :                                            n_left_to_next);
     193             :                     }
     194             :                 }
     195             :             }
     196             :         }
     197             : 
     198           6 :       while (n_left_from > 0 && n_left_to_next > 0)
     199             :         {
     200             :           u32 bi0;
     201             :           vlib_buffer_t *b0;
     202             :           snap_header_t *h0;
     203             :           snap_protocol_info_t *pi0;
     204             :           u8 next0, is_ethernet0, len0;
     205             :           u32 oui0;
     206             : 
     207           3 :           bi0 = from[0];
     208           3 :           to_next[0] = bi0;
     209           3 :           from += 1;
     210           3 :           to_next += 1;
     211           3 :           n_left_from -= 1;
     212           3 :           n_left_to_next -= 1;
     213             : 
     214           3 :           b0 = vlib_get_buffer (vm, bi0);
     215             : 
     216           3 :           h0 = vlib_buffer_get_current (b0);
     217             : 
     218           3 :           oui0 = snap_header_get_oui (h0);
     219             : 
     220           3 :           is_ethernet0 = oui0 == IEEE_OUI_ethernet;
     221             : 
     222           3 :           len0 = sizeof (h0[0]) - (is_ethernet0 ? sizeof (h0->protocol) : 0);
     223             : 
     224           3 :           vlib_buffer_advance (b0, len0);
     225             : 
     226           3 :           pi0 = snap_get_protocol_info (sm, h0);
     227             : 
     228           3 :           next0 = pi0 ? pi0->next_index : SNAP_INPUT_NEXT_DROP;
     229             : 
     230           3 :           next0 = is_ethernet0 ? SNAP_INPUT_NEXT_ETHERNET_TYPE : next0;
     231             : 
     232             :           /* In case of error. */
     233           3 :           b0->error = node->errors[SNAP_ERROR_UNKNOWN_PROTOCOL];
     234             : 
     235             :           /* Sent packet to wrong next? */
     236           3 :           if (PREDICT_FALSE (next0 != next_index))
     237             :             {
     238             :               /* Return old frame; remove incorrectly enqueued packet. */
     239           1 :               vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1);
     240             : 
     241             :               /* Send to correct next. */
     242           1 :               next_index = next0;
     243           1 :               vlib_get_next_frame (vm, node, next_index,
     244             :                                    to_next, n_left_to_next);
     245             : 
     246           1 :               to_next[0] = bi0;
     247           1 :               to_next += 1;
     248           1 :               n_left_to_next -= 1;
     249             :             }
     250             :         }
     251             : 
     252           3 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     253             :     }
     254             : 
     255           3 :   return from_frame->n_vectors;
     256             : }
     257             : 
     258             : static char *snap_error_strings[] = {
     259             : #define _(f,s) s,
     260             :   foreach_snap_error
     261             : #undef _
     262             : };
     263             : 
     264             : /* *INDENT-OFF* */
     265      178120 : VLIB_REGISTER_NODE (snap_input_node) = {
     266             :   .function = snap_input,
     267             :   .name = "snap-input",
     268             :   /* Takes a vector of packets. */
     269             :   .vector_size = sizeof (u32),
     270             : 
     271             :   .n_errors = SNAP_N_ERROR,
     272             :   .error_strings = snap_error_strings,
     273             : 
     274             :   .n_next_nodes = SNAP_INPUT_N_NEXT,
     275             :   .next_nodes = {
     276             :     [SNAP_INPUT_NEXT_DROP] = "error-drop",
     277             :     [SNAP_INPUT_NEXT_PUNT] = "error-punt",
     278             :     [SNAP_INPUT_NEXT_ETHERNET_TYPE] = "ethernet-input-type",
     279             :   },
     280             : 
     281             :   .format_buffer = format_snap_header_with_length,
     282             :   .format_trace = format_snap_input_trace,
     283             :   .unformat_buffer = unformat_snap_header,
     284             : };
     285             : /* *INDENT-ON* */
     286             : 
     287             : static void
     288         559 : snap_setup_node (vlib_main_t *vm, u32 node_index)
     289             : {
     290         559 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     291         559 :   pg_node_t *pn = pg_get_node (node_index);
     292             : 
     293         559 :   n->format_buffer = format_snap_header_with_length;
     294         559 :   n->unformat_buffer = unformat_snap_header;
     295         559 :   pn->unformat_edit = unformat_pg_snap_header;
     296         559 : }
     297             : 
     298             : static clib_error_t *
     299         559 : snap_input_init (vlib_main_t * vm)
     300             : {
     301             :   {
     302         559 :     clib_error_t *error = vlib_call_init_function (vm, snap_init);
     303         559 :     if (error)
     304           0 :       clib_error_report (error);
     305             :   }
     306             : 
     307         559 :   snap_setup_node (vm, snap_input_node.index);
     308             : 
     309         559 :   llc_register_input_protocol (vm, LLC_PROTOCOL_snap, snap_input_node.index);
     310             : 
     311         559 :   return 0;
     312             : }
     313             : 
     314       30239 : VLIB_INIT_FUNCTION (snap_input_init);
     315             : 
     316             : void
     317           2 : snap_register_input_protocol (vlib_main_t * vm,
     318             :                               char *name,
     319             :                               u32 ieee_oui, u16 protocol, u32 node_index)
     320             : {
     321           2 :   snap_main_t *sm = &snap_main;
     322             :   snap_protocol_info_t *pi;
     323             :   snap_header_t h;
     324             :   snap_oui_and_protocol_t key;
     325             : 
     326             :   {
     327           2 :     clib_error_t *error = vlib_call_init_function (vm, snap_input_init);
     328           2 :     if (error)
     329           0 :       clib_error_report (error);
     330             :   }
     331             : 
     332           2 :   h.protocol = clib_host_to_net_u16 (protocol);
     333           2 :   h.oui[0] = (ieee_oui >> 16) & 0xff;
     334           2 :   h.oui[1] = (ieee_oui >> 8) & 0xff;
     335           2 :   h.oui[2] = (ieee_oui >> 0) & 0xff;
     336           2 :   pi = snap_get_protocol_info (sm, &h);
     337           2 :   if (pi)
     338           0 :     return;
     339             : 
     340           2 :   vec_add2 (sm->protocols, pi, 1);
     341             : 
     342           2 :   pi->name = format (0, "%s", name);
     343           2 :   pi->node_index = node_index;
     344           2 :   pi->next_index = vlib_node_add_next (vm, snap_input_node.index, node_index);
     345             : 
     346           2 :   key.oui = ieee_oui;
     347           2 :   key.protocol = clib_host_to_net_u16 (protocol);
     348             : 
     349           2 :   mhash_set (&sm->protocol_hash, &key, pi - sm->protocols, /* old_value */ 0);
     350           4 :   hash_set_mem (sm->protocol_info_by_name, name, pi - sm->protocols);
     351             : }
     352             : 
     353             : /*
     354             :  * fd.io coding-style-patch-verification: ON
     355             :  *
     356             :  * Local Variables:
     357             :  * eval: (c-set-style "gnu")
     358             :  * End:
     359             :  */

Generated by: LCOV version 1.14