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