blob: 7b11fdad8b1283378a06abfee62382267ede41d8 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Neale Rannscbe25aa2019-09-30 10:53:31 +000044//#include <vnet/ethernet/arp.h>
John Lo405e41b2016-04-23 15:14:12 -040045#include <vnet/l2/l2_input.h>
Neale Ranns3b81a1e2018-09-06 09:50:26 -070046#include <vnet/l2/l2_bd.h>
Neale Rannsb80c5362016-10-08 13:03:40 +010047#include <vnet/adj/adj.h>
Neale Rannscbe25aa2019-09-30 10:53:31 +000048#include <vnet/adj/adj_mcast.h>
49#include <vnet/ip-neighbor/ip_neighbor.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050
Neale Ranns5e575b12016-10-03 09:40:25 +010051/**
52 * @file
53 * @brief Loopback Interfaces.
54 *
55 * This file contains code to manage loopback interfaces.
56 */
57
Neale Rannscbe25aa2019-09-30 10:53:31 +000058static const u8 *
Neale Ranns32e1c012016-11-22 17:07:28 +000059ethernet_ip4_mcast_dst_addr (void)
60{
61 const static u8 ethernet_mcast_dst_mac[] = {
62 0x1, 0x0, 0x5e, 0x0, 0x0, 0x0,
63 };
64
65 return (ethernet_mcast_dst_mac);
66}
67
Neale Rannscbe25aa2019-09-30 10:53:31 +000068static const u8 *
Neale Ranns32e1c012016-11-22 17:07:28 +000069ethernet_ip6_mcast_dst_addr (void)
70{
71 const static u8 ethernet_mcast_dst_mac[] = {
72 0x33, 0x33, 0x00, 0x0, 0x0, 0x0,
73 };
74
75 return (ethernet_mcast_dst_mac);
76}
77
Neale Rannsb80c5362016-10-08 13:03:40 +010078/**
79 * @brief build a rewrite string to use for sending packets of type 'link_type'
80 * to 'dst_address'
81 */
82u8 *
83ethernet_build_rewrite (vnet_main_t * vnm,
84 u32 sw_if_index,
85 vnet_link_t link_type, const void *dst_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -070086{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070087 vnet_sw_interface_t *sub_sw = vnet_get_sw_interface (vnm, sw_if_index);
88 vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
89 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
90 ethernet_main_t *em = &ethernet_main;
91 ethernet_interface_t *ei;
Neale Rannsb80c5362016-10-08 13:03:40 +010092 ethernet_header_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 ethernet_type_t type;
94 uword n_bytes = sizeof (h[0]);
Neale Rannsb80c5362016-10-08 13:03:40 +010095 u8 *rewrite = NULL;
Pavel Kotucek15ac81c2017-06-20 14:00:26 +020096 u8 is_p2p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
Neale Ranns17ff3c12018-07-04 10:24:24 -070098 if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
99 (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200100 is_p2p = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700101 if (sub_sw != sup_sw)
102 {
103 if (sub_sw->sub.eth.flags.one_tag)
104 {
105 n_bytes += sizeof (ethernet_vlan_header_t);
106 }
107 else if (sub_sw->sub.eth.flags.two_tags)
108 {
109 n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
110 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200111 else if (PREDICT_FALSE (is_p2p))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700112 {
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200113 n_bytes = sizeof (ethernet_header_t);
114 }
115 if (PREDICT_FALSE (!is_p2p))
116 {
117 // Check for encaps that are not supported for L3 interfaces
118 if (!(sub_sw->sub.eth.flags.exact_match) ||
119 (sub_sw->sub.eth.flags.default_sub) ||
120 (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
121 (sub_sw->sub.eth.flags.inner_vlan_id_any))
122 {
123 return 0;
124 }
125 }
126 else
127 {
128 n_bytes = sizeof (ethernet_header_t);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700129 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Neale Rannsb80c5362016-10-08 13:03:40 +0100132 switch (link_type)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700133 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100134#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700135 _(IP4, IP4);
136 _(IP6, IP6);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800137 _(MPLS, MPLS);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700138 _(ARP, ARP);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139#undef _
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700140 default:
Neale Rannsb80c5362016-10-08 13:03:40 +0100141 return NULL;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700142 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
Neale Rannsb80c5362016-10-08 13:03:40 +0100144 vec_validate (rewrite, n_bytes - 1);
145 h = (ethernet_header_t *) rewrite;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
Damjan Marionf1213b82016-03-13 02:22:06 +0100147 clib_memcpy (h->src_address, ei->address, sizeof (h->src_address));
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200148 if (is_p2p)
149 {
150 clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
151 sizeof (h->dst_address));
152 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 else
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200154 {
155 if (dst_address)
156 clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
157 else
Dave Barachb7b92992018-10-17 10:38:51 -0400158 clib_memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200159 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200161 if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700162 {
163 ethernet_vlan_header_t *outer = (void *) (h + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700165 h->type = sub_sw->sub.eth.flags.dot1ad ?
166 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
167 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
168 outer->priority_cfi_and_id =
169 clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
170 outer->type = clib_host_to_net_u16 (type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700172 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200173 else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700174 {
175 ethernet_vlan_header_t *outer = (void *) (h + 1);
176 ethernet_vlan_header_t *inner = (void *) (outer + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700178 h->type = sub_sw->sub.eth.flags.dot1ad ?
179 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
180 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
181 outer->priority_cfi_and_id =
182 clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
183 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
184 inner->priority_cfi_and_id =
185 clib_host_to_net_u16 (sub_sw->sub.eth.inner_vlan_id);
186 inner->type = clib_host_to_net_u16 (type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700188 }
189 else
190 {
191 h->type = clib_host_to_net_u16 (type);
192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193
Neale Rannsb80c5362016-10-08 13:03:40 +0100194 return (rewrite);
195}
196
197void
198ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
199{
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200200 vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000201
Neale Ranns17ff3c12018-07-04 10:24:24 -0700202 if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
203 (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200204 {
205 default_update_adjacency (vnm, sw_if_index, ai);
206 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100207 else
208 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000209 ip_adjacency_t *adj;
210
211 adj = adj_get (ai);
212
213 switch (adj->lookup_next_index)
214 {
215 case IP_LOOKUP_NEXT_GLEAN:
216 adj_glean_update_rewrite (ai);
217 break;
218 case IP_LOOKUP_NEXT_ARP:
219 ip_neighbor_update (vnm, ai);
220 break;
221 case IP_LOOKUP_NEXT_BCAST:
222 adj_nbr_update_rewrite (ai,
223 ADJ_NBR_REWRITE_FLAG_COMPLETE,
224 ethernet_build_rewrite
225 (vnm,
226 adj->rewrite_header.sw_if_index,
227 adj->ia_link,
228 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
229 break;
230 case IP_LOOKUP_NEXT_MCAST:
231 {
232 /*
233 * Construct a partial rewrite from the known ethernet mcast dest MAC
234 */
235 u8 *rewrite;
236 u8 offset;
237
238 rewrite = ethernet_build_rewrite
239 (vnm,
240 sw_if_index,
241 adj->ia_link,
242 (adj->ia_nh_proto == FIB_PROTOCOL_IP6 ?
243 ethernet_ip6_mcast_dst_addr () :
244 ethernet_ip4_mcast_dst_addr ()));
245
246 /*
247 * Complete the remaining fields of the adj's rewrite to direct the
248 * complete of the rewrite at switch time by copying in the IP
249 * dst address's bytes.
250 * Ofset is 2 bytes into the destintation address.
251 */
252 offset = vec_len (rewrite) - 2;
253 adj_mcast_update_rewrite (ai, rewrite, offset);
254
255 break;
256 }
257 case IP_LOOKUP_NEXT_DROP:
258 case IP_LOOKUP_NEXT_PUNT:
259 case IP_LOOKUP_NEXT_LOCAL:
260 case IP_LOOKUP_NEXT_REWRITE:
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 ASSERT (0);
266 break;
267 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100268 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269}
270
Neale Ranns3be6b282016-12-20 14:24:01 +0000271static clib_error_t *
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700272ethernet_mac_change (vnet_hw_interface_t * hi,
273 const u8 * old_address, const u8 * mac_address)
Neale Ranns3be6b282016-12-20 14:24:01 +0000274{
275 ethernet_interface_t *ei;
276 ethernet_main_t *em;
277
278 em = &ethernet_main;
279 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
280
281 vec_validate (hi->hw_address,
282 STRUCT_SIZE_OF (ethernet_header_t, src_address) - 1);
283 clib_memcpy (hi->hw_address, mac_address, vec_len (hi->hw_address));
284
285 clib_memcpy (ei->address, (u8 *) mac_address, sizeof (ei->address));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000286
287 {
288 ethernet_address_change_ctx_t *cb;
289 vec_foreach (cb, em->address_change_callbacks)
290 cb->function (em, hi->sw_if_index, cb->function_opaque);
291 }
Neale Ranns3be6b282016-12-20 14:24:01 +0000292
293 return (NULL);
294}
295
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700296/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
298 .name = "Ethernet",
299 .format_address = format_ethernet_address,
300 .format_header = format_ethernet_header_with_length,
301 .unformat_hw_address = unformat_ethernet_address,
302 .unformat_header = unformat_ethernet_header,
Neale Rannsb80c5362016-10-08 13:03:40 +0100303 .build_rewrite = ethernet_build_rewrite,
304 .update_adjacency = ethernet_update_adjacency,
Neale Ranns3be6b282016-12-20 14:24:01 +0000305 .mac_addr_change_function = ethernet_mac_change,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700307/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700309uword
310unformat_ethernet_interface (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700312 vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
313 u32 *result = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700314 u32 hw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700315 ethernet_main_t *em = &ethernet_main;
316 ethernet_interface_t *eif;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700318 if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319 return 0;
320
321 eif = ethernet_get_interface (em, hw_if_index);
322 if (eif)
323 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700324 *result = hw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325 return 1;
326 }
327 return 0;
328}
329
330clib_error_t *
331ethernet_register_interface (vnet_main_t * vnm,
332 u32 dev_class_index,
333 u32 dev_instance,
Neale Ranns192b13f2019-03-15 02:16:20 -0700334 const u8 * address,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700335 u32 * hw_if_index_return,
336 ethernet_flag_change_function_t flag_change)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700338 ethernet_main_t *em = &ethernet_main;
339 ethernet_interface_t *ei;
340 vnet_hw_interface_t *hi;
341 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342 u32 hw_if_index;
343
344 pool_get (em->interfaces, ei);
345 ei->flag_change = flag_change;
346
347 hw_if_index = vnet_register_interface
348 (vnm,
349 dev_class_index, dev_instance,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700350 ethernet_hw_interface_class.index, ei - em->interfaces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 *hw_if_index_return = hw_if_index;
352
353 hi = vnet_get_hw_interface (vnm, hw_if_index);
354
355 ethernet_setup_node (vnm->vlib_main, hi->output_node_index);
356
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700357 hi->min_packet_bytes = hi->min_supported_packet_bytes =
358 ETHERNET_MIN_PACKET_BYTES;
359 hi->max_packet_bytes = hi->max_supported_packet_bytes =
360 ETHERNET_MAX_PACKET_BYTES;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
Dave Barach5fa45252020-02-26 10:27:08 -0500362 /* Default ethernet MTU, 9000 unless set by ethernet_config see below */
363 vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, em->default_mtu);
Damjan Marionfe7d4a22018-04-13 19:43:39 +0200364
Damjan Marionf1213b82016-03-13 02:22:06 +0100365 clib_memcpy (ei->address, address, sizeof (ei->address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 vec_add (hi->hw_address, address, sizeof (ei->address));
Benoît Ganne9fb6d402019-04-15 15:28:21 +0200367 CLIB_MEM_UNPOISON (hi->hw_address, 8);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368
369 if (error)
370 {
371 pool_put (em->interfaces, ei);
372 return error;
373 }
374 return error;
375}
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700376
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377void
378ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
379{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700380 ethernet_main_t *em = &ethernet_main;
381 ethernet_interface_t *ei;
382 vnet_hw_interface_t *hi;
383 main_intf_t *main_intf;
384 vlan_table_t *vlan_table;
385 u32 idx;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386
387 hi = vnet_get_hw_interface (vnm, hw_if_index);
388 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
389
390 /* Delete vlan mapping table for dot1q and dot1ad. */
391 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700392 if (main_intf->dot1q_vlans)
393 {
394 vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
395 for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
396 {
397 if (vlan_table->vlans[idx].qinqs)
398 {
399 pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
John Lod63abff2018-10-04 16:22:21 -0400400 vlan_table->vlans[idx].qinqs = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700401 }
402 }
403 pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
Steve Shin8a3e5752018-02-20 11:38:34 -0800404 main_intf->dot1q_vlans = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700406 if (main_intf->dot1ad_vlans)
407 {
408 vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
409 for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
410 {
411 if (vlan_table->vlans[idx].qinqs)
412 {
413 pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
John Lod63abff2018-10-04 16:22:21 -0400414 vlan_table->vlans[idx].qinqs = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700415 }
416 }
417 pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
Steve Shin8a3e5752018-02-20 11:38:34 -0800418 main_intf->dot1ad_vlans = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700420
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 vnet_delete_hw_interface (vnm, hw_if_index);
422 pool_put (em->interfaces, ei);
423}
424
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700425u32
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
427{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700428 ethernet_main_t *em = &ethernet_main;
429 vnet_hw_interface_t *hi;
430 ethernet_interface_t *ei;
John Lo4a302ee2020-05-12 22:34:39 -0400431 u32 opn_flags = flags & ETHERNET_INTERFACE_FLAGS_SET_OPN_MASK;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700432
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433 hi = vnet_get_hw_interface (vnm, hw_if_index);
434
435 ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
436
437 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
John Lo4a302ee2020-05-12 22:34:39 -0400438
439 /* preserve status bits and update last set operation bits */
440 ei->flags = (ei->flags & ETHERNET_INTERFACE_FLAGS_STATUS_MASK) | opn_flags;
441
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 if (ei->flag_change)
John Lo4a302ee2020-05-12 22:34:39 -0400443 {
444 switch (opn_flags)
445 {
446 case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
447 if (hi->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER)
448 {
449 if (ei->flag_change (vnm, hi, opn_flags) != ~0)
450 {
451 ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
452 return 0;
453 }
454 ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
455 return ~0;
456 }
457 /* fall through */
458 case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
459 ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
460 /* fall through */
461 case ETHERNET_INTERFACE_FLAG_MTU:
462 return ei->flag_change (vnm, hi, opn_flags);
463 default:
464 return ~0;
465 }
466 }
467 return ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468}
469
Dave Barach635ec3b2018-07-13 20:12:45 -0400470/**
471 * Echo packets back to ethernet/l2-input.
Dave Barach635ec3b2018-07-13 20:12:45 -0400472 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700473static uword
474simulated_ethernet_interface_tx (vlib_main_t * vm,
Dave Barach635ec3b2018-07-13 20:12:45 -0400475 vlib_node_runtime_t *
476 node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477{
Dave Barach78451a62018-07-21 09:25:00 -0400478 u32 n_left_from, *from;
479 u32 next_index = 0;
480 u32 n_bytes;
Damjan Marion586afd72017-04-05 19:18:20 +0200481 u32 thread_index = vm->thread_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700482 vnet_main_t *vnm = vnet_get_main ();
483 vnet_interface_main_t *im = &vnm->interface_main;
Dave Barach635ec3b2018-07-13 20:12:45 -0400484 l2_input_config_t *config;
Dave Barach78451a62018-07-21 09:25:00 -0400485 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
486 u16 nexts[VLIB_FRAME_SIZE], *next;
487 u32 new_rx_sw_if_index = ~0;
488 u32 new_tx_sw_if_index = ~0;
John Lo405e41b2016-04-23 15:14:12 -0400489
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 n_left_from = frame->n_vectors;
Damjan Mariona3d59862018-11-10 10:23:00 +0100491 from = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492
Dave Barach78451a62018-07-21 09:25:00 -0400493 vlib_get_buffers (vm, from, bufs, n_left_from);
494 b = bufs;
495 next = nexts;
Dave Barach635ec3b2018-07-13 20:12:45 -0400496
Dave Barach78451a62018-07-21 09:25:00 -0400497 /* Ordinarily, this is the only config lookup. */
498 config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
499 next_index =
Dave Barach635ec3b2018-07-13 20:12:45 -0400500 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
501 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
Dave Barach78451a62018-07-21 09:25:00 -0400502 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
503 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
Dave Barach635ec3b2018-07-13 20:12:45 -0400504
Dave Barach78451a62018-07-21 09:25:00 -0400505 while (n_left_from >= 4)
506 {
507 u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
508 u32 not_all_match_config;
Dave Barach635ec3b2018-07-13 20:12:45 -0400509
Dave Barach78451a62018-07-21 09:25:00 -0400510 /* Prefetch next iteration. */
511 if (PREDICT_TRUE (n_left_from >= 8))
512 {
513 vlib_prefetch_buffer_header (b[4], STORE);
514 vlib_prefetch_buffer_header (b[5], STORE);
515 vlib_prefetch_buffer_header (b[6], STORE);
516 vlib_prefetch_buffer_header (b[7], STORE);
517 }
Dave Barach635ec3b2018-07-13 20:12:45 -0400518
Dave Barach78451a62018-07-21 09:25:00 -0400519 /* Make sure all pkts were transmitted on the same (loop) intfc */
520 sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
521 sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
522 sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
523 sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
Dave Barach635ec3b2018-07-13 20:12:45 -0400524
Dave Barach78451a62018-07-21 09:25:00 -0400525 not_all_match_config = (sw_if_index0 ^ sw_if_index1)
526 ^ (sw_if_index2 ^ sw_if_index3);
527 not_all_match_config += sw_if_index0 ^ new_rx_sw_if_index;
528
529 /* Speed path / expected case: all pkts on the same intfc */
530 if (PREDICT_TRUE (not_all_match_config == 0))
531 {
532 next[0] = next_index;
533 next[1] = next_index;
534 next[2] = next_index;
535 next[3] = next_index;
536 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
537 vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
538 vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
539 vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
540 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
541 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
542 vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
543 vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
544 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
545 n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
546 n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
547 n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
548
549 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
550 {
551 vnet_update_l2_len (b[0]);
552 vnet_update_l2_len (b[1]);
553 vnet_update_l2_len (b[2]);
554 vnet_update_l2_len (b[3]);
555 }
556
557 /* increment TX interface stat */
558 vlib_increment_combined_counter (im->combined_sw_if_counters +
559 VNET_INTERFACE_COUNTER_TX,
560 thread_index, new_rx_sw_if_index,
561 4 /* pkts */ , n_bytes);
562 b += 4;
563 next += 4;
564 n_left_from -= 4;
565 continue;
566 }
567
568 /*
569 * Slow path: we know that at least one of the pkts
570 * was transmitted on a different sw_if_index, so
571 * check each sw_if_index against the cached data and proceed
572 * accordingly.
573 *
574 * This shouldn't happen, but code can (and does) bypass the
575 * per-interface output node, so deal with it.
576 */
577 if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
578 != new_rx_sw_if_index))
579 {
580 config = l2input_intf_config
581 (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
582 next_index =
583 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
584 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
585 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
586 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
587 }
588 next[0] = next_index;
589 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
590 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
591 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
592 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
593 vnet_update_l2_len (b[0]);
594
595 vlib_increment_combined_counter (im->combined_sw_if_counters +
596 VNET_INTERFACE_COUNTER_TX,
597 thread_index, new_rx_sw_if_index,
598 1 /* pkts */ , n_bytes);
599
600 if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
601 != new_rx_sw_if_index))
602 {
603 config = l2input_intf_config
604 (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
605 next_index =
606 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
607 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
608 new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
609 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
610 }
611 next[1] = next_index;
612 vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
613 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
614 n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
615 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
616 vnet_update_l2_len (b[1]);
617
618 vlib_increment_combined_counter (im->combined_sw_if_counters +
619 VNET_INTERFACE_COUNTER_TX,
620 thread_index, new_rx_sw_if_index,
621 1 /* pkts */ , n_bytes);
622
623 if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
624 != new_rx_sw_if_index))
625 {
626 config = l2input_intf_config
627 (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
628 next_index =
629 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
630 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
631 new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
632 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
633 }
634 next[2] = next_index;
635 vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
636 vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
637 n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
638 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
639 vnet_update_l2_len (b[2]);
640
641 vlib_increment_combined_counter (im->combined_sw_if_counters +
642 VNET_INTERFACE_COUNTER_TX,
643 thread_index, new_rx_sw_if_index,
644 1 /* pkts */ , n_bytes);
645
646 if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
647 != new_rx_sw_if_index))
648 {
649 config = l2input_intf_config
650 (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
651 next_index =
652 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
653 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
654 new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
655 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
656 }
657 next[3] = next_index;
658 vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
659 vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
660 n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
661 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
662 vnet_update_l2_len (b[3]);
663
664 vlib_increment_combined_counter (im->combined_sw_if_counters +
665 VNET_INTERFACE_COUNTER_TX,
666 thread_index, new_rx_sw_if_index,
667 1 /* pkts */ , n_bytes);
668 b += 4;
669 next += 4;
670 n_left_from -= 4;
671 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672 while (n_left_from > 0)
673 {
Dave Barach78451a62018-07-21 09:25:00 -0400674 if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
675 != new_rx_sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 {
Dave Barach78451a62018-07-21 09:25:00 -0400677 config = l2input_intf_config
678 (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
679 next_index =
680 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
681 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
682 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
683 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 }
Dave Barach78451a62018-07-21 09:25:00 -0400685 next[0] = next_index;
686 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
687 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
688 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
689 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
690 vnet_update_l2_len (b[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691
Dave Barach78451a62018-07-21 09:25:00 -0400692 vlib_increment_combined_counter (im->combined_sw_if_counters +
693 VNET_INTERFACE_COUNTER_TX,
694 thread_index, new_rx_sw_if_index,
695 1 /* pkts */ , n_bytes);
696 b += 1;
697 next += 1;
698 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699 }
700
Dave Barach78451a62018-07-21 09:25:00 -0400701 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Dave Barach635ec3b2018-07-13 20:12:45 -0400702
703 return frame->n_vectors;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704}
705
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700706static u8 *
707format_simulated_ethernet_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708{
709 u32 dev_instance = va_arg (*args, u32);
710 return format (s, "loop%d", dev_instance);
711}
712
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000713static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700714simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
715 u32 flags)
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000716{
717 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700718 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000719 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
720 return 0;
721}
722
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700723static clib_error_t *
724simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
725 const u8 * old_address, const u8 * mac_address)
726{
727 l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
728
729 return (NULL);
730}
731
732
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700733/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
735 .name = "Loopback",
736 .format_device_name = format_simulated_ethernet_name,
737 .tx_function = simulated_ethernet_interface_tx,
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000738 .admin_up_down_function = simulated_ethernet_admin_up_down,
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700739 .mac_addr_change_function = simulated_ethernet_mac_change,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700741/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600743/*
744 * Maintain a bitmap of allocated loopback instance numbers.
745 */
746#define LOOPBACK_MAX_INSTANCE (16 * 1024)
747
748static u32
749loopback_instance_alloc (u8 is_specified, u32 want)
750{
751 ethernet_main_t *em = &ethernet_main;
752
753 /*
754 * Check for dynamically allocaetd instance number.
755 */
756 if (!is_specified)
757 {
758 u32 bit;
759
760 bit = clib_bitmap_first_clear (em->bm_loopback_instances);
761 if (bit >= LOOPBACK_MAX_INSTANCE)
762 {
763 return ~0;
764 }
765 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
766 bit, 1);
767 return bit;
768 }
769
770 /*
771 * In range?
772 */
773 if (want >= LOOPBACK_MAX_INSTANCE)
774 {
775 return ~0;
776 }
777
778 /*
779 * Already in use?
780 */
781 if (clib_bitmap_get (em->bm_loopback_instances, want))
782 {
783 return ~0;
784 }
785
786 /*
787 * Grant allocation request.
788 */
789 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
790 want, 1);
791
792 return want;
793}
794
795static int
796loopback_instance_free (u32 instance)
797{
798 ethernet_main_t *em = &ethernet_main;
799
800 if (instance >= LOOPBACK_MAX_INSTANCE)
801 {
802 return -1;
803 }
804
805 if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
806 {
807 return -1;
808 }
809
810 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
811 instance, 0);
812 return 0;
813}
814
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700815int
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600816vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
817 u8 is_specified, u32 user_instance)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700819 vnet_main_t *vnm = vnet_get_main ();
820 vlib_main_t *vm = vlib_get_main ();
821 clib_error_t *error;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600822 u32 instance;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823 u8 address[6];
824 u32 hw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700825 vnet_hw_interface_t *hw_if;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826 u32 slot;
827 int rv = 0;
828
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700829 ASSERT (sw_if_indexp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700831 *sw_if_indexp = (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832
Dave Barachb7b92992018-10-17 10:38:51 -0400833 clib_memset (address, 0, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
835 /*
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600836 * Allocate a loopback instance. Either select on dynamically
837 * or try to use the desired user_instance number.
838 */
839 instance = loopback_instance_alloc (is_specified, user_instance);
840 if (instance == ~0)
841 {
842 return VNET_API_ERROR_INVALID_REGISTRATION;
843 }
844
845 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700846 * Default MAC address (dead:0000:0000 + instance) is allocated
847 * if zero mac_address is configured. Otherwise, user-configurable MAC
848 * address is programmed on the loopback interface.
849 */
850 if (memcmp (address, mac_address, sizeof (address)))
Damjan Marionf1213b82016-03-13 02:22:06 +0100851 clib_memcpy (address, mac_address, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852 else
853 {
854 address[0] = 0xde;
855 address[1] = 0xad;
856 address[5] = instance;
857 }
858
859 error = ethernet_register_interface
860 (vnm,
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600861 ethernet_simulated_device_class.index, instance, address, &hw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862 /* flag change */ 0);
863
864 if (error)
865 {
866 rv = VNET_API_ERROR_INVALID_REGISTRATION;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700867 clib_error_report (error);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868 return rv;
869 }
870
871 hw_if = vnet_get_hw_interface (vnm, hw_if_index);
872 slot = vlib_node_add_named_next_with_slot
873 (vm, hw_if->tx_node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700874 "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700875 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
876
Dave Barach635ec3b2018-07-13 20:12:45 -0400877 slot = vlib_node_add_named_next_with_slot
878 (vm, hw_if->tx_node_index,
879 "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
880 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
881
Ed Warnickecb9cada2015-12-08 15:45:58 -0700882 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700883 vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700884 *sw_if_indexp = si->sw_if_index;
Neale Ranns87dad112018-04-09 01:53:01 -0700885
886 /* By default don't flood to loopbacks, as packets just keep
887 * coming back ... If this loopback becomes a BVI, we'll change it */
888 si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 }
890
891 return 0;
892}
893
894static clib_error_t *
895create_simulated_ethernet_interfaces (vlib_main_t * vm,
896 unformat_input_t * input,
897 vlib_cli_command_t * cmd)
898{
899 int rv;
900 u32 sw_if_index;
901 u8 mac_address[6];
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600902 u8 is_specified = 0;
903 u32 user_instance = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904
Dave Barachb7b92992018-10-17 10:38:51 -0400905 clib_memset (mac_address, 0, sizeof (mac_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700906
907 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
908 {
909 if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700910 ;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600911 if (unformat (input, "instance %d", &user_instance))
912 is_specified = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700913 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700914 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915 }
916
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600917 rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
918 is_specified, user_instance);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700919
920 if (rv)
921 return clib_error_return (0, "vnet_create_loopback_interface failed");
922
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700923 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
924 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700925 return 0;
926}
927
Billy McFall2d085d92016-09-13 21:47:55 -0400928/*?
929 * Create a loopback interface. Optionally, a MAC Address can be
930 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
931 *
932 * @cliexpar
933 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600934 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
935 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400936 * Example of how to create a loopback interface:
937 * @cliexcmd{loopback create-interface}
938?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700939/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
941 .path = "loopback create-interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600942 .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 .function = create_simulated_ethernet_interfaces,
944};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700945/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946
Billy McFall2d085d92016-09-13 21:47:55 -0400947/*?
948 * Create a loopback interface. Optionally, a MAC Address can be
949 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
950 *
951 * @cliexpar
952 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600953 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
954 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400955 * Example of how to create a loopback interface:
956 * @cliexcmd{create loopback interface}
957?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700958/* *INDENT-OFF* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700959VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
960 .path = "create loopback interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600961 .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
Alpesh Patel370a24e2016-04-08 07:27:37 -0700962 .function = create_simulated_ethernet_interfaces,
963};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700964/* *INDENT-ON* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700965
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966ethernet_interface_t *
967ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
968{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700969 vnet_hw_interface_t *i =
970 vnet_get_hw_interface (vnet_get_main (), hw_if_index);
971 return (i->hw_class_index ==
972 ethernet_hw_interface_class.
973 index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974}
975
Matthew G Smithd459bf32019-09-04 15:01:04 -0500976mac_address_t *
977ethernet_interface_add_del_address (ethernet_main_t * em,
978 u32 hw_if_index, const u8 * address,
979 u8 is_add)
980{
981 ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
982 mac_address_t *if_addr = 0;
983
984 /* return if there is not an ethernet interface for this hw interface */
985 if (!ei)
986 return 0;
987
988 /* determine whether the address is configured on the interface */
989 vec_foreach (if_addr, ei->secondary_addrs)
990 {
991 if (!ethernet_mac_address_equal (if_addr->bytes, address))
992 continue;
993
994 break;
995 }
996
997 if (if_addr && vec_is_member (ei->secondary_addrs, if_addr))
998 {
999 /* delete found address */
1000 if (!is_add)
1001 {
1002 vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
1003 if_addr = 0;
1004 }
1005 /* address already found, so nothing needs to be done if adding */
1006 }
1007 else
1008 {
1009 /* if_addr could be 0 or past the end of the vector. reset to 0 */
1010 if_addr = 0;
1011
1012 /* add new address */
1013 if (is_add)
1014 {
1015 vec_add2 (ei->secondary_addrs, if_addr, 1);
1016 clib_memcpy (&if_addr->bytes, address, sizeof (if_addr->bytes));
1017 }
1018 }
1019
1020 return if_addr;
1021}
1022
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001023int
1024vnet_delete_loopback_interface (u32 sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001026 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001027
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001028 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1030
Eyal Barib52c0342018-07-16 19:18:56 +03001031 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1032 if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
1033 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -06001034
Eyal Barib52c0342018-07-16 19:18:56 +03001035 if (loopback_instance_free (hw->dev_instance) < 0)
1036 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -06001037
Eyal Barib52c0342018-07-16 19:18:56 +03001038 ethernet_delete_interface (vnm, hw->hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039
1040 return 0;
1041}
1042
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001043int
Neale Ranns669f4e32019-10-28 07:56:15 -07001044vnet_create_sub_interface (u32 sw_if_index, u32 id,
1045 u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
1046 u32 * sub_sw_if_index)
1047{
1048 vnet_main_t *vnm = vnet_get_main ();
1049 vnet_interface_main_t *im = &vnm->interface_main;
1050 vnet_hw_interface_t *hi;
1051 u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
1052 vnet_sw_interface_t template;
1053 uword *p;
1054 u64 *kp;
1055
1056 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1057
1058 p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1059 if (p)
1060 {
1061 return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
1062 }
1063
1064 clib_memset (&template, 0, sizeof (template));
1065 template.type = VNET_SW_INTERFACE_TYPE_SUB;
1066 template.flood_class = VNET_FLOOD_CLASS_NORMAL;
1067 template.sup_sw_if_index = sw_if_index;
1068 template.sub.id = id;
1069 template.sub.eth.raw_flags = flags;
1070 template.sub.eth.outer_vlan_id = outer_vlan_id;
1071 template.sub.eth.inner_vlan_id = inner_vlan_id;
1072
1073 if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
1074 return (VNET_API_ERROR_UNSPECIFIED);
1075
1076 kp = clib_mem_alloc (sizeof (*kp));
1077 *kp = sup_and_sub_key;
1078
1079 hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
1080 hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
1081
1082 return (0);
1083}
1084
1085int
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001086vnet_delete_sub_interface (u32 sw_if_index)
1087{
1088 vnet_main_t *vnm = vnet_get_main ();
Steve Shina36f08c2018-03-07 13:29:29 -08001089 vnet_sw_interface_t *si;
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001090 int rv = 0;
1091
1092 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1093 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1094
Steve Shina36f08c2018-03-07 13:29:29 -08001095 si = vnet_get_sw_interface (vnm, sw_if_index);
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001096 if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
Neale Ranns17ff3c12018-07-04 10:24:24 -07001097 si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001098 si->type == VNET_SW_INTERFACE_TYPE_P2P)
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001099 {
John Lo5957a142018-01-18 12:44:50 -05001100 vnet_interface_main_t *im = &vnm->interface_main;
1101 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001102 u64 sup_and_sub_key =
1103 ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
John Lo5957a142018-01-18 12:44:50 -05001104 hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1105 hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001106 vnet_delete_sw_interface (vnm, sw_if_index);
1107 }
1108 else
John Lo5957a142018-01-18 12:44:50 -05001109 rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
1110
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001111 return rv;
1112}
1113
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114static clib_error_t *
1115delete_simulated_ethernet_interfaces (vlib_main_t * vm,
1116 unformat_input_t * input,
1117 vlib_cli_command_t * cmd)
1118{
1119 int rv;
1120 u32 sw_if_index = ~0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001121 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122
1123 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1124 {
1125 if (unformat (input, "intfc %U",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001126 unformat_vnet_sw_interface, vnm, &sw_if_index))
1127 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001129 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130 }
1131
1132 if (sw_if_index == ~0)
1133 return clib_error_return (0, "interface not specified");
1134
1135 rv = vnet_delete_loopback_interface (sw_if_index);
1136
1137 if (rv)
1138 return clib_error_return (0, "vnet_delete_loopback_interface failed");
1139
1140 return 0;
1141}
1142
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001143static clib_error_t *
1144delete_sub_interface (vlib_main_t * vm,
1145 unformat_input_t * input, vlib_cli_command_t * cmd)
1146{
1147 int rv = 0;
1148 u32 sw_if_index = ~0;
1149 vnet_main_t *vnm = vnet_get_main ();
1150
1151 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1152 {
1153 if (unformat
1154 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1155 ;
1156 else
1157 break;
1158 }
1159 if (sw_if_index == ~0)
1160 return clib_error_return (0, "interface doesn't exist");
1161
1162 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1163 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1164 else
1165 rv = vnet_delete_sub_interface (sw_if_index);
1166 if (rv)
1167 return clib_error_return (0, "delete_subinterface_interface failed");
1168 return 0;
1169}
1170
Billy McFall2d085d92016-09-13 21:47:55 -04001171/*?
1172 * Delete a loopback interface.
1173 *
1174 * @cliexpar
1175 * The following two command syntaxes are equivalent:
1176 * @cliexcmd{loopback delete-interface intfc <interface>}
1177 * @cliexcmd{delete loopback interface intfc <interface>}
1178 * Example of how to delete a loopback interface:
1179 * @cliexcmd{loopback delete-interface intfc loop0}
1180?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001181/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1183 .path = "loopback delete-interface",
Billy McFall2d085d92016-09-13 21:47:55 -04001184 .short_help = "loopback delete-interface intfc <interface>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185 .function = delete_simulated_ethernet_interfaces,
1186};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001187/* *INDENT-ON* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001188
Billy McFall2d085d92016-09-13 21:47:55 -04001189/*?
1190 * Delete a loopback interface.
1191 *
1192 * @cliexpar
1193 * The following two command syntaxes are equivalent:
1194 * @cliexcmd{loopback delete-interface intfc <interface>}
1195 * @cliexcmd{delete loopback interface intfc <interface>}
1196 * Example of how to delete a loopback interface:
1197 * @cliexcmd{delete loopback interface intfc loop0}
1198?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001199/* *INDENT-OFF* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001200VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1201 .path = "delete loopback interface",
1202 .short_help = "delete loopback interface intfc <interface>",
1203 .function = delete_simulated_ethernet_interfaces,
1204};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001205/* *INDENT-ON* */
1206
Billy McFall2d085d92016-09-13 21:47:55 -04001207/*?
1208 * Delete a sub-interface.
1209 *
1210 * @cliexpar
1211 * Example of how to delete a sub-interface:
1212 * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1213?*/
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001214/* *INDENT-OFF* */
1215VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1216 .path = "delete sub-interface",
1217 .short_help = "delete sub-interface <interface>",
1218 .function = delete_sub_interface,
1219};
1220/* *INDENT-ON* */
1221
Paul Vinciguerra491741a2020-03-02 16:10:54 -05001222/* ethernet { ... } configuration. */
1223/*?
1224 *
1225 * @cfgcmd{default-mtu &lt;n&gt;}
1226 * Specify the default mtu in the range of 64-9000. The default is 9000 bytes.
1227 *
1228 */
Dave Barach5fa45252020-02-26 10:27:08 -05001229static clib_error_t *
1230ethernet_config (vlib_main_t * vm, unformat_input_t * input)
1231{
1232 ethernet_main_t *em = &ethernet_main;
1233
1234 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1235 {
1236 if (unformat (input, "default-mtu %u", &em->default_mtu))
1237 {
1238 if (em->default_mtu < 64 || em->default_mtu > 9000)
1239 return clib_error_return (0, "default MTU must be >=64, <=9000");
1240 }
1241 else
1242 {
1243 return clib_error_return (0, "unknown input '%U'",
1244 format_unformat_error, input);
1245 }
1246 }
1247 return 0;
1248}
1249
1250VLIB_CONFIG_FUNCTION (ethernet_config, "ethernet");
1251
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001252/*
1253 * fd.io coding-style-patch-verification: ON
1254 *
1255 * Local Variables:
1256 * eval: (c-set-style "gnu")
1257 * End:
1258 */