blob: 7b2b162f1a0ae1ad3211f815d8613b934983c2d2 [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 Ranns37029302018-08-10 05:30:06 -070044#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 Ranns0bfe5d82016-08-25 15:29:12 +010048
Neale Ranns5e575b12016-10-03 09:40:25 +010049/**
50 * @file
51 * @brief Loopback Interfaces.
52 *
53 * This file contains code to manage loopback interfaces.
54 */
55
Neale Ranns32e1c012016-11-22 17:07:28 +000056const u8 *
57ethernet_ip4_mcast_dst_addr (void)
58{
59 const static u8 ethernet_mcast_dst_mac[] = {
60 0x1, 0x0, 0x5e, 0x0, 0x0, 0x0,
61 };
62
63 return (ethernet_mcast_dst_mac);
64}
65
66const u8 *
67ethernet_ip6_mcast_dst_addr (void)
68{
69 const static u8 ethernet_mcast_dst_mac[] = {
70 0x33, 0x33, 0x00, 0x0, 0x0, 0x0,
71 };
72
73 return (ethernet_mcast_dst_mac);
74}
75
Neale Rannsb80c5362016-10-08 13:03:40 +010076/**
77 * @brief build a rewrite string to use for sending packets of type 'link_type'
78 * to 'dst_address'
79 */
80u8 *
81ethernet_build_rewrite (vnet_main_t * vnm,
82 u32 sw_if_index,
83 vnet_link_t link_type, const void *dst_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -070084{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070085 vnet_sw_interface_t *sub_sw = vnet_get_sw_interface (vnm, sw_if_index);
86 vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
87 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
88 ethernet_main_t *em = &ethernet_main;
89 ethernet_interface_t *ei;
Neale Rannsb80c5362016-10-08 13:03:40 +010090 ethernet_header_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 ethernet_type_t type;
92 uword n_bytes = sizeof (h[0]);
Neale Rannsb80c5362016-10-08 13:03:40 +010093 u8 *rewrite = NULL;
Pavel Kotucek15ac81c2017-06-20 14:00:26 +020094 u8 is_p2p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
Neale Ranns17ff3c12018-07-04 10:24:24 -070096 if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
97 (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
Pavel Kotucek15ac81c2017-06-20 14:00:26 +020098 is_p2p = 1;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070099 if (sub_sw != sup_sw)
100 {
101 if (sub_sw->sub.eth.flags.one_tag)
102 {
103 n_bytes += sizeof (ethernet_vlan_header_t);
104 }
105 else if (sub_sw->sub.eth.flags.two_tags)
106 {
107 n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
108 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200109 else if (PREDICT_FALSE (is_p2p))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700110 {
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200111 n_bytes = sizeof (ethernet_header_t);
112 }
113 if (PREDICT_FALSE (!is_p2p))
114 {
115 // Check for encaps that are not supported for L3 interfaces
116 if (!(sub_sw->sub.eth.flags.exact_match) ||
117 (sub_sw->sub.eth.flags.default_sub) ||
118 (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
119 (sub_sw->sub.eth.flags.inner_vlan_id_any))
120 {
121 return 0;
122 }
123 }
124 else
125 {
126 n_bytes = sizeof (ethernet_header_t);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700127 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129
Neale Rannsb80c5362016-10-08 13:03:40 +0100130 switch (link_type)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700131 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100132#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700133 _(IP4, IP4);
134 _(IP6, IP6);
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800135 _(MPLS, MPLS);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700136 _(ARP, ARP);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137#undef _
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700138 default:
Neale Rannsb80c5362016-10-08 13:03:40 +0100139 return NULL;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700140 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
Neale Rannsb80c5362016-10-08 13:03:40 +0100142 vec_validate (rewrite, n_bytes - 1);
143 h = (ethernet_header_t *) rewrite;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144 ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
Damjan Marionf1213b82016-03-13 02:22:06 +0100145 clib_memcpy (h->src_address, ei->address, sizeof (h->src_address));
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200146 if (is_p2p)
147 {
148 clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
149 sizeof (h->dst_address));
150 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 else
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200152 {
153 if (dst_address)
154 clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
155 else
Dave Barachb7b92992018-10-17 10:38:51 -0400156 clib_memset (h->dst_address, ~0, sizeof (h->dst_address)); /* broadcast */
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200157 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200159 if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700160 {
161 ethernet_vlan_header_t *outer = (void *) (h + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700163 h->type = sub_sw->sub.eth.flags.dot1ad ?
164 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
165 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
166 outer->priority_cfi_and_id =
167 clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
168 outer->type = clib_host_to_net_u16 (type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700170 }
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200171 else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700172 {
173 ethernet_vlan_header_t *outer = (void *) (h + 1);
174 ethernet_vlan_header_t *inner = (void *) (outer + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700176 h->type = sub_sw->sub.eth.flags.dot1ad ?
177 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
178 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
179 outer->priority_cfi_and_id =
180 clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
181 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
182 inner->priority_cfi_and_id =
183 clib_host_to_net_u16 (sub_sw->sub.eth.inner_vlan_id);
184 inner->type = clib_host_to_net_u16 (type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700186 }
187 else
188 {
189 h->type = clib_host_to_net_u16 (type);
190 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
Neale Rannsb80c5362016-10-08 13:03:40 +0100192 return (rewrite);
193}
194
195void
196ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
197{
198 ip_adjacency_t *adj;
199
200 adj = adj_get (ai);
201
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200202 vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
Neale Ranns17ff3c12018-07-04 10:24:24 -0700203 if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
204 (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200205 {
206 default_update_adjacency (vnm, sw_if_index, ai);
207 }
208 else if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto)
Neale Rannsb80c5362016-10-08 13:03:40 +0100209 {
210 arp_update_adjacency (vnm, sw_if_index, ai);
211 }
212 else if (FIB_PROTOCOL_IP6 == adj->ia_nh_proto)
213 {
214 ip6_ethernet_update_adjacency (vnm, sw_if_index, ai);
215 }
216 else
217 {
218 ASSERT (0);
219 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220}
221
Neale Ranns3be6b282016-12-20 14:24:01 +0000222static clib_error_t *
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700223ethernet_mac_change (vnet_hw_interface_t * hi,
224 const u8 * old_address, const u8 * mac_address)
Neale Ranns3be6b282016-12-20 14:24:01 +0000225{
226 ethernet_interface_t *ei;
227 ethernet_main_t *em;
228
229 em = &ethernet_main;
230 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
231
232 vec_validate (hi->hw_address,
233 STRUCT_SIZE_OF (ethernet_header_t, src_address) - 1);
234 clib_memcpy (hi->hw_address, mac_address, vec_len (hi->hw_address));
235
236 clib_memcpy (ei->address, (u8 *) mac_address, sizeof (ei->address));
237 ethernet_arp_change_mac (hi->sw_if_index);
238 ethernet_ndp_change_mac (hi->sw_if_index);
239
240 return (NULL);
241}
242
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700243/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
245 .name = "Ethernet",
246 .format_address = format_ethernet_address,
247 .format_header = format_ethernet_header_with_length,
248 .unformat_hw_address = unformat_ethernet_address,
249 .unformat_header = unformat_ethernet_header,
Neale Rannsb80c5362016-10-08 13:03:40 +0100250 .build_rewrite = ethernet_build_rewrite,
251 .update_adjacency = ethernet_update_adjacency,
Neale Ranns3be6b282016-12-20 14:24:01 +0000252 .mac_addr_change_function = ethernet_mac_change,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700254/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700256uword
257unformat_ethernet_interface (unformat_input_t * input, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700259 vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
260 u32 *result = va_arg (*args, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 u32 hw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700262 ethernet_main_t *em = &ethernet_main;
263 ethernet_interface_t *eif;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700265 if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 return 0;
267
268 eif = ethernet_get_interface (em, hw_if_index);
269 if (eif)
270 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700271 *result = hw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 return 1;
273 }
274 return 0;
275}
276
277clib_error_t *
278ethernet_register_interface (vnet_main_t * vnm,
279 u32 dev_class_index,
280 u32 dev_instance,
Neale Ranns192b13f2019-03-15 02:16:20 -0700281 const u8 * address,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700282 u32 * hw_if_index_return,
283 ethernet_flag_change_function_t flag_change)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700285 ethernet_main_t *em = &ethernet_main;
286 ethernet_interface_t *ei;
287 vnet_hw_interface_t *hi;
288 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 u32 hw_if_index;
290
291 pool_get (em->interfaces, ei);
292 ei->flag_change = flag_change;
293
294 hw_if_index = vnet_register_interface
295 (vnm,
296 dev_class_index, dev_instance,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700297 ethernet_hw_interface_class.index, ei - em->interfaces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 *hw_if_index_return = hw_if_index;
299
300 hi = vnet_get_hw_interface (vnm, hw_if_index);
301
302 ethernet_setup_node (vnm->vlib_main, hi->output_node_index);
303
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700304 hi->min_packet_bytes = hi->min_supported_packet_bytes =
305 ETHERNET_MIN_PACKET_BYTES;
306 hi->max_packet_bytes = hi->max_supported_packet_bytes =
307 ETHERNET_MAX_PACKET_BYTES;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
309 /* Standard default ethernet MTU. */
Ole Troand7231612018-06-07 10:17:57 +0200310 vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000);
Damjan Marionfe7d4a22018-04-13 19:43:39 +0200311
Damjan Marionf1213b82016-03-13 02:22:06 +0100312 clib_memcpy (ei->address, address, sizeof (ei->address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313 vec_add (hi->hw_address, address, sizeof (ei->address));
314
315 if (error)
316 {
317 pool_put (em->interfaces, ei);
318 return error;
319 }
320 return error;
321}
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700322
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323void
324ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
325{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700326 ethernet_main_t *em = &ethernet_main;
327 ethernet_interface_t *ei;
328 vnet_hw_interface_t *hi;
329 main_intf_t *main_intf;
330 vlan_table_t *vlan_table;
331 u32 idx;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332
333 hi = vnet_get_hw_interface (vnm, hw_if_index);
334 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
335
336 /* Delete vlan mapping table for dot1q and dot1ad. */
337 main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700338 if (main_intf->dot1q_vlans)
339 {
340 vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
341 for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
342 {
343 if (vlan_table->vlans[idx].qinqs)
344 {
345 pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
John Lod63abff2018-10-04 16:22:21 -0400346 vlan_table->vlans[idx].qinqs = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700347 }
348 }
349 pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
Steve Shin8a3e5752018-02-20 11:38:34 -0800350 main_intf->dot1q_vlans = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700352 if (main_intf->dot1ad_vlans)
353 {
354 vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
355 for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
356 {
357 if (vlan_table->vlans[idx].qinqs)
358 {
359 pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
John Lod63abff2018-10-04 16:22:21 -0400360 vlan_table->vlans[idx].qinqs = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700361 }
362 }
363 pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
Steve Shin8a3e5752018-02-20 11:38:34 -0800364 main_intf->dot1ad_vlans = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700366
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367 vnet_delete_hw_interface (vnm, hw_if_index);
368 pool_put (em->interfaces, ei);
369}
370
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700371u32
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
373{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700374 ethernet_main_t *em = &ethernet_main;
375 vnet_hw_interface_t *hi;
376 ethernet_interface_t *ei;
377
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 hi = vnet_get_hw_interface (vnm, hw_if_index);
379
380 ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
381
382 ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
Damjan Marion650223c2018-11-14 16:55:53 +0100383 ei->flags = flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 if (ei->flag_change)
385 return ei->flag_change (vnm, hi, flags);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700386 return (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387}
388
Dave Barach635ec3b2018-07-13 20:12:45 -0400389/**
390 * Echo packets back to ethernet/l2-input.
Dave Barach635ec3b2018-07-13 20:12:45 -0400391 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392static uword
393simulated_ethernet_interface_tx (vlib_main_t * vm,
Dave Barach635ec3b2018-07-13 20:12:45 -0400394 vlib_node_runtime_t *
395 node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396{
Dave Barach78451a62018-07-21 09:25:00 -0400397 u32 n_left_from, *from;
398 u32 next_index = 0;
399 u32 n_bytes;
Damjan Marion586afd72017-04-05 19:18:20 +0200400 u32 thread_index = vm->thread_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700401 vnet_main_t *vnm = vnet_get_main ();
402 vnet_interface_main_t *im = &vnm->interface_main;
Dave Barach635ec3b2018-07-13 20:12:45 -0400403 l2_input_config_t *config;
Dave Barach78451a62018-07-21 09:25:00 -0400404 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
405 u16 nexts[VLIB_FRAME_SIZE], *next;
406 u32 new_rx_sw_if_index = ~0;
407 u32 new_tx_sw_if_index = ~0;
John Lo405e41b2016-04-23 15:14:12 -0400408
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 n_left_from = frame->n_vectors;
Damjan Mariona3d59862018-11-10 10:23:00 +0100410 from = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411
Dave Barach78451a62018-07-21 09:25:00 -0400412 vlib_get_buffers (vm, from, bufs, n_left_from);
413 b = bufs;
414 next = nexts;
Dave Barach635ec3b2018-07-13 20:12:45 -0400415
Dave Barach78451a62018-07-21 09:25:00 -0400416 /* Ordinarily, this is the only config lookup. */
417 config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
418 next_index =
Dave Barach635ec3b2018-07-13 20:12:45 -0400419 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
420 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
Dave Barach78451a62018-07-21 09:25:00 -0400421 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
422 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
Dave Barach635ec3b2018-07-13 20:12:45 -0400423
Dave Barach78451a62018-07-21 09:25:00 -0400424 while (n_left_from >= 4)
425 {
426 u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
427 u32 not_all_match_config;
Dave Barach635ec3b2018-07-13 20:12:45 -0400428
Dave Barach78451a62018-07-21 09:25:00 -0400429 /* Prefetch next iteration. */
430 if (PREDICT_TRUE (n_left_from >= 8))
431 {
432 vlib_prefetch_buffer_header (b[4], STORE);
433 vlib_prefetch_buffer_header (b[5], STORE);
434 vlib_prefetch_buffer_header (b[6], STORE);
435 vlib_prefetch_buffer_header (b[7], STORE);
436 }
Dave Barach635ec3b2018-07-13 20:12:45 -0400437
Dave Barach78451a62018-07-21 09:25:00 -0400438 /* Make sure all pkts were transmitted on the same (loop) intfc */
439 sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
440 sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
441 sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
442 sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
Dave Barach635ec3b2018-07-13 20:12:45 -0400443
Dave Barach78451a62018-07-21 09:25:00 -0400444 not_all_match_config = (sw_if_index0 ^ sw_if_index1)
445 ^ (sw_if_index2 ^ sw_if_index3);
446 not_all_match_config += sw_if_index0 ^ new_rx_sw_if_index;
447
448 /* Speed path / expected case: all pkts on the same intfc */
449 if (PREDICT_TRUE (not_all_match_config == 0))
450 {
451 next[0] = next_index;
452 next[1] = next_index;
453 next[2] = next_index;
454 next[3] = next_index;
455 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
456 vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
457 vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
458 vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
459 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
460 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
461 vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
462 vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
463 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
464 n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
465 n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
466 n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
467
468 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
469 {
470 vnet_update_l2_len (b[0]);
471 vnet_update_l2_len (b[1]);
472 vnet_update_l2_len (b[2]);
473 vnet_update_l2_len (b[3]);
474 }
475
476 /* increment TX interface stat */
477 vlib_increment_combined_counter (im->combined_sw_if_counters +
478 VNET_INTERFACE_COUNTER_TX,
479 thread_index, new_rx_sw_if_index,
480 4 /* pkts */ , n_bytes);
481 b += 4;
482 next += 4;
483 n_left_from -= 4;
484 continue;
485 }
486
487 /*
488 * Slow path: we know that at least one of the pkts
489 * was transmitted on a different sw_if_index, so
490 * check each sw_if_index against the cached data and proceed
491 * accordingly.
492 *
493 * This shouldn't happen, but code can (and does) bypass the
494 * per-interface output node, so deal with it.
495 */
496 if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
497 != new_rx_sw_if_index))
498 {
499 config = l2input_intf_config
500 (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
501 next_index =
502 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
503 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
504 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
505 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
506 }
507 next[0] = next_index;
508 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
509 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
510 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
511 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
512 vnet_update_l2_len (b[0]);
513
514 vlib_increment_combined_counter (im->combined_sw_if_counters +
515 VNET_INTERFACE_COUNTER_TX,
516 thread_index, new_rx_sw_if_index,
517 1 /* pkts */ , n_bytes);
518
519 if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
520 != new_rx_sw_if_index))
521 {
522 config = l2input_intf_config
523 (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
524 next_index =
525 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
526 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
527 new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
528 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
529 }
530 next[1] = next_index;
531 vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
532 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
533 n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
534 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
535 vnet_update_l2_len (b[1]);
536
537 vlib_increment_combined_counter (im->combined_sw_if_counters +
538 VNET_INTERFACE_COUNTER_TX,
539 thread_index, new_rx_sw_if_index,
540 1 /* pkts */ , n_bytes);
541
542 if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
543 != new_rx_sw_if_index))
544 {
545 config = l2input_intf_config
546 (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
547 next_index =
548 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
549 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
550 new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
551 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
552 }
553 next[2] = next_index;
554 vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
555 vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
556 n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
557 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
558 vnet_update_l2_len (b[2]);
559
560 vlib_increment_combined_counter (im->combined_sw_if_counters +
561 VNET_INTERFACE_COUNTER_TX,
562 thread_index, new_rx_sw_if_index,
563 1 /* pkts */ , n_bytes);
564
565 if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
566 != new_rx_sw_if_index))
567 {
568 config = l2input_intf_config
569 (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
570 next_index =
571 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
572 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
573 new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
574 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
575 }
576 next[3] = next_index;
577 vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
578 vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
579 n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
580 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
581 vnet_update_l2_len (b[3]);
582
583 vlib_increment_combined_counter (im->combined_sw_if_counters +
584 VNET_INTERFACE_COUNTER_TX,
585 thread_index, new_rx_sw_if_index,
586 1 /* pkts */ , n_bytes);
587 b += 4;
588 next += 4;
589 n_left_from -= 4;
590 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700591 while (n_left_from > 0)
592 {
Dave Barach78451a62018-07-21 09:25:00 -0400593 if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
594 != new_rx_sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595 {
Dave Barach78451a62018-07-21 09:25:00 -0400596 config = l2input_intf_config
597 (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
598 next_index =
599 config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
600 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
601 new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
602 new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700603 }
Dave Barach78451a62018-07-21 09:25:00 -0400604 next[0] = next_index;
605 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
606 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
607 n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
608 if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
609 vnet_update_l2_len (b[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610
Dave Barach78451a62018-07-21 09:25:00 -0400611 vlib_increment_combined_counter (im->combined_sw_if_counters +
612 VNET_INTERFACE_COUNTER_TX,
613 thread_index, new_rx_sw_if_index,
614 1 /* pkts */ , n_bytes);
615 b += 1;
616 next += 1;
617 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618 }
619
Dave Barach78451a62018-07-21 09:25:00 -0400620 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Dave Barach635ec3b2018-07-13 20:12:45 -0400621
622 return frame->n_vectors;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623}
624
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700625static u8 *
626format_simulated_ethernet_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627{
628 u32 dev_instance = va_arg (*args, u32);
629 return format (s, "loop%d", dev_instance);
630}
631
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000632static clib_error_t *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700633simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
634 u32 flags)
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000635{
636 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700637 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000638 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
639 return 0;
640}
641
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700642static clib_error_t *
643simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
644 const u8 * old_address, const u8 * mac_address)
645{
646 l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
647
648 return (NULL);
649}
650
651
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700652/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
654 .name = "Loopback",
655 .format_device_name = format_simulated_ethernet_name,
656 .tx_function = simulated_ethernet_interface_tx,
Pierre Pfisterf00f91a2016-03-09 18:22:32 +0000657 .admin_up_down_function = simulated_ethernet_admin_up_down,
Neale Ranns3b81a1e2018-09-06 09:50:26 -0700658 .mac_addr_change_function = simulated_ethernet_mac_change,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700660/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600662/*
663 * Maintain a bitmap of allocated loopback instance numbers.
664 */
665#define LOOPBACK_MAX_INSTANCE (16 * 1024)
666
667static u32
668loopback_instance_alloc (u8 is_specified, u32 want)
669{
670 ethernet_main_t *em = &ethernet_main;
671
672 /*
673 * Check for dynamically allocaetd instance number.
674 */
675 if (!is_specified)
676 {
677 u32 bit;
678
679 bit = clib_bitmap_first_clear (em->bm_loopback_instances);
680 if (bit >= LOOPBACK_MAX_INSTANCE)
681 {
682 return ~0;
683 }
684 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
685 bit, 1);
686 return bit;
687 }
688
689 /*
690 * In range?
691 */
692 if (want >= LOOPBACK_MAX_INSTANCE)
693 {
694 return ~0;
695 }
696
697 /*
698 * Already in use?
699 */
700 if (clib_bitmap_get (em->bm_loopback_instances, want))
701 {
702 return ~0;
703 }
704
705 /*
706 * Grant allocation request.
707 */
708 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
709 want, 1);
710
711 return want;
712}
713
714static int
715loopback_instance_free (u32 instance)
716{
717 ethernet_main_t *em = &ethernet_main;
718
719 if (instance >= LOOPBACK_MAX_INSTANCE)
720 {
721 return -1;
722 }
723
724 if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
725 {
726 return -1;
727 }
728
729 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
730 instance, 0);
731 return 0;
732}
733
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700734int
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600735vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
736 u8 is_specified, u32 user_instance)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700738 vnet_main_t *vnm = vnet_get_main ();
739 vlib_main_t *vm = vlib_get_main ();
740 clib_error_t *error;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600741 u32 instance;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 u8 address[6];
743 u32 hw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700744 vnet_hw_interface_t *hw_if;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 u32 slot;
746 int rv = 0;
747
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700748 ASSERT (sw_if_indexp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700749
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700750 *sw_if_indexp = (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751
Dave Barachb7b92992018-10-17 10:38:51 -0400752 clib_memset (address, 0, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753
754 /*
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600755 * Allocate a loopback instance. Either select on dynamically
756 * or try to use the desired user_instance number.
757 */
758 instance = loopback_instance_alloc (is_specified, user_instance);
759 if (instance == ~0)
760 {
761 return VNET_API_ERROR_INVALID_REGISTRATION;
762 }
763
764 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765 * Default MAC address (dead:0000:0000 + instance) is allocated
766 * if zero mac_address is configured. Otherwise, user-configurable MAC
767 * address is programmed on the loopback interface.
768 */
769 if (memcmp (address, mac_address, sizeof (address)))
Damjan Marionf1213b82016-03-13 02:22:06 +0100770 clib_memcpy (address, mac_address, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700771 else
772 {
773 address[0] = 0xde;
774 address[1] = 0xad;
775 address[5] = instance;
776 }
777
778 error = ethernet_register_interface
779 (vnm,
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600780 ethernet_simulated_device_class.index, instance, address, &hw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781 /* flag change */ 0);
782
783 if (error)
784 {
785 rv = VNET_API_ERROR_INVALID_REGISTRATION;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700786 clib_error_report (error);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 return rv;
788 }
789
790 hw_if = vnet_get_hw_interface (vnm, hw_if_index);
791 slot = vlib_node_add_named_next_with_slot
792 (vm, hw_if->tx_node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700793 "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
795
Dave Barach635ec3b2018-07-13 20:12:45 -0400796 slot = vlib_node_add_named_next_with_slot
797 (vm, hw_if->tx_node_index,
798 "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
799 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
800
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700802 vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 *sw_if_indexp = si->sw_if_index;
Neale Ranns87dad112018-04-09 01:53:01 -0700804
805 /* By default don't flood to loopbacks, as packets just keep
806 * coming back ... If this loopback becomes a BVI, we'll change it */
807 si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808 }
809
810 return 0;
811}
812
813static clib_error_t *
814create_simulated_ethernet_interfaces (vlib_main_t * vm,
815 unformat_input_t * input,
816 vlib_cli_command_t * cmd)
817{
818 int rv;
819 u32 sw_if_index;
820 u8 mac_address[6];
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600821 u8 is_specified = 0;
822 u32 user_instance = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823
Dave Barachb7b92992018-10-17 10:38:51 -0400824 clib_memset (mac_address, 0, sizeof (mac_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825
826 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827 {
828 if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700829 ;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600830 if (unformat (input, "instance %d", &user_instance))
831 is_specified = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700833 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834 }
835
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600836 rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
837 is_specified, user_instance);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838
839 if (rv)
840 return clib_error_return (0, "vnet_create_loopback_interface failed");
841
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700842 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
843 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700844 return 0;
845}
846
Billy McFall2d085d92016-09-13 21:47:55 -0400847/*?
848 * Create a loopback interface. Optionally, a MAC Address can be
849 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
850 *
851 * @cliexpar
852 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600853 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
854 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400855 * Example of how to create a loopback interface:
856 * @cliexcmd{loopback create-interface}
857?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700858/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
860 .path = "loopback create-interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600861 .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862 .function = create_simulated_ethernet_interfaces,
863};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700864/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865
Billy McFall2d085d92016-09-13 21:47:55 -0400866/*?
867 * Create a loopback interface. Optionally, a MAC Address can be
868 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
869 *
870 * @cliexpar
871 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600872 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
873 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400874 * Example of how to create a loopback interface:
875 * @cliexcmd{create loopback interface}
876?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700877/* *INDENT-OFF* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700878VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
879 .path = "create loopback interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600880 .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
Alpesh Patel370a24e2016-04-08 07:27:37 -0700881 .function = create_simulated_ethernet_interfaces,
882};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700883/* *INDENT-ON* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700884
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885ethernet_interface_t *
886ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
887{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700888 vnet_hw_interface_t *i =
889 vnet_get_hw_interface (vnet_get_main (), hw_if_index);
890 return (i->hw_class_index ==
891 ethernet_hw_interface_class.
892 index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893}
894
Matthew G Smithd459bf32019-09-04 15:01:04 -0500895mac_address_t *
896ethernet_interface_add_del_address (ethernet_main_t * em,
897 u32 hw_if_index, const u8 * address,
898 u8 is_add)
899{
900 ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
901 mac_address_t *if_addr = 0;
902
903 /* return if there is not an ethernet interface for this hw interface */
904 if (!ei)
905 return 0;
906
907 /* determine whether the address is configured on the interface */
908 vec_foreach (if_addr, ei->secondary_addrs)
909 {
910 if (!ethernet_mac_address_equal (if_addr->bytes, address))
911 continue;
912
913 break;
914 }
915
916 if (if_addr && vec_is_member (ei->secondary_addrs, if_addr))
917 {
918 /* delete found address */
919 if (!is_add)
920 {
921 vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
922 if_addr = 0;
923 }
924 /* address already found, so nothing needs to be done if adding */
925 }
926 else
927 {
928 /* if_addr could be 0 or past the end of the vector. reset to 0 */
929 if_addr = 0;
930
931 /* add new address */
932 if (is_add)
933 {
934 vec_add2 (ei->secondary_addrs, if_addr, 1);
935 clib_memcpy (&if_addr->bytes, address, sizeof (if_addr->bytes));
936 }
937 }
938
939 return if_addr;
940}
941
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700942int
943vnet_delete_loopback_interface (u32 sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700945 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700947 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
949
Eyal Barib52c0342018-07-16 19:18:56 +0300950 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
951 if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
952 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600953
Eyal Barib52c0342018-07-16 19:18:56 +0300954 if (loopback_instance_free (hw->dev_instance) < 0)
955 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600956
Eyal Barib52c0342018-07-16 19:18:56 +0300957 ethernet_delete_interface (vnm, hw->hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958
959 return 0;
960}
961
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200962int
Neale Ranns669f4e32019-10-28 07:56:15 -0700963vnet_create_sub_interface (u32 sw_if_index, u32 id,
964 u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
965 u32 * sub_sw_if_index)
966{
967 vnet_main_t *vnm = vnet_get_main ();
968 vnet_interface_main_t *im = &vnm->interface_main;
969 vnet_hw_interface_t *hi;
970 u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
971 vnet_sw_interface_t template;
972 uword *p;
973 u64 *kp;
974
975 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
976
977 p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
978 if (p)
979 {
980 return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
981 }
982
983 clib_memset (&template, 0, sizeof (template));
984 template.type = VNET_SW_INTERFACE_TYPE_SUB;
985 template.flood_class = VNET_FLOOD_CLASS_NORMAL;
986 template.sup_sw_if_index = sw_if_index;
987 template.sub.id = id;
988 template.sub.eth.raw_flags = flags;
989 template.sub.eth.outer_vlan_id = outer_vlan_id;
990 template.sub.eth.inner_vlan_id = inner_vlan_id;
991
992 if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
993 return (VNET_API_ERROR_UNSPECIFIED);
994
995 kp = clib_mem_alloc (sizeof (*kp));
996 *kp = sup_and_sub_key;
997
998 hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
999 hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
1000
1001 return (0);
1002}
1003
1004int
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001005vnet_delete_sub_interface (u32 sw_if_index)
1006{
1007 vnet_main_t *vnm = vnet_get_main ();
Steve Shina36f08c2018-03-07 13:29:29 -08001008 vnet_sw_interface_t *si;
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001009 int rv = 0;
1010
1011 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1012 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1013
Steve Shina36f08c2018-03-07 13:29:29 -08001014 si = vnet_get_sw_interface (vnm, sw_if_index);
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001015 if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
Neale Ranns17ff3c12018-07-04 10:24:24 -07001016 si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
Pavel Kotucek15ac81c2017-06-20 14:00:26 +02001017 si->type == VNET_SW_INTERFACE_TYPE_P2P)
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001018 {
John Lo5957a142018-01-18 12:44:50 -05001019 vnet_interface_main_t *im = &vnm->interface_main;
1020 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001021 u64 sup_and_sub_key =
1022 ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
John Lo5957a142018-01-18 12:44:50 -05001023 hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1024 hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001025 vnet_delete_sw_interface (vnm, sw_if_index);
1026 }
1027 else
John Lo5957a142018-01-18 12:44:50 -05001028 rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
1029
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001030 return rv;
1031}
1032
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033static clib_error_t *
1034delete_simulated_ethernet_interfaces (vlib_main_t * vm,
1035 unformat_input_t * input,
1036 vlib_cli_command_t * cmd)
1037{
1038 int rv;
1039 u32 sw_if_index = ~0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001040 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041
1042 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1043 {
1044 if (unformat (input, "intfc %U",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001045 unformat_vnet_sw_interface, vnm, &sw_if_index))
1046 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001048 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 }
1050
1051 if (sw_if_index == ~0)
1052 return clib_error_return (0, "interface not specified");
1053
1054 rv = vnet_delete_loopback_interface (sw_if_index);
1055
1056 if (rv)
1057 return clib_error_return (0, "vnet_delete_loopback_interface failed");
1058
1059 return 0;
1060}
1061
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001062static clib_error_t *
1063delete_sub_interface (vlib_main_t * vm,
1064 unformat_input_t * input, vlib_cli_command_t * cmd)
1065{
1066 int rv = 0;
1067 u32 sw_if_index = ~0;
1068 vnet_main_t *vnm = vnet_get_main ();
1069
1070 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1071 {
1072 if (unformat
1073 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1074 ;
1075 else
1076 break;
1077 }
1078 if (sw_if_index == ~0)
1079 return clib_error_return (0, "interface doesn't exist");
1080
1081 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1082 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1083 else
1084 rv = vnet_delete_sub_interface (sw_if_index);
1085 if (rv)
1086 return clib_error_return (0, "delete_subinterface_interface failed");
1087 return 0;
1088}
1089
Billy McFall2d085d92016-09-13 21:47:55 -04001090/*?
1091 * Delete a loopback interface.
1092 *
1093 * @cliexpar
1094 * The following two command syntaxes are equivalent:
1095 * @cliexcmd{loopback delete-interface intfc <interface>}
1096 * @cliexcmd{delete loopback interface intfc <interface>}
1097 * Example of how to delete a loopback interface:
1098 * @cliexcmd{loopback delete-interface intfc loop0}
1099?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001100/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1102 .path = "loopback delete-interface",
Billy McFall2d085d92016-09-13 21:47:55 -04001103 .short_help = "loopback delete-interface intfc <interface>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104 .function = delete_simulated_ethernet_interfaces,
1105};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001106/* *INDENT-ON* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001107
Billy McFall2d085d92016-09-13 21:47:55 -04001108/*?
1109 * Delete a loopback interface.
1110 *
1111 * @cliexpar
1112 * The following two command syntaxes are equivalent:
1113 * @cliexcmd{loopback delete-interface intfc <interface>}
1114 * @cliexcmd{delete loopback interface intfc <interface>}
1115 * Example of how to delete a loopback interface:
1116 * @cliexcmd{delete loopback interface intfc loop0}
1117?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001118/* *INDENT-OFF* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001119VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1120 .path = "delete loopback interface",
1121 .short_help = "delete loopback interface intfc <interface>",
1122 .function = delete_simulated_ethernet_interfaces,
1123};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001124/* *INDENT-ON* */
1125
Billy McFall2d085d92016-09-13 21:47:55 -04001126/*?
1127 * Delete a sub-interface.
1128 *
1129 * @cliexpar
1130 * Example of how to delete a sub-interface:
1131 * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1132?*/
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001133/* *INDENT-OFF* */
1134VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1135 .path = "delete sub-interface",
1136 .short_help = "delete sub-interface <interface>",
1137 .function = delete_sub_interface,
1138};
1139/* *INDENT-ON* */
1140
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001141/*
1142 * fd.io coding-style-patch-verification: ON
1143 *
1144 * Local Variables:
1145 * eval: (c-set-style "gnu")
1146 * End:
1147 */