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