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