crypto crypto-openssl: support hashing operations
[vpp.git] / src / plugins / nsh / nsh_node.c
1 /*
2  * nsh_node.c - nsh nodes
3  *
4  * Copyright (c) 2013 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
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <nsh/nsh.h>
21
22 always_inline void
23 nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr,
24                nsh_entry_t * nsh_entry)
25 {
26   nsh_main_t *nm = &nsh_main;
27   nsh_base_header_t *nsh_base;
28   nsh_tlv_header_t *opt0;
29   nsh_tlv_header_t *limit0;
30   nsh_tlv_header_t *nsh_md2;
31   nsh_option_map_t *nsh_option;
32   u8 old_option_size = 0;
33   u8 new_option_size = 0;
34
35   /* Populate the NSH Header */
36   opt0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data);
37   limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len);
38
39   nsh_md2 = (nsh_tlv_header_t *) ((u8 *) hdr /*nsh_entry->rewrite */  +
40                                   sizeof (nsh_base_header_t));
41   nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
42
43   /* Scan the set of variable metadata, process ones that we understand */
44   while (opt0 < limit0)
45     {
46       old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
47       /* round to 4-byte */
48       old_option_size = ((old_option_size + 3) >> 2) << 2;
49
50       nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
51       if (nsh_option == NULL)
52         {
53           goto next_tlv_md2;
54         }
55
56       if (nm->options[nsh_option->option_id])
57         {
58           if ((*nm->options[nsh_option->option_id]) (b, nsh_md2))
59             {
60               goto next_tlv_md2;
61             }
62
63           /* option length may be varied */
64           new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
65           /* round to 4-byte */
66           new_option_size = ((new_option_size + 3) >> 2) << 2;
67           nsh_entry->rewrite_size += new_option_size;
68
69           nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
70           opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
71
72         }
73       else
74         {
75         next_tlv_md2:
76           opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
77         }
78     }
79
80   /* update nsh header's length */
81   nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
82   nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
83     ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
84   return;
85 }
86
87 always_inline void
88 nsh_md2_swap (vlib_buffer_t * b,
89               nsh_base_header_t * hdr,
90               u32 header_len,
91               nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val)
92 {
93   nsh_main_t *nm = &nsh_main;
94   nsh_base_header_t *nsh_base;
95   nsh_tlv_header_t *opt0;
96   nsh_tlv_header_t *limit0;
97   nsh_tlv_header_t *nsh_md2;
98   nsh_option_map_t *nsh_option;
99   u8 old_option_size = 0;
100   u8 new_option_size = 0;
101
102   /* Populate the NSH Header */
103   opt0 = (nsh_md2_data_t *) (hdr + 1);
104   limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
105
106   nsh_md2 =
107     (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t));
108   nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
109
110   /* Scan the set of variable metadata, process ones that we understand */
111   while (opt0 < limit0)
112     {
113       old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
114       /* round to 4-byte */
115       old_option_size = ((old_option_size + 3) >> 2) << 2;
116
117       nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
118       if (nsh_option == NULL)
119         {
120           goto next_tlv_md2;
121         }
122
123       if (nm->swap_options[nsh_option->option_id])
124         {
125           if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2))
126             {
127               goto next_tlv_md2;
128             }
129
130           /* option length may be varied */
131           new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
132           /* round to 4-byte */
133           new_option_size = ((new_option_size + 3) >> 2) << 2;
134           nsh_entry->rewrite_size += new_option_size;
135           nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
136
137           opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
138
139         }
140       else
141         {
142         next_tlv_md2:
143           opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
144         }
145     }
146
147   /* update nsh header's length */
148   nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
149   nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
150     ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
151   return;
152 }
153
154 always_inline void
155 nsh_md2_decap (vlib_buffer_t * b,
156                nsh_base_header_t * hdr,
157                u32 * header_len, u32 * next, u32 drop_node_val)
158 {
159   nsh_main_t *nm = &nsh_main;
160   nsh_md2_data_t *opt0;
161   nsh_md2_data_t *limit0;
162   nsh_option_map_t *nsh_option;
163   u8 option_len = 0;
164
165   /* Populate the NSH Header */
166   opt0 = (nsh_md2_data_t *) (hdr + 1);
167   limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len);
168
169   /* Scan the set of variable metadata, process ones that we understand */
170   while (opt0 < limit0)
171     {
172       nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
173       if (nsh_option == NULL)
174         {
175           *next = drop_node_val;
176           return;
177         }
178
179       if (nm->pop_options[nsh_option->option_id])
180         {
181           if ((*nm->pop_options[nsh_option->option_id]) (b, opt0))
182             {
183               *next = drop_node_val;
184               return;
185             }
186         }
187       /* round to 4-byte */
188       option_len = ((opt0->length + 3) >> 2) << 2;
189       opt0 =
190         (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
191                             option_len);
192       *next =
193         (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next);
194       *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len);
195     }
196
197   return;
198 }
199
200 static uword
201 nsh_input_map (vlib_main_t * vm,
202                vlib_node_runtime_t * node,
203                vlib_frame_t * from_frame, u32 node_type)
204 {
205   u32 n_left_from, next_index, *from, *to_next;
206   nsh_main_t *nm = &nsh_main;
207
208   from = vlib_frame_vector_args (from_frame);
209   n_left_from = from_frame->n_vectors;
210
211   next_index = node->cached_next_index;
212
213   while (n_left_from > 0)
214     {
215       u32 n_left_to_next;
216
217       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
218
219       while (n_left_from >= 4 && n_left_to_next >= 2)
220         {
221           u32 bi0, bi1;
222           vlib_buffer_t *b0, *b1;
223           u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
224           uword *entry0, *entry1;
225           nsh_base_header_t *hdr0 = 0, *hdr1 = 0;
226           u32 header_len0 = 0, header_len1 = 0;
227           u32 nsp_nsi0, nsp_nsi1;
228           u32 ttl0, ttl1;
229           u32 error0, error1;
230           nsh_map_t *map0 = 0, *map1 = 0;
231           nsh_entry_t *nsh_entry0 = 0, *nsh_entry1 = 0;
232           nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
233           u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
234           nsh_proxy_session_by_key_t key0, key1;
235           uword *p0, *p1;
236           nsh_proxy_session_t *proxy0, *proxy1;
237           u32 sw_if_index0 = 0, sw_if_index1 = 0;
238           ethernet_header_t placeholder_eth0, placeholder_eth1;
239
240           /* Prefetch next iteration. */
241           {
242             vlib_buffer_t *p2, *p3;
243
244             p2 = vlib_get_buffer (vm, from[2]);
245             p3 = vlib_get_buffer (vm, from[3]);
246
247             vlib_prefetch_buffer_header (p2, LOAD);
248             vlib_prefetch_buffer_header (p3, LOAD);
249
250             CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
251             CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
252           }
253
254           bi0 = from[0];
255           bi1 = from[1];
256           to_next[0] = bi0;
257           to_next[1] = bi1;
258           from += 2;
259           to_next += 2;
260           n_left_from -= 2;
261           n_left_to_next -= 2;
262
263           error0 = 0;
264           error1 = 0;
265
266           b0 = vlib_get_buffer (vm, bi0);
267           b1 = vlib_get_buffer (vm, bi1);
268           hdr0 = vlib_buffer_get_current (b0);
269           hdr1 = vlib_buffer_get_current (b1);
270
271           /* Process packet 0 */
272           if (node_type == NSH_INPUT_TYPE)
273             {
274               nsp_nsi0 = hdr0->nsp_nsi;
275               header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
276               ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
277                 (hdr0->length & NSH_TTL_L2_MASK) >> 6;
278               ttl0 = ttl0 - 1;
279               if (PREDICT_FALSE (ttl0 == 0))
280                 {
281                   error0 = NSH_NODE_ERROR_INVALID_TTL;
282                   goto trace0;
283                 }
284             }
285           else if (node_type == NSH_CLASSIFIER_TYPE)
286             {
287               nsp_nsi0 =
288                 clib_host_to_net_u32 (vnet_buffer (b0)->
289                                       l2_classify.opaque_index);
290             }
291           else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
292             {
293               /* Push placeholder Eth header */
294               char placeholder_dst_address[6] =
295                 { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
296               char placeholder_src_address[6] =
297                 { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
298               clib_memcpy_fast (placeholder_eth0.dst_address,
299                                 placeholder_dst_address, 6);
300               clib_memcpy_fast (placeholder_eth0.src_address,
301                                 placeholder_src_address, 6);
302               placeholder_eth0.type = 0x0800;
303               vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
304               hdr0 = vlib_buffer_get_current (b0);
305               clib_memcpy_fast (hdr0, &placeholder_eth0,
306                                 (word) sizeof (ethernet_header_t));
307
308               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
309               nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
310             }
311           else
312             {
313               clib_memset (&key0, 0, sizeof (key0));
314               key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
315               key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
316
317               p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
318               if (PREDICT_FALSE (p0 == 0))
319                 {
320                   error0 = NSH_NODE_ERROR_NO_PROXY;
321                   goto trace0;
322                 }
323
324               proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
325               if (PREDICT_FALSE (proxy0 == 0))
326                 {
327                   error0 = NSH_NODE_ERROR_NO_PROXY;
328                   goto trace0;
329                 }
330               nsp_nsi0 = proxy0->nsp_nsi;
331             }
332
333           entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
334           if (PREDICT_FALSE (entry0 == 0))
335             {
336               error0 = NSH_NODE_ERROR_NO_MAPPING;
337               goto trace0;
338             }
339
340           /* Entry should point to a mapping ... */
341           map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
342           if (PREDICT_FALSE (map0 == 0))
343             {
344               error0 = NSH_NODE_ERROR_NO_MAPPING;
345               goto trace0;
346             }
347
348           /* set up things for next node to transmit ie which node to handle it and where */
349           next0 = map0->next_node;
350           vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
351           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
352
353           if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
354             {
355               /* Manipulate MD2 */
356               if (PREDICT_FALSE (hdr0->md_type == 2))
357                 {
358                   nsh_md2_decap (b0, hdr0, &header_len0, &next0,
359                                  NSH_NODE_NEXT_DROP);
360                   if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
361                     {
362                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
363                       goto trace0;
364                     }
365                   vnet_buffer (b0)->sw_if_index[VLIB_RX] =
366                     map0->rx_sw_if_index;
367                 }
368
369               /* Pop NSH header */
370               vlib_buffer_advance (b0, (word) header_len0);
371               goto trace0;
372             }
373
374           entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
375           if (PREDICT_FALSE (entry0 == 0))
376             {
377               error0 = NSH_NODE_ERROR_NO_ENTRY;
378               goto trace0;
379             }
380
381           nsh_entry0 =
382             (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
383           encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
384           /* rewrite_size should equal to (encap_hdr0->length * 4) */
385           encap_hdr_len0 = nsh_entry0->rewrite_size;
386
387           if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
388             {
389               /* Manipulate MD2 */
390               if (PREDICT_FALSE (hdr0->md_type == 2))
391                 {
392                   nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
393                                 &next0, NSH_NODE_NEXT_DROP);
394                   if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
395                     {
396                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
397                       goto trace0;
398                     }
399                 }
400
401               /* Pop old NSH header */
402               vlib_buffer_advance (b0, (word) header_len0);
403
404               /* After processing, md2's length may be varied */
405               encap_hdr_len0 = nsh_entry0->rewrite_size;
406               /* Push new NSH header */
407               vlib_buffer_advance (b0, -(word) encap_hdr_len0);
408               hdr0 = vlib_buffer_get_current (b0);
409               clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0);
410
411               goto trace0;
412             }
413
414           if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
415             {
416               /* After processing, md2's length may be varied */
417               encap_hdr_len0 = nsh_entry0->rewrite_size;
418               /* Push new NSH header */
419               vlib_buffer_advance (b0, -(word) encap_hdr_len0);
420               hdr0 = vlib_buffer_get_current (b0);
421               clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0);
422
423               /* Manipulate MD2 */
424               if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
425                 {
426                   nsh_md2_encap (b0, hdr0, nsh_entry0);
427                 }
428
429             }
430
431         trace0:
432           b0->error = error0 ? node->errors[error0] : 0;
433
434           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
435             {
436               nsh_input_trace_t *tr =
437                 vlib_add_trace (vm, node, b0, sizeof (*tr));
438               clib_memcpy_fast (&(tr->trace_data), hdr0,
439                                 ((hdr0->length & NSH_LEN_MASK) * 4));
440             }
441
442           /* Process packet 1 */
443           if (node_type == NSH_INPUT_TYPE)
444             {
445               nsp_nsi1 = hdr1->nsp_nsi;
446               header_len1 = (hdr1->length & NSH_LEN_MASK) * 4;
447               ttl1 = (hdr1->ver_o_c & NSH_TTL_H4_MASK) << 2 |
448                 (hdr1->length & NSH_TTL_L2_MASK) >> 6;
449               ttl1 = ttl1 - 1;
450               if (PREDICT_FALSE (ttl1 == 0))
451                 {
452                   error1 = NSH_NODE_ERROR_INVALID_TTL;
453                   goto trace1;
454                 }
455             }
456           else if (node_type == NSH_CLASSIFIER_TYPE)
457             {
458               nsp_nsi1 =
459                 clib_host_to_net_u32 (vnet_buffer (b1)->
460                                       l2_classify.opaque_index);
461             }
462           else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
463             {
464               /* Push placeholder Eth header */
465               char placeholder_dst_address[6] =
466                 { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
467               char placeholder_src_address[6] =
468                 { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
469               clib_memcpy_fast (placeholder_eth1.dst_address,
470                                 placeholder_dst_address, 6);
471               clib_memcpy_fast (placeholder_eth1.src_address,
472                                 placeholder_src_address, 6);
473               placeholder_eth1.type = 0x0800;
474               vlib_buffer_advance (b1, -(word) sizeof (ethernet_header_t));
475               hdr1 = vlib_buffer_get_current (b1);
476               clib_memcpy_fast (hdr1, &placeholder_eth1,
477                                 (word) sizeof (ethernet_header_t));
478
479               sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
480               nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1];
481             }
482           else
483             {
484               clib_memset (&key1, 0, sizeof (key1));
485               key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
486               key1.transport_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
487
488               p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1);
489               if (PREDICT_FALSE (p1 == 0))
490                 {
491                   error1 = NSH_NODE_ERROR_NO_PROXY;
492                   goto trace1;
493                 }
494
495               proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]);
496               if (PREDICT_FALSE (proxy1 == 0))
497                 {
498                   error1 = NSH_NODE_ERROR_NO_PROXY;
499                   goto trace1;
500                 }
501               nsp_nsi1 = proxy1->nsp_nsi;
502             }
503
504           entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1);
505           if (PREDICT_FALSE (entry1 == 0))
506             {
507               error1 = NSH_NODE_ERROR_NO_MAPPING;
508               goto trace1;
509             }
510
511           /* Entry should point to a mapping ... */
512           map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]);
513           if (PREDICT_FALSE (map1 == 0))
514             {
515               error1 = NSH_NODE_ERROR_NO_MAPPING;
516               goto trace1;
517             }
518
519           /* set up things for next node to transmit ie which node to handle it and where */
520           next1 = map1->next_node;
521           vnet_buffer (b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
522           vnet_buffer (b1)->ip.adj_index[VLIB_TX] = map1->adj_index;
523
524           if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP))
525             {
526               /* Manipulate MD2 */
527               if (PREDICT_FALSE (hdr1->md_type == 2))
528                 {
529                   nsh_md2_decap (b1, hdr1, &header_len1, &next1,
530                                  NSH_NODE_NEXT_DROP);
531                   if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
532                     {
533                       error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
534                       goto trace1;
535                     }
536                   vnet_buffer (b1)->sw_if_index[VLIB_RX] =
537                     map1->rx_sw_if_index;
538                 }
539
540               /* Pop NSH header */
541               vlib_buffer_advance (b1, (word) header_len1);
542               goto trace1;
543             }
544
545           entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
546           if (PREDICT_FALSE (entry1 == 0))
547             {
548               error1 = NSH_NODE_ERROR_NO_ENTRY;
549               goto trace1;
550             }
551
552           nsh_entry1 =
553             (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry1[0]);
554           encap_hdr1 = (nsh_base_header_t *) (nsh_entry1->rewrite);
555           /* rewrite_size should equal to (encap_hdr0->length * 4) */
556           encap_hdr_len1 = nsh_entry1->rewrite_size;
557
558           if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP))
559             {
560               /* Manipulate MD2 */
561               if (PREDICT_FALSE (hdr1->md_type == 2))
562                 {
563                   nsh_md2_swap (b1, hdr1, header_len1, nsh_entry1,
564                                 &next1, NSH_NODE_NEXT_DROP);
565                   if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
566                     {
567                       error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
568                       goto trace1;
569                     }
570                 }
571
572               /* Pop old NSH header */
573               vlib_buffer_advance (b1, (word) header_len1);
574
575               /* After processing, md2's length may be varied */
576               encap_hdr_len1 = nsh_entry1->rewrite_size;
577               /* Push new NSH header */
578               vlib_buffer_advance (b1, -(word) encap_hdr_len1);
579               hdr1 = vlib_buffer_get_current (b1);
580               clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1);
581
582               goto trace1;
583             }
584
585           if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH))
586             {
587               /* After processing, md2's length may be varied */
588               encap_hdr_len1 = nsh_entry1->rewrite_size;
589               /* Push new NSH header */
590               vlib_buffer_advance (b1, -(word) encap_hdr_len1);
591               hdr1 = vlib_buffer_get_current (b1);
592               clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1);
593
594               /* Manipulate MD2 */
595               if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2))
596                 {
597                   nsh_md2_encap (b1, hdr1, nsh_entry1);
598                 }
599
600             }
601
602         trace1:
603           b1->error = error1 ? node->errors[error1] : 0;
604
605           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
606             {
607               nsh_input_trace_t *tr =
608                 vlib_add_trace (vm, node, b1, sizeof (*tr));
609               clib_memcpy_fast (&(tr->trace_data), hdr1,
610                                 ((hdr1->length & NSH_LEN_MASK) * 4));
611             }
612
613           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
614                                            n_left_to_next, bi0, bi1, next0,
615                                            next1);
616
617         }
618
619       while (n_left_from > 0 && n_left_to_next > 0)
620         {
621           u32 bi0 = 0;
622           vlib_buffer_t *b0 = NULL;
623           u32 next0 = NSH_NODE_NEXT_DROP;
624           uword *entry0;
625           nsh_base_header_t *hdr0 = 0;
626           u32 header_len0 = 0;
627           u32 nsp_nsi0;
628           u32 ttl0;
629           u32 error0;
630           nsh_map_t *map0 = 0;
631           nsh_entry_t *nsh_entry0 = 0;
632           nsh_base_header_t *encap_hdr0 = 0;
633           u32 encap_hdr_len0 = 0;
634           nsh_proxy_session_by_key_t key0;
635           uword *p0;
636           nsh_proxy_session_t *proxy0 = 0;
637           u32 sw_if_index0 = 0;
638           ethernet_header_t placeholder_eth0;
639
640           bi0 = from[0];
641           to_next[0] = bi0;
642           from += 1;
643           to_next += 1;
644           n_left_from -= 1;
645           n_left_to_next -= 1;
646           error0 = 0;
647
648           b0 = vlib_get_buffer (vm, bi0);
649           hdr0 = vlib_buffer_get_current (b0);
650
651           if (node_type == NSH_INPUT_TYPE)
652             {
653               nsp_nsi0 = hdr0->nsp_nsi;
654               header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
655               ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
656                 (hdr0->length & NSH_TTL_L2_MASK) >> 6;
657               ttl0 = ttl0 - 1;
658               if (PREDICT_FALSE (ttl0 == 0))
659                 {
660                   error0 = NSH_NODE_ERROR_INVALID_TTL;
661                   goto trace00;
662                 }
663             }
664           else if (node_type == NSH_CLASSIFIER_TYPE)
665             {
666               nsp_nsi0 =
667                 clib_host_to_net_u32 (vnet_buffer (b0)->
668                                       l2_classify.opaque_index);
669             }
670           else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
671             {
672               /* Push placeholder Eth header */
673               char placeholder_dst_address[6] =
674                 { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
675               char placeholder_src_address[6] =
676                 { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
677               clib_memcpy_fast (placeholder_eth0.dst_address,
678                                 placeholder_dst_address, 6);
679               clib_memcpy_fast (placeholder_eth0.src_address,
680                                 placeholder_src_address, 6);
681               placeholder_eth0.type = 0x0800;
682               vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
683               hdr0 = vlib_buffer_get_current (b0);
684               clib_memcpy_fast (hdr0, &placeholder_eth0,
685                                 (word) sizeof (ethernet_header_t));
686
687               sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
688               nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
689             }
690           else
691             {
692               clib_memset (&key0, 0, sizeof (key0));
693               key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
694               key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
695
696               p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
697               if (PREDICT_FALSE (p0 == 0))
698                 {
699                   error0 = NSH_NODE_ERROR_NO_PROXY;
700                   goto trace00;
701                 }
702
703               proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
704               if (PREDICT_FALSE (proxy0 == 0))
705                 {
706                   error0 = NSH_NODE_ERROR_NO_PROXY;
707                   goto trace00;
708                 }
709               nsp_nsi0 = proxy0->nsp_nsi;
710             }
711
712           entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
713
714           if (PREDICT_FALSE (entry0 == 0))
715             {
716               error0 = NSH_NODE_ERROR_NO_MAPPING;
717               goto trace00;
718             }
719
720           /* Entry should point to a mapping ... */
721           map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
722
723           if (PREDICT_FALSE (map0 == 0))
724             {
725               error0 = NSH_NODE_ERROR_NO_MAPPING;
726               goto trace00;
727             }
728
729           /* set up things for next node to transmit ie which node to handle it and where */
730           next0 = map0->next_node;
731           vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
732           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
733           vnet_buffer (b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if;
734
735           if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
736             {
737               /* Manipulate MD2 */
738               if (PREDICT_FALSE (hdr0->md_type == 2))
739                 {
740                   nsh_md2_decap (b0, hdr0, &header_len0, &next0,
741                                  NSH_NODE_NEXT_DROP);
742                   if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
743                     {
744                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
745                       goto trace00;
746                     }
747                   vnet_buffer (b0)->sw_if_index[VLIB_RX] =
748                     map0->rx_sw_if_index;
749                 }
750
751               /* Pop NSH header */
752               vlib_buffer_advance (b0, (word) header_len0);
753               goto trace00;
754             }
755
756           entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
757           if (PREDICT_FALSE (entry0 == 0))
758             {
759               error0 = NSH_NODE_ERROR_NO_ENTRY;
760               goto trace00;
761             }
762
763           nsh_entry0 =
764             (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
765           encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
766           /* rewrite_size should equal to (encap_hdr0->length * 4) */
767           encap_hdr_len0 = nsh_entry0->rewrite_size;
768
769           if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
770             {
771               /* Manipulate MD2 */
772               if (PREDICT_FALSE (hdr0->md_type == 2))
773                 {
774                   nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
775                                 &next0, NSH_NODE_NEXT_DROP);
776                   if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
777                     {
778                       error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
779                       goto trace00;
780                     }
781                 }
782
783               /* Pop old NSH header */
784               vlib_buffer_advance (b0, (word) header_len0);
785
786               /* After processing, md2's length may be varied */
787               encap_hdr_len0 = nsh_entry0->rewrite_size;
788               /* Push new NSH header */
789               vlib_buffer_advance (b0, -(word) encap_hdr_len0);
790               hdr0 = vlib_buffer_get_current (b0);
791               clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0);
792
793               goto trace00;
794             }
795
796           if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
797             {
798               /* After processing, md2's length may be varied */
799               encap_hdr_len0 = nsh_entry0->rewrite_size;
800               /* Push new NSH header */
801               vlib_buffer_advance (b0, -(word) encap_hdr_len0);
802               hdr0 = vlib_buffer_get_current (b0);
803               clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0);
804               /* Manipulate MD2 */
805               if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
806                 {
807                   nsh_md2_encap (b0, hdr0, nsh_entry0);
808                 }
809
810             }
811
812         trace00:b0->error = error0 ? node->errors[error0] : 0;
813
814           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
815             {
816               nsh_input_trace_t *tr =
817                 vlib_add_trace (vm, node, b0, sizeof (*tr));
818               clib_memcpy_fast (&(tr->trace_data[0]), hdr0,
819                                 ((hdr0->length & NSH_LEN_MASK) * 4));
820             }
821
822           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
823                                            n_left_to_next, bi0, next0);
824         }
825
826       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
827
828     }
829
830   return from_frame->n_vectors;
831 }
832
833 /**
834  * @brief Graph processing dispatch function for NSH Input
835  *
836  * @node nsh_input
837  * @param *vm
838  * @param *node
839  * @param *from_frame
840  *
841  * @return from_frame->n_vectors
842  *
843  */
844 VLIB_NODE_FN (nsh_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
845                                vlib_frame_t * from_frame)
846 {
847   return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
848 }
849
850 /**
851  * @brief Graph processing dispatch function for NSH-Proxy
852  *
853  * @node nsh_proxy
854  * @param *vm
855  * @param *node
856  * @param *from_frame
857  *
858  * @return from_frame->n_vectors
859  *
860  */
861 VLIB_NODE_FN (nsh_proxy_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
862                                vlib_frame_t * from_frame)
863 {
864   return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
865 }
866
867 /**
868  * @brief Graph processing dispatch function for NSH Classifier
869  *
870  * @node nsh_classifier
871  * @param *vm
872  * @param *node
873  * @param *from_frame
874  *
875  * @return from_frame->n_vectors
876  *
877  */
878 VLIB_NODE_FN (nsh_classifier_node) (vlib_main_t * vm,
879                                     vlib_node_runtime_t * node,
880                                     vlib_frame_t * from_frame)
881 {
882   return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
883 }
884
885 /**
886  * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY
887  *
888  * @node nsh_aware_vnf_proxy
889  * @param *vm
890  * @param *node
891  * @param *from_frame
892  *
893  * @return from_frame->n_vectors
894  *
895  */
896 VLIB_NODE_FN (nsh_aware_vnf_proxy_node) (vlib_main_t * vm,
897                                          vlib_node_runtime_t * node,
898                                          vlib_frame_t * from_frame)
899 {
900   return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE);
901 }
902
903 static char *nsh_node_error_strings[] = {
904 #define _(sym,string) string,
905   foreach_nsh_node_error
906 #undef _
907 };
908
909 /* *INDENT-OFF* */
910
911 /* register nsh-input node */
912 VLIB_REGISTER_NODE (nsh_input_node) = {
913   .name = "nsh-input",
914   .vector_size = sizeof (u32),
915   .format_trace = format_nsh_node_map_trace,
916   .format_buffer = format_nsh_header,
917   .type = VLIB_NODE_TYPE_INTERNAL,
918   .n_errors = ARRAY_LEN (nsh_node_error_strings),
919   .error_strings = nsh_node_error_strings,
920   .n_next_nodes = NSH_NODE_N_NEXT,
921   .next_nodes = {
922 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
923     foreach_nsh_node_next
924 #undef _
925   },
926 };
927
928 /* register nsh-proxy node */
929 VLIB_REGISTER_NODE (nsh_proxy_node) =
930 {
931   .name = "nsh-proxy",
932   .vector_size = sizeof (u32),
933   .format_trace = format_nsh_node_map_trace,
934   .format_buffer = format_nsh_header,
935   .type = VLIB_NODE_TYPE_INTERNAL,
936   .n_errors = ARRAY_LEN (nsh_node_error_strings),
937   .error_strings = nsh_node_error_strings,
938   .n_next_nodes = NSH_NODE_N_NEXT,
939   .next_nodes = {
940 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
941     foreach_nsh_node_next
942 #undef _
943   },
944 };
945
946 /* register nsh-classifier node */
947 VLIB_REGISTER_NODE (nsh_classifier_node) =
948 {
949   .name = "nsh-classifier",
950   .vector_size = sizeof (u32),
951   .format_trace = format_nsh_node_map_trace,
952   .format_buffer = format_nsh_header,
953   .type = VLIB_NODE_TYPE_INTERNAL,
954   .n_errors = ARRAY_LEN (nsh_node_error_strings),
955   .error_strings = nsh_node_error_strings,
956   .n_next_nodes = NSH_NODE_N_NEXT,
957   .next_nodes = {
958 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
959     foreach_nsh_node_next
960 #undef _
961   },
962 };
963
964 /* register nsh-aware-vnf-proxy node */
965 VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) =
966 {
967   .name = "nsh-aware-vnf-proxy",
968   .vector_size = sizeof (u32),
969   .format_trace = format_nsh_node_map_trace,
970   .format_buffer = format_nsh_header,
971   .type = VLIB_NODE_TYPE_INTERNAL,
972   .n_errors = ARRAY_LEN (nsh_node_error_strings),
973   .error_strings = nsh_node_error_strings,
974   .n_next_nodes = NSH_NODE_N_NEXT,
975   .next_nodes = {
976 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
977     foreach_nsh_node_next
978 #undef _
979   },
980 };
981 /* *INDENT-ON* */
982
983 /*
984  * fd.io coding-style-patch-verification: ON
985  *
986  * Local Variables:
987  * eval: (c-set-style "gnu")
988  * End:
989  */