LCOV - code coverage report
Current view: top level - vnet/l2 - l2_patch.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 19 167 11.4 %
Date: 2023-07-05 22:20:52 Functions: 14 23 60.9 %

          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             : #include <vlib/vlib.h>
      16             : #include <vnet/vnet.h>
      17             : #include <vnet/ethernet/ethernet.h>
      18             : #include <vnet/feature/feature.h>
      19             : #include <vppinfra/error.h>
      20             : 
      21             : typedef struct
      22             : {
      23             :   /* vector of dispositions, indexed by rx_sw_if_index */
      24             :   u32 *tx_next_by_rx_sw_if_index;
      25             :   u32 *tx_sw_if_index_by_rx_sw_if_index;
      26             : 
      27             :   /* convenience variables */
      28             :   vlib_main_t *vlib_main;
      29             :   vnet_main_t *vnet_main;
      30             : } l2_patch_main_t;
      31             : 
      32             : typedef struct
      33             : {
      34             :   u32 rx_sw_if_index;
      35             :   u32 tx_sw_if_index;
      36             : } l2_patch_trace_t;
      37             : 
      38             : /* packet trace format function */
      39             : static u8 *
      40           0 : format_l2_patch_trace (u8 * s, va_list * args)
      41             : {
      42           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      43           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      44           0 :   l2_patch_trace_t *t = va_arg (*args, l2_patch_trace_t *);
      45             : 
      46           0 :   s = format (s, "L2_PATCH: rx %d tx %d", t->rx_sw_if_index,
      47             :               t->tx_sw_if_index);
      48           0 :   return s;
      49             : }
      50             : 
      51             : #ifndef CLIB_MARCH_VARIANT
      52             : l2_patch_main_t l2_patch_main;
      53             : #else
      54             : extern l2_patch_main_t l2_patch_main;
      55             : #endif
      56             : 
      57             : extern vlib_node_registration_t l2_patch_node;
      58             : 
      59             : #define foreach_l2_patch_error                  \
      60             : _(PATCHED, "L2 patch packets")                        \
      61             : _(DROPPED, "L2 patch misconfigured drops")
      62             : 
      63             : typedef enum
      64             : {
      65             : #define _(sym,str) L2_PATCH_ERROR_##sym,
      66             :   foreach_l2_patch_error
      67             : #undef _
      68             :     L2_PATCH_N_ERROR,
      69             : } l2_patch_error_t;
      70             : 
      71             : static char *l2_patch_error_strings[] = {
      72             : #define _(sym,string) string,
      73             :   foreach_l2_patch_error
      74             : #undef _
      75             : };
      76             : 
      77             : typedef enum
      78             : {
      79             :   L2_PATCH_NEXT_DROP,
      80             :   L2_PATCH_N_NEXT,
      81             : } l2_patch_next_t;
      82             : 
      83             : static_always_inline void
      84           0 : l2_patch_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
      85             :                 l2_patch_main_t * l2pm, vlib_buffer_t * b, u32 sw_if_index)
      86             : {
      87             :   l2_patch_trace_t *t;
      88             : 
      89           0 :   if ((b->flags & VLIB_BUFFER_IS_TRACED) == 0)
      90           0 :     return;
      91             : 
      92           0 :   t = vlib_add_trace (vm, node, b, sizeof (*t));
      93           0 :   t->rx_sw_if_index = sw_if_index;
      94           0 :   t->tx_sw_if_index = l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index];
      95             : }
      96             : 
      97             : static_always_inline void
      98           0 : l2_patch_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
      99             :                  l2_patch_main_t * l2pm, vlib_buffer_t ** b, u16 * next,
     100             :                  u32 n_left, int do_trace)
     101             : {
     102             :   u32 sw_if_index[4];
     103             : 
     104           0 :   while (n_left >= 4)
     105             :     {
     106             :       /* Prefetch next iteration. */
     107           0 :       if (n_left >= 8)
     108             :         {
     109           0 :           vlib_buffer_t **p = b + 4;
     110           0 :           vlib_prefetch_buffer_header (p[0], LOAD);
     111           0 :           vlib_prefetch_buffer_header (p[1], LOAD);
     112           0 :           vlib_prefetch_buffer_header (p[2], LOAD);
     113           0 :           vlib_prefetch_buffer_header (p[3], LOAD);
     114             :         }
     115             : 
     116           0 :       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     117           0 :       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     118           0 :       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
     119           0 :       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
     120             : 
     121           0 :       ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index[0]] != ~0);
     122           0 :       ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[0]] != ~0);
     123           0 :       ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index[1]] != ~0);
     124           0 :       ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[1]] != ~0);
     125           0 :       ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index[2]] != ~0);
     126           0 :       ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[2]] != ~0);
     127           0 :       ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index[3]] != ~0);
     128           0 :       ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[3]] != ~0);
     129             : 
     130           0 :       next[0] = l2pm->tx_next_by_rx_sw_if_index[sw_if_index[0]];
     131           0 :       next[1] = l2pm->tx_next_by_rx_sw_if_index[sw_if_index[1]];
     132           0 :       next[2] = l2pm->tx_next_by_rx_sw_if_index[sw_if_index[2]];
     133           0 :       next[3] = l2pm->tx_next_by_rx_sw_if_index[sw_if_index[3]];
     134             : 
     135           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
     136           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[0]];
     137           0 :       vnet_buffer (b[1])->sw_if_index[VLIB_TX] =
     138           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[1]];
     139           0 :       vnet_buffer (b[2])->sw_if_index[VLIB_TX] =
     140           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[2]];
     141           0 :       vnet_buffer (b[3])->sw_if_index[VLIB_TX] =
     142           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[3]];
     143             : 
     144           0 :       if (do_trace)
     145             :         {
     146           0 :           l2_patch_trace (vm, node, l2pm, b[0], sw_if_index[0]);
     147           0 :           l2_patch_trace (vm, node, l2pm, b[1], sw_if_index[1]);
     148           0 :           l2_patch_trace (vm, node, l2pm, b[2], sw_if_index[2]);
     149           0 :           l2_patch_trace (vm, node, l2pm, b[3], sw_if_index[3]);
     150             :         }
     151             : 
     152             :       /* next */
     153           0 :       next += 4;
     154           0 :       b += 4;
     155           0 :       n_left -= 4;
     156             :     }
     157             : 
     158           0 :   while (n_left)
     159             :     {
     160           0 :       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     161             : 
     162           0 :       ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index[0]] != ~0);
     163           0 :       ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[0]] != ~0);
     164             : 
     165           0 :       next[0] = l2pm->tx_next_by_rx_sw_if_index[sw_if_index[0]];
     166             : 
     167           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
     168           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index[0]];
     169             : 
     170           0 :       if (do_trace)
     171           0 :         l2_patch_trace (vm, node, l2pm, b[0], sw_if_index[0]);
     172             : 
     173             :       /* next */
     174           0 :       next += 1;
     175           0 :       b += 1;
     176           0 :       n_left -= 1;
     177             :     }
     178           0 : }
     179             : 
     180        2236 : VLIB_NODE_FN (l2_patch_node) (vlib_main_t * vm,
     181             :                               vlib_node_runtime_t * node,
     182             :                               vlib_frame_t * frame)
     183             : {
     184             :   u32 *from;
     185           0 :   l2_patch_main_t *l2pm = &l2_patch_main;
     186           0 :   vlib_node_t *n = vlib_get_node (vm, l2_patch_node.index);
     187           0 :   u32 node_counter_base_index = n->error_heap_index;
     188           0 :   vlib_error_main_t *em = &vm->error_main;
     189             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
     190             :   u16 nexts[VLIB_FRAME_SIZE];
     191             : 
     192           0 :   from = vlib_frame_vector_args (frame);
     193             : 
     194           0 :   vlib_get_buffers (vm, from, bufs, frame->n_vectors);
     195             : 
     196           0 :   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
     197           0 :     l2_patch_inline (vm, node, l2pm, bufs, nexts, frame->n_vectors, 1);
     198             :   else
     199           0 :     l2_patch_inline (vm, node, l2pm, bufs, nexts, frame->n_vectors, 0);
     200             : 
     201           0 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     202             : 
     203           0 :   em->counters[node_counter_base_index + L2_PATCH_ERROR_PATCHED] +=
     204           0 :     frame->n_vectors;
     205             : 
     206           0 :   return frame->n_vectors;
     207             : }
     208             : 
     209             : /* *INDENT-OFF* */
     210      178120 : VLIB_REGISTER_NODE (l2_patch_node) = {
     211             :   .name = "l2-patch",
     212             :   .vector_size = sizeof (u32),
     213             :   .format_trace = format_l2_patch_trace,
     214             :   .type = VLIB_NODE_TYPE_INTERNAL,
     215             : 
     216             :   .n_errors = ARRAY_LEN(l2_patch_error_strings),
     217             :   .error_strings = l2_patch_error_strings,
     218             : 
     219             :   .n_next_nodes = L2_PATCH_N_NEXT,
     220             : 
     221             :   /* edit / add dispositions here */
     222             :   .next_nodes = {
     223             :         [L2_PATCH_NEXT_DROP] = "error-drop",
     224             :   },
     225             : };
     226             : /* *INDENT-ON* */
     227             : 
     228             : extern int
     229             : vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index, int is_add);
     230             : #ifndef CLIB_MARCH_VARIANT
     231             : int
     232           0 : vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index, int is_add)
     233             : {
     234           0 :   l2_patch_main_t *l2pm = &l2_patch_main;
     235             :   vnet_hw_interface_t *rxhi, *txhi;
     236             :   u32 tx_next_index;
     237             : 
     238             :   /*
     239             :    * We assume that the API msg handler has used 2x VALIDATE_SW_IF_INDEX
     240             :    * macros...
     241             :    */
     242             : 
     243           0 :   rxhi = vnet_get_sup_hw_interface (l2pm->vnet_main, rx_sw_if_index);
     244             : 
     245             :   /* Make sure caller didn't pass a vlan subif, etc. */
     246           0 :   if (rxhi->sw_if_index != rx_sw_if_index)
     247           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     248             : 
     249           0 :   txhi = vnet_get_sup_hw_interface (l2pm->vnet_main, tx_sw_if_index);
     250           0 :   if (txhi->sw_if_index != tx_sw_if_index)
     251           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
     252             : 
     253           0 :   if (is_add)
     254             :     {
     255           0 :       tx_next_index = vlib_node_add_next (l2pm->vlib_main,
     256           0 :                                           l2_patch_node.index,
     257           0 :                                           txhi->output_node_index);
     258             : 
     259           0 :       vec_validate_init_empty (l2pm->tx_next_by_rx_sw_if_index,
     260             :                                rx_sw_if_index, ~0);
     261             : 
     262           0 :       l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = tx_next_index;
     263           0 :       vec_validate_init_empty (l2pm->tx_sw_if_index_by_rx_sw_if_index,
     264             :                                rx_sw_if_index, ~0);
     265           0 :       l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index]
     266           0 :         = txhi->sw_if_index;
     267             : 
     268           0 :       ethernet_set_flags (l2pm->vnet_main, rxhi->hw_if_index,
     269             :                           ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
     270             : 
     271           0 :       vnet_feature_enable_disable ("device-input", "l2-patch",
     272             :                                    rxhi->sw_if_index, 1, 0, 0);
     273             :     }
     274             :   else
     275             :     {
     276           0 :       ethernet_set_flags (l2pm->vnet_main, rxhi->hw_if_index,
     277             :                           /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
     278             : 
     279           0 :       vnet_feature_enable_disable ("device-input", "l2-patch",
     280             :                                    rxhi->sw_if_index, 0, 0, 0);
     281           0 :       if (vec_len (l2pm->tx_next_by_rx_sw_if_index) > rx_sw_if_index)
     282             :         {
     283           0 :           l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = ~0;
     284           0 :           l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index] = ~0;
     285             :         }
     286             :     }
     287             : 
     288           0 :   return 0;
     289             : }
     290             : #endif
     291             : 
     292             : static clib_error_t *
     293           0 : test_patch_command_fn (vlib_main_t * vm,
     294             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
     295             : {
     296           0 :   l2_patch_main_t *l2pm = &l2_patch_main;
     297           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     298             :   u32 rx_sw_if_index, tx_sw_if_index;
     299             :   int rv;
     300           0 :   int rx_set = 0;
     301           0 :   int tx_set = 0;
     302           0 :   int is_add = 1;
     303           0 :   clib_error_t *error = NULL;
     304             : 
     305             :   /* Get a line of input. */
     306           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     307           0 :     return 0;
     308             : 
     309           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     310             :     {
     311           0 :       if (unformat (line_input, "rx %U", unformat_vnet_sw_interface,
     312             :                     l2pm->vnet_main, &rx_sw_if_index))
     313           0 :         rx_set = 1;
     314           0 :       else if (unformat (line_input, "tx %U", unformat_vnet_sw_interface,
     315             :                          l2pm->vnet_main, &tx_sw_if_index))
     316           0 :         tx_set = 1;
     317           0 :       else if (unformat (line_input, "del"))
     318           0 :         is_add = 0;
     319             :       else
     320           0 :         break;
     321             :     }
     322             : 
     323           0 :   if (rx_set == 0)
     324             :     {
     325           0 :       error = clib_error_return (0, "rx interface not set");
     326           0 :       goto done;
     327             :     }
     328             : 
     329           0 :   if (tx_set == 0)
     330             :     {
     331           0 :       error = clib_error_return (0, "tx interface not set");
     332           0 :       goto done;
     333             :     }
     334             : 
     335           0 :   rv = vnet_l2_patch_add_del (rx_sw_if_index, tx_sw_if_index, is_add);
     336             : 
     337           0 :   switch (rv)
     338             :     {
     339           0 :     case 0:
     340           0 :       break;
     341             : 
     342           0 :     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
     343           0 :       error = clib_error_return (0, "rx interface not a physical port");
     344           0 :       goto done;
     345             : 
     346           0 :     case VNET_API_ERROR_INVALID_SW_IF_INDEX_2:
     347           0 :       error = clib_error_return (0, "tx interface not a physical port");
     348           0 :       goto done;
     349             : 
     350           0 :     default:
     351           0 :       error = clib_error_return
     352             :         (0, "WARNING: vnet_l2_patch_add_del returned %d", rv);
     353           0 :       goto done;
     354             :     }
     355             : 
     356             : 
     357           0 : done:
     358           0 :   unformat_free (line_input);
     359             : 
     360           0 :   return error;
     361             : }
     362             : 
     363             : /*?
     364             :  * Create or delete a Layer 2 patch.
     365             :  *
     366             :  * @cliexpar
     367             :  * @cliexstart{test l2patch rx <intfc> tx <intfc> [del]}
     368             :  * @cliexend
     369             :  * @todo This is incomplete. This needs a detailed description and a
     370             :  * practical example.
     371             : ?*/
     372             : /* *INDENT-OFF* */
     373      272887 : VLIB_CLI_COMMAND (test_patch_command, static) = {
     374             :     .path = "test l2patch",
     375             :     .short_help = "test l2patch rx <intfc> tx <intfc> [del]",
     376             :     .function = test_patch_command_fn,
     377             : };
     378             : /* *INDENT-ON* */
     379             : 
     380             : /** Display the contents of the l2patch table. */
     381             : static clib_error_t *
     382          49 : show_l2patch (vlib_main_t * vm,
     383             :               unformat_input_t * input, vlib_cli_command_t * cmd)
     384             : {
     385          49 :   l2_patch_main_t *l2pm = &l2_patch_main;
     386             :   u32 rx_sw_if_index;
     387          49 :   u32 no_entries = 1;
     388             : 
     389          49 :   ASSERT (vec_len (l2pm->tx_next_by_rx_sw_if_index) ==
     390             :           vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index));
     391             : 
     392          98 :   for (rx_sw_if_index = 0;
     393          49 :        rx_sw_if_index < vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index);
     394           0 :        rx_sw_if_index++)
     395             :     {
     396           0 :       u32 tx_sw_if_index =
     397           0 :         l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index];
     398           0 :       if (tx_sw_if_index != ~0)
     399             :         {
     400           0 :           no_entries = 0;
     401           0 :           vlib_cli_output (vm, "%26U -> %U",
     402             :                            format_vnet_sw_if_index_name,
     403             :                            l2pm->vnet_main, rx_sw_if_index,
     404             :                            format_vnet_sw_if_index_name,
     405             :                            l2pm->vnet_main, tx_sw_if_index);
     406             :         }
     407             :     }
     408             : 
     409          49 :   if (no_entries)
     410          49 :     vlib_cli_output (vm, "no l2patch entries");
     411             : 
     412          49 :   return 0;
     413             : }
     414             : 
     415             : /*?
     416             :  * Show Layer 2 patch entries.
     417             :  *
     418             :  * @cliexpar
     419             :  * @cliexstart{show l2patch}
     420             :  * @cliexend
     421             :  * @todo This is incomplete. This needs a detailed description and a
     422             :  * practical example.
     423             : ?*/
     424             : /* *INDENT-OFF* */
     425      272887 : VLIB_CLI_COMMAND (show_l2patch_cli, static) = {
     426             :   .path = "show l2patch",
     427             :   .short_help = "Show l2 interface cross-connect entries",
     428             :   .function = show_l2patch,
     429             : };
     430             : /* *INDENT-ON* */
     431             : 
     432             : static clib_error_t *
     433         559 : l2_patch_init (vlib_main_t * vm)
     434             : {
     435         559 :   l2_patch_main_t *mp = &l2_patch_main;
     436             : 
     437         559 :   mp->vlib_main = vm;
     438         559 :   mp->vnet_main = vnet_get_main ();
     439             : 
     440         559 :   return 0;
     441             : }
     442             : 
     443       23519 : VLIB_INIT_FUNCTION (l2_patch_init);
     444             : 
     445             : /*
     446             :  * fd.io coding-style-patch-verification: ON
     447             :  *
     448             :  * Local Variables:
     449             :  * eval: (c-set-style "gnu")
     450             :  * End:
     451             :  */

Generated by: LCOV version 1.14