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