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