d243a45cd417120320ab5284115946ad1b15bbdb
[vpp.git] / src / plugins / map / ip4_map_t.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 #include "map.h"
16
17 #include <vnet/ip/ip_frag.h>
18 #include <vnet/ip/ip4_to_ip6.h>
19
20 typedef enum
21 {
22   IP4_MAPT_NEXT_MAPT_TCP_UDP,
23   IP4_MAPT_NEXT_MAPT_ICMP,
24   IP4_MAPT_NEXT_MAPT_FRAGMENTED,
25   IP4_MAPT_NEXT_ICMP_ERROR,
26   IP4_MAPT_NEXT_DROP,
27   IP4_MAPT_N_NEXT
28 } ip4_mapt_next_t;
29
30 typedef enum
31 {
32   IP4_MAPT_ICMP_NEXT_IP6_LOOKUP,
33   IP4_MAPT_ICMP_NEXT_IP6_FRAG,
34   IP4_MAPT_ICMP_NEXT_DROP,
35   IP4_MAPT_ICMP_N_NEXT
36 } ip4_mapt_icmp_next_t;
37
38 typedef enum
39 {
40   IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP,
41   IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG,
42   IP4_MAPT_TCP_UDP_NEXT_DROP,
43   IP4_MAPT_TCP_UDP_N_NEXT
44 } ip4_mapt_tcp_udp_next_t;
45
46 typedef enum
47 {
48   IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP,
49   IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG,
50   IP4_MAPT_FRAGMENTED_NEXT_DROP,
51   IP4_MAPT_FRAGMENTED_N_NEXT
52 } ip4_mapt_fragmented_next_t;
53
54 //This is used to pass information within the buffer data.
55 //Buffer structure being too small to contain big structures like this.
56 /* *INDENT-OFF* */
57 typedef CLIB_PACKED (struct {
58   ip6_address_t daddr;
59   ip6_address_t saddr;
60   //IPv6 header + Fragmentation header will be here
61   //sizeof(ip6) + sizeof(ip_frag) - sizeof(ip4)
62   u8 unused[28];
63 }) ip4_mapt_pseudo_header_t;
64 /* *INDENT-ON* */
65
66 typedef struct
67 {
68   map_domain_t *d;
69   u16 recv_port;
70 } icmp_to_icmp6_ctx_t;
71
72 static int
73 ip4_to_ip6_set_icmp_cb (vlib_buffer_t * b, ip4_header_t * ip4,
74                         ip6_header_t * ip6, void *arg)
75 {
76   icmp_to_icmp6_ctx_t *ctx = arg;
77
78   ip4_map_t_embedded_address (ctx->d, &ip6->src_address, &ip4->src_address);
79   ip6->dst_address.as_u64[0] =
80     map_get_pfx_net (ctx->d, ip4->dst_address.as_u32, ctx->recv_port);
81   ip6->dst_address.as_u64[1] =
82     map_get_sfx_net (ctx->d, ip4->dst_address.as_u32, ctx->recv_port);
83
84   return 0;
85 }
86
87 static int
88 ip4_to_ip6_set_inner_icmp_cb (vlib_buffer_t * b, ip4_header_t * ip4,
89                               ip6_header_t * ip6, void *arg)
90 {
91   icmp_to_icmp6_ctx_t *ctx = arg;
92
93   //Note that the source address is within the domain
94   //while the destination address is the one outside the domain
95   ip4_map_t_embedded_address (ctx->d, &ip6->dst_address, &ip4->dst_address);
96   ip6->src_address.as_u64[0] =
97     map_get_pfx_net (ctx->d, ip4->src_address.as_u32, ctx->recv_port);
98   ip6->src_address.as_u64[1] =
99     map_get_sfx_net (ctx->d, ip4->src_address.as_u32, ctx->recv_port);
100
101   return 0;
102 }
103
104 static uword
105 ip4_map_t_icmp (vlib_main_t * vm,
106                 vlib_node_runtime_t * node, vlib_frame_t * frame)
107 {
108   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
109   vlib_node_runtime_t *error_node =
110     vlib_node_get_runtime (vm, ip4_map_t_icmp_node.index);
111   from = vlib_frame_vector_args (frame);
112   n_left_from = frame->n_vectors;
113   next_index = node->cached_next_index;
114   vlib_combined_counter_main_t *cm = map_main.domain_counters;
115   u32 thread_index = vm->thread_index;
116
117   while (n_left_from > 0)
118     {
119       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
120
121       while (n_left_from > 0 && n_left_to_next > 0)
122         {
123           u32 pi0;
124           vlib_buffer_t *p0;
125           ip4_mapt_icmp_next_t next0;
126           u8 error0;
127           map_domain_t *d0;
128           u16 len0;
129           icmp_to_icmp6_ctx_t ctx0;
130           ip4_header_t *ip40;
131
132           next0 = IP4_MAPT_ICMP_NEXT_IP6_LOOKUP;
133           pi0 = to_next[0] = from[0];
134           from += 1;
135           n_left_from -= 1;
136           to_next += 1;
137           n_left_to_next -= 1;
138           error0 = MAP_ERROR_NONE;
139
140           p0 = vlib_get_buffer (vm, pi0);
141           vlib_buffer_advance (p0, sizeof (ip4_mapt_pseudo_header_t));  //The pseudo-header is not used
142           len0 =
143             clib_net_to_host_u16 (((ip4_header_t *)
144                                    vlib_buffer_get_current (p0))->length);
145           d0 =
146             pool_elt_at_index (map_main.domains,
147                                vnet_buffer (p0)->map_t.map_domain_index);
148
149           ip40 = vlib_buffer_get_current (p0);
150           ctx0.recv_port = ip4_get_port (ip40, 1);
151           ctx0.d = d0;
152           if (ctx0.recv_port == 0)
153             {
154               // In case of 1:1 mapping, we don't care about the port
155               if (!(d0->ea_bits_len == 0 && d0->rules))
156                 {
157                   error0 = MAP_ERROR_ICMP;
158                   goto err0;
159                 }
160             }
161
162           if (icmp_to_icmp6
163               (p0, ip4_to_ip6_set_icmp_cb, &ctx0,
164                ip4_to_ip6_set_inner_icmp_cb, &ctx0))
165             {
166               error0 = MAP_ERROR_ICMP;
167               goto err0;
168             }
169
170           if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
171             {
172               vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
173               vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP6_LOOKUP;
174               next0 = IP4_MAPT_ICMP_NEXT_IP6_FRAG;
175             }
176         err0:
177           if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
178             {
179               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
180                                                thread_index,
181                                                vnet_buffer (p0)->
182                                                map_t.map_domain_index, 1,
183                                                len0);
184             }
185           else
186             {
187               next0 = IP4_MAPT_ICMP_NEXT_DROP;
188             }
189           p0->error = error_node->errors[error0];
190           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
191                                            to_next, n_left_to_next, pi0,
192                                            next0);
193         }
194       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
195     }
196   return frame->n_vectors;
197 }
198
199 /*
200  * Translate fragmented IPv4 UDP/TCP packet to IPv6.
201  */
202 always_inline int
203 map_ip4_to_ip6_fragmented (vlib_buffer_t * p,
204                            ip4_mapt_pseudo_header_t * pheader)
205 {
206   ip4_header_t *ip4;
207   ip6_header_t *ip6;
208   ip6_frag_hdr_t *frag;
209
210   ip4 = vlib_buffer_get_current (p);
211   frag = (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
212   ip6 =
213     (ip6_header_t *) u8_ptr_add (ip4,
214                                  sizeof (*ip4) - sizeof (*frag) -
215                                  sizeof (*ip6));
216   vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
217
218   //We know that the protocol was one of ICMP, TCP or UDP
219   //because the first fragment was found and cached
220   frag->next_hdr =
221     (ip4->protocol == IP_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP6 : ip4->protocol;
222   frag->identification = frag_id_4to6 (ip4->fragment_id);
223   frag->rsv = 0;
224   frag->fragment_offset_and_more =
225     ip6_frag_hdr_offset_and_more (ip4_get_fragment_offset (ip4),
226                                   clib_net_to_host_u16
227                                   (ip4->flags_and_fragment_offset) &
228                                   IP4_HEADER_FLAG_MORE_FRAGMENTS);
229
230   ip6->ip_version_traffic_class_and_flow_label =
231     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
232   ip6->payload_length =
233     clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
234                           sizeof (*ip4) + sizeof (*frag));
235   ip6->hop_limit = ip4->ttl;
236   ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
237
238   ip6->dst_address.as_u64[0] = pheader->daddr.as_u64[0];
239   ip6->dst_address.as_u64[1] = pheader->daddr.as_u64[1];
240   ip6->src_address.as_u64[0] = pheader->saddr.as_u64[0];
241   ip6->src_address.as_u64[1] = pheader->saddr.as_u64[1];
242
243   return 0;
244 }
245
246 static uword
247 ip4_map_t_fragmented (vlib_main_t * vm,
248                       vlib_node_runtime_t * node, vlib_frame_t * frame)
249 {
250   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
251   from = vlib_frame_vector_args (frame);
252   n_left_from = frame->n_vectors;
253   next_index = node->cached_next_index;
254   vlib_node_runtime_t *error_node =
255     vlib_node_get_runtime (vm, ip4_map_t_fragmented_node.index);
256
257   while (n_left_from > 0)
258     {
259       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
260
261       while (n_left_from > 0 && n_left_to_next > 0)
262         {
263           u32 pi0;
264           vlib_buffer_t *p0;
265           ip4_mapt_pseudo_header_t *pheader0;
266           ip4_mapt_fragmented_next_t next0;
267
268           next0 = IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP;
269           pi0 = to_next[0] = from[0];
270           from += 1;
271           n_left_from -= 1;
272           to_next += 1;
273           n_left_to_next -= 1;
274
275           p0 = vlib_get_buffer (vm, pi0);
276
277           //Accessing pseudo header
278           pheader0 = vlib_buffer_get_current (p0);
279           vlib_buffer_advance (p0, sizeof (*pheader0));
280
281           if (map_ip4_to_ip6_fragmented (p0, pheader0))
282             {
283               p0->error = error_node->errors[MAP_ERROR_FRAGMENT_DROPPED];
284               next0 = IP4_MAPT_FRAGMENTED_NEXT_DROP;
285             }
286           else
287             {
288               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
289                 {
290                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
291                   vnet_buffer (p0)->ip_frag.next_index =
292                     IP_FRAG_NEXT_IP6_LOOKUP;
293                   next0 = IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG;
294                 }
295             }
296
297           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
298                                            to_next, n_left_to_next, pi0,
299                                            next0);
300         }
301       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
302     }
303   return frame->n_vectors;
304 }
305
306 /*
307  * Translate IPv4 UDP/TCP packet to IPv6.
308  */
309 always_inline int
310 map_ip4_to_ip6_tcp_udp (vlib_buffer_t * p, ip4_mapt_pseudo_header_t * pheader)
311 {
312   map_main_t *mm = &map_main;
313   ip4_header_t *ip4;
314   ip6_header_t *ip6;
315   ip_csum_t csum;
316   u16 *checksum;
317   ip6_frag_hdr_t *frag;
318   u32 frag_id;
319   ip4_address_t old_src, old_dst;
320
321   ip4 = vlib_buffer_get_current (p);
322
323   if (ip4->protocol == IP_PROTOCOL_UDP)
324     {
325       udp_header_t *udp = ip4_next_header (ip4);
326       checksum = &udp->checksum;
327
328       /*
329        * UDP checksum is optional over IPv4 but mandatory for IPv6 We
330        * do not check udp->length sanity but use our safe computed
331        * value instead
332        */
333       if (PREDICT_FALSE (!*checksum))
334         {
335           u16 udp_len = clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
336           csum = ip_incremental_checksum (0, udp, udp_len);
337           csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
338           csum =
339             ip_csum_with_carry (csum, clib_host_to_net_u16 (IP_PROTOCOL_UDP));
340           csum = ip_csum_with_carry (csum, *((u64 *) (&ip4->src_address)));
341           *checksum = ~ip_csum_fold (csum);
342         }
343     }
344   else
345     {
346       tcp_header_t *tcp = ip4_next_header (ip4);
347       if (mm->tcp_mss > 0)
348         {
349           csum = tcp->checksum;
350           map_mss_clamping (tcp, &csum, mm->tcp_mss);
351           tcp->checksum = ip_csum_fold (csum);
352         }
353       checksum = &tcp->checksum;
354     }
355
356   old_src.as_u32 = ip4->src_address.as_u32;
357   old_dst.as_u32 = ip4->dst_address.as_u32;
358
359   /* Deal with fragmented packets */
360   if (PREDICT_FALSE (ip4->flags_and_fragment_offset &
361                      clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS)))
362     {
363       ip6 =
364         (ip6_header_t *) u8_ptr_add (ip4,
365                                      sizeof (*ip4) - sizeof (*ip6) -
366                                      sizeof (*frag));
367       frag =
368         (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
369       frag_id = frag_id_4to6 (ip4->fragment_id);
370       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
371     }
372   else
373     {
374       ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
375       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
376       frag = NULL;
377     }
378
379   ip6->ip_version_traffic_class_and_flow_label =
380     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
381   ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
382   ip6->hop_limit = ip4->ttl;
383   ip6->protocol = ip4->protocol;
384   if (PREDICT_FALSE (frag != NULL))
385     {
386       frag->next_hdr = ip6->protocol;
387       frag->identification = frag_id;
388       frag->rsv = 0;
389       frag->fragment_offset_and_more = ip6_frag_hdr_offset_and_more (0, 1);
390       ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
391       ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
392     }
393
394   ip6->dst_address.as_u64[0] = pheader->daddr.as_u64[0];
395   ip6->dst_address.as_u64[1] = pheader->daddr.as_u64[1];
396   ip6->src_address.as_u64[0] = pheader->saddr.as_u64[0];
397   ip6->src_address.as_u64[1] = pheader->saddr.as_u64[1];
398
399   csum = ip_csum_sub_even (*checksum, old_src.as_u32);
400   csum = ip_csum_sub_even (csum, old_dst.as_u32);
401   csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
402   csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
403   csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
404   csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
405   *checksum = ip_csum_fold (csum);
406
407   return 0;
408 }
409
410 static uword
411 ip4_map_t_tcp_udp (vlib_main_t * vm,
412                    vlib_node_runtime_t * node, vlib_frame_t * frame)
413 {
414   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
415   from = vlib_frame_vector_args (frame);
416   n_left_from = frame->n_vectors;
417   next_index = node->cached_next_index;
418   vlib_node_runtime_t *error_node =
419     vlib_node_get_runtime (vm, ip4_map_t_tcp_udp_node.index);
420
421
422   while (n_left_from > 0)
423     {
424       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
425
426       while (n_left_from > 0 && n_left_to_next > 0)
427         {
428           u32 pi0;
429           vlib_buffer_t *p0;
430           ip4_mapt_pseudo_header_t *pheader0;
431           ip4_mapt_tcp_udp_next_t next0;
432
433           pi0 = to_next[0] = from[0];
434           from += 1;
435           n_left_from -= 1;
436           to_next += 1;
437           n_left_to_next -= 1;
438
439           next0 = IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP;
440           p0 = vlib_get_buffer (vm, pi0);
441
442           //Accessing pseudo header
443           pheader0 = vlib_buffer_get_current (p0);
444           vlib_buffer_advance (p0, sizeof (*pheader0));
445
446           if (map_ip4_to_ip6_tcp_udp (p0, pheader0))
447             {
448               p0->error = error_node->errors[MAP_ERROR_UNKNOWN];
449               next0 = IP4_MAPT_TCP_UDP_NEXT_DROP;
450             }
451           else
452             {
453               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
454                 {
455                   //Send to fragmentation node if necessary
456                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
457                   vnet_buffer (p0)->ip_frag.next_index =
458                     IP_FRAG_NEXT_IP6_LOOKUP;
459                   next0 = IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG;
460                 }
461             }
462           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
463                                            to_next, n_left_to_next, pi0,
464                                            next0);
465         }
466       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
467     }
468
469   return frame->n_vectors;
470 }
471
472 static_always_inline void
473 ip4_map_t_classify (vlib_buffer_t * p0, map_domain_t * d0,
474                     ip4_header_t * ip40, u16 ip4_len0, i32 * dst_port0,
475                     u8 * error0, ip4_mapt_next_t * next0, u16 l4_dst_port)
476 {
477   if (PREDICT_FALSE (ip4_get_fragment_offset (ip40)))
478     {
479       *next0 = IP4_MAPT_NEXT_MAPT_FRAGMENTED;
480       if (d0->ea_bits_len == 0 && d0->rules)
481         {
482           *dst_port0 = 0;
483         }
484       else
485         {
486           *dst_port0 = l4_dst_port;
487           *error0 = (*dst_port0 == -1) ? MAP_ERROR_FRAGMENT_MEMORY : *error0;
488         }
489     }
490   else if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_TCP))
491     {
492       vnet_buffer (p0)->map_t.checksum_offset = 36;
493       *next0 = IP4_MAPT_NEXT_MAPT_TCP_UDP;
494       *error0 = ip4_len0 < 40 ? MAP_ERROR_MALFORMED : *error0;
495       *dst_port0 = l4_dst_port;
496     }
497   else if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_UDP))
498     {
499       vnet_buffer (p0)->map_t.checksum_offset = 26;
500       *next0 = IP4_MAPT_NEXT_MAPT_TCP_UDP;
501       *error0 = ip4_len0 < 28 ? MAP_ERROR_MALFORMED : *error0;
502       *dst_port0 = l4_dst_port;
503     }
504   else if (ip40->protocol == IP_PROTOCOL_ICMP)
505     {
506       *next0 = IP4_MAPT_NEXT_MAPT_ICMP;
507       if (d0->ea_bits_len == 0 && d0->rules)
508         *dst_port0 = 0;
509       else if (((icmp46_header_t *) u8_ptr_add (ip40, sizeof (*ip40)))->code
510                == ICMP4_echo_reply
511                || ((icmp46_header_t *)
512                    u8_ptr_add (ip40,
513                                sizeof (*ip40)))->code == ICMP4_echo_request)
514         *dst_port0 = l4_dst_port;
515     }
516   else
517     {
518       *error0 = MAP_ERROR_BAD_PROTOCOL;
519     }
520 }
521
522 static uword
523 ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
524 {
525   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
526   vlib_node_runtime_t *error_node =
527     vlib_node_get_runtime (vm, ip4_map_t_node.index);
528   from = vlib_frame_vector_args (frame);
529   n_left_from = frame->n_vectors;
530   next_index = node->cached_next_index;
531   vlib_combined_counter_main_t *cm = map_main.domain_counters;
532   u32 thread_index = vm->thread_index;
533
534   while (n_left_from > 0)
535     {
536       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
537
538       while (n_left_from > 0 && n_left_to_next > 0)
539         {
540           u32 pi0;
541           vlib_buffer_t *p0;
542           ip4_header_t *ip40;
543           map_domain_t *d0;
544           ip4_mapt_next_t next0 = 0;
545           u16 ip4_len0;
546           u8 error0;
547           i32 dst_port0;
548           ip4_mapt_pseudo_header_t *pheader0;
549
550           pi0 = to_next[0] = from[0];
551           from += 1;
552           n_left_from -= 1;
553           to_next += 1;
554           n_left_to_next -= 1;
555           error0 = MAP_ERROR_NONE;
556
557           p0 = vlib_get_buffer (vm, pi0);
558
559           u16 l4_dst_port = vnet_buffer (p0)->ip.reass.l4_dst_port;
560
561           ip40 = vlib_buffer_get_current (p0);
562           ip4_len0 = clib_host_to_net_u16 (ip40->length);
563           if (PREDICT_FALSE (p0->current_length < ip4_len0 ||
564                              ip40->ip_version_and_header_length != 0x45))
565             {
566               error0 = MAP_ERROR_UNKNOWN;
567             }
568
569           d0 = ip4_map_get_domain (&ip40->dst_address,
570                                    &vnet_buffer (p0)->map_t.map_domain_index,
571                                    &error0);
572
573           if (!d0)
574             {                   /* Guess it wasn't for us */
575               vnet_feature_next (&next0, p0);
576               goto exit;
577             }
578
579           dst_port0 = -1;
580
581           bool df0 =
582             ip40->flags_and_fragment_offset &
583             clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
584
585           vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
586
587           if (PREDICT_FALSE
588               (df0 && !map_main.frag_ignore_df
589                &&
590                ((ip4_len0 +
591                  (sizeof (ip6_header_t) - sizeof (ip4_header_t))) >
592                 vnet_buffer (p0)->map_t.mtu)))
593             {
594               icmp4_error_set_vnet_buffer (p0, ICMP4_destination_unreachable,
595                                            ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
596                                            vnet_buffer (p0)->map_t.mtu -
597                                            (sizeof (ip6_header_t) -
598                                             sizeof (ip4_header_t)));
599               p0->error = error_node->errors[MAP_ERROR_DF_SET];
600               next0 = IP4_MAPT_NEXT_ICMP_ERROR;
601               goto trace;
602             }
603
604           ip4_map_t_classify (p0, d0, ip40, ip4_len0, &dst_port0, &error0,
605                               &next0, l4_dst_port);
606
607           /* Verify that port is not among the well-known ports */
608           if ((d0->psid_length > 0 && d0->psid_offset > 0)
609               && (clib_net_to_host_u16 (dst_port0) <
610                   (0x1 << (16 - d0->psid_offset))))
611             {
612               error0 = MAP_ERROR_SEC_CHECK;
613             }
614
615           //Add MAP-T pseudo header in front of the packet
616           vlib_buffer_advance (p0, -sizeof (*pheader0));
617           pheader0 = vlib_buffer_get_current (p0);
618
619           //Save addresses within the packet
620           ip4_map_t_embedded_address (d0, &pheader0->saddr,
621                                       &ip40->src_address);
622           pheader0->daddr.as_u64[0] =
623             map_get_pfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
624           pheader0->daddr.as_u64[1] =
625             map_get_sfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
626
627           if (PREDICT_TRUE
628               (error0 == MAP_ERROR_NONE && next0 != IP4_MAPT_NEXT_MAPT_ICMP))
629             {
630               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
631                                                thread_index,
632                                                vnet_buffer (p0)->
633                                                map_t.map_domain_index, 1,
634                                                clib_net_to_host_u16
635                                                (ip40->length));
636             }
637
638           next0 = (error0 != MAP_ERROR_NONE) ? IP4_MAPT_NEXT_DROP : next0;
639           p0->error = error_node->errors[error0];
640         trace:
641           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
642             {
643               map_add_trace (vm, node, p0, d0 - map_main.domains, dst_port0);
644             }
645         exit:
646           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
647                                            to_next, n_left_to_next, pi0,
648                                            next0);
649         }
650       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
651     }
652   return frame->n_vectors;
653 }
654
655 static char *map_t_error_strings[] = {
656 #define _(sym,string) string,
657   foreach_map_error
658 #undef _
659 };
660
661 /* *INDENT-OFF* */
662 VNET_FEATURE_INIT (ip4_map_t_feature, static) = {
663     .arc_name = "ip4-unicast",
664     .node_name = "ip4-map-t",
665     .runs_before = VNET_FEATURES ("ip4-flow-classify"),
666     .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
667 };
668
669 VLIB_REGISTER_NODE(ip4_map_t_fragmented_node) = {
670   .function = ip4_map_t_fragmented,
671   .name = "ip4-map-t-fragmented",
672   .vector_size = sizeof(u32),
673   .format_trace = format_map_trace,
674   .type = VLIB_NODE_TYPE_INTERNAL,
675
676   .n_errors = MAP_N_ERROR,
677   .error_strings = map_t_error_strings,
678
679   .n_next_nodes = IP4_MAPT_FRAGMENTED_N_NEXT,
680   .next_nodes = {
681       [IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP] = "ip6-lookup",
682       [IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
683       [IP4_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
684   },
685 };
686 /* *INDENT-ON* */
687
688 /* *INDENT-OFF* */
689 VLIB_REGISTER_NODE(ip4_map_t_icmp_node) = {
690   .function = ip4_map_t_icmp,
691   .name = "ip4-map-t-icmp",
692   .vector_size = sizeof(u32),
693   .format_trace = format_map_trace,
694   .type = VLIB_NODE_TYPE_INTERNAL,
695
696   .n_errors = MAP_N_ERROR,
697   .error_strings = map_t_error_strings,
698
699   .n_next_nodes = IP4_MAPT_ICMP_N_NEXT,
700   .next_nodes = {
701       [IP4_MAPT_ICMP_NEXT_IP6_LOOKUP] = "ip6-lookup",
702       [IP4_MAPT_ICMP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
703       [IP4_MAPT_ICMP_NEXT_DROP] = "error-drop",
704   },
705 };
706 /* *INDENT-ON* */
707
708 /* *INDENT-OFF* */
709 VLIB_REGISTER_NODE(ip4_map_t_tcp_udp_node) = {
710   .function = ip4_map_t_tcp_udp,
711   .name = "ip4-map-t-tcp-udp",
712   .vector_size = sizeof(u32),
713   .format_trace = format_map_trace,
714   .type = VLIB_NODE_TYPE_INTERNAL,
715
716   .n_errors = MAP_N_ERROR,
717   .error_strings = map_t_error_strings,
718
719   .n_next_nodes = IP4_MAPT_TCP_UDP_N_NEXT,
720   .next_nodes = {
721       [IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP] = "ip6-lookup",
722       [IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
723       [IP4_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
724   },
725 };
726 /* *INDENT-ON* */
727
728 /* *INDENT-OFF* */
729 VLIB_REGISTER_NODE(ip4_map_t_node) = {
730   .function = ip4_map_t,
731   .name = "ip4-map-t",
732   .vector_size = sizeof(u32),
733   .format_trace = format_map_trace,
734   .type = VLIB_NODE_TYPE_INTERNAL,
735
736   .n_errors = MAP_N_ERROR,
737   .error_strings = map_t_error_strings,
738
739   .n_next_nodes = IP4_MAPT_N_NEXT,
740   .next_nodes = {
741       [IP4_MAPT_NEXT_MAPT_TCP_UDP] = "ip4-map-t-tcp-udp",
742       [IP4_MAPT_NEXT_MAPT_ICMP] = "ip4-map-t-icmp",
743       [IP4_MAPT_NEXT_MAPT_FRAGMENTED] = "ip4-map-t-fragmented",
744       [IP4_MAPT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
745       [IP4_MAPT_NEXT_DROP] = "error-drop",
746   },
747 };
748 /* *INDENT-ON* */
749
750 /*
751  * fd.io coding-style-patch-verification: ON
752  *
753  * Local Variables:
754  * eval: (c-set-style "gnu")
755  * End:
756  */