Add support for multiple microarchitectures in single binary
[vpp.git] / vnet / vnet / ethernet / node.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * ethernet_node.c: ethernet packet processing
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vlib/vlib.h>
41 #include <vnet/pg/pg.h>
42 #include <vnet/ethernet/ethernet.h>
43 #include <vppinfra/sparse_vec.h>
44 #include <vnet/l2/l2_bvi.h>
45
46
47 #define foreach_ethernet_input_next             \
48   _ (PUNT, "error-punt")                        \
49   _ (DROP, "error-drop")                        \
50   _ (LLC, "llc-input")                          
51
52 typedef enum {
53 #define _(s,n) ETHERNET_INPUT_NEXT_##s,
54   foreach_ethernet_input_next
55 #undef _
56   ETHERNET_INPUT_N_NEXT,
57 } ethernet_input_next_t;
58
59 typedef struct {
60   u8 packet_data[32];
61 } ethernet_input_trace_t;
62
63 static u8 * format_ethernet_input_trace (u8 * s, va_list * va)
64 {
65   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
66   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
67   ethernet_input_trace_t * t = va_arg (*va, ethernet_input_trace_t *);
68
69   s = format (s, "%U", format_ethernet_header, t->packet_data);
70
71   return s;
72 }
73
74 vlib_node_registration_t ethernet_input_node;
75
76 typedef enum {
77   ETHERNET_INPUT_VARIANT_ETHERNET,
78   ETHERNET_INPUT_VARIANT_ETHERNET_TYPE,
79   ETHERNET_INPUT_VARIANT_VLAN,
80   ETHERNET_INPUT_VARIANT_NOT_L2,
81 } ethernet_input_variant_t;
82
83
84 // Compare two ethernet macs. Return 1 if they are the same, 0 if different
85 static_always_inline u32
86 eth_mac_equal (u8 * mac1, u8 * mac2) {
87   return (*((u32 *)(mac1+0)) == *((u32 *)(mac2+0)) &&
88           *((u32 *)(mac1+2)) == *((u32 *)(mac2+2)));
89 }
90
91
92 // Parse the ethernet header to extract vlan tags and innermost ethertype
93 static_always_inline void
94 parse_header (ethernet_input_variant_t variant,
95               vlib_buffer_t * b0,
96               u16 * type, 
97               u16 * orig_type, 
98               u16 * outer_id,
99               u16 * inner_id,
100               u32 * match_flags) {
101   u8 vlan_count;
102
103   if (variant == ETHERNET_INPUT_VARIANT_ETHERNET 
104       || variant == ETHERNET_INPUT_VARIANT_NOT_L2) {
105     ethernet_header_t * e0;
106
107     e0 = (void *) (b0->data + b0->current_data);
108
109     vnet_buffer (b0)->ethernet.start_of_ethernet_header = b0->current_data;
110
111     vlib_buffer_advance (b0, sizeof (e0[0]));
112
113     *type = clib_net_to_host_u16(e0->type);
114   } else if (variant == ETHERNET_INPUT_VARIANT_ETHERNET_TYPE) {
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 ((*type == ETHERNET_TYPE_VLAN) ||
137       (*type == ETHERNET_TYPE_DOT1AD) ||
138       (*type == ETHERNET_TYPE_VLAN_9100) ||
139       (*type == ETHERNET_TYPE_VLAN_9200))
140   {
141     ethernet_vlan_header_t * h0;
142     u16 tag;
143  
144     *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_1_TAG;
145
146     h0 = (void *) (b0->data + b0->current_data);
147
148     tag = clib_net_to_host_u16 (h0->priority_cfi_and_id);
149
150     *outer_id = tag & 0xfff;
151
152     *type = clib_net_to_host_u16(h0->type);
153
154     vlib_buffer_advance (b0, sizeof (h0[0]));
155     vlan_count = 1;
156
157     if (*type == ETHERNET_TYPE_VLAN) {
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
172       if (*type == ETHERNET_TYPE_VLAN) {
173         // More than double tagged packet
174         *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG;
175         vlan_count = 3; // "unknown" number, aka, 3-or-more
176       }
177     }
178   }
179   ethernet_buffer_set_vlan_count(b0, vlan_count);
180 }
181
182 // Determine the subinterface for this packet, given the result of the
183 // vlan table lookups and vlan header parsing. Check the most specific
184 // matches first.
185 static_always_inline void
186 identify_subint (vnet_hw_interface_t * hi,
187                  vlib_buffer_t * b0,
188                  u32 match_flags, 
189                  main_intf_t * main_intf, 
190                  vlan_intf_t * vlan_intf, 
191                  qinq_intf_t * qinq_intf, 
192                  u32 * new_sw_if_index, 
193                  u8 * error0, 
194                  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     // 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       ethernet_header_t * e0;
209       e0 = (void *) (b0->data + vnet_buffer (b0)->ethernet.start_of_ethernet_header);
210
211       if (!(ethernet_address_cast(e0->dst_address))) {
212         if (!eth_mac_equal((u8 *)e0, hi->hw_address)) {
213           *error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
214         }
215       }
216     }
217
218     // Check for down subinterface
219     *error0 = (*new_sw_if_index) != ~0 ? (*error0) : ETHERNET_ERROR_DOWN;
220   }
221 }
222
223 static_always_inline void
224 determine_next_node (ethernet_main_t * em,
225                      ethernet_input_variant_t variant,
226                      u32 is_l20, 
227                      u32 type0, 
228                      vlib_buffer_t * b0,
229                      u8 * error0,
230                      u8 * next0)
231 {
232   if (PREDICT_FALSE (*error0 != ETHERNET_ERROR_NONE)) {
233     // some error occurred
234     *next0 = ETHERNET_INPUT_NEXT_DROP;
235   } else if (is_l20) {
236     *next0 = em->l2_next;
237     // record the L2 len and reset the buffer so the L2 header is preserved
238     vnet_buffer(b0)->l2.l2_len = b0->current_data;
239     vlib_buffer_advance(b0, - ethernet_buffer_header_size(b0));
240
241   // check for common IP/MPLS ethertypes
242   } else if (type0 == ETHERNET_TYPE_IP4) {
243     *next0 = em->l3_next.input_next_ip4;
244   } else if (type0 == ETHERNET_TYPE_IP6) {
245     *next0 = em->l3_next.input_next_ip6;
246   } else if (type0 == ETHERNET_TYPE_MPLS_UNICAST) {
247     *next0 = em->l3_next.input_next_mpls;
248
249   } else if (em->redirect_l3) {
250     // L3 Redirect is on, the cached common next nodes will be
251     // pointing to the redirect node, catch the uncommon types here
252     *next0 = em->redirect_l3_next;
253   } else {
254     // uncommon ethertype, check table
255     u32 i0;
256     i0 = sparse_vec_index (em->l3_next.input_next_by_type, type0);
257     *next0 = vec_elt (em->l3_next.input_next_by_type, i0);
258     *error0 = i0 == SPARSE_VEC_INVALID_INDEX ? ETHERNET_ERROR_UNKNOWN_TYPE : *error0;
259
260     // The table is not populated with LLC values, so check that now.
261     // If variant is variant_ethernet then we came from LLC processing. Don't 
262     // go back there; drop instead using by keeping the drop/bad table result.
263     if ((type0 < 0x600) && (variant == ETHERNET_INPUT_VARIANT_ETHERNET)) {
264       *next0 = ETHERNET_INPUT_NEXT_LLC;
265     }
266   }
267 }
268
269 static_always_inline uword
270 ethernet_input_inline (vlib_main_t * vm,
271                        vlib_node_runtime_t * node,
272                        vlib_frame_t * from_frame,
273                        ethernet_input_variant_t variant)
274 {
275   vnet_main_t * vnm = vnet_get_main();
276   ethernet_main_t * em = &ethernet_main;
277   vlib_node_runtime_t * error_node;
278   u32 n_left_from, next_index, * from, * to_next;
279   u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
280   u32 cpu_index = os_get_cpu_number();
281
282   if (variant != ETHERNET_INPUT_VARIANT_ETHERNET)
283     error_node = vlib_node_get_runtime (vm, ethernet_input_node.index);
284   else
285     error_node = node;
286
287   from = vlib_frame_vector_args (from_frame);
288   n_left_from = from_frame->n_vectors;
289
290   if (node->flags & VLIB_NODE_FLAG_TRACE)
291     vlib_trace_frame_buffers_only (vm, node,
292                                    from,
293                                    n_left_from,
294                                    sizeof (from[0]),
295                                    sizeof (ethernet_input_trace_t));
296
297   next_index = node->cached_next_index;
298   stats_sw_if_index = node->runtime_data[0];
299   stats_n_packets = stats_n_bytes = 0;
300
301   while (n_left_from > 0)
302     {
303       u32 n_left_to_next;
304
305       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
306
307       while (n_left_from >= 4 && n_left_to_next >= 2)
308         {
309           u32 bi0, bi1;
310           vlib_buffer_t * b0, * b1;
311           u8 next0, next1, error0, error1;
312           u16 type0, orig_type0, type1, orig_type1;
313           u16 outer_id0, inner_id0, outer_id1, inner_id1;
314           u32 match_flags0, match_flags1;
315           u32 old_sw_if_index0, new_sw_if_index0, len0, old_sw_if_index1, new_sw_if_index1, len1;
316           vnet_hw_interface_t * hi0, * hi1;
317           main_intf_t * main_intf0, * main_intf1;
318           vlan_intf_t * vlan_intf0, * vlan_intf1;
319           qinq_intf_t * qinq_intf0, * qinq_intf1;
320           u32 is_l20, is_l21;
321
322           /* Prefetch next iteration. */
323           {
324             vlib_buffer_t * b2, * b3;
325
326             b2 = vlib_get_buffer (vm, from[2]);
327             b3 = vlib_get_buffer (vm, from[3]);
328
329             vlib_prefetch_buffer_header (b2, STORE);
330             vlib_prefetch_buffer_header (b3, STORE);
331
332             CLIB_PREFETCH (b2->data, sizeof (ethernet_header_t), LOAD);
333             CLIB_PREFETCH (b3->data, sizeof (ethernet_header_t), LOAD);
334           }
335
336           bi0 = from[0];
337           bi1 = from[1];
338           to_next[0] = bi0;
339           to_next[1] = bi1;
340           from += 2;
341           to_next += 2;
342           n_left_to_next -= 2;
343           n_left_from -= 2;
344
345           b0 = vlib_get_buffer (vm, bi0);
346           b1 = vlib_get_buffer (vm, bi1);
347
348           error0 = error1 = ETHERNET_ERROR_NONE;
349
350           parse_header (variant, 
351                         b0,
352                         &type0, 
353                         &orig_type0, 
354                         &outer_id0,
355                         &inner_id0,
356                         &match_flags0);
357
358           parse_header (variant, 
359                         b1,
360                         &type1, 
361                         &orig_type1, 
362                         &outer_id1,
363                         &inner_id1,
364                         &match_flags1);
365
366           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
367           old_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
368
369           eth_vlan_table_lookups (em, 
370                               vnm, 
371                               old_sw_if_index0, 
372                               orig_type0, 
373                               outer_id0,
374                               inner_id0,
375                               &hi0,
376                               &main_intf0,  
377                               &vlan_intf0, 
378                               &qinq_intf0);
379
380           eth_vlan_table_lookups (em, 
381                               vnm, 
382                               old_sw_if_index1, 
383                               orig_type1, 
384                               outer_id1,
385                               inner_id1,
386                               &hi1,
387                               &main_intf1,  
388                               &vlan_intf1, 
389                               &qinq_intf1);
390
391           identify_subint (hi0,
392                            b0,
393                            match_flags0, 
394                            main_intf0, 
395                            vlan_intf0, 
396                            qinq_intf0, 
397                            &new_sw_if_index0, 
398                            &error0, 
399                            &is_l20);
400
401           identify_subint (hi1,
402                            b1,
403                            match_flags1, 
404                            main_intf1, 
405                            vlan_intf1, 
406                            qinq_intf1, 
407                            &new_sw_if_index1, 
408                            &error1, 
409                            &is_l21);
410
411           // Save RX sw_if_index for later nodes
412           vnet_buffer (b0)->sw_if_index[VLIB_RX] = error0 != ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
413           vnet_buffer (b1)->sw_if_index[VLIB_RX] = error1 != ETHERNET_ERROR_NONE ? old_sw_if_index1 : new_sw_if_index1;
414
415           // Check if there is a stat to take (valid and non-main sw_if_index for pkt 0 or pkt 1)
416           if (((new_sw_if_index0 != ~0) && (new_sw_if_index0 != old_sw_if_index0)) ||
417               ((new_sw_if_index1 != ~0) && (new_sw_if_index1 != old_sw_if_index1))) {
418
419             len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
420                    - vnet_buffer (b0)->ethernet.start_of_ethernet_header;
421             len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data
422                    - vnet_buffer (b1)->ethernet.start_of_ethernet_header;
423
424             stats_n_packets += 2;
425             stats_n_bytes += len0 + len1;
426
427               if (PREDICT_FALSE (! (new_sw_if_index0 == stats_sw_if_index && new_sw_if_index1 == stats_sw_if_index)))
428                 {
429                   stats_n_packets -= 2;
430                   stats_n_bytes -= len0 + len1;
431
432                   if (new_sw_if_index0 != old_sw_if_index0 && new_sw_if_index0 != ~0)
433                     vlib_increment_combined_counter 
434                         (vnm->interface_main.combined_sw_if_counters
435                          + VNET_INTERFACE_COUNTER_RX,
436                          cpu_index, 
437                          new_sw_if_index0,
438                          1,
439                          len0);
440                   if (new_sw_if_index1 != old_sw_if_index1 && new_sw_if_index1 != ~0)
441                     vlib_increment_combined_counter 
442                         (vnm->interface_main.combined_sw_if_counters
443                          + VNET_INTERFACE_COUNTER_RX,
444                          cpu_index, 
445                          new_sw_if_index1,
446                          1,
447                          len1);
448
449                   if (new_sw_if_index0 == new_sw_if_index1)
450                     {
451                       if (stats_n_packets > 0)
452                         {
453                           vlib_increment_combined_counter 
454                               (vnm->interface_main.combined_sw_if_counters
455                                + VNET_INTERFACE_COUNTER_RX,
456                                cpu_index, 
457                                stats_sw_if_index,
458                                stats_n_packets,
459                                stats_n_bytes);
460                           stats_n_packets = stats_n_bytes = 0;
461                         }
462                       stats_sw_if_index = new_sw_if_index0;
463                     }
464                 }
465             }
466
467           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
468               is_l20 = is_l21 = 0;
469
470           determine_next_node(em, variant, is_l20, type0, b0, &error0, &next0);
471           determine_next_node(em, variant, is_l21, type1, b1, &error1, &next1);
472           
473           b0->error = error_node->errors[error0];
474           b1->error = error_node->errors[error1];
475
476           // verify speculative enqueue
477           vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1);
478         }
479
480       while (n_left_from > 0 && n_left_to_next > 0)
481         {
482           u32 bi0;
483           vlib_buffer_t * b0;
484           u8 error0, next0;
485           u16 type0, orig_type0;
486           u16 outer_id0, inner_id0;
487           u32 match_flags0;
488           u32 old_sw_if_index0, new_sw_if_index0, len0;
489           vnet_hw_interface_t * hi0;
490           main_intf_t * main_intf0;
491           vlan_intf_t * vlan_intf0;
492           qinq_intf_t * qinq_intf0;
493           u32 is_l20;
494
495           // Prefetch next iteration
496           if (n_left_from > 1) {
497             vlib_buffer_t * p2;
498             
499             p2 = vlib_get_buffer (vm, from[1]);
500             vlib_prefetch_buffer_header (p2, STORE);
501             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
502           }
503
504           bi0 = from[0];
505           to_next[0] = bi0;
506           from += 1;
507           to_next += 1;
508           n_left_from -= 1;
509           n_left_to_next -= 1;
510
511           b0 = vlib_get_buffer (vm, bi0);
512
513           error0 = ETHERNET_ERROR_NONE;
514
515           parse_header (variant, 
516                         b0,
517                         &type0, 
518                         &orig_type0, 
519                         &outer_id0,
520                         &inner_id0,
521                         &match_flags0);
522
523           old_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
524
525           eth_vlan_table_lookups (em, 
526                               vnm, 
527                               old_sw_if_index0, 
528                               orig_type0, 
529                               outer_id0,
530                               inner_id0,
531                               &hi0,
532                               &main_intf0,  
533                               &vlan_intf0, 
534                               &qinq_intf0);
535
536           identify_subint (hi0,
537                            b0,
538                            match_flags0, 
539                            main_intf0, 
540                            vlan_intf0, 
541                            qinq_intf0, 
542                            &new_sw_if_index0, 
543                            &error0, 
544                            &is_l20);
545
546           // Save RX sw_if_index for later nodes
547           vnet_buffer (b0)->sw_if_index[VLIB_RX] = error0 != ETHERNET_ERROR_NONE ? old_sw_if_index0 : new_sw_if_index0;
548
549           // Increment subinterface stats
550           // Note that interface-level counters have already been incremented
551           // prior to calling this function. Thus only subinterface counters
552           // are incremented here.
553           //
554           // Interface level counters include packets received on the main 
555           // interface and all subinterfaces. Subinterface level counters
556           // include only those packets received on that subinterface
557           // Increment stats if the subint is valid and it is not the main intf
558           if ((new_sw_if_index0 != ~0) && (new_sw_if_index0 != old_sw_if_index0)) {
559
560             len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data
561                 - vnet_buffer (b0)->ethernet.start_of_ethernet_header;
562
563             stats_n_packets += 1;
564             stats_n_bytes += len0;
565
566             // Batch stat increments from the same subinterface so counters
567             // don't need to be incremented for every packet. 
568             if (PREDICT_FALSE (new_sw_if_index0 != stats_sw_if_index)) {
569               stats_n_packets -= 1;
570               stats_n_bytes -= len0;
571
572               if (new_sw_if_index0 != ~0)
573                 vlib_increment_combined_counter 
574                     (vnm->interface_main.combined_sw_if_counters
575                      + VNET_INTERFACE_COUNTER_RX,
576                      cpu_index, 
577                      new_sw_if_index0,
578                      1,
579                      len0);
580               if (stats_n_packets > 0) {
581                 vlib_increment_combined_counter 
582                     (vnm->interface_main.combined_sw_if_counters
583                      + VNET_INTERFACE_COUNTER_RX,
584                      cpu_index, 
585                      stats_sw_if_index,
586                      stats_n_packets,
587                      stats_n_bytes);
588                 stats_n_packets = stats_n_bytes = 0;
589               }
590               stats_sw_if_index = new_sw_if_index0;
591             }
592           }
593
594           if (variant == ETHERNET_INPUT_VARIANT_NOT_L2)
595               is_l20 = 0;
596
597           determine_next_node(em, variant, is_l20, type0, b0, &error0, &next0);
598
599           b0->error = error_node->errors[error0];
600           
601           // verify speculative enqueue
602           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
603                                            to_next, n_left_to_next,
604                                            bi0, next0);
605         }
606
607       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
608     }
609
610     // Increment any remaining batched stats
611     if (stats_n_packets > 0)
612     {
613       vlib_increment_combined_counter 
614           (vnm->interface_main.combined_sw_if_counters
615            + VNET_INTERFACE_COUNTER_RX,
616            cpu_index, 
617            stats_sw_if_index,
618            stats_n_packets,
619            stats_n_bytes);
620       node->runtime_data[0] = stats_sw_if_index;
621     }
622
623   return from_frame->n_vectors;
624 }
625
626 static uword
627 ethernet_input (vlib_main_t * vm,
628                 vlib_node_runtime_t * node,
629                 vlib_frame_t * from_frame)
630 { return ethernet_input_inline (vm, node, from_frame, ETHERNET_INPUT_VARIANT_ETHERNET); }
631
632 static uword
633 ethernet_input_type (vlib_main_t * vm,
634                      vlib_node_runtime_t * node,
635                      vlib_frame_t * from_frame)
636 { return ethernet_input_inline (vm, node, from_frame, ETHERNET_INPUT_VARIANT_ETHERNET_TYPE); }
637
638 static uword
639 ethernet_input_not_l2 (vlib_main_t * vm,
640                        vlib_node_runtime_t * node,
641                      vlib_frame_t * from_frame)
642 { return ethernet_input_inline (vm, node, from_frame, ETHERNET_INPUT_VARIANT_NOT_L2); }
643
644
645 // Return the subinterface config struct for the given sw_if_index
646 // Also return via parameter the appropriate match flags for the
647 // configured number of tags.
648 // On error (unsupported or not ethernet) return 0.
649 static subint_config_t *
650 ethernet_sw_interface_get_config (vnet_main_t * vnm,
651                                   u32 sw_if_index,
652                                   u32 * flags,
653                                   u32 * unsupported) {
654   ethernet_main_t * em = &ethernet_main;
655   vnet_hw_interface_t * hi;
656   vnet_sw_interface_t * si;
657   main_intf_t * main_intf;
658   vlan_table_t * vlan_table;
659   qinq_table_t * qinq_table;
660   subint_config_t * subint = 0;
661   
662   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
663
664   if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index)) {
665     *unsupported = 0;
666     goto done;  // non-ethernet interface
667   }
668
669   // ensure there's an entry for the main intf (shouldn't really be necessary)
670   vec_validate (em->main_intfs, hi->hw_if_index);
671   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
672
673   // Locate the subint for the given ethernet config
674   si = vnet_get_sw_interface (vnm, sw_if_index);
675
676   if (si->sub.eth.flags.default_sub) {
677     subint = &main_intf->default_subint;
678     *flags = SUBINT_CONFIG_MATCH_0_TAG |
679              SUBINT_CONFIG_MATCH_1_TAG |
680              SUBINT_CONFIG_MATCH_2_TAG |
681              SUBINT_CONFIG_MATCH_3_TAG;
682   } else if ((si->sub.eth.flags.no_tags) ||
683              (si->sub.eth.raw_flags == 0)) {
684     // if no flags are set then this is a main interface
685     // so treat as untagged
686     subint = &main_intf->untagged_subint;
687     *flags = SUBINT_CONFIG_MATCH_0_TAG;
688   } else {
689     // one or two tags
690     // first get the vlan table
691     if (si->sub.eth.flags.dot1ad) {
692       if (main_intf->dot1ad_vlans == 0) {
693         // Allocate a vlan table from the pool
694         pool_get(em->vlan_pool, vlan_table); 
695         main_intf->dot1ad_vlans = vlan_table - em->vlan_pool;
696       } else {
697         // Get ptr to existing vlan table
698         vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
699       }
700     } else { // dot1q
701       if (main_intf->dot1q_vlans == 0) {
702         // Allocate a vlan table from the pool
703         pool_get(em->vlan_pool, vlan_table); 
704         main_intf->dot1q_vlans = vlan_table - em->vlan_pool;
705       } else {
706         // Get ptr to existing vlan table
707         vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
708       }
709     }
710
711     if (si->sub.eth.flags.one_tag) {
712       *flags = si->sub.eth.flags.exact_match ?
713         SUBINT_CONFIG_MATCH_1_TAG :
714         (SUBINT_CONFIG_MATCH_1_TAG |
715          SUBINT_CONFIG_MATCH_2_TAG |
716          SUBINT_CONFIG_MATCH_3_TAG);
717
718       if (si->sub.eth.flags.outer_vlan_id_any) {
719         // not implemented yet
720         *unsupported =1;
721         goto done;
722       } else {
723         // a single vlan, a common case
724         subint = &vlan_table->vlans[si->sub.eth.outer_vlan_id].single_tag_subint;
725       }
726
727     } else {
728       // Two tags
729       *flags = si->sub.eth.flags.exact_match ?
730         SUBINT_CONFIG_MATCH_2_TAG :
731         (SUBINT_CONFIG_MATCH_2_TAG |
732          SUBINT_CONFIG_MATCH_3_TAG);
733
734       if (si->sub.eth.flags.outer_vlan_id_any && si->sub.eth.flags.inner_vlan_id_any) {
735         // not implemented yet
736         *unsupported = 1;
737         goto done;
738       }
739
740       if (si->sub.eth.flags.inner_vlan_id_any) {
741         // a specific outer and "any" inner
742         // don't need a qinq table for this
743         subint = &vlan_table->vlans[si->sub.eth.outer_vlan_id].inner_any_subint;
744         if (si->sub.eth.flags.exact_match) {
745           *flags = SUBINT_CONFIG_MATCH_2_TAG;
746         } else {
747           *flags = SUBINT_CONFIG_MATCH_2_TAG |
748                    SUBINT_CONFIG_MATCH_3_TAG;
749         }
750       } else {
751         // a specific outer + specifc innner vlan id, a common case
752
753         // get the qinq table
754         if (vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs == 0) {
755           // Allocate a qinq table from the pool
756           pool_get(em->qinq_pool, qinq_table); 
757           vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs = qinq_table - em->qinq_pool;
758         } else {
759           // Get ptr to existing qinq table
760           qinq_table = vec_elt_at_index (em->qinq_pool, vlan_table->vlans[si->sub.eth.outer_vlan_id].qinqs);
761         }
762         subint = &qinq_table->vlans[si->sub.eth.inner_vlan_id].subint;
763       }
764     }
765   }
766
767  done:
768   return subint;
769 }
770
771 clib_error_t *
772 ethernet_sw_interface_up_down (vnet_main_t * vnm,
773                                u32 sw_if_index,
774                                u32 flags)
775 {
776   subint_config_t * subint;
777   u32 dummy_flags;
778   u32 dummy_unsup;
779   clib_error_t * error = 0;
780
781   // Find the config for this subinterface
782   subint = ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags, &dummy_unsup);
783
784   if (subint == 0) {
785     // not implemented yet or not ethernet
786     goto done;
787   }
788
789   subint->sw_if_index =
790     ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? sw_if_index : ~0);
791
792  done:
793   return error;
794 }
795
796 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_sw_interface_up_down);
797
798
799 // Set the L2/L3 mode for the subinterface
800 void
801 ethernet_sw_interface_set_l2_mode (vnet_main_t * vnm,
802                                    u32 sw_if_index,
803                                    u32 l2)
804 {
805   subint_config_t *subint;
806   u32 dummy_flags;
807   u32 dummy_unsup;
808   int is_port;
809   vnet_sw_interface_t * sw = vnet_get_sw_interface (vnm, sw_if_index);
810
811   is_port = !(sw->type == VNET_SW_INTERFACE_TYPE_SUB);
812
813   // Find the config for this subinterface
814   subint = ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags, &dummy_unsup);
815
816   if (subint == 0) {
817     // unimplemented or not ethernet
818     goto done;
819   }
820
821   // Double check that the config we found is for our interface (or the interface is down)
822   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
823
824   if (l2) {
825     subint->flags |= SUBINT_CONFIG_L2;
826     if (is_port) 
827         subint->flags |= 
828             SUBINT_CONFIG_MATCH_0_TAG | SUBINT_CONFIG_MATCH_1_TAG
829             | SUBINT_CONFIG_MATCH_2_TAG | SUBINT_CONFIG_MATCH_3_TAG;
830   } else {
831     subint->flags &= ~SUBINT_CONFIG_L2;
832     if (is_port) 
833         subint->flags &= 
834             ~(SUBINT_CONFIG_MATCH_1_TAG | SUBINT_CONFIG_MATCH_2_TAG
835                     | SUBINT_CONFIG_MATCH_3_TAG);
836   }
837
838  done:
839   return;
840 }
841
842 /*
843  * Set the L2/L3 mode for the subinterface regardless of port
844  */
845 void
846 ethernet_sw_interface_set_l2_mode_noport (vnet_main_t * vnm,
847                                           u32 sw_if_index,
848                                           u32 l2)
849 {
850   subint_config_t *subint;
851   u32 dummy_flags;
852   u32 dummy_unsup;
853
854   /* Find the config for this subinterface */
855   subint = ethernet_sw_interface_get_config (vnm, sw_if_index, &dummy_flags, &dummy_unsup);
856
857   if (subint == 0) {
858     /* unimplemented or not ethernet */
859     goto done;
860   }
861
862   /*
863    * Double check that the config we found is for our interface (or the
864    * interface is down)
865    */
866   ASSERT ((subint->sw_if_index == sw_if_index) | (subint->sw_if_index == ~0));
867
868   if (l2) {
869     subint->flags |= SUBINT_CONFIG_L2;
870   } else {
871     subint->flags &= ~SUBINT_CONFIG_L2;
872   }
873
874  done:
875   return;
876 }
877
878 static clib_error_t *
879 ethernet_sw_interface_add_del (vnet_main_t * vnm,
880                                u32 sw_if_index,
881                                u32 is_create)
882 {
883   clib_error_t * error = 0;
884   subint_config_t *subint;
885   u32 match_flags;
886   u32 unsupported=0;
887
888   // Find the config for this subinterface
889   subint = ethernet_sw_interface_get_config (vnm, sw_if_index, &match_flags, &unsupported);
890
891   if (subint == 0) {
892     // not implemented yet or not ethernet
893     if (unsupported) {
894       // this is the NYI case 
895       error = clib_error_return (0, "not implemented yet");
896     }
897     goto done;
898   }
899
900  if (!is_create) {
901    subint->flags = 0;
902    return error;
903  }
904
905   // Initialize the subint
906   if (subint->flags & SUBINT_CONFIG_VALID) {
907     // Error vlan already in use
908     error = clib_error_return (0, "vlan is already in use");
909   } else {
910     // Note that config is L3 by defaulty
911     subint->flags = SUBINT_CONFIG_VALID | match_flags;
912     subint->sw_if_index = ~0;  // because interfaces are initially down
913   }
914
915  done:
916   return error;
917 }
918
919 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ethernet_sw_interface_add_del);
920
921 static char * ethernet_error_strings[] = {
922 #define ethernet_error(n,c,s) s,
923 #include "error.def"
924 #undef ethernet_error
925 };
926
927 VLIB_REGISTER_NODE (ethernet_input_node) = {
928   .function = ethernet_input,
929   .name = "ethernet-input",
930   /* Takes a vector of packets. */
931   .vector_size = sizeof (u32),
932
933   .n_errors = ETHERNET_N_ERROR,
934   .error_strings = ethernet_error_strings,
935
936   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
937   .next_nodes = {
938 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
939     foreach_ethernet_input_next
940 #undef _
941   },
942
943   .format_buffer = format_ethernet_header_with_length,
944   .format_trace = format_ethernet_input_trace,
945   .unformat_buffer = unformat_ethernet_header,
946 };
947
948 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_node, ethernet_input)
949
950 VLIB_REGISTER_NODE (ethernet_input_type_node,static) = {
951   .function = ethernet_input_type,
952   .name = "ethernet-input-type",
953   /* Takes a vector of packets. */
954   .vector_size = sizeof (u32),
955
956   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
957   .next_nodes = {
958 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
959     foreach_ethernet_input_next
960 #undef _
961   },
962 };
963
964 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_type_node, ethernet_input_type)
965
966 VLIB_REGISTER_NODE (ethernet_input_not_l2_node,static) = {
967   .function = ethernet_input_not_l2,
968   .name = "ethernet-input-not-l2",
969   /* Takes a vector of packets. */
970   .vector_size = sizeof (u32),
971
972   .n_next_nodes = ETHERNET_INPUT_N_NEXT,
973   .next_nodes = {
974 #define _(s,n) [ETHERNET_INPUT_NEXT_##s] = n,
975     foreach_ethernet_input_next
976 #undef _
977   },
978 };
979
980 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_input_not_l2_node, ethernet_input_not_l2)
981
982 void ethernet_set_rx_redirect (vnet_main_t * vnm, 
983                                vnet_hw_interface_t * hi, 
984                                u32 enable)
985 {
986   // Insure all packets go to ethernet-input (i.e. untagged ipv4 packets
987   // don't go directly to ip4-input)
988   vnet_hw_interface_rx_redirect_to_node 
989       (vnm, hi->hw_if_index, enable ? ethernet_input_node.index : ~0);
990 }
991
992
993 /*
994  * Initialization and registration for the next_by_ethernet structure
995  */
996
997 clib_error_t * next_by_ethertype_init (next_by_ethertype_t * l3_next)
998 {
999   l3_next->input_next_by_type = sparse_vec_new
1000     (/* elt bytes */ sizeof (l3_next->input_next_by_type[0]),
1001      /* bits in index */ BITS (((ethernet_header_t *) 0)->type));
1002
1003   vec_validate (l3_next->sparse_index_by_input_next_index, ETHERNET_INPUT_NEXT_DROP);
1004   vec_validate (l3_next->sparse_index_by_input_next_index, ETHERNET_INPUT_NEXT_PUNT);
1005   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_DROP]
1006     = SPARSE_VEC_INVALID_INDEX;
1007   l3_next->sparse_index_by_input_next_index[ETHERNET_INPUT_NEXT_PUNT]
1008     = SPARSE_VEC_INVALID_INDEX;
1009  
1010   /* 
1011    * Make sure we don't wipe out an ethernet registration by mistake 
1012    * Can happen if init function ordering constraints are missing.
1013    */
1014   if (CLIB_DEBUG > 0)
1015     {
1016       ethernet_main_t * em = &ethernet_main;
1017       ASSERT(em->next_by_ethertype_register_called == 0);
1018     }
1019
1020   return 0;
1021 }
1022
1023 // Add an ethertype -> next index mapping to the structure
1024 clib_error_t * next_by_ethertype_register (next_by_ethertype_t * l3_next,
1025                                            u32                   ethertype,
1026                                            u32                   next_index)
1027 {
1028   u32 i;
1029   u16 * n;
1030   ethernet_main_t * em = &ethernet_main;
1031
1032   if (CLIB_DEBUG > 0)
1033     {
1034       ethernet_main_t * em = &ethernet_main;
1035       em->next_by_ethertype_register_called = 1;
1036     }
1037
1038   /* Setup ethernet type -> next index sparse vector mapping. */
1039   n = sparse_vec_validate (l3_next->input_next_by_type, ethertype);
1040   n[0] = next_index;
1041
1042   /* Rebuild next index -> sparse index inverse mapping when sparse vector
1043      is updated. */
1044   vec_validate (l3_next->sparse_index_by_input_next_index, next_index);
1045   for (i = 1; i < vec_len (l3_next->input_next_by_type); i++)
1046     l3_next->sparse_index_by_input_next_index[l3_next->input_next_by_type[i]] = i;
1047
1048   // do not allow the cached next index's to be updated if L3
1049   // redirect is enabled, as it will have overwritten them
1050   if (!em->redirect_l3) {
1051     // Cache common ethertypes directly
1052     if (ethertype == ETHERNET_TYPE_IP4) {
1053       l3_next->input_next_ip4 = next_index;
1054     } else if (ethertype == ETHERNET_TYPE_IP6) {
1055       l3_next->input_next_ip6 = next_index;
1056     } else if (ethertype == ETHERNET_TYPE_MPLS_UNICAST) {
1057       l3_next->input_next_mpls = next_index;
1058     }
1059   }
1060   return 0;
1061 }
1062
1063
1064 static clib_error_t * ethernet_input_init (vlib_main_t * vm)
1065 {
1066   ethernet_main_t * em = &ethernet_main;
1067   __attribute__((unused)) vlan_table_t * invalid_vlan_table;
1068   __attribute__((unused)) qinq_table_t * invalid_qinq_table;
1069
1070   ethernet_setup_node (vm, ethernet_input_node.index);
1071   ethernet_setup_node (vm, ethernet_input_type_node.index);
1072   ethernet_setup_node (vm, ethernet_input_not_l2_node.index);
1073
1074   next_by_ethertype_init (&em->l3_next);
1075  
1076   // Initialize pools and vector for vlan parsing
1077   vec_validate (em->main_intfs, 10);  // 10 main interfaces
1078   pool_alloc(em->vlan_pool, 10);
1079   pool_alloc(em->qinq_pool, 1);
1080
1081   // The first vlan pool will always be reserved for an invalid table
1082   pool_get(em->vlan_pool, invalid_vlan_table); // first id = 0
1083   // The first qinq pool will always be reserved for an invalid table
1084   pool_get(em->qinq_pool, invalid_qinq_table); // first id = 0
1085
1086   return 0;
1087 }
1088
1089 VLIB_INIT_FUNCTION (ethernet_input_init);
1090
1091 void
1092 ethernet_register_input_type (vlib_main_t * vm,
1093                               ethernet_type_t type,
1094                               u32 node_index)
1095 {
1096   ethernet_main_t * em = &ethernet_main;
1097   ethernet_type_info_t * ti;
1098   u32 i;
1099
1100   {
1101     clib_error_t * error = vlib_call_init_function (vm, ethernet_init);
1102     if (error)
1103       clib_error_report (error);
1104   }
1105
1106   ti = ethernet_get_type_info (em, type);
1107   ti->node_index = node_index;
1108   ti->next_index = vlib_node_add_next (vm, 
1109                                        ethernet_input_node.index,
1110                                        node_index);
1111   i = vlib_node_add_next (vm, 
1112                           ethernet_input_type_node.index,
1113                           node_index);
1114   ASSERT (i == ti->next_index);
1115
1116   i = vlib_node_add_next (vm, 
1117                           ethernet_input_not_l2_node.index,
1118                           node_index);
1119   ASSERT (i == ti->next_index);
1120
1121   // Add the L3 node for this ethertype to the next nodes structure
1122   next_by_ethertype_register (&em->l3_next, type, ti->next_index);
1123
1124   // Call the registration functions for other nodes that want a mapping
1125   l2bvi_register_input_type (vm, type, node_index);
1126 }
1127
1128 void
1129 ethernet_register_l2_input (vlib_main_t * vm,
1130                             u32 node_index)
1131 {
1132   ethernet_main_t * em = &ethernet_main;
1133   u32 i;
1134
1135   em->l2_next = vlib_node_add_next (vm, ethernet_input_node.index, node_index);
1136
1137   /* 
1138    * Even if we never use these arcs, we have to align the next indices...
1139    */
1140   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1141
1142   ASSERT (i == em->l2_next);
1143
1144   i = vlib_node_add_next (vm, 
1145                           ethernet_input_not_l2_node.index,
1146                           node_index);
1147   ASSERT (i == em->l2_next);
1148 }
1149
1150 // Register a next node for L3 redirect, and enable L3 redirect
1151 void
1152 ethernet_register_l3_redirect (vlib_main_t * vm,
1153                                u32 node_index)
1154 {
1155   ethernet_main_t * em = &ethernet_main;
1156   u32 i;
1157
1158   em->redirect_l3 = 1;
1159   em->redirect_l3_next = vlib_node_add_next(vm,
1160                                             ethernet_input_node.index,
1161                                             node_index);
1162   /*
1163    * Change the cached next nodes to the redirect node
1164    */
1165   em->l3_next.input_next_ip4 = em->redirect_l3_next;
1166   em->l3_next.input_next_ip6 = em->redirect_l3_next;
1167   em->l3_next.input_next_mpls = em->redirect_l3_next;
1168
1169   /*
1170    * Even if we never use these arcs, we have to align the next indices...
1171    */
1172   i = vlib_node_add_next (vm, ethernet_input_type_node.index, node_index);
1173
1174   ASSERT (i == em->redirect_l3_next);
1175 }