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