blob: 408b0eb0dc4edacd14a8b6cc36f4d7225be58e0c [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,
281 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
Dave Barach635ec3b2018-07-13 20:12:45 -0400662VLIB_DEVICE_TX_FUNCTION_MULTIARCH (ethernet_simulated_device_class,
663 simulated_ethernet_interface_tx);
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600664
665/*
666 * Maintain a bitmap of allocated loopback instance numbers.
667 */
668#define LOOPBACK_MAX_INSTANCE (16 * 1024)
669
670static u32
671loopback_instance_alloc (u8 is_specified, u32 want)
672{
673 ethernet_main_t *em = &ethernet_main;
674
675 /*
676 * Check for dynamically allocaetd instance number.
677 */
678 if (!is_specified)
679 {
680 u32 bit;
681
682 bit = clib_bitmap_first_clear (em->bm_loopback_instances);
683 if (bit >= LOOPBACK_MAX_INSTANCE)
684 {
685 return ~0;
686 }
687 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
688 bit, 1);
689 return bit;
690 }
691
692 /*
693 * In range?
694 */
695 if (want >= LOOPBACK_MAX_INSTANCE)
696 {
697 return ~0;
698 }
699
700 /*
701 * Already in use?
702 */
703 if (clib_bitmap_get (em->bm_loopback_instances, want))
704 {
705 return ~0;
706 }
707
708 /*
709 * Grant allocation request.
710 */
711 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
712 want, 1);
713
714 return want;
715}
716
717static int
718loopback_instance_free (u32 instance)
719{
720 ethernet_main_t *em = &ethernet_main;
721
722 if (instance >= LOOPBACK_MAX_INSTANCE)
723 {
724 return -1;
725 }
726
727 if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
728 {
729 return -1;
730 }
731
732 em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
733 instance, 0);
734 return 0;
735}
736
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700737int
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600738vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
739 u8 is_specified, u32 user_instance)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700741 vnet_main_t *vnm = vnet_get_main ();
742 vlib_main_t *vm = vlib_get_main ();
743 clib_error_t *error;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600744 u32 instance;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 u8 address[6];
746 u32 hw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700747 vnet_hw_interface_t *hw_if;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748 u32 slot;
749 int rv = 0;
750
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700751 ASSERT (sw_if_indexp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700753 *sw_if_indexp = (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754
Dave Barachb7b92992018-10-17 10:38:51 -0400755 clib_memset (address, 0, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756
757 /*
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600758 * Allocate a loopback instance. Either select on dynamically
759 * or try to use the desired user_instance number.
760 */
761 instance = loopback_instance_alloc (is_specified, user_instance);
762 if (instance == ~0)
763 {
764 return VNET_API_ERROR_INVALID_REGISTRATION;
765 }
766
767 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700768 * Default MAC address (dead:0000:0000 + instance) is allocated
769 * if zero mac_address is configured. Otherwise, user-configurable MAC
770 * address is programmed on the loopback interface.
771 */
772 if (memcmp (address, mac_address, sizeof (address)))
Damjan Marionf1213b82016-03-13 02:22:06 +0100773 clib_memcpy (address, mac_address, sizeof (address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774 else
775 {
776 address[0] = 0xde;
777 address[1] = 0xad;
778 address[5] = instance;
779 }
780
781 error = ethernet_register_interface
782 (vnm,
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600783 ethernet_simulated_device_class.index, instance, address, &hw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784 /* flag change */ 0);
785
786 if (error)
787 {
788 rv = VNET_API_ERROR_INVALID_REGISTRATION;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700789 clib_error_report (error);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 return rv;
791 }
792
793 hw_if = vnet_get_hw_interface (vnm, hw_if_index);
794 slot = vlib_node_add_named_next_with_slot
795 (vm, hw_if->tx_node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700796 "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
798
Dave Barach635ec3b2018-07-13 20:12:45 -0400799 slot = vlib_node_add_named_next_with_slot
800 (vm, hw_if->tx_node_index,
801 "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
802 ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
803
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700805 vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806 *sw_if_indexp = si->sw_if_index;
Neale Ranns87dad112018-04-09 01:53:01 -0700807
808 /* By default don't flood to loopbacks, as packets just keep
809 * coming back ... If this loopback becomes a BVI, we'll change it */
810 si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811 }
812
813 return 0;
814}
815
816static clib_error_t *
817create_simulated_ethernet_interfaces (vlib_main_t * vm,
818 unformat_input_t * input,
819 vlib_cli_command_t * cmd)
820{
821 int rv;
822 u32 sw_if_index;
823 u8 mac_address[6];
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600824 u8 is_specified = 0;
825 u32 user_instance = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826
Dave Barachb7b92992018-10-17 10:38:51 -0400827 clib_memset (mac_address, 0, sizeof (mac_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828
829 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
830 {
831 if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700832 ;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600833 if (unformat (input, "instance %d", &user_instance))
834 is_specified = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700835 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700836 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700837 }
838
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600839 rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
840 is_specified, user_instance);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841
842 if (rv)
843 return clib_error_return (0, "vnet_create_loopback_interface failed");
844
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700845 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
846 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847 return 0;
848}
849
Billy McFall2d085d92016-09-13 21:47:55 -0400850/*?
851 * Create a loopback interface. Optionally, a MAC Address can be
852 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
853 *
854 * @cliexpar
855 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600856 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
857 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400858 * Example of how to create a loopback interface:
859 * @cliexcmd{loopback create-interface}
860?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700861/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
863 .path = "loopback create-interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600864 .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865 .function = create_simulated_ethernet_interfaces,
866};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700867/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868
Billy McFall2d085d92016-09-13 21:47:55 -0400869/*?
870 * Create a loopback interface. Optionally, a MAC Address can be
871 * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
872 *
873 * @cliexpar
874 * The following two command syntaxes are equivalent:
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600875 * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
876 * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
Billy McFall2d085d92016-09-13 21:47:55 -0400877 * Example of how to create a loopback interface:
878 * @cliexcmd{create loopback interface}
879?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700880/* *INDENT-OFF* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700881VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
882 .path = "create loopback interface",
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600883 .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
Alpesh Patel370a24e2016-04-08 07:27:37 -0700884 .function = create_simulated_ethernet_interfaces,
885};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700886/* *INDENT-ON* */
Alpesh Patel370a24e2016-04-08 07:27:37 -0700887
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888ethernet_interface_t *
889ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
890{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700891 vnet_hw_interface_t *i =
892 vnet_get_hw_interface (vnet_get_main (), hw_if_index);
893 return (i->hw_class_index ==
894 ethernet_hw_interface_class.
895 index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896}
897
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700898int
899vnet_delete_loopback_interface (u32 sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700901 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700902
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700903 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
905
Eyal Barib52c0342018-07-16 19:18:56 +0300906 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
907 if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
908 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600909
Eyal Barib52c0342018-07-16 19:18:56 +0300910 if (loopback_instance_free (hw->dev_instance) < 0)
911 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
Jon Loeligerc83c3b72017-02-23 13:57:35 -0600912
Eyal Barib52c0342018-07-16 19:18:56 +0300913 ethernet_delete_interface (vnm, hw->hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914
915 return 0;
916}
917
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200918int
919vnet_delete_sub_interface (u32 sw_if_index)
920{
921 vnet_main_t *vnm = vnet_get_main ();
Steve Shina36f08c2018-03-07 13:29:29 -0800922 vnet_sw_interface_t *si;
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200923 int rv = 0;
924
925 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
926 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
927
Steve Shina36f08c2018-03-07 13:29:29 -0800928 si = vnet_get_sw_interface (vnm, sw_if_index);
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200929 if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
Neale Ranns17ff3c12018-07-04 10:24:24 -0700930 si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
Pavel Kotucek15ac81c2017-06-20 14:00:26 +0200931 si->type == VNET_SW_INTERFACE_TYPE_P2P)
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200932 {
John Lo5957a142018-01-18 12:44:50 -0500933 vnet_interface_main_t *im = &vnm->interface_main;
934 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200935 u64 sup_and_sub_key =
936 ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
John Lo5957a142018-01-18 12:44:50 -0500937 hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
938 hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200939 vnet_delete_sw_interface (vnm, sw_if_index);
940 }
941 else
John Lo5957a142018-01-18 12:44:50 -0500942 rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
943
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200944 return rv;
945}
946
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947static clib_error_t *
948delete_simulated_ethernet_interfaces (vlib_main_t * vm,
949 unformat_input_t * input,
950 vlib_cli_command_t * cmd)
951{
952 int rv;
953 u32 sw_if_index = ~0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700954 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700955
956 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
957 {
958 if (unformat (input, "intfc %U",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700959 unformat_vnet_sw_interface, vnm, &sw_if_index))
960 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700962 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 }
964
965 if (sw_if_index == ~0)
966 return clib_error_return (0, "interface not specified");
967
968 rv = vnet_delete_loopback_interface (sw_if_index);
969
970 if (rv)
971 return clib_error_return (0, "vnet_delete_loopback_interface failed");
972
973 return 0;
974}
975
Pavel Kotucekd85590a2016-08-26 13:35:40 +0200976static clib_error_t *
977delete_sub_interface (vlib_main_t * vm,
978 unformat_input_t * input, vlib_cli_command_t * cmd)
979{
980 int rv = 0;
981 u32 sw_if_index = ~0;
982 vnet_main_t *vnm = vnet_get_main ();
983
984 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
985 {
986 if (unformat
987 (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
988 ;
989 else
990 break;
991 }
992 if (sw_if_index == ~0)
993 return clib_error_return (0, "interface doesn't exist");
994
995 if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
996 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
997 else
998 rv = vnet_delete_sub_interface (sw_if_index);
999 if (rv)
1000 return clib_error_return (0, "delete_subinterface_interface failed");
1001 return 0;
1002}
1003
Billy McFall2d085d92016-09-13 21:47:55 -04001004/*?
1005 * Delete a loopback interface.
1006 *
1007 * @cliexpar
1008 * The following two command syntaxes are equivalent:
1009 * @cliexcmd{loopback delete-interface intfc <interface>}
1010 * @cliexcmd{delete loopback interface intfc <interface>}
1011 * Example of how to delete a loopback interface:
1012 * @cliexcmd{loopback delete-interface intfc loop0}
1013?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001014/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1016 .path = "loopback delete-interface",
Billy McFall2d085d92016-09-13 21:47:55 -04001017 .short_help = "loopback delete-interface intfc <interface>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018 .function = delete_simulated_ethernet_interfaces,
1019};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001020/* *INDENT-ON* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001021
Billy McFall2d085d92016-09-13 21:47:55 -04001022/*?
1023 * Delete a loopback interface.
1024 *
1025 * @cliexpar
1026 * The following two command syntaxes are equivalent:
1027 * @cliexcmd{loopback delete-interface intfc <interface>}
1028 * @cliexcmd{delete loopback interface intfc <interface>}
1029 * Example of how to delete a loopback interface:
1030 * @cliexcmd{delete loopback interface intfc loop0}
1031?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001032/* *INDENT-OFF* */
Alpesh S. Patel633951c2016-04-12 09:58:56 -07001033VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1034 .path = "delete loopback interface",
1035 .short_help = "delete loopback interface intfc <interface>",
1036 .function = delete_simulated_ethernet_interfaces,
1037};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001038/* *INDENT-ON* */
1039
Billy McFall2d085d92016-09-13 21:47:55 -04001040/*?
1041 * Delete a sub-interface.
1042 *
1043 * @cliexpar
1044 * Example of how to delete a sub-interface:
1045 * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1046?*/
Pavel Kotucekd85590a2016-08-26 13:35:40 +02001047/* *INDENT-OFF* */
1048VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1049 .path = "delete sub-interface",
1050 .short_help = "delete sub-interface <interface>",
1051 .function = delete_sub_interface,
1052};
1053/* *INDENT-ON* */
1054
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001055/*
1056 * fd.io coding-style-patch-verification: ON
1057 *
1058 * Local Variables:
1059 * eval: (c-set-style "gnu")
1060 * End:
1061 */