Packets recieved on VLAN-0 map to the main interface
[vpp.git] / src / vnet / ethernet / node.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_node.c: ethernet packet processing
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 <vlib/vlib.h>
41 #include <vnet/pg/pg.h>
42 #include <vnet/ethernet/ethernet.h>
43 #include <vppinfra/sparse_vec.h>
44 #include <vnet/l2/l2_bvi.h>
45
46
47 #define foreach_ethernet_input_next             \
48   _ (PUNT, "error-punt")                        \
49   _ (DROP, "error-drop")                        \
50   _ (LLC, "llc-input")
51
52 typedef enum
53 {
54 #define _(s,n) ETHERNET_INPUT_NEXT_##s,
55   foreach_ethernet_input_next
56 #undef _
57     ETHERNET_INPUT_N_NEXT,
58 } ethernet_input_next_t;
59
60 typedef struct
61 {
62   u8 packet_data[32];
63 } ethernet_input_trace_t;
64
65 static u8 *
66 format_ethernet_input_trace (u8 * s, va_list * va)
67 {
68   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
69   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
70   ethernet_input_trace_t *t = va_arg (*va, ethernet_input_trace_t *);
71
72   s = format (s, "%U", format_ethernet_header, t->packet_data);
73
74   return s;
75 }
76
77 vlib_node_registration_t ethernet_input_node;
78
79 typedef enum
80 {
81   ETHERNET_INPUT_VARIANT_ETHERNET,
82   ETHERNET_INPUT_VARIANT_ETHERNET_TYPE,
83   ETHERNET_INPUT_VARIANT_NOT_L2,
84 } ethernet_input_variant_t;
85
86
87 // Parse the ethernet header to extract vlan tags and innermost ethertype
88 static_always_inline void
89 parse_header (ethernet_input_variant_t variant,
90               vlib_buffer_t * b0,
91               u16 * type,
92               u16 * orig_type,
93               u16 * outer_id, u16 * inner_id, u32 * match_flags)
94 {
95   u8 vlan_count;
96
97   if (variant == ETHERNET_INPUT_VARIANT_ETHERNET
98       || variant == ETHERNET_INPUT_VARIANT_NOT_L2)
99     {
100       ethernet_header_t *e0;
101
102       e0 = (void *) (b0->data + b0->current_data);
103
104       vnet_buffer (b0)->ethernet.start_of_ethernet_header = b0->current_data;
105
106       vlib_buffer_advance (b0, sizeof (e0[0]));
107
108       *type = clib_net_to_host_u16 (e0->type);
109     }
110   else if (variant == ETHERNET_INPUT_VARIANT_ETHERNET_TYPE)
111     {
112       // here when prior node was LLC/SNAP processing
113       u16 *e0;
114
115       e0 = (void *) (b0->data + b0->current_data);
116
117       vlib_buffer_advance (b0, sizeof (e0[0]));
118
119       *type = clib_net_to_host_u16 (e0[0]);
120     }
121
122   // save for distinguishing between dot1q and dot1ad later
123   *orig_type = *type;
124
125   // default the tags to 0 (used if there is no corresponding tag)
126   *outer_id = 0;
127   *inner_id = 0;
128
129   *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_0_TAG;
130   vlan_count = 0;
131
132   // check for vlan encaps
133   if (ethernet_frame_is_tagged (*type))
134     {
135       ethernet_vlan_header_t *h0;
136       u16 tag;
137
138       *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_1_TAG;
139
140       h0 = (void *) (b0->data + b0->current_data);
141
142       tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
143
144       *outer_id = tag & 0xfff;
145       if (0 == *outer_id)
146         *match_flags &= ~SUBINT_CONFIG_MATCH_1_TAG;
147
148       *type = clib_net_to_host_u16 (h0->type);
149
150       vlib_buffer_advance (b0, sizeof (h0[0]));
151       vlan_count = 1;
152
153       if (*type == ETHERNET_TYPE_VLAN)
154         {
155           // Double tagged packet
156           *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_2_TAG;
157
158           h0 = (void *) (b0->data + b0->current_data);
159
160           tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
161
162           *inner_id = tag & 0xfff;
163
164           *type = clib_net_to_host_u16 (h0->type);
165
166           vlib_buffer_advance (b0, sizeof (h0[0]));
167           vlan_count = 2;
168
169           if (*type == ETHERNET_TYPE_VLAN)
170             {
171               // More than double tagged packet
172               *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG;
173               vlan_count = 3;   // "unknown" number, aka, 3-or-more
174             }
175         }
176     }
177   ethernet_buffer_set_vlan_count (b0, vlan_count);
178 }
179
180 // Determine the subinterface for this packet, given the result of the
181 // vlan table lookups and vlan header parsing. Check the most specific
182 // matches first.
183 static_always_inline void
184 identify_subint (vnet_hw_interface_t * hi,
185                  vlib_buffer_t * b0,
186                  u32 match_flags,
187                  main_intf_t * main_intf,
188                  vlan_intf_t * vlan_intf,
189                  qinq_intf_t * qinq_intf,
190                  u32 * new_sw_if_index, u8 * error0, u32 * is_l2)
191 {
192   u32 matched;
193
194   matched = eth_identify_subint (hi, b0, match_flags,
195                                  main_intf, vlan_intf, qinq_intf,
196                                  new_sw_if_index, error0, is_l2);
197
198   if (matched)
199     {
200
201       // Perform L3 my-mac filter
202       // A unicast packet arriving on an L3 interface must have a dmac matching the interface mac.
203       // This is required for promiscuous mode, else we will forward packets we aren't supposed to.
204       if (!(*is_l2))
205         {
206           ethernet_header_t *e0;
207           e0 =
208             (void *) (b0->data +
209                       vnet_buffer (b0)->ethernet.start_of_ethernet_header);
210
211           if (!(ethernet_address_cast (e0->dst_address)))
212             {
213               if (!eth_mac_equal ((u8 *) e0, hi->hw_address))
214                 {
215                   *error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
216                 }
217             }
218         }
219
220       // Check for down subinterface
221       *error0 = (*new_sw_if_index) != ~0 ? (*error0) : ETHERNET_ERROR_DOWN;
222     }
223 }
224
225 static_always_inline void
226 determine_next_node (ethernet_main_t * em,
227                      ethernet_input_variant_t variant,
228                      u32 is_l20,
229                      u32 type0, vlib_buffer_t * b0, u8 * error0, u8 * next0)
230 {
231   if (PREDICT_FALSE (*error0 != ETHERNET_ERROR_NONE))
232     {
233       // some error occurred
234       *next0 = ETHERNET_INPUT_NEXT_DROP;
235     }
236   else if (is_l20)
237     {
238       *next0 = em->l2_next;
239       // record the L2 len and reset the buffer so the L2 header is preserved
240       u32 eth_start = vnet_buffer (b0)->ethernet.start_of_ethernet_header;
241       vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start;
242       vlib_buffer_advance (b0, -ethernet_buffer_header_size (b0));
243
244       // check for common IP/MPLS ethertypes
245     }
246   else if (type0 == ETHERNET_TYPE_IP4)
247     {
248       *next0 = em->l3_next.input_next_ip4;
249     }
250   else if (type0 == ETHERNET_TYPE_IP6)
251     {
252       *next0 = em->l3_next.input_next_ip6;
253     }
254   else if (type0 == ETHERNET_TYPE_MPLS)
255     {
256       *next0 = em->l3_next.input_next_mpls;
257
258     }
259   else if (em->redirect_l3)
260     {
261       // L3 Redirect is on, the cached common next nodes will be
262       // pointing to the redirect node, catch the uncommon types here
263       *next0 = em->redirect_l3_next;
264     }
265   else
266     {
267       // uncommon ethertype, check table
268       u32 i0;
269       i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
270       *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
271       *error0 =
272         i0 ==
273         SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0;
274
275       // The table is not populated with LLC values, so check that now.
276       // If variant is variant_ethernet then we came from LLC processing. Don't
277       // go back there; drop instead using by keeping the drop/bad table result.
278       if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET))
279         {
280           *next0 = ETHERNET_INPUT_NEXT_LLC;
281         }
282     }
283 }
284
285 static_always_inline uword
286 ethernet_input_inline (vlib_main_t * vm,
287                        vlib_node_runtime_t * node,
288                        vlib_frame_t * from_frame,
289                        ethernet_input_variant_t variant)
290 {
291   vnet_main_t *vnm = vnet_get_main ();
292   ethernet_main_t *em = &ethernet_main;
293   vlib_node_runtime_t *error_node;
294   u32 n_left_from, next_index, *from, *to_next;
295   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
296   u32 thread_index = vlib_get_thread_index ();
297   u32 cached_sw_if_index = ~0;
298   u32 cached_is_l2 = 0;         /* shut up gcc */
299   vnet_hw_interface_t *hi = NULL;       /* used for main interface only */
300
301   if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
302     error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
303   else
304     error_node = node;
305
306   from = vlib_frame_vector_args (from_frame);
307   n_left_from = from_frame->n_vectors;
308
309   if (node->flags & VLIB_NODE_FLAG_TRACE)
310     vlib_trace_frame_buffers_only (vm, node,
311                                    from,
312                                    n_left_from,
313                                    sizeof (from[0]),
314                                    sizeof (ethernet_input_trace_t));
315
316   next_index = node->cached_next_index;
317   stats_sw_if_index = node->runtime_data[0];
318   stats_n_packets = stats_n_bytes = 0;
319
320   while (n_left_from > 0)
321     {
322       u32 n_left_to_next;
323
324       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
325
326       while (n_left_from >= 4 && n_left_to_next >= 2)
327         {
328           u32 bi0, bi1;
329           vlib_buffer_t *b0, *b1;
330           u8 next0, next1, error0, error1;
331           u16 type0, orig_type0, type1, orig_type1;
332           u16 outer_id0, inner_id0, outer_id1, inner_id1;
333           u32 match_flags0, match_flags1;
334           u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1,
335             new_sw_if_index1, len1;
336           vnet_hw_interface_t *hi0, *hi1;
337           main_intf_t *main_intf0, *main_intf1;
338           vlan_intf_t *vlan_intf0, *vlan_intf1;
339           qinq_intf_t *qinq_intf0, *qinq_intf1;
340           u32 is_l20, is_l21;
341           ethernet_header_t *e0, *e1;
342
343           /* Prefetch next iteration. */
344           {
345             vlib_buffer_t *b2, *b3;
346
347             b2 = vlib_get_buffer (vm, from[2]);
348             b3 = vlib_get_buffer (vm, from[3]);
349
350             vlib_prefetch_buffer_header (b2, STORE);
351             vlib_prefetch_buffer_header (b3, STORE);
352
353             CLIB_PREFETCH (b2->data, sizeof (ethernet_header_t), LOAD);
354             CLIB_PREFETCH (b3->data, sizeof (ethernet_header_t), LOAD);
355           }
356
357           bi0 = from[0];
358           bi1 = from[1];
359           to_next[0] = bi0;
360           to_next[1] = bi1;
361           from += 2;
362           to_next += 2;
363           n_left_to_next -= 2;
364           n_left_from -= 2;
365
366           b0 = vlib_get_buffer (vm, bi0);
367           b1 = vlib_get_buffer (vm, bi1);
368
369           error0 = error1 = ETHERNET_ERROR_NONE;
370           e0 = vlib_buffer_get_current (b0);
371           type0 = clib_net_to_host_u16 (e0->type);
372           e1 = vlib_buffer_get_current (b1);
373           type1 = clib_net_to_host_u16 (e1->type);
374
375           /* Speed-path for the untagged case */
376           if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
377                             && !ethernet_frame_is_tagged (type0)
378                             && !ethernet_frame_is_tagged (type1)))
379             {
380               main_intf_t *intf0;
381               subint_config_t *subint0;
382               u32 sw_if_index0, sw_if_index1;
383
384               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
385               sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
386               is_l20 = cached_is_l2;
387
388               /* This is probably wholly unnecessary */
389               if (PREDICT_FALSE (sw_if_index0 != sw_if_index1))
390                 goto slowpath;
391
392               /* Now sw_if_index0 == sw_if_index1  */
393               if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
394                 {
395                   cached_sw_if_index = sw_if_index0;
396                   hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
397                   intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
398                   subint0 = &intf0->untagged_subint;
399                   cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
400                 }
401
402               vnet_buffer (b0)->ethernet.start_of_ethernet_header =
403                 b0->current_data;
404               vnet_buffer (b1)->ethernet.start_of_ethernet_header =
405                 b1->current_data;
406
407               if (PREDICT_TRUE (is_l20 != 0))
408                 {
409                   next0 = em->l2_next;
410                   vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
411                   next1 = em->l2_next;
412                   vnet_buffer (b1)->l2.l2_len = sizeof (ethernet_header_t);
413                 }
414               else
415                 {
416                   if (!ethernet_address_cast (e0->dst_address) &&
417                       (hi->hw_address != 0) &&
418                       !eth_mac_equal ((u8 *) e0, hi->hw_address))
419                     error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
420                   if (!ethernet_address_cast (e1->dst_address) &&
421                       (hi->hw_address != 0) &&
422                       !eth_mac_equal ((u8 *) e1, hi->hw_address))
423                     error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
424                   determine_next_node (em, variant, 0, type0, b0,
425                                        &error0, &next0);
426                   vlib_buffer_advance (b0, sizeof (ethernet_header_t));
427                   determine_next_node (em, variant, 0, type1, b1,
428                                        &error1, &next1);
429                   vlib_buffer_advance (b1, sizeof (ethernet_header_t));
430                 }
431               goto ship_it01;
432             }
433
434           /* Slow-path for the tagged case */
435         slowpath:
436           parse_header (variant,
437                         b0,
438                         &type0,
439                         &orig_type0, &outer_id0, &inner_id0, &match_flags0);
440
441           parse_header (variant,
442                         b1,
443                         &type1,
444                         &orig_type1, &outer_id1, &inner_id1, &match_flags1);
445
446           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
447           old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
448
449           eth_vlan_table_lookups (em,
450                                   vnm,
451                                   old_sw_if_index0,
452                                   orig_type0,
453                                   outer_id0,
454                                   inner_id0,
455                                   &hi0,
456                                   &main_intf0, &vlan_intf0, &qinq_intf0);
457
458           eth_vlan_table_lookups (em,
459                                   vnm,
460                                   old_sw_if_index1,
461                                   orig_type1,
462                                   outer_id1,
463                                   inner_id1,
464                                   &hi1,
465                                   &main_intf1, &vlan_intf1, &qinq_intf1);
466
467           identify_subint (hi0,
468                            b0,
469                            match_flags0,
470                            main_intf0,
471                            vlan_intf0,
472                            qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
473
474           identify_subint (hi1,
475                            b1,
476                            match_flags1,
477                            main_intf1,
478                            vlan_intf1,
479                            qinq_intf1, &new_sw_if_index1, &error1, &is_l21);
480
481           // Save RX sw_if_index for later nodes
482           vnet_buffer (b0)->sw_if_index[VLIB_RX] =
483             error0 !=
484             ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
485           vnet_buffer (b1)->sw_if_index[VLIB_RX] =
486             error1 !=
487             ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
488
489           // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
490           if (((new_sw_if_index0 != ~0)
491                && (new_sw_if_index0 != old_sw_if_index0))
492               || ((new_sw_if_index1 != ~0)
493                   && (new_sw_if_index1 != old_sw_if_index1)))
494             {
495
496               len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
497                 - vnet_buffer (b0)->ethernet.start_of_ethernet_header;
498               len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
499                 - vnet_buffer (b1)->ethernet.start_of_ethernet_header;
500
501               stats_n_packets += 2;
502               stats_n_bytes += len0 + len1;
503
504               if (PREDICT_FALSE
505                   (!(new_sw_if_index0 == stats_sw_if_index
506                      && new_sw_if_index1 == stats_sw_if_index)))
507                 {
508                   stats_n_packets -= 2;
509                   stats_n_bytes -= len0 + len1;
510
511                   if (new_sw_if_index0 != old_sw_if_index0
512                       && new_sw_if_index0 != ~0)
513                     vlib_increment_combined_counter (vnm->
514                                                      interface_main.combined_sw_if_counters
515                                                      +
516                                                      VNET_INTERFACE_COUNTER_RX,
517                                                      thread_index,
518                                                      new_sw_if_index0, 1,
519                                                      len0);
520                   if (new_sw_if_index1 != old_sw_if_index1
521                       && new_sw_if_index1 != ~0)
522                     vlib_increment_combined_counter (vnm->
523                                                      interface_main.combined_sw_if_counters
524                                                      +
525                                                      VNET_INTERFACE_COUNTER_RX,
526                                                      thread_index,
527                                                      new_sw_if_index1, 1,
528                                                      len1);
529
530                   if (new_sw_if_index0 == new_sw_if_index1)
531                     {
532                       if (stats_n_packets > 0)
533                         {
534                           vlib_increment_combined_counter
535                             (vnm->interface_main.combined_sw_if_counters
536                              + VNET_INTERFACE_COUNTER_RX,
537                              thread_index,
538                              stats_sw_if_index,
539                              stats_n_packets, stats_n_bytes);
540                           stats_n_packets = stats_n_bytes = 0;
541                         }
542                       stats_sw_if_index = new_sw_if_index0;
543                     }
544                 }
545             }
546
547           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
548             is_l20 = is_l21 = 0;
549
550           determine_next_node (em, variant, is_l20, type0, b0, &error0,
551                                &next0);
552           determine_next_node (em, variant, is_l21, type1, b1, &error1,
553                                &next1);
554
555         ship_it01:
556           b0->error = error_node->errors[error0];
557           b1->error = error_node->errors[error1];
558
559           // verify speculative enqueue
560           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
561                                            n_left_to_next, bi0, bi1, next0,
562                                            next1);
563         }
564
565       while (n_left_from > 0 && n_left_to_next > 0)
566         {
567           u32 bi0;
568           vlib_buffer_t *b0;
569           u8 error0, next0;
570           u16 type0, orig_type0;
571           u16 outer_id0, inner_id0;
572           u32 match_flags0;
573           u32 old_sw_if_index0, new_sw_if_index0, len0;
574           vnet_hw_interface_t *hi0;
575           main_intf_t *main_intf0;
576           vlan_intf_t *vlan_intf0;
577           qinq_intf_t *qinq_intf0;
578           ethernet_header_t *e0;
579           u32 is_l20;
580
581           // Prefetch next iteration
582           if (n_left_from > 1)
583             {
584               vlib_buffer_t *p2;
585
586               p2 = vlib_get_buffer (vm, from[1]);
587               vlib_prefetch_buffer_header (p2, STORE);
588               CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
589             }
590
591           bi0 = from[0];
592           to_next[0] = bi0;
593           from += 1;
594           to_next += 1;
595           n_left_from -= 1;
596           n_left_to_next -= 1;
597
598           b0 = vlib_get_buffer (vm, bi0);
599
600           error0 = ETHERNET_ERROR_NONE;
601           e0 = vlib_buffer_get_current (b0);
602           type0 = clib_net_to_host_u16 (e0->type);
603
604           /* Speed-path for the untagged case */
605           if (PREDICT_TRUE (variant == ETHERNET_INPUT_VARIANT_ETHERNET
606                             && !ethernet_frame_is_tagged (type0)))
607             {
608               main_intf_t *intf0;
609               subint_config_t *subint0;
610               u32 sw_if_index0;
611
612               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
613               is_l20 = cached_is_l2;
614
615               if (PREDICT_FALSE (cached_sw_if_index != sw_if_index0))
616                 {
617                   cached_sw_if_index = sw_if_index0;
618                   hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
619                   intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
620                   subint0 = &intf0->untagged_subint;
621                   cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
622                 }
623
624               vnet_buffer (b0)->ethernet.start_of_ethernet_header =
625                 b0->current_data;
626
627               if (PREDICT_TRUE (is_l20 != 0))
628                 {
629                   next0 = em->l2_next;
630                   vnet_buffer (b0)->l2.l2_len = sizeof (ethernet_header_t);
631                 }
632               else
633                 {
634                   if (!ethernet_address_cast (e0->dst_address) &&
635                       (hi->hw_address != 0) &&
636                       !eth_mac_equal ((u8 *) e0, hi->hw_address))
637                     error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
638                   determine_next_node (em, variant, 0, type0, b0,
639                                        &error0, &next0);
640                   vlib_buffer_advance (b0, sizeof (ethernet_header_t));
641                 }
642               goto ship_it0;
643             }
644
645           /* Slow-path for the tagged case */
646           parse_header (variant,
647                         b0,
648                         &type0,
649                         &orig_type0, &outer_id0, &inner_id0, &match_flags0);
650
651           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
652
653           eth_vlan_table_lookups (em,
654                                   vnm,
655                                   old_sw_if_index0,
656                                   orig_type0,
657                                   outer_id0,
658                                   inner_id0,
659                                   &hi0,
660                                   &main_intf0, &vlan_intf0, &qinq_intf0);
661
662           identify_subint (hi0,
663                            b0,
664                            match_flags0,
665                            main_intf0,
666                            vlan_intf0,
667                            qinq_intf0, &new_sw_if_index0, &error0, &is_l20);
668
669           // Save RX sw_if_index for later nodes
670           vnet_buffer (b0)->sw_if_index[VLIB_RX] =
671             error0 !=
672             ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
673
674           // Increment subinterface stats
675           // Note that interface-level counters have already been incremented
676           // prior to calling this function. Thus only subinterface counters
677           // are incremented here.
678           //
679           // Interface level counters include packets received on the main
680           // interface and all subinterfaces. Subinterface level counters
681           // include only those packets received on that subinterface
682           // Increment stats if the subint is valid and it is not the main intf
683           if ((new_sw_if_index0 != ~0)
684               && (new_sw_if_index0 != old_sw_if_index0))
685             {
686
687               len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
688                 - vnet_buffer (b0)->ethernet.start_of_ethernet_header;
689
690               stats_n_packets += 1;
691               stats_n_bytes += len0;
692
693               // Batch stat increments from the same subinterface so counters
694               // don't need to be incremented for every packet.
695               if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index))
696                 {
697                   stats_n_packets -= 1;
698                   stats_n_bytes -= len0;
699
700                   if (new_sw_if_index0 != ~0)
701                     vlib_increment_combined_counter
702                       (vnm->interface_main.combined_sw_if_counters
703                        + VNET_INTERFACE_COUNTER_RX,
704                        thread_index, new_sw_if_index0, 1, len0);
705                   if (stats_n_packets > 0)
706                     {
707                       vlib_increment_combined_counter
708                         (vnm->interface_main.combined_sw_if_counters
709                          + VNET_INTERFACE_COUNTER_RX,
710                          thread_index,
711                          stats_sw_if_index, stats_n_packets, stats_n_bytes);
712                       stats_n_packets = stats_n_bytes = 0;
713                     }
714                   stats_sw_if_index = new_sw_if_index0;
715                 }
716             }
717
718           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
719             is_l20 = 0;
720
721           determine_next_node (em, variant, is_l20, type0, b0, &error0,
722                                &next0);
723
724         ship_it0:
725           b0->error = error_node->errors[error0];
726
727           // verify speculative enqueue
728           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
729                                            to_next, n_left_to_next,
730                                            bi0, next0);
731         }
732
733       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
734     }
735
736   // Increment any remaining batched stats
737   if (stats_n_packets > 0)
738     {
739       vlib_increment_combined_counter
740         (vnm->interface_main.combined_sw_if_counters
741          + VNET_INTERFACE_COUNTER_RX,
742          thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
743       node->runtime_data[0] = stats_sw_if_index;
744     }
745
746   return from_frame->n_vectors;
747 }
748
749 static uword
750 ethernet_input (vlib_main_t * vm,
751                 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
752 {
753   return ethernet_input_inline (vm, node, from_frame,
754                                 ETHERNET_INPUT_VARIANT_ETHERNET);
755 }
756
757 static uword
758 ethernet_input_type (vlib_main_t * vm,
759                      vlib_node_runtime_t * node, vlib_frame_t * from_frame)
760 {
761   return ethernet_input_inline (vm, node, from_frame,
762                                 ETHERNET_INPUT_VARIANT_ETHERNET_TYPE);
763 }
764
765 static uword
766 ethernet_input_not_l2 (vlib_main_t * vm,
767                        vlib_node_runtime_t * node, vlib_frame_t * from_frame)
768 {
769   return ethernet_input_inline (vm, node, from_frame,
770                                 ETHERNET_INPUT_VARIANT_NOT_L2);
771 }
772
773
774 // Return the subinterface config struct for the given sw_if_index
775 // Also return via parameter the appropriate match flags for the
776 // configured number of tags.
777 // On error (unsupported or not ethernet) return 0.
778 static subint_config_t *
779 ethernet_sw_interface_get_config (vnet_main_t * vnm,
780                                   u32 sw_if_index,
781                                   u32 * flags, u32 * unsupported)
782 {
783   ethernet_main_t *em = &ethernet_main;
784   vnet_hw_interface_t *hi;
785   vnet_sw_interface_t *si;
786   main_intf_t *main_intf;
787   vlan_table_t *vlan_table;
788   qinq_table_t *qinq_table;
789   subint_config_t *subint = 0;
790
791   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
792
793   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index))
794     {
795       *unsupported = 0;
796       goto done;                // non-ethernet interface
797     }
798
799   // ensure there's an entry for the main intf (shouldn't really be necessary)
800   vec_validate (em->main_intfs, hi->hw_if_index);
801   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
802
803   // Locate the subint for the given ethernet config
804   si = vnet_get_sw_interface (vnm, sw_if_index);
805
806   if (si->sub.eth.flags.default_sub)
807     {
808       subint = &main_intf->default_subint;
809       *flags = SUBINT_CONFIG_MATCH_0_TAG |
810         SUBINT_CONFIG_MATCH_1_TAG |
811         SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
812     }
813   else if ((si->sub.eth.flags.no_tags) || (si->sub.eth.raw_flags == 0))
814     {
815       // if no flags are set then this is a main interface
816       // so treat as untagged
817       subint = &main_intf->untagged_subint;
818       *flags = SUBINT_CONFIG_MATCH_0_TAG;
819     }
820   else
821     {
822       // one or two tags
823       // first get the vlan table
824       if (si->sub.eth.flags.dot1ad)
825         {
826           if (main_intf->dot1ad_vlans == 0)
827             {
828               // Allocate a vlan table from the pool
829               pool_get (em->vlan_pool, vlan_table);
830               main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
831             }
832           else
833             {
834               // Get ptr to existing vlan table
835               vlan_table =
836                 vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
837             }
838         }
839       else
840         {                       // dot1q
841           if (main_intf->dot1q_vlans == 0)
842             {
843               // Allocate a vlan table from the pool
844               pool_get (em->vlan_pool, vlan_table);
845               main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
846             }
847           else
848             {
849               // Get ptr to existing vlan table
850               vlan_table =
851                 vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
852             }
853         }
854
855       if (si->sub.eth.flags.one_tag)
856         {
857           *flags = si->sub.eth.flags.exact_match ?
858             SUBINT_CONFIG_MATCH_1_TAG :
859             (SUBINT_CONFIG_MATCH_1_TAG |
860              SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
861
862           if (si->sub.eth.flags.outer_vlan_id_any)
863             {
864               // not implemented yet
865               *unsupported = 1;
866               goto done;
867             }
868           else
869             {
870               // a single vlan, a common case
871               subint =
872                 &vlan_table->vlans[si->sub.eth.
873                                    outer_vlan_id].single_tag_subint;
874             }
875
876         }
877       else
878         {
879           // Two tags
880           *flags = si->sub.eth.flags.exact_match ?
881             SUBINT_CONFIG_MATCH_2_TAG :
882             (SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG);
883
884           if (si->sub.eth.flags.outer_vlan_id_any
885               && si->sub.eth.flags.inner_vlan_id_any)
886             {
887               // not implemented yet
888               *unsupported = 1;
889               goto done;
890             }
891
892           if (si->sub.eth.flags.inner_vlan_id_any)
893             {
894               // a specific outer and "any" inner
895               // don't need a qinq table for this
896               subint =
897                 &vlan_table->vlans[si->sub.eth.
898                                    outer_vlan_id].inner_any_subint;
899               if (si->sub.eth.flags.exact_match)
900                 {
901                   *flags = SUBINT_CONFIG_MATCH_2_TAG;
902                 }
903               else
904                 {
905                   *flags = SUBINT_CONFIG_MATCH_2_TAG |
906                     SUBINT_CONFIG_MATCH_3_TAG;
907                 }
908             }
909           else
910             {
911               // a specific outer + specifc innner vlan id, a common case
912
913               // get the qinq table
914               if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0)
915                 {
916                   // Allocate a qinq table from the pool
917                   pool_get (em->qinq_pool, qinq_table);
918                   vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs =
919                     qinq_table - em->qinq_pool;
920                 }
921               else
922                 {
923                   // Get ptr to existing qinq table
924                   qinq_table =
925                     vec_elt_at_index (em->qinq_pool,
926                                       vlan_table->vlans[si->sub.
927                                                         eth.outer_vlan_id].
928                                       qinqs);
929                 }
930               subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
931             }
932         }
933     }
934
935 done:
936   return subint;
937 }
938
939 clib_error_t *
940 ethernet_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
941 {
942   subint_config_t *subint;
943   u32 dummy_flags;
944   u32 dummy_unsup;
945   clib_error_t *error = 0;
946
947   // Find the config for this subinterface
948   subint =
949     ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
950                                       &dummy_unsup);
951
952   if (subint == 0)
953     {
954       // not implemented yet or not ethernet
955       goto done;
956     }
957
958   subint->sw_if_index =
959     ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
960
961 done:
962   return error;
963 }
964
965 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
966
967
968 // Set the L2/L3 mode for the subinterface
969 void
970 ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm, u32 sw_if_index, u32 l2)
971 {
972   subint_config_t *subint;
973   u32 dummy_flags;
974   u32 dummy_unsup;
975   int is_port;
976   vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
977
978   is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
979
980   // Find the config for this subinterface
981   subint =
982     ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
983                                       &dummy_unsup);
984
985   if (subint == 0)
986     {
987       // unimplemented or not ethernet
988       goto done;
989     }
990
991   // Double check that the config we found is for our interface (or the interface is down)
992   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
993
994   if (l2)
995     {
996       subint->flags |= SUBINT_CONFIG_L2;
997       if (is_port)
998         subint->flags |=
999           SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
1000           | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
1001     }
1002   else
1003     {
1004       subint->flags &= ~SUBINT_CONFIG_L2;
1005       if (is_port)
1006         subint->flags &=
1007           ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
1008             | SUBINT_CONFIG_MATCH_3_TAG);
1009     }
1010
1011 done:
1012   return;
1013 }
1014
1015 /*
1016  * Set the L2/L3 mode for the subinterface regardless of port
1017  */
1018 void
1019 ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
1020                                           u32 sw_if_index, u32 l2)
1021 {
1022   subint_config_t *subint;
1023   u32 dummy_flags;
1024   u32 dummy_unsup;
1025
1026   /* Find the config for this subinterface */
1027   subint =
1028     ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags,
1029                                       &dummy_unsup);
1030
1031   if (subint == 0)
1032     {
1033       /* unimplemented or not ethernet */
1034       goto done;
1035     }
1036
1037   /*
1038    * Double check that the config we found is for our interface (or the
1039    * interface is down)
1040    */
1041   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
1042
1043   if (l2)
1044     {
1045       subint->flags |= SUBINT_CONFIG_L2;
1046     }
1047   else
1048     {
1049       subint->flags &= ~SUBINT_CONFIG_L2;
1050     }
1051
1052 done:
1053   return;
1054 }
1055
1056 static clib_error_t *
1057 ethernet_sw_interface_add_del (vnet_main_t * vnm,
1058                                u32 sw_if_index, u32 is_create)
1059 {
1060   clib_error_t *error = 0;
1061   subint_config_t *subint;
1062   u32 match_flags;
1063   u32 unsupported = 0;
1064
1065   // Find the config for this subinterface
1066   subint =
1067     ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags,
1068                                       &unsupported);
1069
1070   if (subint == 0)
1071     {
1072       // not implemented yet or not ethernet
1073       if (unsupported)
1074         {
1075           // this is the NYI case
1076           error = clib_error_return (0, "not implemented yet");
1077         }
1078       goto done;
1079     }
1080
1081   if (!is_create)
1082     {
1083       subint->flags = 0;
1084       return error;
1085     }
1086
1087   // Initialize the subint
1088   if (subint->flags & SUBINT_CONFIG_VALID)
1089     {
1090       // Error vlan already in use
1091       error = clib_error_return (0, "vlan is already in use");
1092     }
1093   else
1094     {
1095       // Note that config is L3 by defaulty
1096       subint->flags = SUBINT_CONFIG_VALID | match_flags;
1097       subint->sw_if_index = ~0; // because interfaces are initially down
1098     }
1099
1100 done:
1101   return error;
1102 }
1103
1104 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
1105
1106 static char *ethernet_error_strings[] = {
1107 #define ethernet_error(n,c,s) s,
1108 #include "error.def"
1109 #undef ethernet_error
1110 };
1111
1112 /* *INDENT-OFF* */
1113 VLIB_REGISTER_NODE (ethernet_input_node) = {
1114   .function = ethernet_input,
1115   .name = "ethernet-input",
1116   /* Takes a vector of packets. */
1117   .vector_size = sizeof (u32),
1118   .n_errors = ETHERNET_N_ERROR,
1119   .error_strings = ethernet_error_strings,
1120   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1121   .next_nodes = {
1122 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1123     foreach_ethernet_input_next
1124 #undef _
1125   },
1126   .format_buffer = format_ethernet_header_with_length,
1127   .format_trace = format_ethernet_input_trace,
1128   .unformat_buffer = unformat_ethernet_header,
1129 };
1130 /* *INDENT-ON* */
1131
1132 /* *INDENT-OFF* */
1133 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_node, ethernet_input)
1134 /* *INDENT-ON* */
1135
1136 /* *INDENT-OFF* */
1137 VLIB_REGISTER_NODE (ethernet_input_type_node, static) = {
1138   .function = ethernet_input_type,
1139   .name = "ethernet-input-type",
1140   /* Takes a vector of packets. */
1141   .vector_size = sizeof (u32),
1142   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1143   .next_nodes = {
1144 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1145     foreach_ethernet_input_next
1146 #undef _
1147   },
1148 };
1149 /* *INDENT-ON* */
1150
1151 /* *INDENT-OFF* */
1152 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_type_node, ethernet_input_type)
1153 /* *INDENT-ON* */
1154
1155 /* *INDENT-OFF* */
1156 VLIB_REGISTER_NODE (ethernet_input_not_l2_node, static) = {
1157   .function = ethernet_input_not_l2,
1158   .name = "ethernet-input-not-l2",
1159   /* Takes a vector of packets. */
1160   .vector_size = sizeof (u32),
1161   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
1162   .next_nodes = {
1163 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
1164     foreach_ethernet_input_next
1165 #undef _
1166   },
1167 };
1168 /* *INDENT-ON* */
1169
1170
1171 /* *INDENT-OFF* */
1172 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_not_l2_node,
1173                               ethernet_input_not_l2)
1174 /* *INDENT-ON* */
1175
1176
1177 void
1178 ethernet_set_rx_redirect (vnet_main_t * vnm,
1179                           vnet_hw_interface_t * hi, u32 enable)
1180 {
1181   // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
1182   // don't go directly to ip4-input)
1183   vnet_hw_interface_rx_redirect_to_node
1184     (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
1185 }
1186
1187
1188 /*
1189  * Initialization and registration for the next_by_ethernet structure
1190  */
1191
1192 clib_error_t *
1193 next_by_ethertype_init (next_by_ethertype_t * l3_next)
1194 {
1195   l3_next->input_next_by_type = sparse_vec_new
1196     ( /* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
1197      /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
1198
1199   vec_validate (l3_next->sparse_index_by_input_next_index,
1200                 ETHERNET_INPUT_NEXT_DROP);
1201   vec_validate (l3_next->sparse_index_by_input_next_index,
1202                 ETHERNET_INPUT_NEXT_PUNT);
1203   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP] =
1204     SPARSE_VEC_INVALID_INDEX;
1205   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT] =
1206     SPARSE_VEC_INVALID_INDEX;
1207
1208   /*
1209    * Make sure we don't wipe out an ethernet registration by mistake
1210    * Can happen if init function ordering constraints are missing.
1211    */
1212   if (CLIB_DEBUG > 0)
1213     {
1214       ethernet_main_t *em = &ethernet_main;
1215       ASSERT (em->next_by_ethertype_register_called == 0);
1216     }
1217
1218   return 0;
1219 }
1220
1221 // Add an ethertype -> next index mapping to the structure
1222 clib_error_t *
1223 next_by_ethertype_register (next_by_ethertype_t * l3_next,
1224                             u32 ethertype, u32 next_index)
1225 {
1226   u32 i;
1227   u16 *n;
1228   ethernet_main_t *em = &ethernet_main;
1229
1230   if (CLIB_DEBUG > 0)
1231     {
1232       ethernet_main_t *em = &ethernet_main;
1233       em->next_by_ethertype_register_called = 1;
1234     }
1235
1236   /* Setup ethernet type -> next index sparse vector mapping. */
1237   n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
1238   n[0] = next_index;
1239
1240   /* Rebuild next index -> sparse index inverse mapping when sparse vector
1241      is updated. */
1242   vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
1243   for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
1244     l3_next->
1245       sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
1246
1247   // do not allow the cached next index's to be updated if L3
1248   // redirect is enabled, as it will have overwritten them
1249   if (!em->redirect_l3)
1250     {
1251       // Cache common ethertypes directly
1252       if (ethertype == ETHERNET_TYPE_IP4)
1253         {
1254           l3_next->input_next_ip4 = next_index;
1255         }
1256       else if (ethertype == ETHERNET_TYPE_IP6)
1257         {
1258           l3_next->input_next_ip6 = next_index;
1259         }
1260       else if (ethertype == ETHERNET_TYPE_MPLS)
1261         {
1262           l3_next->input_next_mpls = next_index;
1263         }
1264     }
1265   return 0;
1266 }
1267
1268
1269 static clib_error_t *
1270 ethernet_input_init (vlib_main_t * vm)
1271 {
1272   ethernet_main_t *em = &ethernet_main;
1273   __attribute__ ((unused)) vlan_table_t *invalid_vlan_table;
1274   __attribute__ ((unused)) qinq_table_t *invalid_qinq_table;
1275
1276   ethernet_setup_node (vm, ethernet_input_node.index);
1277   ethernet_setup_node (vm, ethernet_input_type_node.index);
1278   ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
1279
1280   next_by_ethertype_init (&em->l3_next);
1281
1282   // Initialize pools and vector for vlan parsing
1283   vec_validate (em->main_intfs, 10);    // 10 main interfaces
1284   pool_alloc (em->vlan_pool, 10);
1285   pool_alloc (em->qinq_pool, 1);
1286
1287   // The first vlan pool will always be reserved for an invalid table
1288   pool_get (em->vlan_pool, invalid_vlan_table); // first id = 0
1289   // The first qinq pool will always be reserved for an invalid table
1290   pool_get (em->qinq_pool, invalid_qinq_table); // first id = 0
1291
1292   return 0;
1293 }
1294
1295 VLIB_INIT_FUNCTION (ethernet_input_init);
1296
1297 void
1298 ethernet_register_input_type (vlib_main_t * vm,
1299                               ethernet_type_t type, u32 node_index)
1300 {
1301   ethernet_main_t *em = &ethernet_main;
1302   ethernet_type_info_t *ti;
1303   u32 i;
1304
1305   {
1306     clib_error_t *error = vlib_call_init_function (vm, ethernet_init);
1307     if (error)
1308       clib_error_report (error);
1309   }
1310
1311   ti = ethernet_get_type_info (em, type);
1312   ti->node_index = node_index;
1313   ti->next_index = vlib_node_add_next (vm,
1314                                        ethernet_input_node.index, node_index);
1315   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1316   ASSERT (i == ti->next_index);
1317
1318   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
1319   ASSERT (i == ti->next_index);
1320
1321   // Add the L3 node for this ethertype to the next nodes structure
1322   next_by_ethertype_register (&em->l3_next, type, ti->next_index);
1323
1324   // Call the registration functions for other nodes that want a mapping
1325   l2bvi_register_input_type (vm, type, node_index);
1326 }
1327
1328 void
1329 ethernet_register_l2_input (vlib_main_t * vm, u32 node_index)
1330 {
1331   ethernet_main_t *em = &ethernet_main;
1332   u32 i;
1333
1334   em->l2_next =
1335     vlib_node_add_next (vm, ethernet_input_node.index, node_index);
1336
1337   /*
1338    * Even if we never use these arcs, we have to align the next indices...
1339    */
1340   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1341
1342   ASSERT (i == em->l2_next);
1343
1344   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
1345   ASSERT (i == em->l2_next);
1346 }
1347
1348 // Register a next node for L3 redirect, and enable L3 redirect
1349 void
1350 ethernet_register_l3_redirect (vlib_main_t * vm, u32 node_index)
1351 {
1352   ethernet_main_t *em = &ethernet_main;
1353   u32 i;
1354
1355   em->redirect_l3 = 1;
1356   em->redirect_l3_next = vlib_node_add_next (vm,
1357                                              ethernet_input_node.index,
1358                                              node_index);
1359   /*
1360    * Change the cached next nodes to the redirect node
1361    */
1362   em->l3_next.input_next_ip4 = em->redirect_l3_next;
1363   em->l3_next.input_next_ip6 = em->redirect_l3_next;
1364   em->l3_next.input_next_mpls = em->redirect_l3_next;
1365
1366   /*
1367    * Even if we never use these arcs, we have to align the next indices...
1368    */
1369   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1370
1371   ASSERT (i == em->redirect_l3_next);
1372
1373   i = vlib_node_add_next (vm, ethernet_input_not_l2_node.index, node_index);
1374
1375   ASSERT (i == em->redirect_l3_next);
1376 }
1377
1378 /*
1379  * fd.io coding-style-patch-verification: ON
1380  *
1381  * Local Variables:
1382  * eval: (c-set-style "gnu")
1383  * End:
1384  */