LCOV - code coverage report
Current view: top level - vnet/devices/pipe - pipe.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 171 270 63.3 %
Date: 2023-10-26 01:39:38 Functions: 20 28 71.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 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/devices/pipe/pipe.h>
      17             : 
      18             : #include <vppinfra/sparse_vec.h>
      19             : 
      20             : /**
      21             :  * @file
      22             :  * @brief Pipe Interfaces.
      23             :  *
      24             :  * A pipe interface, like the UNIX pipe, is a pair of vpp interfaces
      25             :  * that are joined.
      26             :  */
      27             : const static pipe_t PIPE_INVALID = {
      28             :   .sw_if_index = ~0,
      29             :   .subint = {0},
      30             : };
      31             : 
      32             : /**
      33             :  * Various 'module' level variables
      34             :  */
      35             : typedef struct pipe_main_t_
      36             : {
      37             :   /**
      38             :    * Allocated pipe instances
      39             :    */
      40             :   uword *instances;
      41             : 
      42             :   /**
      43             :    * the per-swif-index array of pipes. Each end of the pipe is stored against
      44             :    * its respective sw_if_index
      45             :    */
      46             :   pipe_t *pipes;
      47             : } pipe_main_t;
      48             : 
      49             : static pipe_main_t pipe_main;
      50             : 
      51             : /*
      52             :  * The pipe rewrite is the same size as an ethernet header (since it
      53             :  * is an ethernet interface and the DP is optimised for writing
      54             :  * sizeof(ethernet_header_t) rewrites. However, there are no MAC addresses
      55             :  * since pipes don't have them.
      56             :  */
      57             : static u8 *
      58           0 : pipe_build_rewrite (vnet_main_t * vnm,
      59             :                     u32 sw_if_index,
      60             :                     vnet_link_t link_type, const void *dst_address)
      61             : {
      62             :   ethernet_header_t *h;
      63             :   ethernet_type_t type;
      64           0 :   u8 *rewrite = NULL;
      65             : 
      66           0 :   switch (link_type)
      67             :     {
      68             : #define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
      69           0 :       _(IP4, IP4);
      70           0 :       _(IP6, IP6);
      71           0 :       _(MPLS, MPLS);
      72           0 :       _(ARP, ARP);
      73             : #undef _
      74           0 :     default:
      75           0 :       return NULL;
      76             :     }
      77             : 
      78           0 :   vec_validate (rewrite, sizeof (ethernet_header_t));
      79             : 
      80           0 :   h = (ethernet_header_t *) rewrite;
      81           0 :   h->type = clib_host_to_net_u16 (type);
      82             : 
      83           0 :   return (rewrite);
      84             : }
      85             : 
      86             : /* *INDENT-OFF* */
      87        8063 : VNET_HW_INTERFACE_CLASS (pipe_hw_interface_class) = {
      88             :   .name = "Pipe",
      89             :   .build_rewrite = pipe_build_rewrite,
      90             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
      91             : };
      92             : /* *INDENT-ON* */
      93             : 
      94             : pipe_t *
      95          10 : pipe_get (u32 sw_if_index)
      96             : {
      97          21 :   vec_validate_init_empty (pipe_main.pipes, sw_if_index, PIPE_INVALID);
      98             : 
      99          10 :   return (&pipe_main.pipes[sw_if_index]);
     100             : }
     101             : 
     102             : uword
     103           0 : unformat_pipe_interface (unformat_input_t * input, va_list * args)
     104             : {
     105           0 :   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
     106           0 :   u32 *result = va_arg (*args, u32 *);
     107             :   u32 hw_if_index;
     108           0 :   ethernet_main_t *em = &ethernet_main;
     109             :   ethernet_interface_t *eif;
     110             : 
     111           0 :   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
     112           0 :     return 0;
     113             : 
     114           0 :   eif = ethernet_get_interface (em, hw_if_index);
     115           0 :   if (eif)
     116             :     {
     117           0 :       *result = hw_if_index;
     118           0 :       return 1;
     119             :     }
     120           0 :   return 0;
     121             : }
     122             : 
     123             : #define VNET_PIPE_TX_NEXT_ETHERNET_INPUT VNET_INTERFACE_TX_N_NEXT
     124             : 
     125             : /*
     126             :  * The TX function bounces the packets back to pipe-rx with the TX interface
     127             :  * swapped to the RX.
     128             :  */
     129             : static uword
     130          15 : pipe_tx (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     131             : {
     132             :   u32 n_left_from, n_left_to_next, n_copy, *from, *to_next;
     133          15 :   u32 next_index = VNET_PIPE_TX_NEXT_ETHERNET_INPUT;
     134          15 :   u32 i, sw_if_index = 0;
     135             :   vlib_buffer_t *b;
     136             :   pipe_t *pipe;
     137             : 
     138          15 :   n_left_from = frame->n_vectors;
     139          15 :   from = vlib_frame_vector_args (frame);
     140             : 
     141          30 :   while (n_left_from > 0)
     142             :     {
     143          15 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     144             : 
     145          15 :       n_copy = clib_min (n_left_from, n_left_to_next);
     146             : 
     147          15 :       clib_memcpy_fast (to_next, from, n_copy * sizeof (from[0]));
     148          15 :       n_left_to_next -= n_copy;
     149          15 :       n_left_from -= n_copy;
     150          15 :       i = 0;
     151        1020 :       while (i < n_copy)
     152             :         {
     153        1005 :           b = vlib_get_buffer (vm, from[i]);
     154        1005 :           sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
     155             : 
     156        1005 :           pipe = &pipe_main.pipes[sw_if_index];
     157             :           // Set up RX index to be recv'd by the other end of the pipe
     158        1005 :           vnet_buffer (b)->sw_if_index[VLIB_RX] = pipe->sw_if_index;
     159        1005 :           vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0;
     160             : 
     161        1005 :           i++;
     162             :         }
     163          15 :       from += n_copy;
     164             : 
     165          15 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     166             :     }
     167             : 
     168          15 :   return frame->n_vectors;
     169             : }
     170             : 
     171             : static u8 *
     172           4 : format_pipe_name (u8 * s, va_list * args)
     173             : {
     174           4 :   u32 dev_instance = va_arg (*args, u32);
     175           4 :   return format (s, "pipe%d", dev_instance);
     176             : }
     177             : 
     178             : static clib_error_t *
     179           2 : pipe_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     180             : {
     181             :   vnet_hw_interface_t *hi;
     182             :   u32 id, sw_if_index;
     183             : 
     184           2 :   u32 hw_flags = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     185             :                   VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
     186           2 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     187             : 
     188             :   /* *INDENT-OFF* */
     189           2 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     190         134 :   hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
     191             :   ({
     192             :     vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
     193             :   }));
     194             :   /* *INDENT-ON* */
     195             : 
     196           2 :   return (NULL);
     197             : }
     198             : 
     199             : /* *INDENT-OFF* */
     200       12095 : VNET_DEVICE_CLASS (pipe_device_class) = {
     201             :   .name = "Pipe",
     202             :   .format_device_name = format_pipe_name,
     203             :   .tx_function = pipe_tx,
     204             :   .admin_up_down_function = pipe_admin_up_down,
     205             : };
     206             : /* *INDENT-ON* */
     207             : 
     208             : #define foreach_pipe_rx_next                    \
     209             :   _ (DROP, "error-drop")
     210             : 
     211             : typedef enum pipe_rx_next_t_
     212             : {
     213             : #define _(s,n) PIPE_RX_NEXT_##s,
     214             :   foreach_pipe_rx_next
     215             : #undef _
     216             :     PIPE_RX_N_NEXT,
     217             : } pipe_rx_next_t;
     218             : 
     219             : typedef struct pipe_rx_trace_t_
     220             : {
     221             :   u8 packet_data[32];
     222             : } pipe_rx_trace_t;
     223             : 
     224             : static u8 *
     225         817 : format_pipe_rx_trace (u8 * s, va_list * va)
     226             : {
     227         817 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     228         817 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     229         817 :   pipe_rx_trace_t *t = va_arg (*va, pipe_rx_trace_t *);
     230             : 
     231         817 :   s = format (s, "%U", format_ethernet_header, t->packet_data);
     232             : 
     233         817 :   return s;
     234             : }
     235             : 
     236             : /*
     237             :  * The pipe-rx node is a sibling of ethernet-input so steal it's
     238             :  * next node mechanism
     239             :  */
     240             : static_always_inline void
     241        1005 : pipe_determine_next_node (ethernet_main_t * em,
     242             :                           u32 is_l20,
     243             :                           u32 type0,
     244             :                           vlib_buffer_t * b0, pipe_rx_next_t * next0)
     245             : {
     246        1005 :   if (is_l20)
     247             :     {
     248         469 :       *next0 = em->l2_next;
     249             :     }
     250         536 :   else if (type0 == ETHERNET_TYPE_IP4)
     251             :     {
     252         536 :       *next0 = em->l3_next.input_next_ip4;
     253             :     }
     254           0 :   else if (type0 == ETHERNET_TYPE_IP6)
     255             :     {
     256           0 :       *next0 = em->l3_next.input_next_ip6;
     257             :     }
     258           0 :   else if (type0 == ETHERNET_TYPE_MPLS)
     259             :     {
     260           0 :       *next0 = em->l3_next.input_next_mpls;
     261             : 
     262             :     }
     263           0 :   else if (em->redirect_l3)
     264             :     {
     265             :       // L3 Redirect is on, the cached common next nodes will be
     266             :       // pointing to the redirect node, catch the uncommon types here
     267           0 :       *next0 = em->redirect_l3_next;
     268             :     }
     269             :   else
     270             :     {
     271             :       // uncommon ethertype, check table
     272             :       u32 i0;
     273           0 :       i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
     274           0 :       *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
     275             : 
     276             :       // The table is not populated with LLC values, so check that now.
     277           0 :       if (type0 < 0x600)
     278             :         {
     279           0 :           *next0 = PIPE_RX_NEXT_DROP;
     280             :         }
     281             :     }
     282        1005 : }
     283             : 
     284             : static_always_inline uword
     285          15 : pipe_rx (vlib_main_t * vm,
     286             :          vlib_node_runtime_t * node, vlib_frame_t * from_frame)
     287             : {
     288             :   u32 n_left_from, next_index, *from, *to_next;
     289             :   u32 n_left_to_next;
     290             : 
     291          15 :   from = vlib_frame_vector_args (from_frame);
     292          15 :   n_left_from = from_frame->n_vectors;
     293             : 
     294          15 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     295          15 :     vlib_trace_frame_buffers_only (vm, node,
     296             :                                    from,
     297             :                                    n_left_from,
     298             :                                    sizeof (from[0]),
     299             :                                    sizeof (pipe_rx_trace_t));
     300             : 
     301          15 :   next_index = node->cached_next_index;
     302             : 
     303          30 :   while (n_left_from > 0)
     304             :     {
     305          15 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     306             : 
     307         495 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     308             :         {
     309             :           u32 bi0, sw_if_index0, bi1, sw_if_index1;
     310             :           pipe_rx_next_t next0, next1;
     311             :           ethernet_header_t *e0, *e1;
     312             :           vlib_buffer_t *b0, *b1;
     313             :           pipe_t *pipe0, *pipe1;
     314             :           u8 is_l20, is_l21;
     315             :           u16 type0, type1;
     316             : 
     317             :           // Prefetch next iteration
     318             :           {
     319             :             vlib_buffer_t *p2, *p3;
     320             : 
     321         480 :             p2 = vlib_get_buffer (vm, from[2]);
     322         480 :             p3 = vlib_get_buffer (vm, from[3]);
     323         480 :             vlib_prefetch_buffer_header (p2, STORE);
     324         480 :             vlib_prefetch_buffer_header (p3, STORE);
     325         480 :             clib_prefetch_load (p2->data);
     326         480 :             clib_prefetch_load (p3->data);
     327             :           }
     328             : 
     329         480 :           bi0 = from[0];
     330         480 :           to_next[0] = bi0;
     331         480 :           bi1 = from[1];
     332         480 :           to_next[1] = bi1;
     333         480 :           from += 2;
     334         480 :           to_next += 2;
     335         480 :           n_left_from -= 2;
     336         480 :           n_left_to_next -= 2;
     337             : 
     338         480 :           b0 = vlib_get_buffer (vm, bi0);
     339         480 :           b1 = vlib_get_buffer (vm, bi1);
     340             : 
     341         480 :           e0 = vlib_buffer_get_current (b0);
     342         480 :           e1 = vlib_buffer_get_current (b1);
     343         480 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     344         480 :           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
     345         480 :           type0 = clib_net_to_host_u16 (e0->type);
     346         480 :           type1 = clib_net_to_host_u16 (e1->type);
     347         480 :           pipe0 = &pipe_main.pipes[sw_if_index0];
     348         480 :           pipe1 = &pipe_main.pipes[sw_if_index1];
     349             : 
     350         480 :           vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
     351         480 :           vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
     352             : 
     353         480 :           vnet_buffer (b0)->l3_hdr_offset =
     354         480 :             vnet_buffer (b0)->l2_hdr_offset + sizeof (ethernet_header_t);
     355         480 :           vnet_buffer (b1)->l3_hdr_offset =
     356         480 :             vnet_buffer (b1)->l2_hdr_offset + sizeof (ethernet_header_t);
     357         480 :           b0->flags |=
     358             :             VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
     359             :             VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     360         480 :           b1->flags |=
     361             :             VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
     362             :             VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     363             : 
     364         480 :           is_l20 = pipe0->subint.flags & SUBINT_CONFIG_L2;
     365         480 :           is_l21 = pipe1->subint.flags & SUBINT_CONFIG_L2;
     366             : 
     367             :           /*
     368             :            * from discussion with Neale - we do not support the tagged traffic.
     369             :            * So assume a simple ethernet header
     370             :            */
     371         480 :           vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
     372         480 :           vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
     373         480 :           vlib_buffer_advance (b0, is_l20 ? 0 : sizeof (ethernet_header_t));
     374         480 :           vlib_buffer_advance (b1, is_l21 ? 0 : sizeof (ethernet_header_t));
     375             : 
     376         480 :           pipe_determine_next_node (&ethernet_main, is_l20, type0, b0,
     377             :                                     &next0);
     378         480 :           pipe_determine_next_node (&ethernet_main, is_l21, type1, b1,
     379             :                                     &next1);
     380             : 
     381         480 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     382             :                                            to_next, n_left_to_next,
     383             :                                            bi0, bi1, next0, next1);
     384             :         }
     385          60 :       while (n_left_from > 0 && n_left_to_next > 0)
     386             :         {
     387             :           u32 bi0, sw_if_index0;
     388             :           vlib_buffer_t *b0;
     389             :           pipe_rx_next_t next0;
     390             :           ethernet_header_t *e0;
     391             :           pipe_t *pipe0;
     392             :           u16 type0;
     393             :           u8 is_l20;
     394             : 
     395          45 :           bi0 = from[0];
     396          45 :           to_next[0] = bi0;
     397          45 :           from += 1;
     398          45 :           to_next += 1;
     399          45 :           n_left_from -= 1;
     400          45 :           n_left_to_next -= 1;
     401             : 
     402          45 :           b0 = vlib_get_buffer (vm, bi0);
     403             : 
     404          45 :           e0 = vlib_buffer_get_current (b0);
     405          45 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     406          45 :           type0 = clib_net_to_host_u16 (e0->type);
     407          45 :           pipe0 = &pipe_main.pipes[sw_if_index0];
     408             : 
     409          45 :           vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
     410          45 :           vnet_buffer (b0)->l3_hdr_offset =
     411          45 :             vnet_buffer (b0)->l2_hdr_offset + sizeof (ethernet_header_t);
     412          45 :           b0->flags |=
     413             :             VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
     414             :             VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
     415             : 
     416          45 :           is_l20 = pipe0->subint.flags & SUBINT_CONFIG_L2;
     417             : 
     418          45 :           vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
     419          45 :           vlib_buffer_advance (b0, is_l20 ? 0 : sizeof (ethernet_header_t));
     420             : 
     421          45 :           pipe_determine_next_node (&ethernet_main, is_l20, type0, b0,
     422             :                                     &next0);
     423             : 
     424          45 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     425             :                                            to_next, n_left_to_next,
     426             :                                            bi0, next0);
     427             :         }
     428             : 
     429          15 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     430             :     }
     431             : 
     432          15 :   return from_frame->n_vectors;
     433             : }
     434             : 
     435             : /* *INDENT-OFF* */
     436      183788 : VLIB_REGISTER_NODE (pipe_rx_node) = {
     437             :   .function = pipe_rx,
     438             :   .name = "pipe-rx",
     439             :   /* Takes a vector of packets. */
     440             :   .vector_size = sizeof (u32),
     441             :   .format_trace = format_pipe_rx_trace,
     442             : 
     443             :   .sibling_of = "ethernet-input",
     444             : };
     445             : /* *INDENT-ON* */
     446             : 
     447             : /*
     448             :  * Maintain a bitmap of allocated pipe instance numbers.
     449             :  */
     450             : #define PIPE_MAX_INSTANCE               (16 * 1024)
     451             : 
     452             : static u32
     453           2 : pipe_instance_alloc (u8 is_specified, u32 want)
     454             : {
     455             :   /*
     456             :    * Check for dynamically allocaetd instance number.
     457             :    */
     458           2 :   if (!is_specified)
     459             :     {
     460             :       u32 bit;
     461             : 
     462           1 :       bit = clib_bitmap_first_clear (pipe_main.instances);
     463           1 :       if (bit >= PIPE_MAX_INSTANCE)
     464             :         {
     465           0 :           return ~0;
     466             :         }
     467           1 :       pipe_main.instances = clib_bitmap_set (pipe_main.instances, bit, 1);
     468           1 :       return bit;
     469             :     }
     470             : 
     471             :   /*
     472             :    * In range?
     473             :    */
     474           1 :   if (want >= PIPE_MAX_INSTANCE)
     475             :     {
     476           0 :       return ~0;
     477             :     }
     478             : 
     479             :   /*
     480             :    * Already in use?
     481             :    */
     482           1 :   if (clib_bitmap_get (pipe_main.instances, want))
     483             :     {
     484           0 :       return ~0;
     485             :     }
     486             : 
     487             :   /*
     488             :    * Grant allocation request.
     489             :    */
     490           1 :   pipe_main.instances = clib_bitmap_set (pipe_main.instances, want, 1);
     491             : 
     492           1 :   return want;
     493             : }
     494             : 
     495             : static int
     496           0 : pipe_instance_free (u32 instance)
     497             : {
     498           0 :   if (instance >= PIPE_MAX_INSTANCE)
     499             :     {
     500           0 :       return -1;
     501             :     }
     502             : 
     503           0 :   if (clib_bitmap_get (pipe_main.instances, instance) == 0)
     504             :     {
     505           0 :       return -1;
     506             :     }
     507             : 
     508           0 :   pipe_main.instances = clib_bitmap_set (pipe_main.instances, instance, 0);
     509           0 :   return 0;
     510             : }
     511             : 
     512             : static clib_error_t *
     513           4 : pipe_create_sub_interface (vnet_hw_interface_t * hi,
     514             :                            u32 sub_id, u32 * sw_if_index)
     515             : {
     516             :   vnet_sw_interface_t template;
     517             : 
     518           4 :   clib_memset (&template, 0, sizeof (template));
     519           4 :   template.type = VNET_SW_INTERFACE_TYPE_PIPE;
     520           4 :   template.flood_class = VNET_FLOOD_CLASS_NORMAL;
     521           4 :   template.sup_sw_if_index = hi->sw_if_index;
     522           4 :   template.sub.id = sub_id;
     523             : 
     524           4 :   return (vnet_create_sw_interface (vnet_get_main (),
     525             :                                     &template, sw_if_index));
     526             : }
     527             : 
     528             : int
     529           2 : vnet_create_pipe_interface (u8 is_specified,
     530             :                             u32 user_instance,
     531             :                             u32 * parent_sw_if_index, u32 pipe_sw_if_index[2])
     532             : {
     533           2 :   vnet_main_t *vnm = vnet_get_main ();
     534           2 :   vlib_main_t *vm = vlib_get_main ();
     535           2 :   vnet_eth_interface_registration_t eir = {};
     536           2 :   u8 address[6] = {
     537             :     [0] = 0x22,
     538             :     [1] = 0x22,
     539             :   };
     540             :   vnet_hw_interface_t *hi;
     541             :   clib_error_t *error;
     542             :   u32 hw_if_index;
     543             :   u32 instance;
     544             :   u32 slot;
     545           2 :   int rv = 0;
     546             : 
     547           2 :   ASSERT (parent_sw_if_index);
     548             : 
     549           2 :   clib_memset (address, 0, sizeof (address));
     550             : 
     551             :   /*
     552             :    * Allocate a pipe instance.  Either select one dynamically
     553             :    * or try to use the desired user_instance number.
     554             :    */
     555           2 :   instance = pipe_instance_alloc (is_specified, user_instance);
     556           2 :   if (instance == ~0)
     557             :     {
     558           0 :       return VNET_API_ERROR_INVALID_REGISTRATION;
     559             :     }
     560             : 
     561             :   /*
     562             :    * Default MAC address (0000:0000:0000 + instance) is allocated
     563             :    */
     564           2 :   address[5] = instance;
     565             : 
     566           2 :   eir.dev_class_index = pipe_device_class.index;
     567           2 :   eir.dev_instance = instance;
     568           2 :   eir.address = address;
     569           2 :   hw_if_index = vnet_eth_register_interface (vnm, &eir);
     570             : 
     571           2 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     572           2 :   *parent_sw_if_index = hi->sw_if_index;
     573           2 :   slot = vlib_node_add_named_next_with_slot (vm, hi->tx_node_index,
     574             :                                              "pipe-rx",
     575             :                                              VNET_PIPE_TX_NEXT_ETHERNET_INPUT);
     576           2 :   ASSERT (slot == VNET_PIPE_TX_NEXT_ETHERNET_INPUT);
     577             : 
     578             :   /*
     579             :    * create two sub-interfaces, one for each end of the pipe.
     580             :    */
     581           2 :   error = pipe_create_sub_interface (hi, 0, &pipe_sw_if_index[0]);
     582             : 
     583           2 :   if (error)
     584           0 :     goto oops;
     585             : 
     586           2 :   error = pipe_create_sub_interface (hi, 1, &pipe_sw_if_index[1]);
     587             : 
     588           2 :   if (error)
     589           0 :     goto oops;
     590             : 
     591           2 :   hash_set (hi->sub_interface_sw_if_index_by_id, 0, pipe_sw_if_index[0]);
     592           2 :   hash_set (hi->sub_interface_sw_if_index_by_id, 1, pipe_sw_if_index[1]);
     593             : 
     594           2 :   vec_validate_init_empty (pipe_main.pipes, pipe_sw_if_index[0],
     595             :                            PIPE_INVALID);
     596           2 :   vec_validate_init_empty (pipe_main.pipes, pipe_sw_if_index[1],
     597             :                            PIPE_INVALID);
     598             : 
     599           2 :   pipe_main.pipes[pipe_sw_if_index[0]].sw_if_index = pipe_sw_if_index[1];
     600           2 :   pipe_main.pipes[pipe_sw_if_index[1]].sw_if_index = pipe_sw_if_index[0];
     601             : 
     602           2 :   return 0;
     603             : 
     604           0 : oops:
     605           0 :   clib_error_report (error);
     606           0 :   return rv;
     607             : }
     608             : 
     609             : typedef struct pipe_hw_walk_ctx_t_
     610             : {
     611             :   pipe_cb_fn_t cb;
     612             :   void *ctx;
     613             : } pipe_hw_walk_ctx_t;
     614             : 
     615             : static walk_rc_t
     616           0 : pipe_hw_walk (vnet_main_t * vnm, u32 hw_if_index, void *args)
     617             : {
     618             :   vnet_hw_interface_t *hi;
     619             :   pipe_hw_walk_ctx_t *ctx;
     620             : 
     621           0 :   ctx = args;
     622           0 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     623             : 
     624           0 :   if (hi->dev_class_index == pipe_device_class.index)
     625             :     {
     626             :       u32 pipe_sw_if_index[2], id, sw_if_index;
     627             : 
     628             :       /* *INDENT-OFF* */
     629           0 :       hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
     630             :       ({
     631             :         ASSERT(id < 2);
     632             :         pipe_sw_if_index[id] = sw_if_index;
     633             :       }));
     634             :       /* *INDENT-ON* */
     635             : 
     636           0 :       ctx->cb (hi->sw_if_index, pipe_sw_if_index, hi->dev_instance, ctx->ctx);
     637             :     }
     638             : 
     639           0 :   return (WALK_CONTINUE);
     640             : }
     641             : 
     642             : void
     643           0 : pipe_walk (pipe_cb_fn_t fn, void *ctx)
     644             : {
     645           0 :   pipe_hw_walk_ctx_t wctx = {
     646             :     .cb = fn,
     647             :     .ctx = ctx,
     648             :   };
     649             : 
     650           0 :   ASSERT (fn);
     651             : 
     652           0 :   vnet_hw_interface_walk (vnet_get_main (), pipe_hw_walk, &wctx);
     653           0 : }
     654             : 
     655             : static clib_error_t *
     656           0 : create_pipe_interfaces (vlib_main_t * vm,
     657             :                         unformat_input_t * input, vlib_cli_command_t * cmd)
     658             : {
     659             :   int rv;
     660             :   u32 sw_if_index;
     661             :   u32 pipe_sw_if_index[2];
     662           0 :   u8 is_specified = 0;
     663           0 :   u32 user_instance = 0;
     664             : 
     665           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     666             :     {
     667           0 :       if (unformat (input, "instance %d", &user_instance))
     668           0 :         is_specified = 1;
     669             :       else
     670           0 :         break;
     671             :     }
     672             : 
     673           0 :   rv = vnet_create_pipe_interface (is_specified, user_instance,
     674             :                                    &sw_if_index, pipe_sw_if_index);
     675             : 
     676           0 :   if (rv)
     677           0 :     return clib_error_return (0, "vnet_create_pipe_interface failed");
     678             : 
     679           0 :   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
     680             :                    vnet_get_main (), sw_if_index);
     681           0 :   return 0;
     682             : }
     683             : 
     684             : /*?
     685             :  * Create a pipe interface.
     686             :  *
     687             :  * @cliexpar
     688             :  * The following two command syntaxes are equivalent:
     689             :  * @cliexcmd{pipe create-interface [mac <mac-addr>] [instance <instance>]}
     690             :  * Example of how to create a pipe interface:
     691             :  * @cliexcmd{pipe create}
     692             :  ?*/
     693             : /* *INDENT-OFF* */
     694      285289 : VLIB_CLI_COMMAND (pipe_create_interface_command, static) = {
     695             :   .path = "pipe create",
     696             :   .short_help = "pipe create [instance <instance>]",
     697             :   .function = create_pipe_interfaces,
     698             : };
     699             : /* *INDENT-ON* */
     700             : 
     701             : int
     702           0 : vnet_delete_pipe_interface (u32 sw_if_index)
     703             : {
     704           0 :   vnet_main_t *vnm = vnet_get_main ();
     705             :   vnet_sw_interface_t *si;
     706             :   vnet_hw_interface_t *hi;
     707             :   u32 instance, id;
     708             :   u32 hw_if_index;
     709             : 
     710           0 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
     711           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     712             : 
     713           0 :   si = vnet_get_sw_interface (vnm, sw_if_index);
     714           0 :   hw_if_index = si->hw_if_index;
     715           0 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     716           0 :   instance = hi->dev_instance;
     717             : 
     718           0 :   if (pipe_instance_free (instance) < 0)
     719             :     {
     720           0 :       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     721             :     }
     722             : 
     723             :   /* *INDENT-OFF* */
     724           0 :   hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
     725             :   ({
     726             :     vnet_delete_sub_interface(sw_if_index);
     727             :     pipe_main.pipes[sw_if_index] = PIPE_INVALID;
     728             :   }));
     729             :   /* *INDENT-ON* */
     730             : 
     731           0 :   ethernet_delete_interface (vnm, hw_if_index);
     732             : 
     733           0 :   return 0;
     734             : }
     735             : 
     736             : static clib_error_t *
     737           0 : delete_pipe_interfaces (vlib_main_t * vm,
     738             :                         unformat_input_t * input, vlib_cli_command_t * cmd)
     739             : {
     740           0 :   vnet_main_t *vnm = vnet_get_main ();
     741           0 :   u32 sw_if_index = ~0;
     742             :   int rv;
     743             : 
     744           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     745             :     {
     746           0 :       if (unformat (input, "%U",
     747             :                     unformat_vnet_sw_interface, vnm, &sw_if_index))
     748             :         ;
     749             :       else
     750           0 :         break;
     751             :     }
     752             : 
     753           0 :   if (sw_if_index == ~0)
     754           0 :     return clib_error_return (0, "interface not specified");
     755             : 
     756           0 :   rv = vnet_delete_pipe_interface (sw_if_index);
     757             : 
     758           0 :   if (rv)
     759           0 :     return clib_error_return (0, "vnet_delete_pipe_interface failed");
     760             : 
     761           0 :   return 0;
     762             : }
     763             : 
     764             : /*?
     765             :  * Delete a pipe interface.
     766             :  *
     767             :  * @cliexpar
     768             :  * The following two command syntaxes are equivalent:
     769             :  * @cliexcmd{pipe delete intfc <interface>}
     770             :  * Example of how to delete a pipe interface:
     771             :  * @cliexcmd{pipe delete-interface intfc loop0}
     772             :  ?*/
     773             : /* *INDENT-OFF* */
     774      285289 : VLIB_CLI_COMMAND (pipe_delete_interface_command, static) = {
     775             :   .path = "pipe delete",
     776             :   .short_help = "pipe delete <interface>",
     777             :   .function = delete_pipe_interfaces,
     778             : };
     779             : /* *INDENT-ON* */
     780             : 
     781             : /*
     782             :  * fd.io coding-style-patch-verification: ON
     783             :  *
     784             :  * Local Variables:
     785             :  * eval: (c-set-style "gnu")
     786             :  * End:
     787             :  */

Generated by: LCOV version 1.14