d79669206a9b9bc46206a1bb22861836907df6eb
[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   CLIB_MEM_UNPOISON (hi->hw_address, 8);
315
316   if (error)
317     {
318       pool_put (em->interfaces, ei);
319       return error;
320     }
321   return error;
322 }
323
324 void
325 ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
326 {
327   ethernet_main_t *em = &ethernet_main;
328   ethernet_interface_t *ei;
329   vnet_hw_interface_t *hi;
330   main_intf_t *main_intf;
331   vlan_table_t *vlan_table;
332   u32 idx;
333
334   hi = vnet_get_hw_interface (vnm, hw_if_index);
335   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
336
337   /* Delete vlan mapping table for dot1q and dot1ad. */
338   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
339   if (main_intf->dot1q_vlans)
340     {
341       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
342       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
343         {
344           if (vlan_table->vlans[idx].qinqs)
345             {
346               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
347               vlan_table->vlans[idx].qinqs = 0;
348             }
349         }
350       pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
351       main_intf->dot1q_vlans = 0;
352     }
353   if (main_intf->dot1ad_vlans)
354     {
355       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
356       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
357         {
358           if (vlan_table->vlans[idx].qinqs)
359             {
360               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
361               vlan_table->vlans[idx].qinqs = 0;
362             }
363         }
364       pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
365       main_intf->dot1ad_vlans = 0;
366     }
367
368   vnet_delete_hw_interface (vnm, hw_if_index);
369   pool_put (em->interfaces, ei);
370 }
371
372 u32
373 ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
374 {
375   ethernet_main_t *em = &ethernet_main;
376   vnet_hw_interface_t *hi;
377   ethernet_interface_t *ei;
378
379   hi = vnet_get_hw_interface (vnm, hw_if_index);
380
381   ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
382
383   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
384   ei->flags = flags;
385   if (ei->flag_change)
386     return ei->flag_change (vnm, hi, flags);
387   return (u32) ~ 0;
388 }
389
390 /**
391  * Echo packets back to ethernet/l2-input.
392  */
393 static uword
394 simulated_ethernet_interface_tx (vlib_main_t * vm,
395                                  vlib_node_runtime_t *
396                                  node, vlib_frame_t * frame)
397 {
398   u32 n_left_from, *from;
399   u32 next_index = 0;
400   u32 n_bytes;
401   u32 thread_index = vm->thread_index;
402   vnet_main_t *vnm = vnet_get_main ();
403   vnet_interface_main_t *im = &vnm->interface_main;
404   l2_input_config_t *config;
405   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
406   u16 nexts[VLIB_FRAME_SIZE], *next;
407   u32 new_rx_sw_if_index = ~0;
408   u32 new_tx_sw_if_index = ~0;
409
410   n_left_from = frame->n_vectors;
411   from = vlib_frame_vector_args (frame);
412
413   vlib_get_buffers (vm, from, bufs, n_left_from);
414   b = bufs;
415   next = nexts;
416
417   /* Ordinarily, this is the only config lookup. */
418   config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
419   next_index =
420     config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
421     VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
422   new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
423   new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
424
425   while (n_left_from >= 4)
426     {
427       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
428       u32 not_all_match_config;
429
430       /* Prefetch next iteration. */
431       if (PREDICT_TRUE (n_left_from >= 8))
432         {
433           vlib_prefetch_buffer_header (b[4], STORE);
434           vlib_prefetch_buffer_header (b[5], STORE);
435           vlib_prefetch_buffer_header (b[6], STORE);
436           vlib_prefetch_buffer_header (b[7], STORE);
437         }
438
439       /* Make sure all pkts were transmitted on the same (loop) intfc */
440       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
441       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
442       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
443       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
444
445       not_all_match_config = (sw_if_index0 ^ sw_if_index1)
446         ^ (sw_if_index2 ^ sw_if_index3);
447       not_all_match_config += sw_if_index0 ^ new_rx_sw_if_index;
448
449       /* Speed path / expected case: all pkts on the same intfc */
450       if (PREDICT_TRUE (not_all_match_config == 0))
451         {
452           next[0] = next_index;
453           next[1] = next_index;
454           next[2] = next_index;
455           next[3] = next_index;
456           vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
457           vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
458           vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
459           vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
460           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
461           vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
462           vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
463           vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
464           n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
465           n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
466           n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
467           n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
468
469           if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
470             {
471               vnet_update_l2_len (b[0]);
472               vnet_update_l2_len (b[1]);
473               vnet_update_l2_len (b[2]);
474               vnet_update_l2_len (b[3]);
475             }
476
477           /* increment TX interface stat */
478           vlib_increment_combined_counter (im->combined_sw_if_counters +
479                                            VNET_INTERFACE_COUNTER_TX,
480                                            thread_index, new_rx_sw_if_index,
481                                            4 /* pkts */ , n_bytes);
482           b += 4;
483           next += 4;
484           n_left_from -= 4;
485           continue;
486         }
487
488       /*
489        * Slow path: we know that at least one of the pkts
490        * was transmitted on a different sw_if_index, so
491        * check each sw_if_index against the cached data and proceed
492        * accordingly.
493        *
494        * This shouldn't happen, but code can (and does) bypass the
495        * per-interface output node, so deal with it.
496        */
497       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
498                          != new_rx_sw_if_index))
499         {
500           config = l2input_intf_config
501             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
502           next_index =
503             config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
504             VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
505           new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
506           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
507         }
508       next[0] = next_index;
509       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
510       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
511       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
512       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
513         vnet_update_l2_len (b[0]);
514
515       vlib_increment_combined_counter (im->combined_sw_if_counters +
516                                        VNET_INTERFACE_COUNTER_TX,
517                                        thread_index, new_rx_sw_if_index,
518                                        1 /* pkts */ , n_bytes);
519
520       if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
521                          != new_rx_sw_if_index))
522         {
523           config = l2input_intf_config
524             (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
525           next_index =
526             config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
527             VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
528           new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
529           new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
530         }
531       next[1] = next_index;
532       vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
533       vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
534       n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
535       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
536         vnet_update_l2_len (b[1]);
537
538       vlib_increment_combined_counter (im->combined_sw_if_counters +
539                                        VNET_INTERFACE_COUNTER_TX,
540                                        thread_index, new_rx_sw_if_index,
541                                        1 /* pkts */ , n_bytes);
542
543       if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
544                          != new_rx_sw_if_index))
545         {
546           config = l2input_intf_config
547             (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
548           next_index =
549             config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
550             VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
551           new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
552           new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
553         }
554       next[2] = next_index;
555       vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
556       vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
557       n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
558       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
559         vnet_update_l2_len (b[2]);
560
561       vlib_increment_combined_counter (im->combined_sw_if_counters +
562                                        VNET_INTERFACE_COUNTER_TX,
563                                        thread_index, new_rx_sw_if_index,
564                                        1 /* pkts */ , n_bytes);
565
566       if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
567                          != new_rx_sw_if_index))
568         {
569           config = l2input_intf_config
570             (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
571           next_index =
572             config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
573             VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
574           new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
575           new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
576         }
577       next[3] = next_index;
578       vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
579       vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
580       n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
581       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
582         vnet_update_l2_len (b[3]);
583
584       vlib_increment_combined_counter (im->combined_sw_if_counters +
585                                        VNET_INTERFACE_COUNTER_TX,
586                                        thread_index, new_rx_sw_if_index,
587                                        1 /* pkts */ , n_bytes);
588       b += 4;
589       next += 4;
590       n_left_from -= 4;
591     }
592   while (n_left_from > 0)
593     {
594       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
595                          != new_rx_sw_if_index))
596         {
597           config = l2input_intf_config
598             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
599           next_index =
600             config->bridge ? VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
601             VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT;
602           new_tx_sw_if_index = config->bvi ? L2INPUT_BVI : ~0;
603           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
604         }
605       next[0] = next_index;
606       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
607       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
608       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
609       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
610         vnet_update_l2_len (b[0]);
611
612       vlib_increment_combined_counter (im->combined_sw_if_counters +
613                                        VNET_INTERFACE_COUNTER_TX,
614                                        thread_index, new_rx_sw_if_index,
615                                        1 /* pkts */ , n_bytes);
616       b += 1;
617       next += 1;
618       n_left_from -= 1;
619     }
620
621   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
622
623   return frame->n_vectors;
624 }
625
626 static u8 *
627 format_simulated_ethernet_name (u8 * s, va_list * args)
628 {
629   u32 dev_instance = va_arg (*args, u32);
630   return format (s, "loop%d", dev_instance);
631 }
632
633 static clib_error_t *
634 simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
635                                   u32 flags)
636 {
637   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
638     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
639   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
640   return 0;
641 }
642
643 static clib_error_t *
644 simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
645                                const u8 * old_address, const u8 * mac_address)
646 {
647   l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
648
649   return (NULL);
650 }
651
652
653 /* *INDENT-OFF* */
654 VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
655   .name = "Loopback",
656   .format_device_name = format_simulated_ethernet_name,
657   .tx_function = simulated_ethernet_interface_tx,
658   .admin_up_down_function = simulated_ethernet_admin_up_down,
659   .mac_addr_change_function = simulated_ethernet_mac_change,
660 };
661 /* *INDENT-ON* */
662
663 /*
664  * Maintain a bitmap of allocated loopback instance numbers.
665  */
666 #define LOOPBACK_MAX_INSTANCE           (16 * 1024)
667
668 static u32
669 loopback_instance_alloc (u8 is_specified, u32 want)
670 {
671   ethernet_main_t *em = &ethernet_main;
672
673   /*
674    * Check for dynamically allocaetd instance number.
675    */
676   if (!is_specified)
677     {
678       u32 bit;
679
680       bit = clib_bitmap_first_clear (em->bm_loopback_instances);
681       if (bit >= LOOPBACK_MAX_INSTANCE)
682         {
683           return ~0;
684         }
685       em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
686                                                    bit, 1);
687       return bit;
688     }
689
690   /*
691    * In range?
692    */
693   if (want >= LOOPBACK_MAX_INSTANCE)
694     {
695       return ~0;
696     }
697
698   /*
699    * Already in use?
700    */
701   if (clib_bitmap_get (em->bm_loopback_instances, want))
702     {
703       return ~0;
704     }
705
706   /*
707    * Grant allocation request.
708    */
709   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
710                                                want, 1);
711
712   return want;
713 }
714
715 static int
716 loopback_instance_free (u32 instance)
717 {
718   ethernet_main_t *em = &ethernet_main;
719
720   if (instance >= LOOPBACK_MAX_INSTANCE)
721     {
722       return -1;
723     }
724
725   if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
726     {
727       return -1;
728     }
729
730   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
731                                                instance, 0);
732   return 0;
733 }
734
735 int
736 vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
737                                 u8 is_specified, u32 user_instance)
738 {
739   vnet_main_t *vnm = vnet_get_main ();
740   vlib_main_t *vm = vlib_get_main ();
741   clib_error_t *error;
742   u32 instance;
743   u8 address[6];
744   u32 hw_if_index;
745   vnet_hw_interface_t *hw_if;
746   u32 slot;
747   int rv = 0;
748
749   ASSERT (sw_if_indexp);
750
751   *sw_if_indexp = (u32) ~ 0;
752
753   clib_memset (address, 0, sizeof (address));
754
755   /*
756    * Allocate a loopback instance.  Either select on dynamically
757    * or try to use the desired user_instance number.
758    */
759   instance = loopback_instance_alloc (is_specified, user_instance);
760   if (instance == ~0)
761     {
762       return VNET_API_ERROR_INVALID_REGISTRATION;
763     }
764
765   /*
766    * Default MAC address (dead:0000:0000 + instance) is allocated
767    * if zero mac_address is configured. Otherwise, user-configurable MAC
768    * address is programmed on the loopback interface.
769    */
770   if (memcmp (address, mac_address, sizeof (address)))
771     clib_memcpy (address, mac_address, sizeof (address));
772   else
773     {
774       address[0] = 0xde;
775       address[1] = 0xad;
776       address[5] = instance;
777     }
778
779   error = ethernet_register_interface
780     (vnm,
781      ethernet_simulated_device_class.index, instance, address, &hw_if_index,
782      /* flag change */ 0);
783
784   if (error)
785     {
786       rv = VNET_API_ERROR_INVALID_REGISTRATION;
787       clib_error_report (error);
788       return rv;
789     }
790
791   hw_if = vnet_get_hw_interface (vnm, hw_if_index);
792   slot = vlib_node_add_named_next_with_slot
793     (vm, hw_if->tx_node_index,
794      "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
795   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
796
797   slot = vlib_node_add_named_next_with_slot
798     (vm, hw_if->tx_node_index,
799      "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
800   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
801
802   {
803     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
804     *sw_if_indexp = si->sw_if_index;
805
806     /* By default don't flood to loopbacks, as packets just keep
807      * coming back ... If this loopback becomes a BVI, we'll change it */
808     si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
809   }
810
811   return 0;
812 }
813
814 static clib_error_t *
815 create_simulated_ethernet_interfaces (vlib_main_t * vm,
816                                       unformat_input_t * input,
817                                       vlib_cli_command_t * cmd)
818 {
819   int rv;
820   u32 sw_if_index;
821   u8 mac_address[6];
822   u8 is_specified = 0;
823   u32 user_instance = 0;
824
825   clib_memset (mac_address, 0, sizeof (mac_address));
826
827   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
828     {
829       if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
830         ;
831       if (unformat (input, "instance %d", &user_instance))
832         is_specified = 1;
833       else
834         break;
835     }
836
837   rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
838                                        is_specified, user_instance);
839
840   if (rv)
841     return clib_error_return (0, "vnet_create_loopback_interface failed");
842
843   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
844                    sw_if_index);
845   return 0;
846 }
847
848 /*?
849  * Create a loopback interface. Optionally, a MAC Address can be
850  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
851  *
852  * @cliexpar
853  * The following two command syntaxes are equivalent:
854  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
855  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
856  * Example of how to create a loopback interface:
857  * @cliexcmd{loopback create-interface}
858 ?*/
859 /* *INDENT-OFF* */
860 VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
861   .path = "loopback create-interface",
862   .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
863   .function = create_simulated_ethernet_interfaces,
864 };
865 /* *INDENT-ON* */
866
867 /*?
868  * Create a loopback interface. Optionally, a MAC Address can be
869  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
870  *
871  * @cliexpar
872  * The following two command syntaxes are equivalent:
873  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
874  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
875  * Example of how to create a loopback interface:
876  * @cliexcmd{create loopback interface}
877 ?*/
878 /* *INDENT-OFF* */
879 VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
880   .path = "create loopback interface",
881   .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
882   .function = create_simulated_ethernet_interfaces,
883 };
884 /* *INDENT-ON* */
885
886 ethernet_interface_t *
887 ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
888 {
889   vnet_hw_interface_t *i =
890     vnet_get_hw_interface (vnet_get_main (), hw_if_index);
891   return (i->hw_class_index ==
892           ethernet_hw_interface_class.
893           index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
894 }
895
896 mac_address_t *
897 ethernet_interface_add_del_address (ethernet_main_t * em,
898                                     u32 hw_if_index, const u8 * address,
899                                     u8 is_add)
900 {
901   ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
902   mac_address_t *if_addr = 0;
903
904   /* return if there is not an ethernet interface for this hw interface */
905   if (!ei)
906     return 0;
907
908   /* determine whether the address is configured on the interface */
909   vec_foreach (if_addr, ei->secondary_addrs)
910   {
911     if (!ethernet_mac_address_equal (if_addr->bytes, address))
912       continue;
913
914     break;
915   }
916
917   if (if_addr && vec_is_member (ei->secondary_addrs, if_addr))
918     {
919       /* delete found address */
920       if (!is_add)
921         {
922           vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
923           if_addr = 0;
924         }
925       /* address already found, so nothing needs to be done if adding */
926     }
927   else
928     {
929       /* if_addr could be 0 or past the end of the vector. reset to 0 */
930       if_addr = 0;
931
932       /* add new address */
933       if (is_add)
934         {
935           vec_add2 (ei->secondary_addrs, if_addr, 1);
936           clib_memcpy (&if_addr->bytes, address, sizeof (if_addr->bytes));
937         }
938     }
939
940   return if_addr;
941 }
942
943 int
944 vnet_delete_loopback_interface (u32 sw_if_index)
945 {
946   vnet_main_t *vnm = vnet_get_main ();
947
948   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
949     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
950
951   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
952   if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
953     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
954
955   if (loopback_instance_free (hw->dev_instance) < 0)
956     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
957
958   ethernet_delete_interface (vnm, hw->hw_if_index);
959
960   return 0;
961 }
962
963 int
964 vnet_create_sub_interface (u32 sw_if_index, u32 id,
965                            u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
966                            u32 * sub_sw_if_index)
967 {
968   vnet_main_t *vnm = vnet_get_main ();
969   vnet_interface_main_t *im = &vnm->interface_main;
970   vnet_hw_interface_t *hi;
971   u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
972   vnet_sw_interface_t template;
973   uword *p;
974   u64 *kp;
975
976   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
977
978   p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
979   if (p)
980     {
981       return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
982     }
983
984   clib_memset (&template, 0, sizeof (template));
985   template.type = VNET_SW_INTERFACE_TYPE_SUB;
986   template.flood_class = VNET_FLOOD_CLASS_NORMAL;
987   template.sup_sw_if_index = sw_if_index;
988   template.sub.id = id;
989   template.sub.eth.raw_flags = flags;
990   template.sub.eth.outer_vlan_id = outer_vlan_id;
991   template.sub.eth.inner_vlan_id = inner_vlan_id;
992
993   if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
994     return (VNET_API_ERROR_UNSPECIFIED);
995
996   kp = clib_mem_alloc (sizeof (*kp));
997   *kp = sup_and_sub_key;
998
999   hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
1000   hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
1001
1002   return (0);
1003 }
1004
1005 int
1006 vnet_delete_sub_interface (u32 sw_if_index)
1007 {
1008   vnet_main_t *vnm = vnet_get_main ();
1009   vnet_sw_interface_t *si;
1010   int rv = 0;
1011
1012   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1013     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1014
1015   si = vnet_get_sw_interface (vnm, sw_if_index);
1016   if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
1017       si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
1018       si->type == VNET_SW_INTERFACE_TYPE_P2P)
1019     {
1020       vnet_interface_main_t *im = &vnm->interface_main;
1021       vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1022       u64 sup_and_sub_key =
1023         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
1024       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
1025       hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
1026       vnet_delete_sw_interface (vnm, sw_if_index);
1027     }
1028   else
1029     rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
1030
1031   return rv;
1032 }
1033
1034 static clib_error_t *
1035 delete_simulated_ethernet_interfaces (vlib_main_t * vm,
1036                                       unformat_input_t * input,
1037                                       vlib_cli_command_t * cmd)
1038 {
1039   int rv;
1040   u32 sw_if_index = ~0;
1041   vnet_main_t *vnm = vnet_get_main ();
1042
1043   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1044     {
1045       if (unformat (input, "intfc %U",
1046                     unformat_vnet_sw_interface, vnm, &sw_if_index))
1047         ;
1048       else
1049         break;
1050     }
1051
1052   if (sw_if_index == ~0)
1053     return clib_error_return (0, "interface not specified");
1054
1055   rv = vnet_delete_loopback_interface (sw_if_index);
1056
1057   if (rv)
1058     return clib_error_return (0, "vnet_delete_loopback_interface failed");
1059
1060   return 0;
1061 }
1062
1063 static clib_error_t *
1064 delete_sub_interface (vlib_main_t * vm,
1065                       unformat_input_t * input, vlib_cli_command_t * cmd)
1066 {
1067   int rv = 0;
1068   u32 sw_if_index = ~0;
1069   vnet_main_t *vnm = vnet_get_main ();
1070
1071   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1072     {
1073       if (unformat
1074           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1075         ;
1076       else
1077         break;
1078     }
1079   if (sw_if_index == ~0)
1080     return clib_error_return (0, "interface doesn't exist");
1081
1082   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
1083     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1084   else
1085     rv = vnet_delete_sub_interface (sw_if_index);
1086   if (rv)
1087     return clib_error_return (0, "delete_subinterface_interface failed");
1088   return 0;
1089 }
1090
1091 /*?
1092  * Delete a loopback interface.
1093  *
1094  * @cliexpar
1095  * The following two command syntaxes are equivalent:
1096  * @cliexcmd{loopback delete-interface intfc <interface>}
1097  * @cliexcmd{delete loopback interface intfc <interface>}
1098  * Example of how to delete a loopback interface:
1099  * @cliexcmd{loopback delete-interface intfc loop0}
1100 ?*/
1101 /* *INDENT-OFF* */
1102 VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
1103   .path = "loopback delete-interface",
1104   .short_help = "loopback delete-interface intfc <interface>",
1105   .function = delete_simulated_ethernet_interfaces,
1106 };
1107 /* *INDENT-ON* */
1108
1109 /*?
1110  * Delete a loopback interface.
1111  *
1112  * @cliexpar
1113  * The following two command syntaxes are equivalent:
1114  * @cliexcmd{loopback delete-interface intfc <interface>}
1115  * @cliexcmd{delete loopback interface intfc <interface>}
1116  * Example of how to delete a loopback interface:
1117  * @cliexcmd{delete loopback interface intfc loop0}
1118 ?*/
1119 /* *INDENT-OFF* */
1120 VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
1121   .path = "delete loopback interface",
1122   .short_help = "delete loopback interface intfc <interface>",
1123   .function = delete_simulated_ethernet_interfaces,
1124 };
1125 /* *INDENT-ON* */
1126
1127 /*?
1128  * Delete a sub-interface.
1129  *
1130  * @cliexpar
1131  * Example of how to delete a sub-interface:
1132  * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
1133 ?*/
1134 /* *INDENT-OFF* */
1135 VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
1136   .path = "delete sub-interface",
1137   .short_help = "delete sub-interface <interface>",
1138   .function = delete_sub_interface,
1139 };
1140 /* *INDENT-ON* */
1141
1142 /*
1143  * fd.io coding-style-patch-verification: ON
1144  *
1145  * Local Variables:
1146  * eval: (c-set-style "gnu")
1147  * End:
1148  */