Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * ethernet_interface.c: ethernet interfaces
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vnet/vnet.h>
41 : #include <vnet/ip/ip.h>
42 : #include <vnet/pg/pg.h>
43 : #include <vnet/ethernet/ethernet.h>
44 : //#include <vnet/ethernet/arp.h>
45 : #include <vnet/l2/l2_input.h>
46 : #include <vnet/l2/l2_bd.h>
47 : #include <vnet/adj/adj.h>
48 : #include <vnet/adj/adj_mcast.h>
49 : #include <vnet/ip-neighbor/ip_neighbor.h>
50 :
51 : /**
52 : * @file
53 : * @brief Loopback Interfaces.
54 : *
55 : * This file contains code to manage loopback interfaces.
56 : */
57 :
58 : static const u8 *
59 44 : ethernet_ip4_mcast_dst_addr (void)
60 : {
61 : const static u8 ethernet_mcast_dst_mac[] = {
62 : 0x1, 0x0, 0x5e, 0x0, 0x0, 0x0,
63 : };
64 :
65 44 : return (ethernet_mcast_dst_mac);
66 : }
67 :
68 : static const u8 *
69 1954 : ethernet_ip6_mcast_dst_addr (void)
70 : {
71 : const static u8 ethernet_mcast_dst_mac[] = {
72 : 0x33, 0x33, 0x00, 0x0, 0x0, 0x0,
73 : };
74 :
75 1954 : return (ethernet_mcast_dst_mac);
76 : }
77 :
78 : /**
79 : * @brief build a rewrite string to use for sending packets of type 'link_type'
80 : * to 'dst_address'
81 : */
82 : u8 *
83 37858 : ethernet_build_rewrite (vnet_main_t * vnm,
84 : u32 sw_if_index,
85 : vnet_link_t link_type, const void *dst_address)
86 : {
87 37858 : vnet_sw_interface_t *sub_sw = vnet_get_sw_interface (vnm, sw_if_index);
88 37858 : vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
89 37858 : vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
90 37858 : ethernet_main_t *em = ðernet_main;
91 : ethernet_interface_t *ei;
92 : ethernet_header_t *h;
93 : ethernet_type_t type;
94 37858 : uword n_bytes = sizeof (h[0]);
95 37858 : u8 *rewrite = NULL;
96 37858 : u8 is_p2p = 0;
97 :
98 37858 : if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
99 37826 : (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
100 34 : is_p2p = 1;
101 37858 : if (sub_sw != sup_sw)
102 : {
103 440 : if (sub_sw->sub.eth.flags.one_tag)
104 : {
105 306 : n_bytes += sizeof (ethernet_vlan_header_t);
106 : }
107 134 : else if (sub_sw->sub.eth.flags.two_tags)
108 : {
109 100 : n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
110 : }
111 34 : else if (PREDICT_FALSE (is_p2p))
112 : {
113 34 : n_bytes = sizeof (ethernet_header_t);
114 : }
115 440 : if (PREDICT_FALSE (!is_p2p))
116 : {
117 : // Check for encaps that are not supported for L3 interfaces
118 406 : if (!(sub_sw->sub.eth.flags.exact_match) ||
119 406 : (sub_sw->sub.eth.flags.default_sub) ||
120 406 : (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
121 : (sub_sw->sub.eth.flags.inner_vlan_id_any))
122 : {
123 0 : return 0;
124 : }
125 : }
126 : else
127 : {
128 34 : n_bytes = sizeof (ethernet_header_t);
129 : }
130 : }
131 :
132 37858 : switch (link_type)
133 : {
134 : #define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
135 10957 : _(IP4, IP4);
136 14479 : _(IP6, IP6);
137 57 : _(MPLS, MPLS);
138 12365 : _(ARP, ARP);
139 : #undef _
140 0 : default:
141 0 : return NULL;
142 : }
143 :
144 37858 : vec_validate (rewrite, n_bytes - 1);
145 37858 : h = (ethernet_header_t *) rewrite;
146 37858 : ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
147 37858 : clib_memcpy (h->src_address, &ei->address, sizeof (h->src_address));
148 37858 : if (is_p2p)
149 : {
150 34 : clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
151 : sizeof (h->dst_address));
152 : }
153 : else
154 : {
155 37824 : if (dst_address)
156 23575 : clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
157 : else
158 14249 : clib_memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
159 : }
160 :
161 37858 : if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
162 306 : {
163 306 : ethernet_vlan_header_t *outer = (void *) (h + 1);
164 :
165 306 : h->type = sub_sw->sub.eth.flags.dot1ad ?
166 0 : clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
167 306 : clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
168 306 : outer->priority_cfi_and_id =
169 306 : clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
170 306 : outer->type = clib_host_to_net_u16 (type);
171 :
172 : }
173 37552 : else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
174 100 : {
175 100 : ethernet_vlan_header_t *outer = (void *) (h + 1);
176 100 : ethernet_vlan_header_t *inner = (void *) (outer + 1);
177 :
178 100 : h->type = sub_sw->sub.eth.flags.dot1ad ?
179 100 : clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
180 0 : clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
181 100 : outer->priority_cfi_and_id =
182 100 : clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
183 100 : outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
184 100 : inner->priority_cfi_and_id =
185 100 : clib_host_to_net_u16 (sub_sw->sub.eth.inner_vlan_id);
186 100 : inner->type = clib_host_to_net_u16 (type);
187 :
188 : }
189 : else
190 : {
191 37452 : h->type = clib_host_to_net_u16 (type);
192 : }
193 :
194 37858 : return (rewrite);
195 : }
196 :
197 : void
198 20471 : ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
199 : {
200 20471 : vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
201 :
202 20471 : if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
203 20439 : (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
204 : {
205 34 : default_update_adjacency (vnm, sw_if_index, ai);
206 : }
207 : else
208 : {
209 : ip_adjacency_t *adj;
210 :
211 20437 : adj = adj_get (ai);
212 :
213 20437 : switch (adj->lookup_next_index)
214 : {
215 8527 : case IP_LOOKUP_NEXT_GLEAN:
216 8527 : adj_glean_update_rewrite (ai);
217 8527 : break;
218 9905 : case IP_LOOKUP_NEXT_ARP:
219 : case IP_LOOKUP_NEXT_REWRITE:
220 9905 : ip_neighbor_update (vnm, ai);
221 9905 : break;
222 7 : case IP_LOOKUP_NEXT_BCAST:
223 7 : adj_nbr_update_rewrite (ai,
224 : ADJ_NBR_REWRITE_FLAG_COMPLETE,
225 : ethernet_build_rewrite
226 : (vnm,
227 : adj->rewrite_header.sw_if_index,
228 7 : adj->ia_link,
229 : VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
230 7 : break;
231 1998 : case IP_LOOKUP_NEXT_MCAST:
232 : {
233 : /*
234 : * Construct a partial rewrite from the known ethernet mcast dest MAC
235 : */
236 : u8 *rewrite;
237 : u8 offset;
238 :
239 3996 : rewrite = ethernet_build_rewrite
240 : (vnm,
241 : sw_if_index,
242 1998 : adj->ia_link,
243 1998 : (adj->ia_nh_proto == FIB_PROTOCOL_IP6 ?
244 1954 : ethernet_ip6_mcast_dst_addr () :
245 44 : ethernet_ip4_mcast_dst_addr ()));
246 :
247 : /*
248 : * Complete the remaining fields of the adj's rewrite to direct the
249 : * complete of the rewrite at switch time by copying in the IP
250 : * dst address's bytes.
251 : * Ofset is 2 bytes into the destintation address.
252 : */
253 1998 : offset = vec_len (rewrite) - 2;
254 1998 : adj_mcast_update_rewrite (ai, rewrite, offset);
255 :
256 1998 : break;
257 : }
258 0 : case IP_LOOKUP_NEXT_DROP:
259 : case IP_LOOKUP_NEXT_PUNT:
260 : case IP_LOOKUP_NEXT_LOCAL:
261 : case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
262 : case IP_LOOKUP_NEXT_MIDCHAIN:
263 : case IP_LOOKUP_NEXT_ICMP_ERROR:
264 : case IP_LOOKUP_N_NEXT:
265 0 : ASSERT (0);
266 0 : break;
267 : }
268 20471 : }
269 20471 : }
270 :
271 : static void
272 17688 : ethernet_interface_address_copy (ethernet_interface_address_t * dst,
273 : const u8 * mac)
274 : {
275 17688 : clib_memcpy (&dst->mac, (u8 *) mac, sizeof (dst->mac));
276 : /*
277 : * ethernet dataplane loads mac as u64, makes sure the last 2 bytes are 0
278 : * for comparison purpose
279 : */
280 17688 : dst->zero = 0;
281 17688 : }
282 :
283 : static void
284 5261 : ethernet_set_mac (vnet_hw_interface_t * hi, ethernet_interface_t * ei,
285 : const u8 * mac_address)
286 : {
287 5261 : vec_validate (hi->hw_address, sizeof (mac_address_t) - 1);
288 5261 : clib_memcpy (hi->hw_address, mac_address, sizeof (mac_address_t));
289 5261 : ethernet_interface_address_copy (&ei->address, mac_address);
290 5261 : }
291 :
292 : static clib_error_t *
293 31 : ethernet_mac_change (vnet_hw_interface_t * hi,
294 : const u8 * old_address, const u8 * mac_address)
295 : {
296 : ethernet_interface_t *ei;
297 : ethernet_main_t *em;
298 :
299 31 : em = ðernet_main;
300 31 : ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
301 :
302 31 : ethernet_set_mac (hi, ei, mac_address);
303 :
304 : {
305 : ethernet_address_change_ctx_t *cb;
306 : u32 id, sw_if_index;
307 93 : vec_foreach (cb, em->address_change_callbacks)
308 : {
309 62 : cb->function (em, hi->sw_if_index, cb->function_opaque);
310 : /* clang-format off */
311 448 : hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
312 : ({
313 : cb->function (em, sw_if_index, cb->function_opaque);
314 : }));
315 : /* clang-format on */
316 : }
317 : }
318 :
319 31 : return (NULL);
320 : }
321 :
322 : static clib_error_t *
323 0 : ethernet_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
324 : u32 frame_size)
325 : {
326 0 : ethernet_interface_t *ei =
327 0 : pool_elt_at_index (ethernet_main.interfaces, hi->hw_instance);
328 :
329 0 : if (ei->cb.set_max_frame_size)
330 0 : return ei->cb.set_max_frame_size (vnm, hi, frame_size);
331 :
332 0 : return vnet_error (
333 : VNET_ERR_UNSUPPORTED,
334 : "underlying driver doesn't support changing Max Frame Size");
335 : }
336 :
337 : /* *INDENT-OFF* */
338 8063 : VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
339 : .name = "Ethernet",
340 : .tx_hash_fn_type = VNET_HASH_FN_TYPE_ETHERNET,
341 : .format_address = format_ethernet_address,
342 : .format_header = format_ethernet_header_with_length,
343 : .unformat_hw_address = unformat_ethernet_address,
344 : .unformat_header = unformat_ethernet_header,
345 : .build_rewrite = ethernet_build_rewrite,
346 : .update_adjacency = ethernet_update_adjacency,
347 : .mac_addr_change_function = ethernet_mac_change,
348 : .set_max_frame_size = ethernet_set_max_frame_size,
349 : };
350 : /* *INDENT-ON* */
351 :
352 : uword
353 0 : unformat_ethernet_interface (unformat_input_t * input, va_list * args)
354 : {
355 0 : vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
356 0 : u32 *result = va_arg (*args, u32 *);
357 : u32 hw_if_index;
358 0 : ethernet_main_t *em = ðernet_main;
359 : ethernet_interface_t *eif;
360 :
361 0 : if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
362 0 : return 0;
363 :
364 0 : eif = ethernet_get_interface (em, hw_if_index);
365 0 : if (eif)
366 : {
367 0 : *result = hw_if_index;
368 0 : return 1;
369 : }
370 0 : return 0;
371 : }
372 :
373 : u32
374 5230 : vnet_eth_register_interface (vnet_main_t *vnm,
375 : vnet_eth_interface_registration_t *r)
376 : {
377 5230 : ethernet_main_t *em = ðernet_main;
378 : ethernet_interface_t *ei;
379 : vnet_hw_interface_t *hi;
380 : u32 hw_if_index;
381 :
382 5230 : pool_get (em->interfaces, ei);
383 5230 : clib_memcpy (&ei->cb, &r->cb, sizeof (vnet_eth_if_callbacks_t));
384 :
385 5230 : hw_if_index = vnet_register_interface (
386 : vnm, r->dev_class_index, r->dev_instance,
387 5230 : ethernet_hw_interface_class.index, ei - em->interfaces);
388 :
389 5230 : hi = vnet_get_hw_interface (vnm, hw_if_index);
390 :
391 5230 : ethernet_setup_node (vnm->vlib_main, hi->output_node_index);
392 :
393 5230 : hi->min_frame_size = ETHERNET_MIN_PACKET_BYTES;
394 5230 : hi->frame_overhead =
395 5230 : r->frame_overhead ?
396 : r->frame_overhead :
397 : sizeof (ethernet_header_t) + 2 * sizeof (ethernet_vlan_header_t);
398 10460 : hi->max_frame_size = r->max_frame_size ?
399 5230 : r->max_frame_size :
400 5230 : ethernet_main.default_mtu + hi->frame_overhead;
401 : ;
402 :
403 : /* Default ethernet MTU, 9000 unless set by ethernet_config see below */
404 5230 : vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, em->default_mtu);
405 :
406 5230 : ethernet_set_mac (hi, ei, r->address);
407 5230 : return hw_if_index;
408 : }
409 :
410 : void
411 728 : ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
412 : {
413 728 : ethernet_main_t *em = ðernet_main;
414 : ethernet_interface_t *ei;
415 : vnet_hw_interface_t *hi;
416 : main_intf_t *main_intf;
417 : vlan_table_t *vlan_table;
418 : u32 idx;
419 :
420 728 : hi = vnet_get_hw_interface (vnm, hw_if_index);
421 728 : ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
422 :
423 : /* Delete vlan mapping table for dot1q and dot1ad. */
424 728 : main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
425 728 : if (main_intf->dot1q_vlans)
426 : {
427 3 : vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
428 12291 : for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
429 : {
430 12288 : if (vlan_table->vlans[idx].qinqs)
431 : {
432 0 : pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
433 0 : vlan_table->vlans[idx].qinqs = 0;
434 : }
435 : }
436 3 : pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
437 3 : main_intf->dot1q_vlans = 0;
438 : }
439 728 : if (main_intf->dot1ad_vlans)
440 : {
441 0 : vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
442 0 : for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
443 : {
444 0 : if (vlan_table->vlans[idx].qinqs)
445 : {
446 0 : pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
447 0 : vlan_table->vlans[idx].qinqs = 0;
448 : }
449 : }
450 0 : pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
451 0 : main_intf->dot1ad_vlans = 0;
452 : }
453 :
454 728 : vnet_delete_hw_interface (vnm, hw_if_index);
455 728 : pool_put (em->interfaces, ei);
456 728 : }
457 :
458 : u32
459 2309 : ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
460 : {
461 2309 : ethernet_main_t *em = ðernet_main;
462 : vnet_hw_interface_t *hi;
463 : ethernet_interface_t *ei;
464 2309 : u32 opn_flags = flags & ETHERNET_INTERFACE_FLAGS_SET_OPN_MASK;
465 :
466 2309 : hi = vnet_get_hw_interface (vnm, hw_if_index);
467 :
468 2309 : ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
469 :
470 2309 : ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
471 :
472 : /* preserve status bits and update last set operation bits */
473 2309 : ei->flags = (ei->flags & ETHERNET_INTERFACE_FLAGS_STATUS_MASK) | opn_flags;
474 :
475 2309 : if (ei->cb.flag_change)
476 : {
477 1947 : switch (opn_flags)
478 : {
479 946 : case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
480 946 : if (hi->caps & VNET_HW_IF_CAP_MAC_FILTER)
481 : {
482 0 : if (ei->cb.flag_change (vnm, hi, opn_flags) != ~0)
483 : {
484 0 : ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
485 0 : return 0;
486 : }
487 0 : ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
488 0 : return ~0;
489 : }
490 : /* fall through */
491 : case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
492 1947 : ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
493 1947 : return ei->cb.flag_change (vnm, hi, opn_flags);
494 0 : default:
495 0 : return ~0;
496 : }
497 : }
498 362 : return ~0;
499 : }
500 :
501 : /**
502 : * Echo packets back to ethernet/l2-input.
503 : */
504 : static uword
505 132 : simulated_ethernet_interface_tx (vlib_main_t * vm,
506 : vlib_node_runtime_t *
507 : node, vlib_frame_t * frame)
508 : {
509 : u32 n_left_from, *from;
510 132 : u32 next_index = 0;
511 : u32 n_bytes;
512 132 : u32 thread_index = vm->thread_index;
513 132 : vnet_main_t *vnm = vnet_get_main ();
514 132 : vnet_interface_main_t *im = &vnm->interface_main;
515 : l2_input_config_t *config;
516 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
517 : u16 nexts[VLIB_FRAME_SIZE], *next;
518 132 : u32 new_rx_sw_if_index = ~0;
519 132 : u32 new_tx_sw_if_index = ~0;
520 :
521 132 : n_left_from = frame->n_vectors;
522 132 : from = vlib_frame_vector_args (frame);
523 :
524 132 : vlib_get_buffers (vm, from, bufs, n_left_from);
525 132 : b = bufs;
526 132 : next = nexts;
527 :
528 : /* Ordinarily, this is the only config lookup. */
529 132 : config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
530 132 : next_index = (l2_input_is_bridge (config) ?
531 132 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
532 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
533 132 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
534 132 : new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
535 :
536 238 : while (n_left_from >= 4)
537 : {
538 : u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
539 : u32x4 xor_ifx4;
540 :
541 : /* Prefetch next iteration. */
542 106 : if (PREDICT_TRUE (n_left_from >= 8))
543 : {
544 66 : vlib_prefetch_buffer_header (b[4], STORE);
545 66 : vlib_prefetch_buffer_header (b[5], STORE);
546 66 : vlib_prefetch_buffer_header (b[6], STORE);
547 66 : vlib_prefetch_buffer_header (b[7], STORE);
548 : }
549 :
550 : /* Make sure all pkts were transmitted on the same (loop) intfc */
551 106 : sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
552 106 : sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
553 106 : sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
554 106 : sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
555 :
556 106 : xor_ifx4 = u32x4_gather (&sw_if_index0, &sw_if_index1, &sw_if_index2,
557 : &sw_if_index3);
558 :
559 : /* Speed path / expected case: all pkts on the same intfc */
560 106 : if (PREDICT_TRUE (u32x4_is_all_equal (xor_ifx4, new_rx_sw_if_index)))
561 : {
562 106 : next[0] = next_index;
563 106 : next[1] = next_index;
564 106 : next[2] = next_index;
565 106 : next[3] = next_index;
566 106 : vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
567 106 : vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
568 106 : vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
569 106 : vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
570 106 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
571 106 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
572 106 : vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
573 106 : vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
574 106 : n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
575 106 : n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
576 106 : n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
577 106 : n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
578 :
579 106 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
580 : {
581 44 : vnet_update_l2_len (b[0]);
582 44 : vnet_update_l2_len (b[1]);
583 44 : vnet_update_l2_len (b[2]);
584 44 : vnet_update_l2_len (b[3]);
585 : }
586 :
587 : /* increment TX interface stat */
588 106 : vlib_increment_combined_counter (im->combined_sw_if_counters +
589 : VNET_INTERFACE_COUNTER_TX,
590 : thread_index, new_rx_sw_if_index,
591 : 4 /* pkts */ , n_bytes);
592 106 : b += 4;
593 106 : next += 4;
594 106 : n_left_from -= 4;
595 106 : continue;
596 : }
597 :
598 : /*
599 : * Slow path: we know that at least one of the pkts
600 : * was transmitted on a different sw_if_index, so
601 : * check each sw_if_index against the cached data and proceed
602 : * accordingly.
603 : *
604 : * This shouldn't happen, but code can (and does) bypass the
605 : * per-interface output node, so deal with it.
606 : */
607 0 : if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
608 : != new_rx_sw_if_index))
609 : {
610 0 : config = l2input_intf_config
611 0 : (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
612 0 : next_index = (l2_input_is_bridge (config) ?
613 0 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
614 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
615 0 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
616 0 : new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
617 : }
618 0 : next[0] = next_index;
619 0 : vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
620 0 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
621 0 : n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
622 0 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
623 0 : vnet_update_l2_len (b[0]);
624 :
625 0 : vlib_increment_combined_counter (im->combined_sw_if_counters +
626 : VNET_INTERFACE_COUNTER_TX,
627 : thread_index, new_rx_sw_if_index,
628 : 1 /* pkts */ , n_bytes);
629 :
630 0 : if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
631 : != new_rx_sw_if_index))
632 : {
633 0 : config = l2input_intf_config
634 0 : (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
635 0 : next_index = (l2_input_is_bridge (config) ?
636 0 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
637 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
638 0 : new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
639 0 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
640 : }
641 0 : next[1] = next_index;
642 0 : vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
643 0 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
644 0 : n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
645 0 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
646 0 : vnet_update_l2_len (b[1]);
647 :
648 0 : vlib_increment_combined_counter (im->combined_sw_if_counters +
649 : VNET_INTERFACE_COUNTER_TX,
650 : thread_index, new_rx_sw_if_index,
651 : 1 /* pkts */ , n_bytes);
652 :
653 0 : if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
654 : != new_rx_sw_if_index))
655 : {
656 0 : config = l2input_intf_config
657 0 : (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
658 0 : next_index = (l2_input_is_bridge (config) ?
659 0 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
660 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
661 0 : new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
662 0 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
663 : }
664 0 : next[2] = next_index;
665 0 : vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
666 0 : vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
667 0 : n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
668 0 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
669 0 : vnet_update_l2_len (b[2]);
670 :
671 0 : vlib_increment_combined_counter (im->combined_sw_if_counters +
672 : VNET_INTERFACE_COUNTER_TX,
673 : thread_index, new_rx_sw_if_index,
674 : 1 /* pkts */ , n_bytes);
675 :
676 0 : if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
677 : != new_rx_sw_if_index))
678 : {
679 0 : config = l2input_intf_config
680 0 : (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
681 0 : next_index = (l2_input_is_bridge (config) ?
682 0 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
683 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
684 0 : new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
685 0 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
686 : }
687 0 : next[3] = next_index;
688 0 : vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
689 0 : vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
690 0 : n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
691 0 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
692 0 : vnet_update_l2_len (b[3]);
693 :
694 0 : vlib_increment_combined_counter (im->combined_sw_if_counters +
695 : VNET_INTERFACE_COUNTER_TX,
696 : thread_index, new_rx_sw_if_index,
697 : 1 /* pkts */ , n_bytes);
698 0 : b += 4;
699 0 : next += 4;
700 0 : n_left_from -= 4;
701 : }
702 304 : while (n_left_from > 0)
703 : {
704 172 : if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
705 : != new_rx_sw_if_index))
706 : {
707 0 : config = l2input_intf_config
708 0 : (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
709 0 : next_index = (l2_input_is_bridge (config) ?
710 0 : VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
711 : VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
712 0 : new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
713 0 : new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
714 : }
715 172 : next[0] = next_index;
716 172 : vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
717 172 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
718 172 : n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
719 172 : if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
720 102 : vnet_update_l2_len (b[0]);
721 :
722 172 : vlib_increment_combined_counter (im->combined_sw_if_counters +
723 : VNET_INTERFACE_COUNTER_TX,
724 : thread_index, new_rx_sw_if_index,
725 : 1 /* pkts */ , n_bytes);
726 172 : b += 1;
727 172 : next += 1;
728 172 : n_left_from -= 1;
729 : }
730 :
731 132 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
732 :
733 132 : return frame->n_vectors;
734 : }
735 :
736 : static u8 *
737 449 : format_simulated_ethernet_name (u8 * s, va_list * args)
738 : {
739 449 : u32 dev_instance = va_arg (*args, u32);
740 449 : return format (s, "loop%d", dev_instance);
741 : }
742 :
743 : static clib_error_t *
744 200 : simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
745 : u32 flags)
746 : {
747 200 : u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
748 : VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
749 200 : vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
750 200 : return 0;
751 : }
752 :
753 : static clib_error_t *
754 0 : simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
755 : const u8 * old_address, const u8 * mac_address)
756 : {
757 0 : l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
758 :
759 0 : return (NULL);
760 : }
761 :
762 :
763 : /* *INDENT-OFF* */
764 12095 : VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
765 : .name = "Loopback",
766 : .format_device_name = format_simulated_ethernet_name,
767 : .tx_function = simulated_ethernet_interface_tx,
768 : .admin_up_down_function = simulated_ethernet_admin_up_down,
769 : .mac_addr_change_function = simulated_ethernet_mac_change,
770 : };
771 : /* *INDENT-ON* */
772 :
773 : /*
774 : * Maintain a bitmap of allocated loopback instance numbers.
775 : */
776 : #define LOOPBACK_MAX_INSTANCE (16 * 1024)
777 :
778 : static u32
779 178 : loopback_instance_alloc (u8 is_specified, u32 want)
780 : {
781 178 : ethernet_main_t *em = ðernet_main;
782 :
783 : /*
784 : * Check for dynamically allocaetd instance number.
785 : */
786 178 : if (!is_specified)
787 : {
788 : u32 bit;
789 :
790 176 : bit = clib_bitmap_first_clear (em->bm_loopback_instances);
791 176 : if (bit >= LOOPBACK_MAX_INSTANCE)
792 : {
793 0 : return ~0;
794 : }
795 176 : em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
796 : bit, 1);
797 176 : return bit;
798 : }
799 :
800 : /*
801 : * In range?
802 : */
803 2 : if (want >= LOOPBACK_MAX_INSTANCE)
804 : {
805 0 : return ~0;
806 : }
807 :
808 : /*
809 : * Already in use?
810 : */
811 2 : if (clib_bitmap_get (em->bm_loopback_instances, want))
812 : {
813 0 : return ~0;
814 : }
815 :
816 : /*
817 : * Grant allocation request.
818 : */
819 2 : em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
820 : want, 1);
821 :
822 2 : return want;
823 : }
824 :
825 : static int
826 106 : loopback_instance_free (u32 instance)
827 : {
828 106 : ethernet_main_t *em = ðernet_main;
829 :
830 106 : if (instance >= LOOPBACK_MAX_INSTANCE)
831 : {
832 0 : return -1;
833 : }
834 :
835 106 : if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
836 : {
837 0 : return -1;
838 : }
839 :
840 106 : em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
841 : instance, 0);
842 106 : return 0;
843 : }
844 :
845 : int
846 178 : vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
847 : u8 is_specified, u32 user_instance)
848 : {
849 178 : vnet_main_t *vnm = vnet_get_main ();
850 178 : vlib_main_t *vm = vlib_get_main ();
851 : u32 instance;
852 : u8 address[6];
853 : u32 hw_if_index;
854 : vnet_hw_interface_t *hw_if;
855 : u32 slot;
856 :
857 178 : ASSERT (sw_if_indexp);
858 :
859 178 : *sw_if_indexp = (u32) ~ 0;
860 :
861 178 : clib_memset (address, 0, sizeof (address));
862 :
863 : /*
864 : * Allocate a loopback instance. Either select on dynamically
865 : * or try to use the desired user_instance number.
866 : */
867 178 : instance = loopback_instance_alloc (is_specified, user_instance);
868 178 : if (instance == ~0)
869 : {
870 0 : return VNET_API_ERROR_INVALID_REGISTRATION;
871 : }
872 :
873 : /*
874 : * Default MAC address (dead:0000:0000 + instance) is allocated
875 : * if zero mac_address is configured. Otherwise, user-configurable MAC
876 : * address is programmed on the loopback interface.
877 : */
878 178 : if (memcmp (address, mac_address, sizeof (address)))
879 20 : clib_memcpy (address, mac_address, sizeof (address));
880 : else
881 : {
882 158 : address[0] = 0xde;
883 158 : address[1] = 0xad;
884 158 : address[5] = instance;
885 : }
886 :
887 178 : vnet_eth_interface_registration_t eir = {};
888 178 : eir.dev_class_index = ethernet_simulated_device_class.index;
889 178 : eir.dev_instance = instance;
890 178 : eir.address = address;
891 178 : hw_if_index = vnet_eth_register_interface (vnm, &eir);
892 178 : hw_if = vnet_get_hw_interface (vnm, hw_if_index);
893 356 : slot = vlib_node_add_named_next_with_slot
894 178 : (vm, hw_if->tx_node_index,
895 : "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
896 178 : ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
897 :
898 356 : slot = vlib_node_add_named_next_with_slot
899 178 : (vm, hw_if->tx_node_index,
900 : "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
901 178 : ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
902 :
903 : {
904 178 : vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
905 178 : *sw_if_indexp = si->sw_if_index;
906 :
907 : /* By default don't flood to loopbacks, as packets just keep
908 : * coming back ... If this loopback becomes a BVI, we'll change it */
909 178 : si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
910 : }
911 :
912 178 : return 0;
913 : }
914 :
915 : static clib_error_t *
916 9 : create_simulated_ethernet_interfaces (vlib_main_t * vm,
917 : unformat_input_t * input,
918 : vlib_cli_command_t * cmd)
919 : {
920 : int rv;
921 : u32 sw_if_index;
922 : u8 mac_address[6];
923 9 : u8 is_specified = 0;
924 9 : u32 user_instance = 0;
925 :
926 9 : clib_memset (mac_address, 0, sizeof (mac_address));
927 :
928 9 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
929 : {
930 0 : if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
931 : ;
932 0 : if (unformat (input, "instance %d", &user_instance))
933 0 : is_specified = 1;
934 : else
935 0 : break;
936 : }
937 :
938 9 : rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
939 : is_specified, user_instance);
940 :
941 9 : if (rv)
942 0 : return clib_error_return (0, "vnet_create_loopback_interface failed");
943 :
944 9 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
945 : sw_if_index);
946 9 : return 0;
947 : }
948 :
949 : /*?
950 : * Create a loopback interface. Optionally, a MAC Address can be
951 : * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
952 : *
953 : * @cliexpar
954 : * The following two command syntaxes are equivalent:
955 : * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
956 : * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
957 : * Example of how to create a loopback interface:
958 : * @cliexcmd{loopback create-interface}
959 : ?*/
960 : /* *INDENT-OFF* */
961 285289 : VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
962 : .path = "loopback create-interface",
963 : .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
964 : .function = create_simulated_ethernet_interfaces,
965 : };
966 : /* *INDENT-ON* */
967 :
968 : /*?
969 : * Create a loopback interface. Optionally, a MAC Address can be
970 : * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
971 : *
972 : * @cliexpar
973 : * The following two command syntaxes are equivalent:
974 : * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
975 : * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
976 : * Example of how to create a loopback interface:
977 : * @cliexcmd{create loopback interface}
978 : ?*/
979 : /* *INDENT-OFF* */
980 285289 : VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
981 : .path = "create loopback interface",
982 : .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
983 : .function = create_simulated_ethernet_interfaces,
984 : };
985 : /* *INDENT-ON* */
986 :
987 : ethernet_interface_t *
988 2255320 : ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
989 : {
990 : vnet_hw_interface_t *i =
991 2255320 : vnet_get_hw_interface (vnet_get_main (), hw_if_index);
992 2255320 : return (i->hw_class_index ==
993 2255320 : ethernet_hw_interface_class.
994 2255320 : index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
995 : }
996 :
997 : mac_address_t *
998 25990 : ethernet_interface_add_del_address (ethernet_main_t * em,
999 : u32 hw_if_index, const u8 * address,
1000 : u8 is_add)
1001 : {
1002 25990 : ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
1003 25990 : ethernet_interface_address_t *if_addr = 0;
1004 25990 : int found = 0;
1005 :
1006 : /* return if there is not an ethernet interface for this hw interface */
1007 25990 : if (!ei)
1008 0 : return 0;
1009 :
1010 : /* determine whether the address is configured on the interface */
1011 281190 : vec_foreach (if_addr, ei->secondary_addrs)
1012 : {
1013 268756 : if (ethernet_mac_address_equal (if_addr->mac.bytes, address))
1014 : {
1015 13556 : found = 1;
1016 13556 : break;
1017 : }
1018 : }
1019 :
1020 25990 : if (is_add)
1021 : {
1022 14818 : if (!found)
1023 : {
1024 : /* address not found yet: add it */
1025 12427 : vec_add2 (ei->secondary_addrs, if_addr, 1);
1026 12427 : ethernet_interface_address_copy (if_addr, address);
1027 : }
1028 14818 : return &if_addr->mac;
1029 : }
1030 :
1031 : /* delete case */
1032 11172 : if (found)
1033 11165 : vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
1034 :
1035 11172 : return 0;
1036 : }
1037 :
1038 : int
1039 106 : vnet_delete_loopback_interface (u32 sw_if_index)
1040 : {
1041 106 : vnet_main_t *vnm = vnet_get_main ();
1042 :
1043 106 : if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1044 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1045 :
1046 106 : vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1047 106 : if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
1048 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1049 :
1050 106 : if (loopback_instance_free (hw->dev_instance) < 0)
1051 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1052 :
1053 106 : ethernet_delete_interface (vnm, hw->hw_if_index);
1054 :
1055 106 : return 0;
1056 : }
1057 :
1058 : int
1059 19 : vnet_create_sub_interface (u32 sw_if_index, u32 id,
1060 : u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
1061 : u32 * sub_sw_if_index)
1062 : {
1063 19 : vnet_main_t *vnm = vnet_get_main ();
1064 19 : vnet_interface_main_t *im = &vnm->interface_main;
1065 : vnet_hw_interface_t *hi;
1066 19 : u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
1067 : vnet_sw_interface_t template;
1068 : uword *p;
1069 : u64 *kp;
1070 :
1071 19 : hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1072 :
1073 19 : p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1074 19 : if (p)
1075 : {
1076 0 : return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
1077 : }
1078 :
1079 19 : clib_memset (&template, 0, sizeof (template));
1080 19 : template.type = VNET_SW_INTERFACE_TYPE_SUB;
1081 19 : template.flood_class = VNET_FLOOD_CLASS_NORMAL;
1082 19 : template.sup_sw_if_index = sw_if_index;
1083 19 : template.sub.id = id;
1084 19 : template.sub.eth.raw_flags = flags;
1085 19 : template.sub.eth.outer_vlan_id = outer_vlan_id;
1086 19 : template.sub.eth.inner_vlan_id = inner_vlan_id;
1087 :
1088 19 : if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
1089 0 : return (VNET_API_ERROR_UNSPECIFIED);
1090 :
1091 19 : kp = clib_mem_alloc (sizeof (*kp));
1092 19 : *kp = sup_and_sub_key;
1093 :
1094 19 : hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
1095 38 : hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
1096 :
1097 19 : return (0);
1098 : }
1099 :
1100 : int
1101 64 : vnet_delete_sub_interface (u32 sw_if_index)
1102 : {
1103 64 : vnet_main_t *vnm = vnet_get_main ();
1104 : vnet_sw_interface_t *si;
1105 64 : int rv = 0;
1106 :
1107 64 : if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1108 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1109 :
1110 64 : si = vnet_get_sw_interface (vnm, sw_if_index);
1111 64 : if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
1112 21 : si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
1113 21 : si->type == VNET_SW_INTERFACE_TYPE_P2P)
1114 64 : {
1115 64 : vnet_interface_main_t *im = &vnm->interface_main;
1116 64 : vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1117 64 : u64 sup_and_sub_key =
1118 64 : ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
1119 64 : hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1120 64 : hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
1121 64 : vnet_delete_sw_interface (vnm, sw_if_index);
1122 : }
1123 : else
1124 0 : rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
1125 :
1126 64 : return rv;
1127 : }
1128 :
1129 : static clib_error_t *
1130 0 : delete_simulated_ethernet_interfaces (vlib_main_t * vm,
1131 : unformat_input_t * input,
1132 : vlib_cli_command_t * cmd)
1133 : {
1134 : int rv;
1135 0 : u32 sw_if_index = ~0;
1136 0 : vnet_main_t *vnm = vnet_get_main ();
1137 :
1138 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1139 : {
1140 0 : if (unformat (input, "intfc %U",
1141 : unformat_vnet_sw_interface, vnm, &sw_if_index))
1142 : ;
1143 : else
1144 0 : break;
1145 : }
1146 :
1147 0 : if (sw_if_index == ~0)
1148 0 : return clib_error_return (0, "interface not specified");
1149 :
1150 0 : rv = vnet_delete_loopback_interface (sw_if_index);
1151 :
1152 0 : if (rv)
1153 0 : return clib_error_return (0, "vnet_delete_loopback_interface failed");
1154 :
1155 0 : return 0;
1156 : }
1157 :
1158 : static clib_error_t *
1159 0 : delete_sub_interface (vlib_main_t * vm,
1160 : unformat_input_t * input, vlib_cli_command_t * cmd)
1161 : {
1162 0 : int rv = 0;
1163 0 : u32 sw_if_index = ~0;
1164 0 : vnet_main_t *vnm = vnet_get_main ();
1165 :
1166 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1167 : {
1168 0 : if (unformat
1169 : (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1170 : ;
1171 : else
1172 0 : break;
1173 : }
1174 0 : if (sw_if_index == ~0)
1175 0 : return clib_error_return (0, "interface doesn't exist");
1176 :
1177 0 : if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1178 0 : rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1179 : else
1180 0 : rv = vnet_delete_sub_interface (sw_if_index);
1181 0 : if (rv)
1182 0 : return clib_error_return (0, "delete_subinterface_interface failed");
1183 0 : return 0;
1184 : }
1185 :
1186 : /*?
1187 : * Delete a loopback interface.
1188 : *
1189 : * @cliexpar
1190 : * The following two command syntaxes are equivalent:
1191 : * @cliexcmd{loopback delete-interface intfc <interface>}
1192 : * @cliexcmd{delete loopback interface intfc <interface>}
1193 : * Example of how to delete a loopback interface:
1194 : * @cliexcmd{loopback delete-interface intfc loop0}
1195 : ?*/
1196 : /* *INDENT-OFF* */
1197 285289 : VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1198 : .path = "loopback delete-interface",
1199 : .short_help = "loopback delete-interface intfc <interface>",
1200 : .function = delete_simulated_ethernet_interfaces,
1201 : };
1202 : /* *INDENT-ON* */
1203 :
1204 : /*?
1205 : * Delete a loopback interface.
1206 : *
1207 : * @cliexpar
1208 : * The following two command syntaxes are equivalent:
1209 : * @cliexcmd{loopback delete-interface intfc <interface>}
1210 : * @cliexcmd{delete loopback interface intfc <interface>}
1211 : * Example of how to delete a loopback interface:
1212 : * @cliexcmd{delete loopback interface intfc loop0}
1213 : ?*/
1214 : /* *INDENT-OFF* */
1215 285289 : VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1216 : .path = "delete loopback interface",
1217 : .short_help = "delete loopback interface intfc <interface>",
1218 : .function = delete_simulated_ethernet_interfaces,
1219 : };
1220 : /* *INDENT-ON* */
1221 :
1222 : /*?
1223 : * Delete a sub-interface.
1224 : *
1225 : * @cliexpar
1226 : * Example of how to delete a sub-interface:
1227 : * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1228 : ?*/
1229 : /* *INDENT-OFF* */
1230 285289 : VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1231 : .path = "delete sub-interface",
1232 : .short_help = "delete sub-interface <interface>",
1233 : .function = delete_sub_interface,
1234 : };
1235 : /* *INDENT-ON* */
1236 :
1237 : /* ethernet { ... } configuration. */
1238 : /*?
1239 : *
1240 : * @cfgcmd{default-mtu <n>}
1241 : * Specify the default mtu in the range of 64-9000. The default is 9000 bytes.
1242 : *
1243 : */
1244 : static clib_error_t *
1245 575 : ethernet_config (vlib_main_t * vm, unformat_input_t * input)
1246 : {
1247 575 : ethernet_main_t *em = ðernet_main;
1248 :
1249 575 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1250 : {
1251 0 : if (unformat (input, "default-mtu %u", &em->default_mtu))
1252 : {
1253 0 : if (em->default_mtu < 64 || em->default_mtu > 9000)
1254 0 : return clib_error_return (0, "default MTU must be >=64, <=9000");
1255 : }
1256 : else
1257 : {
1258 0 : return clib_error_return (0, "unknown input '%U'",
1259 : format_unformat_error, input);
1260 : }
1261 : }
1262 575 : return 0;
1263 : }
1264 :
1265 7514 : VLIB_CONFIG_FUNCTION (ethernet_config, "ethernet");
1266 :
1267 : /*
1268 : * fd.io coding-style-patch-verification: ON
1269 : *
1270 : * Local Variables:
1271 : * eval: (c-set-style "gnu")
1272 : * End:
1273 : */
|