vxlan: multiarch optimization of vxlan
[vpp.git] / src / plugins / l2e / l2e_node.c
1 /*
2  * l2e_node.c : l2 emulation node
3  *
4  * Copyright (c) 2019 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <plugins/l2e/l2e.h>
18 #include <vnet/l2/l2_input.h>
19 #include <vnet/l2/feat_bitmap.h>
20
21 #define foreach_l2_emulation                    \
22   _(IP4, "Extract IPv4")                        \
23   _(IP6, "Extract IPv6")
24
25 typedef enum
26 {
27 #define _(sym,str) L2_EMULATION_ERROR_##sym,
28   foreach_l2_emulation
29 #undef _
30     L2_EMULATION_N_ERROR,
31 } l2_emulation_error_t;
32
33 static char *l2_emulation_error_strings[] = {
34 #define _(sym,string) string,
35   foreach_l2_emulation
36 #undef _
37 };
38
39 typedef enum
40 {
41 #define _(sym,str) L2_EMULATION_NEXT_##sym,
42   foreach_l2_emulation
43 #undef _
44     L2_EMULATION_N_NEXT,
45 } l2_emulation_next_t;
46
47 /* packet trace format function */
48 static u8 *
49 format_l2_emulation_trace (u8 * s, va_list * args)
50 {
51   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53   l2_emulation_trace_t *t = va_arg (*args, l2_emulation_trace_t *);
54
55   s = format (s, "l2-emulation: %s", (t->extracted ? "yes" : "no"));
56
57   return s;
58 }
59
60 VLIB_NODE_FN (l2_emulation_node) (vlib_main_t * vm,
61                                   vlib_node_runtime_t * node,
62                                   vlib_frame_t * frame)
63 {
64   l2_emulation_main_t *em = &l2_emulation_main;
65   u32 n_left_from, *from, *to_next;
66   l2_emulation_next_t next_index;
67   u32 ip4_hits = 0;
68   u32 ip6_hits = 0;
69
70   next_index = 0;
71   n_left_from = frame->n_vectors;
72   from = vlib_frame_vector_args (frame);
73
74   while (n_left_from > 0)
75     {
76       u32 n_left_to_next;
77
78       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
79       while (n_left_from >= 4 && n_left_to_next >= 2)
80         {
81           vlib_buffer_t *b0, *b1;
82           u32 sw_if_index0, sw_if_index1;
83           u16 ether_type0, ether_type1;
84           u32 next0 = ~0, next1 = ~0;
85           u8 l2_len0, l2_len1;
86           u32 bi0, bi1;
87           u8 *h0, *h1;
88
89           bi0 = to_next[0] = from[0];
90           bi1 = to_next[1] = from[1];
91
92           from += 2;
93           n_left_from -= 2;
94           to_next += 2;
95           n_left_to_next -= 2;
96
97           b0 = vlib_get_buffer (vm, bi0);
98           b1 = vlib_get_buffer (vm, bi1);
99           l2_len0 = vnet_buffer (b0)->l2.l2_len;
100           l2_len1 = vnet_buffer (b1)->l2.l2_len;
101
102           h0 = vlib_buffer_get_current (b0);
103           h1 = vlib_buffer_get_current (b1);
104
105           ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
106           ether_type1 = clib_net_to_host_u16 (*(u16 *) (h1 + l2_len1 - 2));
107           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
108           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
109
110           /*
111            * only extract unicast
112            */
113           if (PREDICT_TRUE (!(h0[0] & 0x1)))
114             {
115               switch (ether_type0)
116                 {
117                 case ETHERNET_TYPE_IP4:
118                   ASSERT (em->l2_emulations[sw_if_index0].enabled);
119                   ++ip4_hits;
120                   next0 = L2_EMULATION_NEXT_IP4;
121                   vlib_buffer_advance (b0, l2_len0);
122                   break;
123                 case ETHERNET_TYPE_IP6:
124                   ASSERT (em->l2_emulations[sw_if_index0].enabled);
125                   ++ip6_hits;
126                   next0 = L2_EMULATION_NEXT_IP6;
127                   vlib_buffer_advance (b0, l2_len0);
128                 default:
129                   break;
130                 }
131             }
132           if (PREDICT_TRUE (!(h1[0] & 0x1)))
133             {
134               switch (ether_type1)
135                 {
136                 case ETHERNET_TYPE_IP4:
137                   ASSERT (em->l2_emulations[sw_if_index1].enabled);
138                   ++ip4_hits;
139                   next1 = L2_EMULATION_NEXT_IP4;
140                   vlib_buffer_advance (b1, l2_len1);
141                   break;
142                 case ETHERNET_TYPE_IP6:
143                   ASSERT (em->l2_emulations[sw_if_index1].enabled);
144                   ++ip6_hits;
145                   next1 = L2_EMULATION_NEXT_IP6;
146                   vlib_buffer_advance (b1, l2_len1);
147                 default:
148                   break;
149                 }
150             }
151           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
152                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
153             {
154               l2_emulation_trace_t *t =
155                 vlib_add_trace (vm, node, b0, sizeof (*t));
156               t->extracted = (next0 != ~0);
157             }
158           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
159                              && (b1->flags & VLIB_BUFFER_IS_TRACED)))
160             {
161               l2_emulation_trace_t *t =
162                 vlib_add_trace (vm, node, b1, sizeof (*t));
163               t->extracted = (next1 != ~0);
164             }
165
166           /* Determine the next node and remove ourself from bitmap */
167           if (PREDICT_TRUE (next0 == ~0))
168             next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
169                                           L2INPUT_FEAT_L2_EMULATION);
170
171           /* Determine the next node and remove ourself from bitmap */
172           if (PREDICT_TRUE (next1 == ~0))
173             next1 = vnet_l2_feature_next (b1, em->l2_input_feat_next,
174                                           L2INPUT_FEAT_L2_EMULATION);
175
176           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
177                                            to_next, n_left_to_next,
178                                            bi0, bi1, next0, next1);
179         }
180       while (n_left_from > 0 && n_left_to_next > 0)
181         {
182           vlib_buffer_t *b0;
183           u32 sw_if_index0;
184           u16 ether_type0;
185           u32 next0 = ~0;
186           u8 l2_len0;
187           u32 bi0;
188           u8 *h0;
189
190           bi0 = from[0];
191           to_next[0] = bi0;
192           from += 1;
193           to_next += 1;
194           n_left_from -= 1;
195           n_left_to_next -= 1;
196
197           b0 = vlib_get_buffer (vm, bi0);
198           l2_len0 = vnet_buffer (b0)->l2.l2_len;
199
200           h0 = vlib_buffer_get_current (b0);
201           ether_type0 = clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2));
202           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
203
204           /*
205            * only extract unicast
206            */
207           if (PREDICT_TRUE (!(h0[0] & 0x1)))
208             {
209               switch (ether_type0)
210                 {
211                 case ETHERNET_TYPE_IP4:
212                   ASSERT (em->l2_emulations[sw_if_index0].enabled);
213                   ++ip4_hits;
214                   next0 = L2_EMULATION_NEXT_IP4;
215                   vlib_buffer_advance (b0, l2_len0);
216                   break;
217                 case ETHERNET_TYPE_IP6:
218                   ASSERT (em->l2_emulations[sw_if_index0].enabled);
219                   ++ip6_hits;
220                   next0 = L2_EMULATION_NEXT_IP6;
221                   vlib_buffer_advance (b0, l2_len0);
222                 default:
223                   break;
224                 }
225             }
226
227           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
228                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
229             {
230               l2_emulation_trace_t *t =
231                 vlib_add_trace (vm, node, b0, sizeof (*t));
232               t->extracted = (next0 != ~0);
233             }
234
235           /* Determine the next node and remove ourself from bitmap */
236           if (PREDICT_TRUE (next0 == ~0))
237             next0 = vnet_l2_feature_next (b0, em->l2_input_feat_next,
238                                           L2INPUT_FEAT_L2_EMULATION);
239
240           /* verify speculative enqueue, maybe switch current next frame */
241           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
242                                            to_next, n_left_to_next,
243                                            bi0, next0);
244         }
245
246       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
247     }
248
249   vlib_node_increment_counter (vm, node->node_index,
250                                L2_EMULATION_ERROR_IP4, ip4_hits);
251   vlib_node_increment_counter (vm, node->node_index,
252                                L2_EMULATION_ERROR_IP6, ip6_hits);
253
254   return frame->n_vectors;
255 }
256
257 /* *INDENT-OFF* */
258 VLIB_REGISTER_NODE (l2_emulation_node) = {
259   .name = "l2-emulation",
260   .vector_size = sizeof (u32),
261   .format_trace = format_l2_emulation_trace,
262   .type = VLIB_NODE_TYPE_INTERNAL,
263
264   .n_errors = ARRAY_LEN(l2_emulation_error_strings),
265   .error_strings = l2_emulation_error_strings,
266
267   .n_next_nodes = L2_EMULATION_N_NEXT,
268
269   /* edit / add dispositions here */
270   .next_nodes = {
271     [L2_EMULATION_NEXT_IP4] = "ip4-input",
272     [L2_EMULATION_NEXT_IP6] = "ip6-input",
273   },
274 };
275 /* *INDENT-ON* */
276
277 /*
278  * fd.io coding-style-patch-verification: ON
279  *
280  * Local Variables:
281  * eval: (c-set-style "gnu")
282  * End:
283  */