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