1e8b75967d845a9eec2a90cccf809cfa2b737213
[vpp.git] / src / plugins / snat / nat64.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT64 implementation
18  */
19
20 #include <snat/nat64.h>
21 #include <snat/nat64_db.h>
22 #include <vnet/fib/ip4_fib.h>
23
24
25 nat64_main_t nat64_main;
26
27 /* *INDENT-OFF* */
28
29 /* Hook up input features */
30 VNET_FEATURE_INIT (nat64_in2out, static) = {
31   .arc_name = "ip6-unicast",
32   .node_name = "nat64-in2out",
33   .runs_before = VNET_FEATURES ("ip6-lookup"),
34 };
35 VNET_FEATURE_INIT (nat64_out2in, static) = {
36   .arc_name = "ip4-unicast",
37   .node_name = "nat64-out2in",
38   .runs_before = VNET_FEATURES ("ip4-lookup"),
39 };
40
41 /* *INDENT-ON* */
42
43 clib_error_t *
44 nat64_init (vlib_main_t * vm)
45 {
46   nat64_main_t *nm = &nat64_main;
47   clib_error_t *error = 0;
48   vlib_thread_main_t *tm = vlib_get_thread_main ();
49
50   if (tm->n_vlib_mains > 1)
51     {
52       error = clib_error_return (0, "multi thread not supported");
53       goto error;
54     }
55
56   if (nat64_db_init (&nm->db))
57     {
58       error = clib_error_return (0, "NAT64 DB init failed");
59       goto error;
60     }
61
62   /* set session timeouts to default values */
63   nm->udp_timeout = SNAT_UDP_TIMEOUT;
64   nm->icmp_timeout = SNAT_ICMP_TIMEOUT;
65   nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
66   nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
67   nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN;
68
69 error:
70   return error;
71 }
72
73 int
74 nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
75 {
76   nat64_main_t *nm = &nat64_main;
77   snat_address_t *a = 0;
78   snat_interface_t *interface;
79   int i;
80
81   /* Check if address already exists */
82   for (i = 0; i < vec_len (nm->addr_pool); i++)
83     {
84       if (nm->addr_pool[i].addr.as_u32 == addr->as_u32)
85         {
86           a = nm->addr_pool + i;
87           break;
88         }
89     }
90
91   if (is_add)
92     {
93       if (a)
94         return VNET_API_ERROR_VALUE_EXIST;
95
96       vec_add2 (nm->addr_pool, a, 1);
97       a->addr = *addr;
98       a->fib_index = 0;
99       if (vrf_id != ~0)
100         a->fib_index =
101           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
102 #define _(N, i, n, s) \
103       clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535);
104       foreach_snat_protocol
105 #undef _
106     }
107   else
108     {
109       if (!a)
110         return VNET_API_ERROR_NO_SUCH_ENTRY;
111
112 #define _(N, id, n, s) \
113       clib_bitmap_free (a->busy_##n##_port_bitmap);
114       foreach_snat_protocol
115 #undef _
116         vec_del1 (nm->addr_pool, i);
117     }
118
119   /* Add/del external address to FIB */
120   /* *INDENT-OFF* */
121   pool_foreach (interface, nm->interfaces,
122   ({
123     if (interface->is_inside)
124       continue;
125
126     snat_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add);
127     break;
128   }));
129   /* *INDENT-ON* */
130
131   return 0;
132 }
133
134 void
135 nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx)
136 {
137   nat64_main_t *nm = &nat64_main;
138   snat_address_t *a = 0;
139
140   /* *INDENT-OFF* */
141   vec_foreach (a, nm->addr_pool)
142     {
143       if (fn (a, ctx))
144         break;
145     };
146   /* *INDENT-ON* */
147 }
148
149 int
150 nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
151 {
152   nat64_main_t *nm = &nat64_main;
153   snat_interface_t *interface = 0, *i;
154   snat_address_t *ap;
155   const char *feature_name, *arc_name;
156
157   /* Check if address already exists */
158   /* *INDENT-OFF* */
159   pool_foreach (i, nm->interfaces,
160   ({
161     if (i->sw_if_index == sw_if_index)
162       {
163         interface = i;
164         break;
165       }
166   }));
167   /* *INDENT-ON* */
168
169   if (is_add)
170     {
171       if (interface)
172         return VNET_API_ERROR_VALUE_EXIST;
173
174       pool_get (nm->interfaces, interface);
175       interface->sw_if_index = sw_if_index;
176       interface->is_inside = is_inside;
177
178     }
179   else
180     {
181       if (!interface)
182         return VNET_API_ERROR_NO_SUCH_ENTRY;
183
184       pool_put (nm->interfaces, interface);
185     }
186
187   if (!is_inside)
188     {
189       /* *INDENT-OFF* */
190       vec_foreach (ap, nm->addr_pool)
191         snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, is_add);
192       /* *INDENT-ON* */
193     }
194
195   arc_name = is_inside ? "ip6-unicast" : "ip4-unicast";
196   feature_name = is_inside ? "nat64-in2out" : "nat64-out2in";
197
198   return vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
199                                       is_add, 0, 0);
200 }
201
202 void
203 nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx)
204 {
205   nat64_main_t *nm = &nat64_main;
206   snat_interface_t *i = 0;
207
208   /* *INDENT-OFF* */
209   pool_foreach (i, nm->interfaces,
210   ({
211     if (fn (i, ctx))
212       break;
213   }));
214   /* *INDENT-ON* */
215 }
216
217 int
218 nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto,
219                                ip4_address_t * addr, u16 * port)
220 {
221   nat64_main_t *nm = &nat64_main;
222   snat_main_t *sm = &snat_main;
223   int i;
224   snat_address_t *a, *ga = 0;
225   u32 portnum;
226
227   for (i = 0; i < vec_len (nm->addr_pool); i++)
228     {
229       a = nm->addr_pool + i;
230       switch (proto)
231         {
232 #define _(N, j, n, s) \
233         case SNAT_PROTOCOL_##N: \
234           if (a->busy_##n##_ports < (65535-1024)) \
235             { \
236               if (a->fib_index == fib_index) \
237                 { \
238                   while (1) \
239                     { \
240                       portnum = random_u32 (&sm->random_seed); \
241                       portnum &= 0xFFFF; \
242                       if (portnum < 1024) \
243                         continue; \
244                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
245                                                     portnum)) \
246                         continue; \
247                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
248                                                 portnum, 1); \
249                       a->busy_##n##_ports++; \
250                       *port = portnum; \
251                       addr->as_u32 = a->addr.as_u32; \
252                       return 0; \
253                     } \
254                  } \
255                else if (a->fib_index == 0) \
256                  ga = a; \
257             } \
258           break;
259           foreach_snat_protocol
260 #undef _
261         default:
262           clib_warning ("unknown protocol");
263           return 1;
264         }
265     }
266
267   if (ga)
268     {
269       switch (proto)
270         {
271 #define _(N, j, n, s) \
272         case SNAT_PROTOCOL_##N: \
273           while (1) \
274             { \
275               portnum = random_u32 (&sm->random_seed); \
276               portnum &= 0xFFFF; \
277               if (portnum < 1024) \
278                 continue; \
279               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
280                                             portnum)) \
281                 continue; \
282               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
283                                         portnum, 1); \
284               a->busy_##n##_ports++; \
285               *port = portnum; \
286               addr->as_u32 = a->addr.as_u32; \
287               return 0; \
288             }
289           break;
290           foreach_snat_protocol
291 #undef _
292         default:
293           clib_warning ("unknown protocol");
294           return 1;
295         }
296     }
297
298   /* Totally out of translations to use... */
299   //TODO: IPFix
300   return 1;
301 }
302
303 void
304 nat64_free_out_addr_and_port (ip4_address_t * addr, u16 port,
305                               snat_protocol_t proto)
306 {
307   nat64_main_t *nm = &nat64_main;
308   int i;
309   snat_address_t *a;
310
311   for (i = 0; i < vec_len (nm->addr_pool); i++)
312     {
313       a = nm->addr_pool + i;
314       if (addr->as_u32 != a->addr.as_u32)
315         continue;
316       switch (proto)
317         {
318 #define _(N, j, n, s) \
319         case SNAT_PROTOCOL_##N: \
320           ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
321                   port) == 1); \
322           clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port, 0); \
323           a->busy_##n##_ports--; \
324           break;
325           foreach_snat_protocol
326 #undef _
327         default:
328           clib_warning ("unknown protocol");
329           return;
330         }
331       break;
332     }
333 }
334
335 int
336 nat64_add_del_static_bib_entry (ip6_address_t * in_addr,
337                                 ip4_address_t * out_addr, u16 in_port,
338                                 u16 out_port, u8 proto, u32 vrf_id, u8 is_add)
339 {
340   nat64_main_t *nm = &nat64_main;
341   nat64_db_bib_entry_t *bibe;
342   u32 fib_index =
343     fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
344   snat_protocol_t p = ip_proto_to_snat_proto (proto);
345   ip46_address_t addr;
346   int i;
347   snat_address_t *a;
348
349   addr.as_u64[0] = in_addr->as_u64[0];
350   addr.as_u64[1] = in_addr->as_u64[1];
351   bibe =
352     nat64_db_bib_entry_find (&nm->db, &addr, clib_host_to_net_u16 (in_port),
353                              p, fib_index, 1);
354
355   if (is_add)
356     {
357       if (bibe)
358         return VNET_API_ERROR_VALUE_EXIST;
359
360       for (i = 0; i < vec_len (nm->addr_pool); i++)
361         {
362           a = nm->addr_pool + i;
363           if (out_addr->as_u32 != a->addr.as_u32)
364             continue;
365           switch (p)
366             {
367 #define _(N, j, n, s) \
368             case SNAT_PROTOCOL_##N: \
369               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
370                                             out_port)) \
371                 return VNET_API_ERROR_INVALID_VALUE; \
372               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
373                                         out_port, 1); \
374               if (out_port > 1024) \
375                 a->busy_##n##_ports++; \
376               break;
377               foreach_snat_protocol
378 #undef _
379             default:
380               clib_warning ("unknown protocol");
381               return VNET_API_ERROR_INVALID_VALUE_2;
382             }
383           break;
384         }
385       bibe =
386         nat64_db_bib_entry_create (&nm->db, in_addr, out_addr,
387                                    clib_host_to_net_u16 (in_port),
388                                    clib_host_to_net_u16 (out_port), fib_index,
389                                    p, 1);
390       if (!bibe)
391         return VNET_API_ERROR_UNSPECIFIED;
392     }
393   else
394     {
395       if (!bibe)
396         return VNET_API_ERROR_NO_SUCH_ENTRY;
397
398       nat64_free_out_addr_and_port (out_addr, out_port, p);
399       nat64_db_bib_entry_free (&nm->db, bibe);
400     }
401
402   return 0;
403 }
404
405 int
406 nat64_set_udp_timeout (u32 timeout)
407 {
408   nat64_main_t *nm = &nat64_main;
409
410   if (timeout == 0)
411     nm->udp_timeout = SNAT_UDP_TIMEOUT;
412   else if (timeout < SNAT_UDP_TIMEOUT_MIN)
413     return VNET_API_ERROR_INVALID_VALUE;
414   else
415     nm->udp_timeout = timeout;
416
417   return 0;
418 }
419
420 u32
421 nat64_get_udp_timeout (void)
422 {
423   nat64_main_t *nm = &nat64_main;
424
425   return nm->udp_timeout;
426 }
427
428 int
429 nat64_set_icmp_timeout (u32 timeout)
430 {
431   nat64_main_t *nm = &nat64_main;
432
433   if (timeout == 0)
434     nm->icmp_timeout = SNAT_ICMP_TIMEOUT;
435   else
436     nm->icmp_timeout = timeout;
437
438   return 0;
439 }
440
441 u32
442 nat64_get_icmp_timeout (void)
443 {
444   nat64_main_t *nm = &nat64_main;
445
446   return nm->icmp_timeout;
447 }
448
449 int
450 nat64_set_tcp_timeouts (u32 trans, u32 est, u32 incoming_syn)
451 {
452   nat64_main_t *nm = &nat64_main;
453
454   if (trans == 0)
455     nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
456   else
457     nm->tcp_trans_timeout = trans;
458
459   if (est == 0)
460     nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
461   else
462     nm->tcp_est_timeout = est;
463
464   if (incoming_syn == 0)
465     nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN;
466   else
467     nm->tcp_incoming_syn_timeout = incoming_syn;
468
469   return 0;
470 }
471
472 u32
473 nat64_get_tcp_trans_timeout (void)
474 {
475   nat64_main_t *nm = &nat64_main;
476
477   return nm->tcp_trans_timeout;
478 }
479
480 u32
481 nat64_get_tcp_est_timeout (void)
482 {
483   nat64_main_t *nm = &nat64_main;
484
485   return nm->tcp_est_timeout;
486 }
487
488 u32
489 nat64_get_tcp_incoming_syn_timeout (void)
490 {
491   nat64_main_t *nm = &nat64_main;
492
493   return nm->tcp_incoming_syn_timeout;
494 }
495
496 void
497 nat64_session_reset_timeout (nat64_db_st_entry_t * ste, vlib_main_t * vm)
498 {
499   nat64_main_t *nm = &nat64_main;
500   u32 now = (u32) vlib_time_now (vm);
501
502   switch (ste->proto)
503     {
504     case SNAT_PROTOCOL_ICMP:
505       ste->expire = now + nm->icmp_timeout;
506       return;
507     case SNAT_PROTOCOL_TCP:
508       {
509         switch (ste->tcp_state)
510           {
511           case NAT64_TCP_STATE_V4_INIT:
512           case NAT64_TCP_STATE_V6_INIT:
513           case NAT64_TCP_STATE_V4_FIN_RCV:
514           case NAT64_TCP_STATE_V6_FIN_RCV:
515           case NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV:
516           case NAT64_TCP_STATE_TRANS:
517             ste->expire = now + nm->tcp_trans_timeout;
518             return;
519           case NAT64_TCP_STATE_ESTABLISHED:
520             ste->expire = now + nm->tcp_est_timeout;
521             return;
522           default:
523             return;
524           }
525       }
526     case SNAT_PROTOCOL_UDP:
527       ste->expire = now + nm->udp_timeout;
528       return;
529     default:
530       return;
531     }
532 }
533
534 void
535 nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, tcp_header_t * tcp,
536                              u8 is_ip6)
537 {
538   switch (ste->tcp_state)
539     {
540     case NAT64_TCP_STATE_CLOSED:
541       {
542         if (tcp->flags & TCP_FLAG_SYN)
543           {
544             if (is_ip6)
545               ste->tcp_state = NAT64_TCP_STATE_V6_INIT;
546             else
547               ste->tcp_state = NAT64_TCP_STATE_V4_INIT;
548           }
549         return;
550       }
551     case NAT64_TCP_STATE_V4_INIT:
552       {
553         if (is_ip6 && (tcp->flags & TCP_FLAG_SYN))
554           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
555         return;
556       }
557     case NAT64_TCP_STATE_V6_INIT:
558       {
559         if (!is_ip6 && (tcp->flags & TCP_FLAG_SYN))
560           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
561         return;
562       }
563     case NAT64_TCP_STATE_ESTABLISHED:
564       {
565         if (tcp->flags & TCP_FLAG_FIN)
566           {
567             if (is_ip6)
568               ste->tcp_state = NAT64_TCP_STATE_V6_FIN_RCV;
569             else
570               ste->tcp_state = NAT64_TCP_STATE_V4_FIN_RCV;
571           }
572         else if (tcp->flags & TCP_FLAG_RST)
573           {
574             ste->tcp_state = NAT64_TCP_STATE_TRANS;
575           }
576         return;
577       }
578     case NAT64_TCP_STATE_V4_FIN_RCV:
579       {
580         if (is_ip6 && (tcp->flags & TCP_FLAG_FIN))
581           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
582         return;
583       }
584     case NAT64_TCP_STATE_V6_FIN_RCV:
585       {
586         if (!is_ip6 && (tcp->flags & TCP_FLAG_FIN))
587           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
588         return;
589       }
590     case NAT64_TCP_STATE_TRANS:
591       {
592         if (!(tcp->flags & TCP_FLAG_RST))
593           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
594         return;
595       }
596     default:
597       return;
598     }
599 }
600
601 /**
602  * @brief The 'nat64-expire-walk' process's main loop.
603  *
604  * Check expire time for NAT64 sessions.
605  */
606 static uword
607 nat64_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
608                       vlib_frame_t * f)
609 {
610   nat64_main_t *nm = &nat64_main;
611
612   while (1)
613     {
614       vlib_process_wait_for_event_or_clock (vm, 10.0);
615       vlib_process_get_events (vm, NULL);
616       u32 now = (u32) vlib_time_now (vm);
617
618       nad64_db_st_free_expired (&nm->db, now);
619     }
620
621   return 0;
622 }
623
624 static vlib_node_registration_t nat64_expire_walk_node;
625
626 /* *INDENT-OFF* */
627 VLIB_REGISTER_NODE (nat64_expire_walk_node, static) = {
628     .function = nat64_expire_walk_fn,
629     .type = VLIB_NODE_TYPE_PROCESS,
630     .name = "nat64-expire-walk",
631 };
632 /* *INDENT-ON* */
633
634 /*
635  * fd.io coding-style-patch-verification: ON
636  *
637  * Local Variables:
638  * eval: (c-set-style "gnu")
639  * End:
640  */