BVI Interface
[vpp.git] / src / vnet / ethernet / interface.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * ethernet_interface.c: ethernet interfaces
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/pg/pg.h>
43 #include <vnet/ethernet/ethernet.h>
44 #include <vnet/ethernet/arp.h>
45 #include <vnet/l2/l2_input.h>
46 #include <vnet/l2/l2_bd.h>
47 #include <vnet/adj/adj.h>
48
49 /**
50  * @file
51  * @brief Loopback Interfaces.
52  *
53  * This file contains code to manage loopback interfaces.
54  */
55
56 const u8 *
57 ethernet_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
66 const u8 *
67 ethernet_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
76 /**
77  * @brief build a rewrite string to use for sending packets of type 'link_type'
78  * to 'dst_address'
79  */
80 u8 *
81 ethernet_build_rewrite (vnet_main_t * vnm,
82                         u32 sw_if_index,
83                         vnet_link_t link_type, const void *dst_address)
84 {
85   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;
90   ethernet_header_t *h;
91   ethernet_type_t type;
92   uword n_bytes = sizeof (h[0]);
93   u8 *rewrite = NULL;
94   u8 is_p2p = 0;
95
96   if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
97       (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
98     is_p2p = 1;
99   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         }
109       else if (PREDICT_FALSE (is_p2p))
110         {
111           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);
127         }
128     }
129
130   switch (link_type)
131     {
132 #define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
133       _(IP4, IP4);
134       _(IP6, IP6);
135       _(MPLS, MPLS);
136       _(ARP, ARP);
137 #undef _
138     default:
139       return NULL;
140     }
141
142   vec_validate (rewrite, n_bytes - 1);
143   h = (ethernet_header_t *) rewrite;
144   ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
145   clib_memcpy (h->src_address, ei->address, sizeof (h->src_address));
146   if (is_p2p)
147     {
148       clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
149                    sizeof (h->dst_address));
150     }
151   else
152     {
153       if (dst_address)
154         clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
155       else
156         clib_memset (h->dst_address, ~0, sizeof (h->dst_address));      /* broadcast */
157     }
158
159   if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
160     {
161       ethernet_vlan_header_t *outer = (void *) (h + 1);
162
163       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);
169
170     }
171   else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
172     {
173       ethernet_vlan_header_t *outer = (void *) (h + 1);
174       ethernet_vlan_header_t *inner = (void *) (outer + 1);
175
176       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);
185
186     }
187   else
188     {
189       h->type = clib_host_to_net_u16 (type);
190     }
191
192   return (rewrite);
193 }
194
195 void
196 ethernet_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
202   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
203   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
204       (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
205     {
206       default_update_adjacency (vnm, sw_if_index, ai);
207     }
208   else if (FIB_PROTOCOL_IP4 == adj->ia_nh_proto)
209     {
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     }
220 }
221
222 static clib_error_t *
223 ethernet_mac_change (vnet_hw_interface_t * hi,
224                      const u8 * old_address, const u8 * mac_address)
225 {
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
243 /* *INDENT-OFF* */
244 VNET_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,
250   .build_rewrite = ethernet_build_rewrite,
251   .update_adjacency = ethernet_update_adjacency,
252   .mac_addr_change_function = ethernet_mac_change,
253 };
254 /* *INDENT-ON* */
255
256 uword
257 unformat_ethernet_interface (unformat_input_t * input, va_list * args)
258 {
259   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
260   u32 *result = va_arg (*args, u32 *);
261   u32 hw_if_index;
262   ethernet_main_t *em = &ethernet_main;
263   ethernet_interface_t *eif;
264
265   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
266     return 0;
267
268   eif = ethernet_get_interface (em, hw_if_index);
269   if (eif)
270     {
271       *result = hw_if_index;
272       return 1;
273     }
274   return 0;
275 }
276
277 clib_error_t *
278 ethernet_register_interface (vnet_main_t * vnm,
279                              u32 dev_class_index,
280                              u32 dev_instance,
281                              const u8 * address,
282                              u32 * hw_if_index_return,
283                              ethernet_flag_change_function_t flag_change)
284 {
285   ethernet_main_t *em = &ethernet_main;
286   ethernet_interface_t *ei;
287   vnet_hw_interface_t *hi;
288   clib_error_t *error = 0;
289   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,
297      ethernet_hw_interface_class.index, ei - em->interfaces);
298   *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
304   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;
308
309   /* Standard default ethernet MTU. */
310   vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000);
311
312   clib_memcpy (ei->address, address, sizeof (ei->address));
313   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 }
322
323 void
324 ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
325 {
326   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;
332
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);
338   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);
346               vlan_table->vlans[idx].qinqs = 0;
347             }
348         }
349       pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
350       main_intf->dot1q_vlans = 0;
351     }
352   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);
360               vlan_table->vlans[idx].qinqs = 0;
361             }
362         }
363       pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
364       main_intf->dot1ad_vlans = 0;
365     }
366
367   vnet_delete_hw_interface (vnm, hw_if_index);
368   pool_put (em->interfaces, ei);
369 }
370
371 u32
372 ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
373 {
374   ethernet_main_t *em = &ethernet_main;
375   vnet_hw_interface_t *hi;
376   ethernet_interface_t *ei;
377
378   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);
383   ei->flags = flags;
384   if (ei->flag_change)
385     return ei->flag_change (vnm, hi, flags);
386   return (u32) ~ 0;
387 }
388
389 /**
390  * Echo packets back to ethernet/l2-input.
391  */
392 static uword
393 simulated_ethernet_interface_tx (vlib_main_t * vm,
394                                  vlib_node_runtime_t *
395                                  node, vlib_frame_t * frame)
396 {
397   u32 n_left_from, *from;
398   u32 next_index = 0;
399   u32 n_bytes;
400   u32 thread_index = vm->thread_index;
401   vnet_main_t *vnm = vnet_get_main ();
402   vnet_interface_main_t *im = &vnm->interface_main;
403   l2_input_config_t *config;
404   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;
408
409   n_left_from = frame->n_vectors;
410   from = vlib_frame_vector_args (frame);
411
412   vlib_get_buffers (vm, from, bufs, n_left_from);
413   b = bufs;
414   next = nexts;
415
416   /* Ordinarily, this is the only config lookup. */
417   config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
418   next_index =
419     config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
420     VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
421   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];
423
424   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;
428
429       /* 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         }
437
438       /* 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];
443
444       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     }
591   while (n_left_from > 0)
592     {
593       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
594                          != new_rx_sw_if_index))
595         {
596           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];
603         }
604       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]);
610
611       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;
618     }
619
620   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
621
622   return frame->n_vectors;
623 }
624
625 static u8 *
626 format_simulated_ethernet_name (u8 * s, va_list * args)
627 {
628   u32 dev_instance = va_arg (*args, u32);
629   return format (s, "loop%d", dev_instance);
630 }
631
632 static clib_error_t *
633 simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
634                                   u32 flags)
635 {
636   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
637     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
638   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
639   return 0;
640 }
641
642 static clib_error_t *
643 simulated_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
652 /* *INDENT-OFF* */
653 VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
654   .name = "Loopback",
655   .format_device_name = format_simulated_ethernet_name,
656   .tx_function = simulated_ethernet_interface_tx,
657   .admin_up_down_function = simulated_ethernet_admin_up_down,
658   .mac_addr_change_function = simulated_ethernet_mac_change,
659 };
660 /* *INDENT-ON* */
661
662 /*
663  * Maintain a bitmap of allocated loopback instance numbers.
664  */
665 #define LOOPBACK_MAX_INSTANCE           (16 * 1024)
666
667 static u32
668 loopback_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
714 static int
715 loopback_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
734 int
735 vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
736                                 u8 is_specified, u32 user_instance)
737 {
738   vnet_main_t *vnm = vnet_get_main ();
739   vlib_main_t *vm = vlib_get_main ();
740   clib_error_t *error;
741   u32 instance;
742   u8 address[6];
743   u32 hw_if_index;
744   vnet_hw_interface_t *hw_if;
745   u32 slot;
746   int rv = 0;
747
748   ASSERT (sw_if_indexp);
749
750   *sw_if_indexp = (u32) ~ 0;
751
752   clib_memset (address, 0, sizeof (address));
753
754   /*
755    * 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   /*
765    * 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)))
770     clib_memcpy (address, mac_address, sizeof (address));
771   else
772     {
773       address[0] = 0xde;
774       address[1] = 0xad;
775       address[5] = instance;
776     }
777
778   error = ethernet_register_interface
779     (vnm,
780      ethernet_simulated_device_class.index, instance, address, &hw_if_index,
781      /* flag change */ 0);
782
783   if (error)
784     {
785       rv = VNET_API_ERROR_INVALID_REGISTRATION;
786       clib_error_report (error);
787       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,
793      "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
794   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
795
796   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
801   {
802     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
803     *sw_if_indexp = si->sw_if_index;
804
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;
808   }
809
810   return 0;
811 }
812
813 static clib_error_t *
814 create_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];
821   u8 is_specified = 0;
822   u32 user_instance = 0;
823
824   clib_memset (mac_address, 0, sizeof (mac_address));
825
826   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
827     {
828       if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
829         ;
830       if (unformat (input, "instance %d", &user_instance))
831         is_specified = 1;
832       else
833         break;
834     }
835
836   rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
837                                        is_specified, user_instance);
838
839   if (rv)
840     return clib_error_return (0, "vnet_create_loopback_interface failed");
841
842   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
843                    sw_if_index);
844   return 0;
845 }
846
847 /*?
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:
853  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
854  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
855  * Example of how to create a loopback interface:
856  * @cliexcmd{loopback create-interface}
857 ?*/
858 /* *INDENT-OFF* */
859 VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
860   .path = "loopback create-interface",
861   .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
862   .function = create_simulated_ethernet_interfaces,
863 };
864 /* *INDENT-ON* */
865
866 /*?
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:
872  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
873  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
874  * Example of how to create a loopback interface:
875  * @cliexcmd{create loopback interface}
876 ?*/
877 /* *INDENT-OFF* */
878 VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
879   .path = "create loopback interface",
880   .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
881   .function = create_simulated_ethernet_interfaces,
882 };
883 /* *INDENT-ON* */
884
885 ethernet_interface_t *
886 ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
887 {
888   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);
893 }
894
895 int
896 vnet_delete_loopback_interface (u32 sw_if_index)
897 {
898   vnet_main_t *vnm = vnet_get_main ();
899
900   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
901     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
902
903   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
904   if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
905     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
906
907   if (loopback_instance_free (hw->dev_instance) < 0)
908     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
909
910   ethernet_delete_interface (vnm, hw->hw_if_index);
911
912   return 0;
913 }
914
915 int
916 vnet_delete_sub_interface (u32 sw_if_index)
917 {
918   vnet_main_t *vnm = vnet_get_main ();
919   vnet_sw_interface_t *si;
920   int rv = 0;
921
922   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
923     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
924
925   si = vnet_get_sw_interface (vnm, sw_if_index);
926   if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
927       si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
928       si->type == VNET_SW_INTERFACE_TYPE_P2P)
929     {
930       vnet_interface_main_t *im = &vnm->interface_main;
931       vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
932       u64 sup_and_sub_key =
933         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
934       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
935       hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
936       vnet_delete_sw_interface (vnm, sw_if_index);
937     }
938   else
939     rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
940
941   return rv;
942 }
943
944 static clib_error_t *
945 delete_simulated_ethernet_interfaces (vlib_main_t * vm,
946                                       unformat_input_t * input,
947                                       vlib_cli_command_t * cmd)
948 {
949   int rv;
950   u32 sw_if_index = ~0;
951   vnet_main_t *vnm = vnet_get_main ();
952
953   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
954     {
955       if (unformat (input, "intfc %U",
956                     unformat_vnet_sw_interface, vnm, &sw_if_index))
957         ;
958       else
959         break;
960     }
961
962   if (sw_if_index == ~0)
963     return clib_error_return (0, "interface not specified");
964
965   rv = vnet_delete_loopback_interface (sw_if_index);
966
967   if (rv)
968     return clib_error_return (0, "vnet_delete_loopback_interface failed");
969
970   return 0;
971 }
972
973 static clib_error_t *
974 delete_sub_interface (vlib_main_t * vm,
975                       unformat_input_t * input, vlib_cli_command_t * cmd)
976 {
977   int rv = 0;
978   u32 sw_if_index = ~0;
979   vnet_main_t *vnm = vnet_get_main ();
980
981   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
982     {
983       if (unformat
984           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
985         ;
986       else
987         break;
988     }
989   if (sw_if_index == ~0)
990     return clib_error_return (0, "interface doesn't exist");
991
992   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
993     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
994   else
995     rv = vnet_delete_sub_interface (sw_if_index);
996   if (rv)
997     return clib_error_return (0, "delete_subinterface_interface failed");
998   return 0;
999 }
1000
1001 /*?
1002  * Delete a loopback interface.
1003  *
1004  * @cliexpar
1005  * The following two command syntaxes are equivalent:
1006  * @cliexcmd{loopback delete-interface intfc <interface>}
1007  * @cliexcmd{delete loopback interface intfc <interface>}
1008  * Example of how to delete a loopback interface:
1009  * @cliexcmd{loopback delete-interface intfc loop0}
1010 ?*/
1011 /* *INDENT-OFF* */
1012 VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1013   .path = "loopback delete-interface",
1014   .short_help = "loopback delete-interface intfc <interface>",
1015   .function = delete_simulated_ethernet_interfaces,
1016 };
1017 /* *INDENT-ON* */
1018
1019 /*?
1020  * Delete a loopback interface.
1021  *
1022  * @cliexpar
1023  * The following two command syntaxes are equivalent:
1024  * @cliexcmd{loopback delete-interface intfc <interface>}
1025  * @cliexcmd{delete loopback interface intfc <interface>}
1026  * Example of how to delete a loopback interface:
1027  * @cliexcmd{delete loopback interface intfc loop0}
1028 ?*/
1029 /* *INDENT-OFF* */
1030 VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1031   .path = "delete loopback interface",
1032   .short_help = "delete loopback interface intfc <interface>",
1033   .function = delete_simulated_ethernet_interfaces,
1034 };
1035 /* *INDENT-ON* */
1036
1037 /*?
1038  * Delete a sub-interface.
1039  *
1040  * @cliexpar
1041  * Example of how to delete a sub-interface:
1042  * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1043 ?*/
1044 /* *INDENT-OFF* */
1045 VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1046   .path = "delete sub-interface",
1047   .short_help = "delete sub-interface <interface>",
1048   .function = delete_sub_interface,
1049 };
1050 /* *INDENT-ON* */
1051
1052 /*
1053  * fd.io coding-style-patch-verification: ON
1054  *
1055  * Local Variables:
1056  * eval: (c-set-style "gnu")
1057  * End:
1058  */