map: handle ip4 ttl=1 packets in map-t
[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           if (PREDICT_FALSE (ip40->ttl == 1))
582             {
583               icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
584                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
585                                            0);
586               p0->error = error_node->errors[MAP_ERROR_TIME_EXCEEDED];
587               next0 = IP4_MAPT_NEXT_ICMP_ERROR;
588               goto trace;
589             }
590
591           bool df0 =
592             ip40->flags_and_fragment_offset &
593             clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
594
595           vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
596
597           if (PREDICT_FALSE
598               (df0 && !map_main.frag_ignore_df
599                &&
600                ((ip4_len0 +
601                  (sizeof (ip6_header_t) - sizeof (ip4_header_t))) >
602                 vnet_buffer (p0)->map_t.mtu)))
603             {
604               icmp4_error_set_vnet_buffer (p0, ICMP4_destination_unreachable,
605                                            ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
606                                            vnet_buffer (p0)->map_t.mtu -
607                                            (sizeof (ip6_header_t) -
608                                             sizeof (ip4_header_t)));
609               p0->error = error_node->errors[MAP_ERROR_DF_SET];
610               next0 = IP4_MAPT_NEXT_ICMP_ERROR;
611               goto trace;
612             }
613
614           ip4_map_t_classify (p0, d0, ip40, ip4_len0, &dst_port0, &error0,
615                               &next0, l4_dst_port);
616
617           /* Verify that port is not among the well-known ports */
618           if ((d0->psid_length > 0 && d0->psid_offset > 0)
619               && (clib_net_to_host_u16 (dst_port0) <
620                   (0x1 << (16 - d0->psid_offset))))
621             {
622               error0 = MAP_ERROR_SEC_CHECK;
623             }
624
625           //Add MAP-T pseudo header in front of the packet
626           vlib_buffer_advance (p0, -sizeof (*pheader0));
627           pheader0 = vlib_buffer_get_current (p0);
628
629           //Save addresses within the packet
630           ip4_map_t_embedded_address (d0, &pheader0->saddr,
631                                       &ip40->src_address);
632           pheader0->daddr.as_u64[0] =
633             map_get_pfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
634           pheader0->daddr.as_u64[1] =
635             map_get_sfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
636
637           if (PREDICT_TRUE
638               (error0 == MAP_ERROR_NONE && next0 != IP4_MAPT_NEXT_MAPT_ICMP))
639             {
640               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
641                                                thread_index,
642                                                vnet_buffer (p0)->
643                                                map_t.map_domain_index, 1,
644                                                clib_net_to_host_u16
645                                                (ip40->length));
646             }
647
648           next0 = (error0 != MAP_ERROR_NONE) ? IP4_MAPT_NEXT_DROP : next0;
649           p0->error = error_node->errors[error0];
650         trace:
651           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
652             {
653               map_add_trace (vm, node, p0, d0 - map_main.domains, dst_port0);
654             }
655         exit:
656           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
657                                            to_next, n_left_to_next, pi0,
658                                            next0);
659         }
660       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
661     }
662   return frame->n_vectors;
663 }
664
665 static char *map_t_error_strings[] = {
666 #define _(sym,string) string,
667   foreach_map_error
668 #undef _
669 };
670
671 /* *INDENT-OFF* */
672 VNET_FEATURE_INIT (ip4_map_t_feature, static) = {
673     .arc_name = "ip4-unicast",
674     .node_name = "ip4-map-t",
675     .runs_before = VNET_FEATURES ("ip4-flow-classify"),
676     .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
677 };
678
679 VLIB_REGISTER_NODE(ip4_map_t_fragmented_node) = {
680   .function = ip4_map_t_fragmented,
681   .name = "ip4-map-t-fragmented",
682   .vector_size = sizeof(u32),
683   .format_trace = format_map_trace,
684   .type = VLIB_NODE_TYPE_INTERNAL,
685
686   .n_errors = MAP_N_ERROR,
687   .error_strings = map_t_error_strings,
688
689   .n_next_nodes = IP4_MAPT_FRAGMENTED_N_NEXT,
690   .next_nodes = {
691       [IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP] = "ip6-lookup",
692       [IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
693       [IP4_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
694   },
695 };
696 /* *INDENT-ON* */
697
698 /* *INDENT-OFF* */
699 VLIB_REGISTER_NODE(ip4_map_t_icmp_node) = {
700   .function = ip4_map_t_icmp,
701   .name = "ip4-map-t-icmp",
702   .vector_size = sizeof(u32),
703   .format_trace = format_map_trace,
704   .type = VLIB_NODE_TYPE_INTERNAL,
705
706   .n_errors = MAP_N_ERROR,
707   .error_strings = map_t_error_strings,
708
709   .n_next_nodes = IP4_MAPT_ICMP_N_NEXT,
710   .next_nodes = {
711       [IP4_MAPT_ICMP_NEXT_IP6_LOOKUP] = "ip6-lookup",
712       [IP4_MAPT_ICMP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
713       [IP4_MAPT_ICMP_NEXT_DROP] = "error-drop",
714   },
715 };
716 /* *INDENT-ON* */
717
718 /* *INDENT-OFF* */
719 VLIB_REGISTER_NODE(ip4_map_t_tcp_udp_node) = {
720   .function = ip4_map_t_tcp_udp,
721   .name = "ip4-map-t-tcp-udp",
722   .vector_size = sizeof(u32),
723   .format_trace = format_map_trace,
724   .type = VLIB_NODE_TYPE_INTERNAL,
725
726   .n_errors = MAP_N_ERROR,
727   .error_strings = map_t_error_strings,
728
729   .n_next_nodes = IP4_MAPT_TCP_UDP_N_NEXT,
730   .next_nodes = {
731       [IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP] = "ip6-lookup",
732       [IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
733       [IP4_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
734   },
735 };
736 /* *INDENT-ON* */
737
738 /* *INDENT-OFF* */
739 VLIB_REGISTER_NODE(ip4_map_t_node) = {
740   .function = ip4_map_t,
741   .name = "ip4-map-t",
742   .vector_size = sizeof(u32),
743   .format_trace = format_map_trace,
744   .type = VLIB_NODE_TYPE_INTERNAL,
745
746   .n_errors = MAP_N_ERROR,
747   .error_strings = map_t_error_strings,
748
749   .n_next_nodes = IP4_MAPT_N_NEXT,
750   .next_nodes = {
751       [IP4_MAPT_NEXT_MAPT_TCP_UDP] = "ip4-map-t-tcp-udp",
752       [IP4_MAPT_NEXT_MAPT_ICMP] = "ip4-map-t-icmp",
753       [IP4_MAPT_NEXT_MAPT_FRAGMENTED] = "ip4-map-t-fragmented",
754       [IP4_MAPT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
755       [IP4_MAPT_NEXT_DROP] = "error-drop",
756   },
757 };
758 /* *INDENT-ON* */
759
760 /*
761  * fd.io coding-style-patch-verification: ON
762  *
763  * Local Variables:
764  * eval: (c-set-style "gnu")
765  * End:
766  */