blob: 8b30f4705d65ee667ee4fa3c7cfe73963ec81588 [file] [log] [blame]
Neale Ranns17ff3c12018-07-04 10:24:24 -07001/*
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 */
27const static pipe_t PIPE_INVALID = {
28 .sw_if_index = ~0,
29 .subint = {0},
30};
31
32/**
33 * Various 'module' lavel variables
34 */
35typedef 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
49static 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 */
57static u8 *
58pipe_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* */
87VNET_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
94pipe_t *
95pipe_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
102uword
103unformat_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 */
129static uword
130pipe_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
183static u8 *
184format_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
190static clib_error_t *
191pipe_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* */
212VNET_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
223typedef 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
231typedef struct pipe_rx_trace_t_
232{
233 u8 packet_data[32];
234} pipe_rx_trace_t;
235
236static u8 *
237format_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 */
252static_always_inline void
253pipe_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
296static_always_inline uword
297pipe_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
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200362 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
363 vnet_buffer (b1)->l2_hdr_offset = b1->current_data;
364
Neale Ranns17ff3c12018-07-04 10:24:24 -0700365 vnet_buffer (b0)->l3_hdr_offset =
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200366 vnet_buffer (b0)->l2_hdr_offset + sizeof (ethernet_header_t);
Neale Ranns17ff3c12018-07-04 10:24:24 -0700367 vnet_buffer (b1)->l3_hdr_offset =
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200368 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;
Neale Ranns17ff3c12018-07-04 10:24:24 -0700375
376 is_l20 = pipe0->subint.flags & SUBINT_CONFIG_L2;
377 is_l21 = pipe1->subint.flags & SUBINT_CONFIG_L2;
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200378
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
Neale Ranns17ff3c12018-07-04 10:24:24 -0700388 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
Neale Ranns17ff3c12018-07-04 10:24:24 -0700393 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
394 to_next, n_left_to_next,
Lijian Zhangee4efa72018-08-13 16:34:21 +0800395 bi0, bi1, next0, next1);
Neale Ranns17ff3c12018-07-04 10:24:24 -0700396 }
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
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200421 vnet_buffer (b0)->l2_hdr_offset = b0->current_data;
Neale Ranns17ff3c12018-07-04 10:24:24 -0700422 vnet_buffer (b0)->l3_hdr_offset =
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200423 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;
Neale Ranns17ff3c12018-07-04 10:24:24 -0700427
428 is_l20 = pipe0->subint.flags & SUBINT_CONFIG_L2;
Andrew Yourtchenko270055a2018-10-16 12:04:51 +0200429
430 vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
431 vlib_buffer_advance (b0, is_l20 ? 0 : sizeof (ethernet_header_t));
432
Neale Ranns17ff3c12018-07-04 10:24:24 -0700433 pipe_determine_next_node (&ethernet_main, is_l20, type0, b0,
434 &next0);
435
Neale Ranns17ff3c12018-07-04 10:24:24 -0700436 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* */
448VLIB_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
464static u32
465pipe_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
507static int
508pipe_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
524static clib_error_t *
525pipe_create_sub_interface (vnet_hw_interface_t * hi,
Neale Rannsa1ff01e2018-07-09 09:56:32 -0700526 u32 sub_id, u32 * sw_if_index)
Neale Ranns17ff3c12018-07-04 10:24:24 -0700527{
528 vnet_sw_interface_t template;
529
Dave Barachb7b92992018-10-17 10:38:51 -0400530 clib_memset (&template, 0, sizeof (template));
Neale Ranns17ff3c12018-07-04 10:24:24 -0700531 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
540int
541vnet_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 ();
Neale Rannsa1ff01e2018-07-09 09:56:32 -0700547 u8 address[6] = {
Neale Ranns17ff3c12018-07-04 10:24:24 -0700548 [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
Dave Barachb7b92992018-10-17 10:38:51 -0400560 clib_memset (address, 0, sizeof (address));
Neale Ranns17ff3c12018-07-04 10:24:24 -0700561
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
620oops:
621 clib_error_report (error);
622 return rv;
623}
624
625typedef struct pipe_hw_walk_ctx_t_
626{
627 pipe_cb_fn_t cb;
628 void *ctx;
629} pipe_hw_walk_ctx_t;
630
631static walk_rc_t
632pipe_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
658void
659pipe_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
671static clib_error_t *
672create_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* */
710VLIB_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
717int
718vnet_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
752static clib_error_t *
753delete_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* */
790VLIB_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 */