http_static: fix reply data leak
[vpp.git] / src / plugins / nat / nat64 / nat64.c
1 /*
2  * Copyright (c) 2020 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 #include <vppinfra/crc32.h>
17 #include <vnet/fib/ip4_fib.h>
18
19 #include <vnet/ip/reass/ip4_sv_reass.h>
20 #include <vnet/ip/reass/ip6_sv_reass.h>
21 #include <vnet/plugin/plugin.h>
22 #include <vpp/app/version.h>
23
24 #include <nat/lib/ipfix_logging.h>
25 #include <nat/nat64/nat64.h>
26
27 nat64_main_t nat64_main;
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   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
35 };
36 VNET_FEATURE_INIT (nat64_out2in, static) = {
37   .arc_name = "ip4-unicast",
38   .node_name = "nat64-out2in",
39   .runs_before = VNET_FEATURES ("ip4-lookup"),
40   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
41 };
42 VNET_FEATURE_INIT (nat64_in2out_handoff, static) = {
43   .arc_name = "ip6-unicast",
44   .node_name = "nat64-in2out-handoff",
45   .runs_before = VNET_FEATURES ("ip6-lookup"),
46   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
47 };
48 VNET_FEATURE_INIT (nat64_out2in_handoff, static) = {
49   .arc_name = "ip4-unicast",
50   .node_name = "nat64-out2in-handoff",
51   .runs_before = VNET_FEATURES ("ip4-lookup"),
52   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
53 };
54 VLIB_PLUGIN_REGISTER () = {
55     .version = VPP_BUILD_VER,
56     .description = "NAT64",
57 };
58 static u8 well_known_prefix[] = {
59   0x00, 0x64, 0xff, 0x9b,
60   0x00, 0x00, 0x00, 0x00,
61   0x00, 0x00, 0x00, 0x00,
62   0x00, 0x00, 0x00, 0x00
63 };
64
65 #define nat_elog_str(_str)                      \
66 do                                              \
67   {                                             \
68     ELOG_TYPE_DECLARE (e) =                     \
69       {                                         \
70         .format = "nat-msg " _str,              \
71         .format_args = "",                      \
72       };                                        \
73     ELOG_DATA (&vlib_global_main.elog_main, e); \
74   } while (0);
75
76 static void
77 nat64_ip4_add_del_interface_address_cb (ip4_main_t * im, uword opaque,
78                                         u32 sw_if_index,
79                                         ip4_address_t * address,
80                                         u32 address_length,
81                                         u32 if_address_index, u32 is_delete)
82 {
83   nat64_main_t *nm = &nat64_main;
84   int i, j;
85
86   if (plugin_enabled () == 0)
87     return;
88
89   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
90     {
91       if (sw_if_index == nm->auto_add_sw_if_indices[i])
92         {
93           if (!is_delete)
94             {
95               /* Don't trip over lease renewal, static config */
96               for (j = 0; j < vec_len (nm->addr_pool); j++)
97                 if (nm->addr_pool[j].addr.as_u32 == address->as_u32)
98                   return;
99
100               (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
101                                               address, ~0, 1);
102               return;
103             }
104           else
105             {
106               (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
107                                               address, ~0, 0);
108               return;
109             }
110         }
111     }
112 }
113
114 u32
115 nat64_get_worker_in2out (ip6_address_t * addr)
116 {
117   nat64_main_t *nm = &nat64_main;
118   u32 next_worker_index = nm->first_worker_index;
119   u32 hash;
120
121 #ifdef clib_crc32c_uses_intrinsics
122   hash = clib_crc32c ((u8 *) addr->as_u32, 16);
123 #else
124   u64 tmp = addr->as_u64[0] ^ addr->as_u64[1];
125   hash = clib_xxhash (tmp);
126 #endif
127
128   if (PREDICT_TRUE (is_pow2 (_vec_len (nm->workers))))
129     next_worker_index += nm->workers[hash & (_vec_len (nm->workers) - 1)];
130   else
131     next_worker_index += nm->workers[hash % _vec_len (nm->workers)];
132
133   return next_worker_index;
134 }
135
136 static u32
137 get_thread_idx_by_port (u16 e_port)
138 {
139   nat64_main_t *nm = &nat64_main;
140   u32 thread_idx = nm->num_workers;
141   if (nm->num_workers > 1)
142     {
143       thread_idx = nm->first_worker_index +
144                    nm->workers[(e_port - 1024) / nm->port_per_thread %
145                                _vec_len (nm->workers)];
146     }
147   return thread_idx;
148 }
149
150 u32
151 nat64_get_worker_out2in (vlib_buffer_t * b, ip4_header_t * ip)
152 {
153   nat64_main_t *nm = &nat64_main;
154   udp_header_t *udp;
155   u16 port;
156   u32 proto;
157
158   proto = ip_proto_to_nat_proto (ip->protocol);
159   udp = ip4_next_header (ip);
160   port = udp->dst_port;
161
162   /* unknown protocol */
163   if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
164     {
165       nat64_db_t *db;
166       ip46_address_t daddr;
167       nat64_db_bib_entry_t *bibe;
168
169       clib_memset (&daddr, 0, sizeof (daddr));
170       daddr.ip4.as_u32 = ip->dst_address.as_u32;
171
172       vec_foreach (db, nm->db)
173         {
174           bibe = nat64_db_bib_entry_find (db, &daddr, 0, ip->protocol, 0, 0);
175           if (bibe)
176             return (u32) (db - nm->db);
177         }
178       return vlib_get_thread_index ();
179     }
180
181   /* ICMP */
182   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
183     {
184       icmp46_header_t *icmp = (icmp46_header_t *) udp;
185       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
186       if (!icmp_type_is_error_message
187           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
188         port = vnet_buffer (b)->ip.reass.l4_src_port;
189       else
190         {
191           /* if error message, then it's not fragmented and we can access it */
192           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
193           proto = ip_proto_to_nat_proto (inner_ip->protocol);
194           void *l4_header = ip4_next_header (inner_ip);
195           switch (proto)
196             {
197             case NAT_PROTOCOL_ICMP:
198               icmp = (icmp46_header_t *) l4_header;
199               echo = (icmp_echo_header_t *) (icmp + 1);
200               port = echo->identifier;
201               break;
202             case NAT_PROTOCOL_UDP:
203             case NAT_PROTOCOL_TCP:
204               port = ((tcp_udp_header_t *) l4_header)->src_port;
205               break;
206             default:
207               return vlib_get_thread_index ();
208             }
209         }
210     }
211
212   /* worker by outside port  (TCP/UDP) */
213   port = clib_net_to_host_u16 (port);
214   if (port > 1024)
215     return get_thread_idx_by_port (port);
216
217   return vlib_get_thread_index ();
218 }
219
220 clib_error_t *
221 nat64_init (vlib_main_t * vm)
222 {
223   nat64_main_t *nm = &nat64_main;
224   vlib_thread_main_t *tm = vlib_get_thread_main ();
225   ip4_add_del_interface_address_callback_t cb4;
226   vlib_node_t *node;
227
228   clib_memset (nm, 0, sizeof (*nm));
229
230   nm->ip4_main = &ip4_main;
231   nm->log_class = vlib_log_register_class ("nat64", 0);
232
233   nm->port_per_thread = 0xffff - 1024;
234
235   nm->fq_in2out_index = ~0;
236   nm->fq_out2in_index = ~0;
237
238   node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
239   nm->error_node_index = node->index;
240   node = vlib_get_node_by_name (vm, (u8 *) "nat64-in2out");
241   nm->in2out_node_index = node->index;
242   node = vlib_get_node_by_name (vm, (u8 *) "nat64-in2out-slowpath");
243   nm->in2out_slowpath_node_index = node->index;
244   node = vlib_get_node_by_name (vm, (u8 *) "nat64-out2in");
245   nm->out2in_node_index = node->index;
246
247   node = vlib_get_node_by_name (vm, (u8 *) "nat64-expire-worker-walk");
248   nm->expire_worker_walk_node_index = node->index;
249
250   nm->fib_src_hi = fib_source_allocate ("nat64-hi",
251                                         FIB_SOURCE_PRIORITY_HI,
252                                         FIB_SOURCE_BH_SIMPLE);
253   nm->fib_src_low = fib_source_allocate ("nat64-low",
254                                          FIB_SOURCE_PRIORITY_LOW,
255                                          FIB_SOURCE_BH_SIMPLE);
256
257   // set protocol timeouts to defaults
258   nat64_reset_timeouts ();
259
260   /* Set up the interface address add/del callback */
261   cb4.function = nat64_ip4_add_del_interface_address_cb;
262   cb4.function_opaque = 0;
263   vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cb4);
264
265   /* Init counters */
266   nm->total_bibs.name = "total-bibs";
267   nm->total_bibs.stat_segment_name = "/nat64/total-bibs";
268   vlib_validate_simple_counter (&nm->total_bibs, 0);
269   vlib_zero_simple_counter (&nm->total_bibs, 0);
270   nm->total_sessions.name = "total-sessions";
271   nm->total_sessions.stat_segment_name = "/nat64/total-sessions";
272   vlib_validate_simple_counter (&nm->total_sessions, 0);
273   vlib_zero_simple_counter (&nm->total_sessions, 0);
274
275   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
276   if (p)
277     {
278       vlib_thread_registration_t *tr;
279       tr = (vlib_thread_registration_t *) p[0];
280       if (tr)
281         {
282           nm->num_workers = tr->count;
283           nm->first_worker_index = tr->first_index;
284         }
285     }
286
287   if (nm->num_workers > 1)
288     {
289       int i;
290       uword *bitmap = 0;
291
292       for (i = 0; i < nm->num_workers; i++)
293         bitmap = clib_bitmap_set (bitmap, i, 1);
294
295       clib_bitmap_foreach (i, bitmap)
296          {
297           vec_add1(nm->workers, i);
298         }
299
300       clib_bitmap_free (bitmap);
301
302       nm->port_per_thread = (0xffff - 1024) / _vec_len (nm->workers);
303     }
304
305   /* Init IPFIX logging */
306   nat_ipfix_logging_init (vm);
307
308 #define _(x)                                                     \
309   nm->counters.in2out.x.name = #x;                               \
310   nm->counters.in2out.x.stat_segment_name = "/nat64/in2out/" #x; \
311   nm->counters.out2in.x.name = #x;                               \
312   nm->counters.out2in.x.stat_segment_name = "/nat64/out2in/" #x;
313   foreach_nat_counter;
314 #undef _
315   return nat64_api_hookup (vm);
316 }
317
318 VLIB_INIT_FUNCTION (nat64_init);
319
320 static void nat64_free_out_addr_and_port (struct nat64_db_s *db,
321                                           ip4_address_t * addr, u16 port,
322                                           u8 protocol);
323
324 int
325 nat64_init_hash (nat64_config_t c)
326 {
327   vlib_thread_main_t *tm = vlib_get_thread_main ();
328   nat64_main_t *nm = &nat64_main;
329   nat64_db_t *db;
330   int rv = 0;
331
332   vec_validate (nm->db, tm->n_vlib_mains - 1);
333
334   vec_foreach (db, nm->db)
335     {
336       if (nat64_db_init (db, c, nat64_free_out_addr_and_port))
337         {
338           nat64_log_err ("NAT64 DB init failed");
339           rv = 1;
340         }
341     }
342
343   return rv;
344 }
345
346 int
347 nat64_free_hash ()
348 {
349   nat64_main_t *nm = &nat64_main;
350   nat64_db_t *db;
351   int rv = 0;
352
353   vec_foreach (db, nm->db)
354     {
355       if (nat64_db_free (db))
356         {
357           nat64_log_err ("NAT64 DB free failed");
358           rv = 1;
359         }
360     }
361
362   vec_free (nm->db);
363
364   return rv;
365 }
366
367 int
368 nat64_add_del_pool_addr (u32 thread_index,
369                          ip4_address_t * addr, u32 vrf_id, u8 is_add)
370 {
371   nat64_main_t *nm = &nat64_main;
372   nat64_address_t *a = 0;
373   nat64_interface_t *interface;
374   int i;
375   nat64_db_t *db;
376   vlib_thread_main_t *tm = vlib_get_thread_main ();
377
378   /* Check if address already exists */
379   for (i = 0; i < vec_len (nm->addr_pool); i++)
380     {
381       if (nm->addr_pool[i].addr.as_u32 == addr->as_u32)
382         {
383           a = nm->addr_pool + i;
384           break;
385         }
386     }
387
388   if (is_add)
389     {
390       if (a)
391         return VNET_API_ERROR_VALUE_EXIST;
392
393       vec_add2 (nm->addr_pool, a, 1);
394       a->addr = *addr;
395       a->fib_index = ~0;
396       if (vrf_id != ~0)
397         a->fib_index =
398           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
399                                              nm->fib_src_hi);
400 #define _(N, id, n, s) \
401       clib_memset (a->busy_##n##_port_refcounts, 0, sizeof(a->busy_##n##_port_refcounts)); \
402       a->busy_##n##_ports = 0; \
403       vec_validate_init_empty (a->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
404       foreach_nat_protocol
405 #undef _
406     }
407   else
408     {
409       if (!a)
410         return VNET_API_ERROR_NO_SUCH_ENTRY;
411
412       if (a->fib_index != ~0)
413         fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6, nm->fib_src_hi);
414       /* Delete sessions using address */
415       vec_foreach (db, nm->db)
416         {
417           nat64_db_free_out_addr (thread_index, db, &a->addr);
418           vlib_set_simple_counter (&nm->total_bibs, db - nm->db, 0,
419                                    db->bib.bib_entries_num);
420           vlib_set_simple_counter (&nm->total_sessions, db - nm->db, 0,
421                                    db->st.st_entries_num);
422         }
423       vec_del1 (nm->addr_pool, i);
424     }
425
426   /* Add/del external address to FIB */
427   pool_foreach (interface, nm->interfaces)
428    {
429     if (nat64_interface_is_inside(interface))
430       continue;
431
432     nat64_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add);
433     break;
434   }
435
436   return 0;
437 }
438
439 void
440 nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx)
441 {
442   nat64_main_t *nm = &nat64_main;
443   nat64_address_t *a = 0;
444
445   vec_foreach (a, nm->addr_pool)
446     {
447       if (fn (a, ctx))
448         break;
449     };
450 }
451
452 int
453 nat64_add_interface_address (u32 sw_if_index, int is_add)
454 {
455   nat64_main_t *nm = &nat64_main;
456   ip4_main_t *ip4_main = nm->ip4_main;
457   ip4_address_t *first_int_addr;
458   int i;
459
460   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
461
462   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
463     {
464       if (nm->auto_add_sw_if_indices[i] == sw_if_index)
465         {
466           if (is_add)
467             return VNET_API_ERROR_VALUE_EXIST;
468           else
469             {
470               /* if have address remove it */
471               if (first_int_addr)
472                 (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
473                                                 first_int_addr, ~0, 0);
474               vec_del1 (nm->auto_add_sw_if_indices, i);
475               return 0;
476             }
477         }
478     }
479
480   if (!is_add)
481     return VNET_API_ERROR_NO_SUCH_ENTRY;
482
483   /* add to the auto-address list */
484   vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
485
486   /* If the address is already bound - or static - add it now */
487   if (first_int_addr)
488     (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
489                                     first_int_addr, ~0, 1);
490
491   return 0;
492 }
493
494 static void
495 nat64_validate_counters (nat64_main_t * nm, u32 sw_if_index)
496 {
497 #define _(x)                                                          \
498   vlib_validate_simple_counter (&nm->counters.in2out.x, sw_if_index); \
499   vlib_zero_simple_counter (&nm->counters.in2out.x, sw_if_index);     \
500   vlib_validate_simple_counter (&nm->counters.out2in.x, sw_if_index); \
501   vlib_zero_simple_counter (&nm->counters.out2in.x, sw_if_index);
502   foreach_nat_counter;
503 #undef _
504 }
505
506 void
507 nat64_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
508                            int is_add)
509 {
510   nat64_main_t *nm = &nat64_main;
511   fib_prefix_t prefix = {
512     .fp_len = p_len,
513     .fp_proto = FIB_PROTOCOL_IP4,
514     .fp_addr = {
515                 .ip4.as_u32 = addr->as_u32,
516                 },
517   };
518   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
519
520   if (is_add)
521     fib_table_entry_update_one_path (fib_index,
522                                      &prefix,
523                                      nm->fib_src_low,
524                                      (FIB_ENTRY_FLAG_CONNECTED |
525                                       FIB_ENTRY_FLAG_LOCAL |
526                                       FIB_ENTRY_FLAG_EXCLUSIVE),
527                                      DPO_PROTO_IP4,
528                                      NULL,
529                                      sw_if_index,
530                                      ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
531   else
532     fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
533 }
534
535 int
536 nat64_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
537 {
538   vlib_main_t *vm = vlib_get_main ();
539   nat64_main_t *nm = &nat64_main;
540   nat64_interface_t *interface = 0, *i;
541   nat64_address_t *ap;
542   const char *feature_name, *arc_name;
543
544   // TODO: is enabled ? we can't signal if it is not
545
546   /* Check if interface already exists */
547   pool_foreach (i, nm->interfaces)
548    {
549     if (i->sw_if_index == sw_if_index)
550       {
551         interface = i;
552         break;
553       }
554   }
555
556   if (is_add)
557     {
558       if (interface)
559         goto set_flags;
560
561       pool_get (nm->interfaces, interface);
562       interface->sw_if_index = sw_if_index;
563       interface->flags = 0;
564       nat64_validate_counters (nm, sw_if_index);
565     set_flags:
566       if (is_inside)
567         interface->flags |= NAT64_INTERFACE_FLAG_IS_INSIDE;
568       else
569         interface->flags |= NAT64_INTERFACE_FLAG_IS_OUTSIDE;
570
571       nm->total_enabled_count++;
572       vlib_process_signal_event (vm,
573                                  nm->expire_walk_node_index,
574                                  NAT64_CLEANER_RESCHEDULE, 0);
575
576     }
577   else
578     {
579       if (!interface)
580         return VNET_API_ERROR_NO_SUCH_ENTRY;
581
582       if ((nat64_interface_is_inside (interface)
583            && nat64_interface_is_outside (interface)))
584         interface->flags &=
585           is_inside ? ~NAT64_INTERFACE_FLAG_IS_INSIDE :
586           ~NAT64_INTERFACE_FLAG_IS_OUTSIDE;
587       else
588         pool_put (nm->interfaces, interface);
589
590       nm->total_enabled_count--;
591     }
592
593   if (!is_inside)
594     {
595       vec_foreach (ap, nm->addr_pool)
596         nat64_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add);
597     }
598
599   if (nm->num_workers > 1)
600     {
601       feature_name =
602         is_inside ? "nat64-in2out-handoff" : "nat64-out2in-handoff";
603       if (nm->fq_in2out_index == ~0)
604         nm->fq_in2out_index =
605           vlib_frame_queue_main_init (nat64_in2out_node.index, 0);
606       if (nm->fq_out2in_index == ~0)
607         nm->fq_out2in_index =
608           vlib_frame_queue_main_init (nat64_out2in_node.index, 0);
609     }
610   else
611     feature_name = is_inside ? "nat64-in2out" : "nat64-out2in";
612
613   arc_name = is_inside ? "ip6-unicast" : "ip4-unicast";
614
615   if (is_inside)
616     {
617       int rv = ip6_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
618       if (rv)
619         return rv;
620     }
621   else
622     {
623       int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
624       if (rv)
625         return rv;
626     }
627
628   return vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
629                                       is_add, 0, 0);
630 }
631
632 void
633 nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx)
634 {
635   nat64_main_t *nm = &nat64_main;
636   nat64_interface_t *i = 0;
637
638   pool_foreach (i, nm->interfaces)
639    {
640     if (fn (i, ctx))
641       break;
642   }
643 }
644
645 // TODO: plugin independent
646 static_always_inline u16
647 nat64_random_port (u16 min, u16 max)
648 {
649   nat64_main_t *nm = &nat64_main;
650   u32 rwide;
651   u16 r;
652
653   rwide = random_u32 (&nm->random_seed);
654   r = rwide & 0xFFFF;
655   if (r >= min && r <= max)
656     return r;
657
658   return min + (rwide % (max - min + 1));
659 }
660
661 static_always_inline int
662 nat64_alloc_addr_and_port_default (nat64_address_t * addresses,
663                                    u32 fib_index,
664                                    u32 thread_index,
665                                    nat_protocol_t proto,
666                                    ip4_address_t * addr,
667                                    u16 * port,
668                                    u16 port_per_thread, u32 nat_thread_index)
669 {
670   int i;
671   nat64_address_t *a, *ga = 0;
672   u32 portnum;
673
674   for (i = 0; i < vec_len (addresses); i++)
675     {
676       a = addresses + i;
677       switch (proto)
678         {
679 #define _(N, j, n, s) \
680         case NAT_PROTOCOL_##N: \
681           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
682             { \
683               if (a->fib_index == fib_index) \
684                 { \
685                   while (1) \
686                     { \
687                       portnum = (port_per_thread * \
688                         nat_thread_index) + \
689                         nat64_random_port(0, port_per_thread - 1) + 1024; \
690                       if (a->busy_##n##_port_refcounts[portnum]) \
691                         continue; \
692                       --a->busy_##n##_port_refcounts[portnum]; \
693                       a->busy_##n##_ports_per_thread[thread_index]++; \
694                       a->busy_##n##_ports++; \
695                       *addr = a->addr; \
696                       *port = clib_host_to_net_u16(portnum); \
697                       return 0; \
698                     } \
699                 } \
700               else if (a->fib_index == ~0) \
701                 { \
702                   ga = a; \
703                 } \
704             } \
705           break;
706           foreach_nat_protocol
707 #undef _
708         default:
709           return 1;
710         }
711
712     }
713
714   if (ga)
715     {
716       a = ga;
717       switch (proto)
718         {
719 #define _(N, j, n, s) \
720         case NAT_PROTOCOL_##N: \
721           while (1) \
722             { \
723               portnum = (port_per_thread * \
724                 nat_thread_index) + \
725                 nat64_random_port(0, port_per_thread - 1) + 1024; \
726               if (a->busy_##n##_port_refcounts[portnum]) \
727                 continue; \
728               ++a->busy_##n##_port_refcounts[portnum]; \
729               a->busy_##n##_ports_per_thread[thread_index]++; \
730               a->busy_##n##_ports++; \
731               *addr = a->addr; \
732               *port = clib_host_to_net_u16(portnum); \
733               return 0; \
734             }
735           break;
736           foreach_nat_protocol
737 #undef _
738         default:
739           return 1;
740         }
741     }
742
743   /* Totally out of translations to use... */
744   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
745   return 1;
746 }
747
748 int
749 nat64_alloc_out_addr_and_port (u32 fib_index, nat_protocol_t proto,
750                                ip4_address_t * addr, u16 * port,
751                                u32 thread_index)
752 {
753   nat64_main_t *nm = &nat64_main;
754   u32 worker_index = 0;
755   int rv;
756
757   if (nm->num_workers > 1)
758     worker_index = thread_index - nm->first_worker_index;
759
760   rv = nat64_alloc_addr_and_port_default (nm->addr_pool, fib_index,
761                                           thread_index,
762                                           proto, addr, port,
763                                           nm->port_per_thread, worker_index);
764
765   return rv;
766 }
767
768 static void
769 nat64_free_out_addr_and_port (struct nat64_db_s *db, ip4_address_t * addr,
770                               u16 port, u8 protocol)
771 {
772   nat64_main_t *nm = &nat64_main;
773   u32 thread_index = db - nm->db;
774   nat_protocol_t proto = ip_proto_to_nat_proto (protocol);
775   u16 port_host_byte_order = clib_net_to_host_u16 (port);
776   nat64_address_t *a;
777   int i;
778
779   for (i = 0; i < vec_len (nm->addr_pool); i++)
780     {
781       a = nm->addr_pool + i;
782       if (addr->as_u32 != a->addr.as_u32)
783         continue;
784       switch (proto)
785         {
786 #define _(N, j, n, s) \
787         case NAT_PROTOCOL_##N: \
788           ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
789           --a->busy_##n##_port_refcounts[port_host_byte_order]; \
790           a->busy_##n##_ports--; \
791           a->busy_##n##_ports_per_thread[thread_index]--; \
792           break;
793           foreach_nat_protocol
794 #undef _
795         default:
796           nat_elog_str ("unknown protocol");
797           return;
798         }
799       break;
800     }
801 }
802
803 /**
804  * @brief Add/delete static BIB entry in worker thread.
805  */
806 static uword
807 nat64_static_bib_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
808                             vlib_frame_t * f)
809 {
810   nat64_main_t *nm = &nat64_main;
811   u32 thread_index = vm->thread_index;
812   nat64_db_t *db = &nm->db[thread_index];
813   nat64_static_bib_to_update_t *static_bib;
814   nat64_db_bib_entry_t *bibe;
815   ip46_address_t addr;
816
817   pool_foreach (static_bib, nm->static_bibs)
818    {
819     if ((static_bib->thread_index != thread_index) || (static_bib->done))
820       continue;
821
822     if (static_bib->is_add)
823       {
824           (void) nat64_db_bib_entry_create (thread_index, db,
825                                             &static_bib->in_addr,
826                                             &static_bib->out_addr,
827                                             static_bib->in_port,
828                                             static_bib->out_port,
829                                             static_bib->fib_index,
830                                             static_bib->proto, 1);
831           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
832                                    db->bib.bib_entries_num);
833       }
834     else
835       {
836         addr.as_u64[0] = static_bib->in_addr.as_u64[0];
837         addr.as_u64[1] = static_bib->in_addr.as_u64[1];
838         bibe = nat64_db_bib_entry_find (db, &addr, static_bib->in_port,
839                                         static_bib->proto,
840                                         static_bib->fib_index, 1);
841         if (bibe)
842           {
843             nat64_db_bib_entry_free (thread_index, db, bibe);
844             vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
845                                      db->bib.bib_entries_num);
846             vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
847                                      db->st.st_entries_num);
848           }
849       }
850
851       static_bib->done = 1;
852   }
853
854   return 0;
855 }
856
857 static vlib_node_registration_t nat64_static_bib_worker_node;
858
859 VLIB_REGISTER_NODE (nat64_static_bib_worker_node, static) = {
860     .function = nat64_static_bib_worker_fn,
861     .type = VLIB_NODE_TYPE_INPUT,
862     .state = VLIB_NODE_STATE_INTERRUPT,
863     .name = "nat64-static-bib-worker",
864 };
865
866 int
867 nat64_add_del_static_bib_entry (ip6_address_t * in_addr,
868                                 ip4_address_t * out_addr, u16 in_port,
869                                 u16 out_port, u8 proto, u32 vrf_id, u8 is_add)
870 {
871   nat64_main_t *nm = &nat64_main;
872   nat64_db_bib_entry_t *bibe;
873   u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
874                                                      nm->fib_src_hi);
875   nat_protocol_t p = ip_proto_to_nat_proto (proto);
876   ip46_address_t addr;
877   int i;
878   nat64_address_t *a;
879   u32 thread_index = 0;
880   nat64_db_t *db;
881   nat64_static_bib_to_update_t *static_bib;
882   vlib_main_t *worker_vm;
883   u32 *to_be_free = 0, *index;
884
885   if (nm->num_workers > 1)
886     {
887       thread_index = nat64_get_worker_in2out (in_addr);
888       db = &nm->db[thread_index];
889     }
890   else
891     db = &nm->db[nm->num_workers];
892
893   addr.as_u64[0] = in_addr->as_u64[0];
894   addr.as_u64[1] = in_addr->as_u64[1];
895   bibe =
896     nat64_db_bib_entry_find (db, &addr, clib_host_to_net_u16 (in_port),
897                              proto, fib_index, 1);
898
899   if (is_add)
900     {
901       if (bibe)
902         return VNET_API_ERROR_VALUE_EXIST;
903
904       /* outside port must be assigned to same thread as internall address */
905       if ((out_port > 1024) && (nm->num_workers > 1))
906         {
907           if (thread_index != get_thread_idx_by_port (out_port))
908             return VNET_API_ERROR_INVALID_VALUE_2;
909         }
910
911       for (i = 0; i < vec_len (nm->addr_pool); i++)
912         {
913           a = nm->addr_pool + i;
914           if (out_addr->as_u32 != a->addr.as_u32)
915             continue;
916           switch (p)
917             {
918 #define _(N, j, n, s) \
919             case NAT_PROTOCOL_##N: \
920               if (a->busy_##n##_port_refcounts[out_port]) \
921                 return VNET_API_ERROR_INVALID_VALUE; \
922               ++a->busy_##n##_port_refcounts[out_port]; \
923               if (out_port > 1024) \
924                 { \
925                   a->busy_##n##_ports++; \
926                   a->busy_##n##_ports_per_thread[thread_index]++; \
927                 } \
928               break;
929               foreach_nat_protocol
930 #undef _
931             default:
932               clib_memset (&addr, 0, sizeof (addr));
933               addr.ip4.as_u32 = out_addr->as_u32;
934               if (nat64_db_bib_entry_find (db, &addr, 0, proto, fib_index, 0))
935                 return VNET_API_ERROR_INVALID_VALUE;
936             }
937           break;
938         }
939       if (!nm->num_workers)
940         {
941           bibe =
942             nat64_db_bib_entry_create (thread_index, db, in_addr, out_addr,
943                                        clib_host_to_net_u16 (in_port),
944                                        clib_host_to_net_u16 (out_port),
945                                        fib_index, proto, 1);
946           if (!bibe)
947             return VNET_API_ERROR_UNSPECIFIED;
948
949           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
950                                    db->bib.bib_entries_num);
951         }
952     }
953   else
954     {
955       if (!bibe)
956         return VNET_API_ERROR_NO_SUCH_ENTRY;
957
958       if (!nm->num_workers)
959         {
960           nat64_db_bib_entry_free (thread_index, db, bibe);
961           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
962                                    db->bib.bib_entries_num);
963         }
964     }
965
966   if (nm->num_workers)
967     {
968       pool_foreach (static_bib, nm->static_bibs)
969        {
970         if (static_bib->done)
971           vec_add1 (to_be_free, static_bib - nm->static_bibs);
972       }
973       vec_foreach (index, to_be_free)
974         pool_put_index (nm->static_bibs, index[0]);
975       vec_free (to_be_free);
976       pool_get (nm->static_bibs, static_bib);
977       static_bib->in_addr.as_u64[0] = in_addr->as_u64[0];
978       static_bib->in_addr.as_u64[1] = in_addr->as_u64[1];
979       static_bib->in_port = clib_host_to_net_u16 (in_port);
980       static_bib->out_addr.as_u32 = out_addr->as_u32;
981       static_bib->out_port = clib_host_to_net_u16 (out_port);
982       static_bib->fib_index = fib_index;
983       static_bib->proto = proto;
984       static_bib->is_add = is_add;
985       static_bib->thread_index = thread_index;
986       static_bib->done = 0;
987       worker_vm = vlib_get_main_by_index (thread_index);
988       if (worker_vm)
989         vlib_node_set_interrupt_pending (worker_vm,
990                                          nat64_static_bib_worker_node.index);
991       else
992         return VNET_API_ERROR_UNSPECIFIED;
993     }
994
995   return 0;
996 }
997
998 int
999 nat64_set_udp_timeout (u32 timeout)
1000 {
1001   nat64_main_t *nm = &nat64_main;
1002
1003   if (timeout == 0)
1004     nm->udp_timeout = NAT_UDP_TIMEOUT;
1005   else
1006     nm->udp_timeout = timeout;
1007
1008   return 0;
1009 }
1010
1011 u32
1012 nat64_get_udp_timeout (void)
1013 {
1014   nat64_main_t *nm = &nat64_main;
1015
1016   return nm->udp_timeout;
1017 }
1018
1019 int
1020 nat64_set_icmp_timeout (u32 timeout)
1021 {
1022   nat64_main_t *nm = &nat64_main;
1023
1024   if (timeout == 0)
1025     nm->icmp_timeout = NAT_ICMP_TIMEOUT;
1026   else
1027     nm->icmp_timeout = timeout;
1028
1029   return 0;
1030 }
1031
1032 void
1033 nat64_reset_timeouts ()
1034 {
1035   nat64_main_t *nm = &nat64_main;
1036
1037   nm->udp_timeout = NAT_UDP_TIMEOUT;
1038   nm->icmp_timeout = NAT_ICMP_TIMEOUT;
1039   nm->tcp_est_timeout = NAT_TCP_ESTABLISHED_TIMEOUT;
1040   nm->tcp_trans_timeout = NAT_TCP_TRANSITORY_TIMEOUT;
1041 }
1042
1043 u32
1044 nat64_get_icmp_timeout (void)
1045 {
1046   nat64_main_t *nm = &nat64_main;
1047
1048   return nm->icmp_timeout;
1049 }
1050
1051 int
1052 nat64_set_tcp_timeouts (u32 trans, u32 est)
1053 {
1054   nat64_main_t *nm = &nat64_main;
1055
1056   if (trans == 0)
1057     nm->tcp_trans_timeout = NAT_TCP_TRANSITORY_TIMEOUT;
1058   else
1059     nm->tcp_trans_timeout = trans;
1060
1061   if (est == 0)
1062     nm->tcp_est_timeout = NAT_TCP_ESTABLISHED_TIMEOUT;
1063   else
1064     nm->tcp_est_timeout = est;
1065
1066   return 0;
1067 }
1068
1069 u32
1070 nat64_get_tcp_trans_timeout (void)
1071 {
1072   nat64_main_t *nm = &nat64_main;
1073
1074   return nm->tcp_trans_timeout;
1075 }
1076
1077 u32
1078 nat64_get_tcp_est_timeout (void)
1079 {
1080   nat64_main_t *nm = &nat64_main;
1081
1082   return nm->tcp_est_timeout;
1083 }
1084
1085 void
1086 nat64_session_reset_timeout (nat64_db_st_entry_t * ste, vlib_main_t * vm)
1087 {
1088   nat64_main_t *nm = &nat64_main;
1089   u32 now = (u32) vlib_time_now (vm);
1090
1091   switch (ip_proto_to_nat_proto (ste->proto))
1092     {
1093     case NAT_PROTOCOL_ICMP:
1094       ste->expire = now + nm->icmp_timeout;
1095       return;
1096     case NAT_PROTOCOL_TCP:
1097       {
1098         switch (ste->tcp_state)
1099           {
1100           case NAT64_TCP_STATE_V4_INIT:
1101           case NAT64_TCP_STATE_V6_INIT:
1102           case NAT64_TCP_STATE_V4_FIN_RCV:
1103           case NAT64_TCP_STATE_V6_FIN_RCV:
1104           case NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV:
1105           case NAT64_TCP_STATE_TRANS:
1106             ste->expire = now + nm->tcp_trans_timeout;
1107             return;
1108           case NAT64_TCP_STATE_ESTABLISHED:
1109             ste->expire = now + nm->tcp_est_timeout;
1110             return;
1111           default:
1112             return;
1113           }
1114       }
1115     case NAT_PROTOCOL_UDP:
1116       ste->expire = now + nm->udp_timeout;
1117       return;
1118     default:
1119       ste->expire = now + nm->udp_timeout;
1120       return;
1121     }
1122 }
1123
1124 void
1125 nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, tcp_header_t * tcp,
1126                              u8 is_ip6)
1127 {
1128   switch (ste->tcp_state)
1129     {
1130     case NAT64_TCP_STATE_CLOSED:
1131       {
1132         if (tcp->flags & TCP_FLAG_SYN)
1133           {
1134             if (is_ip6)
1135               ste->tcp_state = NAT64_TCP_STATE_V6_INIT;
1136             else
1137               ste->tcp_state = NAT64_TCP_STATE_V4_INIT;
1138           }
1139         return;
1140       }
1141     case NAT64_TCP_STATE_V4_INIT:
1142       {
1143         if (is_ip6 && (tcp->flags & TCP_FLAG_SYN))
1144           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
1145         return;
1146       }
1147     case NAT64_TCP_STATE_V6_INIT:
1148       {
1149         if (!is_ip6 && (tcp->flags & TCP_FLAG_SYN))
1150           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
1151         return;
1152       }
1153     case NAT64_TCP_STATE_ESTABLISHED:
1154       {
1155         if (tcp->flags & TCP_FLAG_FIN)
1156           {
1157             if (is_ip6)
1158               ste->tcp_state = NAT64_TCP_STATE_V6_FIN_RCV;
1159             else
1160               ste->tcp_state = NAT64_TCP_STATE_V4_FIN_RCV;
1161           }
1162         else if (tcp->flags & TCP_FLAG_RST)
1163           {
1164             ste->tcp_state = NAT64_TCP_STATE_TRANS;
1165           }
1166         return;
1167       }
1168     case NAT64_TCP_STATE_V4_FIN_RCV:
1169       {
1170         if (is_ip6 && (tcp->flags & TCP_FLAG_FIN))
1171           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
1172         return;
1173       }
1174     case NAT64_TCP_STATE_V6_FIN_RCV:
1175       {
1176         if (!is_ip6 && (tcp->flags & TCP_FLAG_FIN))
1177           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
1178         return;
1179       }
1180     case NAT64_TCP_STATE_TRANS:
1181       {
1182         if (!(tcp->flags & TCP_FLAG_RST))
1183           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
1184         return;
1185       }
1186     default:
1187       return;
1188     }
1189 }
1190
1191 int
1192 nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, u8 is_add)
1193 {
1194   nat64_main_t *nm = &nat64_main;
1195   nat64_prefix_t *p = 0;
1196   int i;
1197
1198   /* Verify prefix length */
1199   if (plen != 32 && plen != 40 && plen != 48 && plen != 56 && plen != 64
1200       && plen != 96)
1201     return VNET_API_ERROR_INVALID_VALUE;
1202
1203   /* Check if tenant already have prefix */
1204   for (i = 0; i < vec_len (nm->pref64); i++)
1205     {
1206       if (nm->pref64[i].vrf_id == vrf_id)
1207         {
1208           p = nm->pref64 + i;
1209           break;
1210         }
1211     }
1212
1213   if (is_add)
1214     {
1215       if (!p)
1216         {
1217           vec_add2 (nm->pref64, p, 1);
1218           p->fib_index =
1219             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
1220                                                nm->fib_src_hi);
1221           p->vrf_id = vrf_id;
1222         }
1223
1224       p->prefix.as_u64[0] = prefix->as_u64[0];
1225       p->prefix.as_u64[1] = prefix->as_u64[1];
1226       p->plen = plen;
1227     }
1228   else
1229     {
1230       if (!p)
1231         return VNET_API_ERROR_NO_SUCH_ENTRY;
1232
1233       // TODO: missing fib_table_unlock ?
1234
1235       vec_del1 (nm->pref64, i);
1236     }
1237
1238   return 0;
1239 }
1240
1241 void
1242 nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx)
1243 {
1244   nat64_main_t *nm = &nat64_main;
1245   nat64_prefix_t *p = 0;
1246
1247   vec_foreach (p, nm->pref64)
1248     {
1249       if (fn (p, ctx))
1250         break;
1251     };
1252 }
1253
1254 void
1255 nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
1256 {
1257   nat64_main_t *nm = &nat64_main;
1258   nat64_prefix_t *p, *gp = 0, *prefix = 0;
1259
1260   vec_foreach (p, nm->pref64)
1261     {
1262       if (p->fib_index == fib_index)
1263         {
1264           prefix = p;
1265           break;
1266         }
1267
1268       if (p->fib_index == 0)
1269         gp = p;
1270     };
1271
1272   if (!prefix)
1273     prefix = gp;
1274
1275   if (prefix)
1276     {
1277       clib_memcpy_fast (ip6, &p->prefix, sizeof (ip6_address_t));
1278       switch (p->plen)
1279         {
1280         case 32:
1281           ip6->as_u32[1] = ip4->as_u32;
1282           break;
1283         case 40:
1284           ip6->as_u8[5] = ip4->as_u8[0];
1285           ip6->as_u8[6] = ip4->as_u8[1];
1286           ip6->as_u8[7] = ip4->as_u8[2];
1287           ip6->as_u8[9] = ip4->as_u8[3];
1288           break;
1289         case 48:
1290           ip6->as_u8[6] = ip4->as_u8[0];
1291           ip6->as_u8[7] = ip4->as_u8[1];
1292           ip6->as_u8[9] = ip4->as_u8[2];
1293           ip6->as_u8[10] = ip4->as_u8[3];
1294           break;
1295         case 56:
1296           ip6->as_u8[7] = ip4->as_u8[0];
1297           ip6->as_u8[9] = ip4->as_u8[1];
1298           ip6->as_u8[10] = ip4->as_u8[2];
1299           ip6->as_u8[11] = ip4->as_u8[3];
1300           break;
1301         case 64:
1302           ip6->as_u8[9] = ip4->as_u8[0];
1303           ip6->as_u8[10] = ip4->as_u8[1];
1304           ip6->as_u8[11] = ip4->as_u8[2];
1305           ip6->as_u8[12] = ip4->as_u8[3];
1306           break;
1307         case 96:
1308           ip6->as_u32[3] = ip4->as_u32;
1309           break;
1310         default:
1311           nat_elog_str ("invalid prefix length");
1312           break;
1313         }
1314     }
1315   else
1316     {
1317       clib_memcpy_fast (ip6, well_known_prefix, sizeof (ip6_address_t));
1318       ip6->as_u32[3] = ip4->as_u32;
1319     }
1320 }
1321
1322 void
1323 nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
1324 {
1325   nat64_main_t *nm = &nat64_main;
1326   nat64_prefix_t *p, *gp = 0;
1327   u8 plen = 0;
1328
1329   vec_foreach (p, nm->pref64)
1330     {
1331       if (p->fib_index == fib_index)
1332         {
1333           plen = p->plen;
1334           break;
1335         }
1336
1337       if (p->vrf_id == 0)
1338         gp = p;
1339     };
1340
1341   if (!plen)
1342     {
1343       if (gp)
1344         plen = gp->plen;
1345       else
1346         plen = 96;
1347     }
1348
1349   switch (plen)
1350     {
1351     case 32:
1352       ip4->as_u32 = ip6->as_u32[1];
1353       break;
1354     case 40:
1355       ip4->as_u8[0] = ip6->as_u8[5];
1356       ip4->as_u8[1] = ip6->as_u8[6];
1357       ip4->as_u8[2] = ip6->as_u8[7];
1358       ip4->as_u8[3] = ip6->as_u8[9];
1359       break;
1360     case 48:
1361       ip4->as_u8[0] = ip6->as_u8[6];
1362       ip4->as_u8[1] = ip6->as_u8[7];
1363       ip4->as_u8[2] = ip6->as_u8[9];
1364       ip4->as_u8[3] = ip6->as_u8[10];
1365       break;
1366     case 56:
1367       ip4->as_u8[0] = ip6->as_u8[7];
1368       ip4->as_u8[1] = ip6->as_u8[9];
1369       ip4->as_u8[2] = ip6->as_u8[10];
1370       ip4->as_u8[3] = ip6->as_u8[11];
1371       break;
1372     case 64:
1373       ip4->as_u8[0] = ip6->as_u8[9];
1374       ip4->as_u8[1] = ip6->as_u8[10];
1375       ip4->as_u8[2] = ip6->as_u8[11];
1376       ip4->as_u8[3] = ip6->as_u8[12];
1377       break;
1378     case 96:
1379       ip4->as_u32 = ip6->as_u32[3];
1380       break;
1381     default:
1382       nat_elog_str ("invalid prefix length");
1383       break;
1384     }
1385 }
1386
1387 /**
1388  * @brief Per worker process checking expire time for NAT64 sessions.
1389  */
1390 static uword
1391 nat64_expire_worker_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
1392                              vlib_frame_t * f)
1393 {
1394   nat64_main_t *nm = &nat64_main;
1395   u32 thread_index = vm->thread_index;
1396   nat64_db_t *db;
1397   u32 now;
1398
1399   // TODO: barier sync on plugin enabled
1400   if (plugin_enabled () == 0)
1401     return 0;
1402
1403   db = &nm->db[thread_index];
1404   now = (u32) vlib_time_now (vm);
1405
1406   nad64_db_st_free_expired (thread_index, db, now);
1407   vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
1408                            db->bib.bib_entries_num);
1409   vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
1410                            db->st.st_entries_num);
1411   return 0;
1412 }
1413
1414 VLIB_REGISTER_NODE (nat64_expire_worker_walk_node, static) = {
1415     .function = nat64_expire_worker_walk_fn,
1416     .type = VLIB_NODE_TYPE_INPUT,
1417     .state = VLIB_NODE_STATE_INTERRUPT,
1418     .name = "nat64-expire-worker-walk",
1419 };
1420
1421 /**
1422  * @brief Centralized process to drive per worker expire walk.
1423  */
1424 static uword
1425 nat64_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
1426                       vlib_frame_t * f)
1427 {
1428   nat64_main_t *nm = &nat64_main;
1429   vlib_main_t **worker_vms = 0, *worker_vm;
1430   int i;
1431   uword event_type, *event_data = 0;
1432
1433   if (vlib_get_n_threads () == 0)
1434     vec_add1 (worker_vms, vm);
1435   else
1436     {
1437       for (i = 0; i < vlib_get_n_threads (); i++)
1438         {
1439           worker_vm = vlib_get_main_by_index (i);
1440           if (worker_vm)
1441             vec_add1 (worker_vms, worker_vm);
1442         }
1443     }
1444
1445   while (1)
1446     {
1447       if (nm->total_enabled_count)
1448         {
1449           vlib_process_wait_for_event_or_clock (vm, 10.0);
1450           event_type = vlib_process_get_events (vm, &event_data);
1451         }
1452       else
1453         {
1454           vlib_process_wait_for_event (vm);
1455           event_type = vlib_process_get_events (vm, &event_data);
1456         }
1457
1458       switch (event_type)
1459         {
1460         case ~0:
1461           break;
1462         case NAT64_CLEANER_RESCHEDULE:
1463           break;
1464         default:
1465           nat64_log_err ("unknown event %u", event_type);
1466           break;
1467         }
1468
1469       for (i = 0; i < vec_len (worker_vms); i++)
1470         {
1471           worker_vm = worker_vms[i];
1472           vlib_node_set_interrupt_pending (worker_vm,
1473                                            nm->expire_worker_walk_node_index);
1474         }
1475     }
1476
1477   return 0;
1478 }
1479
1480 void
1481 nat64_create_expire_walk_process ()
1482 {
1483   nat64_main_t *nm = &nat64_main;
1484
1485   if (nm->expire_walk_node_index)
1486     return;
1487   nm->expire_walk_node_index = vlib_process_create (vlib_get_main (),
1488                                                     "nat64-expire-walk",
1489                                                     nat64_expire_walk_fn,
1490                                                     16 /* stack_bytes */ );
1491 }
1492
1493 int
1494 nat64_plugin_enable (nat64_config_t c)
1495 {
1496   nat64_main_t *nm = &nat64_main;
1497
1498   if (plugin_enabled () == 1)
1499     {
1500       nat64_log_err ("plugin already enabled!");
1501       return 1;
1502     }
1503
1504   if (!c.bib_buckets)
1505     c.bib_buckets = 1024;
1506
1507   if (!c.bib_memory_size)
1508     c.bib_memory_size = 128 << 20;
1509
1510   if (!c.st_buckets)
1511     c.st_buckets = 2048;
1512
1513   if (!c.st_memory_size)
1514     c.st_memory_size = 256 << 20;
1515
1516   nm->config = c;
1517
1518   if (nat64_init_hash (c))
1519     {
1520       nat64_log_err ("initializing hashes failed!");
1521       return 1;
1522     }
1523
1524   nat64_create_expire_walk_process ();
1525
1526   nm->enabled = 1;
1527   return 0;
1528 }
1529
1530 int
1531 nat64_plugin_disable ()
1532 {
1533   nat64_main_t *nm = &nat64_main;
1534   vnet_main_t *vnm = vnet_get_main ();
1535   int rv = 0;
1536
1537   nat64_address_t *a;
1538   nat64_interface_t *i, *interfaces = 0;
1539
1540   if (plugin_enabled () == 0)
1541     {
1542       nat64_log_err ("plugin already disabled!");
1543       return 1;
1544     }
1545   nm->enabled = 0;
1546
1547   pool_foreach (i, nm->interfaces)
1548    {
1549     vec_add1 (interfaces, *i);
1550   }
1551   vec_foreach (i, interfaces)
1552   {
1553     rv = nat64_interface_add_del (i->sw_if_index, i->flags, 0);
1554     if (rv)
1555       {
1556         nat64_log_err ("%U %s interface del failed",
1557                        format_vnet_sw_if_index_name, vnm, i->sw_if_index,
1558                        i->flags & NAT64_INTERFACE_FLAG_IS_INSIDE ?
1559                        "inside" : "outside");
1560       }
1561   }
1562   vec_free (interfaces);
1563   pool_free (nm->interfaces);
1564
1565   nat64_reset_timeouts ();
1566
1567   if (nat64_free_hash ())
1568     {
1569       rv = 1;
1570       nat64_log_err ("freeing hashes failed!");
1571     }
1572
1573   // TODO: based on nat64_add_del_prefix fib_table_unlock is not called
1574   vec_free (nm->pref64);
1575
1576   if (vec_len (nm->addr_pool))
1577     {
1578       vec_foreach (a, nm->addr_pool)
1579       {
1580         if (a->fib_index != ~0)
1581           fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6, nm->fib_src_hi);
1582       }
1583       vec_free (nm->addr_pool);
1584     }
1585   return rv;
1586 }
1587
1588 uword
1589 unformat_nat_protocol (unformat_input_t * input, va_list * args)
1590 {
1591   u32 *r = va_arg (*args, u32 *);
1592
1593   if (0);
1594 #define _(N, i, n, s) else if (unformat (input, s)) *r = NAT_PROTOCOL_##N;
1595   foreach_nat_protocol
1596 #undef _
1597     else
1598     return 0;
1599   return 1;
1600 }
1601
1602 u8 *
1603 format_nat_protocol (u8 * s, va_list * args)
1604 {
1605   u32 i = va_arg (*args, u32);
1606   u8 *t = 0;
1607
1608   switch (i)
1609     {
1610 #define _(N, j, n, str) case NAT_PROTOCOL_##N: t = (u8 *) str; break;
1611       foreach_nat_protocol
1612 #undef _
1613     default:
1614       s = format (s, "unknown");
1615       return s;
1616     }
1617   s = format (s, "%s", t);
1618   return s;
1619 }
1620
1621 /*
1622  * fd.io coding-style-patch-verification: ON
1623  *
1624  * Local Variables:
1625  * eval: (c-set-style "gnu")
1626  * End:
1627  */