Use IP and MAC API types for neighbors
[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                              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 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (ethernet_simulated_device_class,
663                                    simulated_ethernet_interface_tx);
664
665 /*
666  * Maintain a bitmap of allocated loopback instance numbers.
667  */
668 #define LOOPBACK_MAX_INSTANCE           (16 * 1024)
669
670 static u32
671 loopback_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
717 static int
718 loopback_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
737 int
738 vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
739                                 u8 is_specified, u32 user_instance)
740 {
741   vnet_main_t *vnm = vnet_get_main ();
742   vlib_main_t *vm = vlib_get_main ();
743   clib_error_t *error;
744   u32 instance;
745   u8 address[6];
746   u32 hw_if_index;
747   vnet_hw_interface_t *hw_if;
748   u32 slot;
749   int rv = 0;
750
751   ASSERT (sw_if_indexp);
752
753   *sw_if_indexp = (u32) ~ 0;
754
755   clib_memset (address, 0, sizeof (address));
756
757   /*
758    * 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   /*
768    * 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)))
773     clib_memcpy (address, mac_address, sizeof (address));
774   else
775     {
776       address[0] = 0xde;
777       address[1] = 0xad;
778       address[5] = instance;
779     }
780
781   error = ethernet_register_interface
782     (vnm,
783      ethernet_simulated_device_class.index, instance, address, &hw_if_index,
784      /* flag change */ 0);
785
786   if (error)
787     {
788       rv = VNET_API_ERROR_INVALID_REGISTRATION;
789       clib_error_report (error);
790       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,
796      "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
797   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
798
799   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
804   {
805     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
806     *sw_if_indexp = si->sw_if_index;
807
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;
811   }
812
813   return 0;
814 }
815
816 static clib_error_t *
817 create_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];
824   u8 is_specified = 0;
825   u32 user_instance = 0;
826
827   clib_memset (mac_address, 0, sizeof (mac_address));
828
829   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
830     {
831       if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
832         ;
833       if (unformat (input, "instance %d", &user_instance))
834         is_specified = 1;
835       else
836         break;
837     }
838
839   rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
840                                        is_specified, user_instance);
841
842   if (rv)
843     return clib_error_return (0, "vnet_create_loopback_interface failed");
844
845   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
846                    sw_if_index);
847   return 0;
848 }
849
850 /*?
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:
856  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
857  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
858  * Example of how to create a loopback interface:
859  * @cliexcmd{loopback create-interface}
860 ?*/
861 /* *INDENT-OFF* */
862 VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
863   .path = "loopback create-interface",
864   .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
865   .function = create_simulated_ethernet_interfaces,
866 };
867 /* *INDENT-ON* */
868
869 /*?
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:
875  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
876  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
877  * Example of how to create a loopback interface:
878  * @cliexcmd{create loopback interface}
879 ?*/
880 /* *INDENT-OFF* */
881 VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
882   .path = "create loopback interface",
883   .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
884   .function = create_simulated_ethernet_interfaces,
885 };
886 /* *INDENT-ON* */
887
888 ethernet_interface_t *
889 ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
890 {
891   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);
896 }
897
898 int
899 vnet_delete_loopback_interface (u32 sw_if_index)
900 {
901   vnet_main_t *vnm = vnet_get_main ();
902
903   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
904     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
905
906   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;
909
910   if (loopback_instance_free (hw->dev_instance) < 0)
911     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
912
913   ethernet_delete_interface (vnm, hw->hw_if_index);
914
915   return 0;
916 }
917
918 int
919 vnet_delete_sub_interface (u32 sw_if_index)
920 {
921   vnet_main_t *vnm = vnet_get_main ();
922   vnet_sw_interface_t *si;
923   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
928   si = vnet_get_sw_interface (vnm, sw_if_index);
929   if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
930       si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
931       si->type == VNET_SW_INTERFACE_TYPE_P2P)
932     {
933       vnet_interface_main_t *im = &vnm->interface_main;
934       vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
935       u64 sup_and_sub_key =
936         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
937       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);
939       vnet_delete_sw_interface (vnm, sw_if_index);
940     }
941   else
942     rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
943
944   return rv;
945 }
946
947 static clib_error_t *
948 delete_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;
954   vnet_main_t *vnm = vnet_get_main ();
955
956   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
957     {
958       if (unformat (input, "intfc %U",
959                     unformat_vnet_sw_interface, vnm, &sw_if_index))
960         ;
961       else
962         break;
963     }
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
976 static clib_error_t *
977 delete_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
1004 /*?
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 ?*/
1014 /* *INDENT-OFF* */
1015 VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1016   .path = "loopback delete-interface",
1017   .short_help = "loopback delete-interface intfc <interface>",
1018   .function = delete_simulated_ethernet_interfaces,
1019 };
1020 /* *INDENT-ON* */
1021
1022 /*?
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 ?*/
1032 /* *INDENT-OFF* */
1033 VLIB_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 };
1038 /* *INDENT-ON* */
1039
1040 /*?
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 ?*/
1047 /* *INDENT-OFF* */
1048 VLIB_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
1055 /*
1056  * fd.io coding-style-patch-verification: ON
1057  *
1058  * Local Variables:
1059  * eval: (c-set-style "gnu")
1060  * End:
1061  */