2 * nat44_ei.c - nat44 endpoint dependent plugin
4 * Copyright (c) 2020 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/lib/ipfix_logging.h>
25 #include <nat/lib/nat_syslog.h>
26 #include <nat/nat_inlines.h>
27 #include <nat/nat44/inlines.h>
28 #include <nat/nat_affinity.h>
29 #include <vnet/fib/fib_table.h>
30 #include <vnet/fib/ip4_fib.h>
31 #include <vnet/ip/reass/ip4_sv_reass.h>
32 #include <vppinfra/bihash_16_8.h>
33 #include <nat/nat44/ed_inlines.h>
34 #include <vnet/ip/ip_table.h>
36 #include <nat/nat44-ei/nat44_ei_inlines.h>
37 #include <nat/nat44-ei/nat44_ei.h>
39 nat44_ei_main_t nat44_ei_main;
41 static void nat44_ei_db_free ();
43 static void nat44_ei_db_init (u32 translations, u32 translation_buckets,
47 nat44_ei_plugin_enable (nat44_ei_config_t c)
49 nat44_ei_main_t *nm = &nat44_ei_main;
50 snat_main_t *sm = &snat_main;
52 clib_memset (nm, 0, sizeof (*nm));
58 c.sessions = 10 * 1024;
62 nm->translations = c.sessions;
63 nm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
64 nm->user_buckets = nat_calc_bihash_buckets (c.users);
68 sm->static_mapping_only = c.static_mapping_only;
69 sm->static_mapping_connection_tracking = c.connection_tracking;
70 sm->out2in_dpo = c.out2in_dpo;
71 sm->forwarding_enabled = 0;
73 sm->pat = (!c.static_mapping_only ||
74 (c.static_mapping_only && c.connection_tracking));
76 sm->max_users_per_thread = c.users;
77 sm->max_translations_per_thread = c.sessions;
78 sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
79 sm->max_translations_per_user =
80 c.user_sessions ? c.user_sessions : sm->max_translations_per_thread;
82 sm->inside_vrf_id = c.inside_vrf;
83 sm->inside_fib_index = fib_table_find_or_create_and_lock (
84 FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi);
86 sm->outside_vrf_id = c.outside_vrf;
87 sm->outside_fib_index = fib_table_find_or_create_and_lock (
88 FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi);
90 sm->worker_in2out_cb = nat44_ei_get_in2out_worker_index;
91 sm->worker_out2in_cb = nat44_ei_get_out2in_worker_index;
93 sm->in2out_node_index = sm->ei_in2out_node_index;
94 sm->out2in_node_index = sm->ei_out2in_node_index;
96 sm->in2out_output_node_index = sm->ei_in2out_output_node_index;
100 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
101 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
105 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
106 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
109 nat_reset_timeouts (&sm->timeouts);
110 nat44_ei_db_init (nm->translations, nm->translation_buckets,
112 nat44_ei_set_alloc_default ();
115 // TODO: function for reset counters
116 vlib_zero_simple_counter (&sm->total_users, 0);
117 vlib_zero_simple_counter (&sm->total_sessions, 0);
118 vlib_zero_simple_counter (&sm->user_limit_reached, 0);
120 if (!sm->frame_queue_nelts)
121 sm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
129 nat44_ei_plugin_disable ()
131 nat44_ei_main_t *nm = &nat44_ei_main;
132 snat_main_t *sm = &snat_main;
133 snat_interface_t *i, *vec;
136 // first unregister all nodes from interfaces
137 vec = vec_dup (sm->interfaces);
140 if (nat_interface_is_inside (i))
141 error = snat_interface_add_del (i->sw_if_index, 1, 1);
142 if (nat_interface_is_outside (i))
143 error = snat_interface_add_del (i->sw_if_index, 0, 1);
147 nat_log_err ("error occurred while removing interface %u",
154 vec = vec_dup (sm->output_feature_interfaces);
157 if (nat_interface_is_inside (i))
158 error = snat_interface_add_del_output_feature (i->sw_if_index, 1, 1);
159 if (nat_interface_is_outside (i))
160 error = snat_interface_add_del_output_feature (i->sw_if_index, 0, 1);
164 nat_log_err ("error occurred while removing interface %u",
169 sm->output_feature_interfaces = 0;
174 nat44_addresses_free (&sm->addresses);
175 nat44_addresses_free (&sm->twice_nat_addresses);
177 vec_free (sm->to_resolve);
178 vec_free (sm->auto_add_sw_if_indices);
179 vec_free (sm->auto_add_sw_if_indices_twice_nat);
182 sm->auto_add_sw_if_indices = 0;
183 sm->auto_add_sw_if_indices_twice_nat = 0;
185 sm->forwarding_enabled = 0;
188 clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
189 clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig));
195 nat44_ei_free_session_data (snat_main_t *sm, snat_session_t *s,
196 u32 thread_index, u8 is_ha)
198 clib_bihash_kv_8_8_t kv;
200 init_nat_i2o_k (&kv, s);
201 if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0))
202 nat_elog_warn ("in2out key del failed");
204 init_nat_o2i_k (&kv, s);
205 if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0))
206 nat_elog_warn ("out2in key del failed");
210 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
211 &s->in2out.addr, s->in2out.port,
212 &s->out2in.addr, s->out2in.port, s->nat_proto);
214 nat_ipfix_logging_nat44_ses_delete (
215 thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
216 s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
218 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
219 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
223 if (snat_is_session_static (s))
226 snat_free_outside_address_and_port (sm->addresses, thread_index,
227 &s->out2in.addr, s->out2in.port,
231 static_always_inline void
232 nat44_ei_user_del_sessions (snat_user_t *u, u32 thread_index)
237 snat_main_t *sm = &snat_main;
238 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
242 pool_elt_at_index (tsm->list_pool, u->sessions_per_user_list_head_index);
244 elt = pool_elt_at_index (tsm->list_pool, elt->next);
246 while (elt->value != ~0)
248 s = pool_elt_at_index (tsm->sessions, elt->value);
249 elt = pool_elt_at_index (tsm->list_pool, elt->next);
251 nat44_ei_free_session_data (sm, s, thread_index, 0);
252 nat44_delete_session (sm, s, thread_index);
257 nat44_ei_user_del (ip4_address_t *addr, u32 fib_index)
261 snat_main_t *sm = &snat_main;
262 snat_main_per_thread_data_t *tsm;
264 snat_user_key_t user_key;
265 clib_bihash_kv_8_8_t kv, value;
267 if (sm->endpoint_dependent)
270 user_key.addr.as_u32 = addr->as_u32;
271 user_key.fib_index = fib_index;
272 kv.key = user_key.as_u64;
274 if (sm->num_workers > 1)
276 vec_foreach (tsm, sm->per_thread_data)
278 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
280 nat44_ei_user_del_sessions (
281 pool_elt_at_index (tsm->users, value.value),
290 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
291 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
293 nat44_ei_user_del_sessions (
294 pool_elt_at_index (tsm->users, value.value), tsm->thread_index);
302 nat44_ei_static_mapping_del_sessions (snat_main_t *sm,
303 snat_main_per_thread_data_t *tsm,
304 snat_user_key_t u_key, int addr_only,
305 ip4_address_t e_addr, u16 e_port)
307 clib_bihash_kv_8_8_t kv, value;
308 kv.key = u_key.as_u64;
310 dlist_elt_t *head, *elt;
313 u32 elt_index, head_index, ses_index;
315 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
317 user_index = value.value;
318 u = pool_elt_at_index (tsm->users, user_index);
319 if (u->nstaticsessions)
321 head_index = u->sessions_per_user_list_head_index;
322 head = pool_elt_at_index (tsm->list_pool, head_index);
323 elt_index = head->next;
324 elt = pool_elt_at_index (tsm->list_pool, elt_index);
325 ses_index = elt->value;
326 while (ses_index != ~0)
328 s = pool_elt_at_index (tsm->sessions, ses_index);
329 elt = pool_elt_at_index (tsm->list_pool, elt->next);
330 ses_index = elt->value;
334 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
335 (s->out2in.port != e_port))
339 if (is_lb_session (s))
342 if (!snat_is_session_static (s))
345 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
346 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
356 nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
359 snat_main_t *sm = &snat_main;
360 u32 next_worker_index = 0;
363 next_worker_index = sm->first_worker_index;
364 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
365 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
367 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
368 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
370 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
372 return next_worker_index;
376 nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
377 u32 rx_fib_index0, u8 is_output)
379 snat_main_t *sm = &snat_main;
382 clib_bihash_kv_8_8_t kv, value;
383 snat_static_mapping_t *m;
385 u32 next_worker_index = 0;
387 /* first try static mappings without port */
388 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
390 init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
391 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
394 m = pool_elt_at_index (sm->static_mappings, value.value);
395 return m->workers[0];
399 proto = ip_proto_to_nat_proto (ip0->protocol);
400 udp = ip4_next_header (ip0);
401 port = udp->dst_port;
403 /* unknown protocol */
404 if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
406 /* use current thread */
407 return vlib_get_thread_index ();
410 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
412 icmp46_header_t *icmp = (icmp46_header_t *) udp;
413 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
414 if (!icmp_type_is_error_message (
415 vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
416 port = vnet_buffer (b)->ip.reass.l4_src_port;
419 /* if error message, then it's not fragmented and we can access it */
420 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
421 proto = ip_proto_to_nat_proto (inner_ip->protocol);
422 void *l4_header = ip4_next_header (inner_ip);
425 case NAT_PROTOCOL_ICMP:
426 icmp = (icmp46_header_t *) l4_header;
427 echo = (icmp_echo_header_t *) (icmp + 1);
428 port = echo->identifier;
430 case NAT_PROTOCOL_UDP:
431 case NAT_PROTOCOL_TCP:
432 port = ((tcp_udp_header_t *) l4_header)->src_port;
435 return vlib_get_thread_index ();
440 /* try static mappings with port */
441 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
443 init_nat_k (&kv, ip0->dst_address, port, rx_fib_index0, proto);
444 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
447 m = pool_elt_at_index (sm->static_mappings, value.value);
448 return m->workers[0];
452 /* worker by outside port */
453 next_worker_index = sm->first_worker_index;
455 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
456 return next_worker_index;
460 nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
461 u32 thread_index, nat_protocol_t proto,
462 ip4_address_t *addr, u16 *port, u16 port_per_thread,
463 u32 snat_thread_index)
466 snat_address_t *a, *ga = 0;
469 for (i = 0; i < vec_len (addresses); i++)
474 #define _(N, j, n, s) \
475 case NAT_PROTOCOL_##N: \
476 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
478 if (a->fib_index == fib_index) \
482 portnum = (port_per_thread * snat_thread_index) + \
483 snat_random_port (0, port_per_thread - 1) + 1024; \
484 if (a->busy_##n##_port_refcounts[portnum]) \
486 --a->busy_##n##_port_refcounts[portnum]; \
487 a->busy_##n##_ports_per_thread[thread_index]++; \
488 a->busy_##n##_ports++; \
490 *port = clib_host_to_net_u16 (portnum); \
494 else if (a->fib_index == ~0) \
502 default : nat_elog_info ("unknown protocol");
512 #define _(N, j, n, s) \
513 case NAT_PROTOCOL_##N: \
516 portnum = (port_per_thread * snat_thread_index) + \
517 snat_random_port (0, port_per_thread - 1) + 1024; \
518 if (a->busy_##n##_port_refcounts[portnum]) \
520 ++a->busy_##n##_port_refcounts[portnum]; \
521 a->busy_##n##_ports_per_thread[thread_index]++; \
522 a->busy_##n##_ports++; \
524 *port = clib_host_to_net_u16 (portnum); \
530 default : nat_elog_info ("unknown protocol");
535 /* Totally out of translations to use... */
536 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
541 nat44_ei_alloc_range_cb (snat_address_t *addresses, u32 fib_index,
542 u32 thread_index, nat_protocol_t proto,
543 ip4_address_t *addr, u16 *port, u16 port_per_thread,
544 u32 snat_thread_index)
546 snat_main_t *sm = &snat_main;
547 snat_address_t *a = addresses;
550 ports = sm->end_port - sm->start_port + 1;
552 if (!vec_len (addresses))
557 #define _(N, i, n, s) \
558 case NAT_PROTOCOL_##N: \
559 if (a->busy_##n##_ports < ports) \
563 portnum = snat_random_port (sm->start_port, sm->end_port); \
564 if (a->busy_##n##_port_refcounts[portnum]) \
566 ++a->busy_##n##_port_refcounts[portnum]; \
567 a->busy_##n##_ports++; \
569 *port = clib_host_to_net_u16 (portnum); \
576 default : nat_elog_info ("unknown protocol");
581 /* Totally out of translations to use... */
582 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
587 nat44_ei_alloc_mape_cb (snat_address_t *addresses, u32 fib_index,
588 u32 thread_index, nat_protocol_t proto,
589 ip4_address_t *addr, u16 *port, u16 port_per_thread,
590 u32 snat_thread_index)
592 snat_main_t *sm = &snat_main;
593 snat_address_t *a = addresses;
594 u16 m, ports, portnum, A, j;
595 m = 16 - (sm->psid_offset + sm->psid_length);
596 ports = (1 << (16 - sm->psid_length)) - (1 << m);
598 if (!vec_len (addresses))
603 #define _(N, i, n, s) \
604 case NAT_PROTOCOL_##N: \
605 if (a->busy_##n##_ports < ports) \
609 A = snat_random_port (1, pow2_mask (sm->psid_offset)); \
610 j = snat_random_port (0, pow2_mask (m)); \
611 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
612 if (a->busy_##n##_port_refcounts[portnum]) \
614 ++a->busy_##n##_port_refcounts[portnum]; \
615 a->busy_##n##_ports++; \
617 *port = clib_host_to_net_u16 (portnum); \
624 default : nat_elog_info ("unknown protocol");
629 /* Totally out of translations to use... */
630 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
635 nat44_ei_set_alloc_default ()
637 snat_main_t *sm = &snat_main;
639 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
640 sm->alloc_addr_and_port = nat44_ei_alloc_default_cb;
644 nat44_ei_set_alloc_range (u16 start_port, u16 end_port)
646 snat_main_t *sm = &snat_main;
648 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
649 sm->alloc_addr_and_port = nat44_ei_alloc_range_cb;
650 sm->start_port = start_port;
651 sm->end_port = end_port;
655 nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
657 snat_main_t *sm = &snat_main;
659 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
660 sm->alloc_addr_and_port = nat44_ei_alloc_mape_cb;
662 sm->psid_offset = psid_offset;
663 sm->psid_length = psid_length;
667 nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port,
668 u16 e_port, nat_protocol_t proto,
669 u32 sw_if_index, u32 vrf_id,
670 int addr_only, int identity_nat,
673 snat_main_t *sm = &snat_main;
674 snat_static_map_resolve_t *rp;
676 vec_add2 (sm->to_resolve, rp, 1);
677 clib_memset (rp, 0, sizeof (*rp));
679 rp->l_addr.as_u32 = l_addr.as_u32;
682 rp->sw_if_index = sw_if_index;
685 rp->addr_only = addr_only;
686 rp->identity_nat = identity_nat;
687 rp->tag = vec_dup (tag);
691 nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
692 nat_protocol_t proto, u32 vrf_id, int is_in)
694 snat_main_per_thread_data_t *tsm;
695 clib_bihash_kv_8_8_t kv, value;
697 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
699 clib_bihash_8_8_t *t;
701 if (sm->endpoint_dependent)
702 return VNET_API_ERROR_UNSUPPORTED;
704 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
705 if (sm->num_workers > 1)
706 tsm = vec_elt_at_index (sm->per_thread_data,
707 sm->worker_in2out_cb (&ip, fib_index, 0));
709 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
711 init_nat_k (&kv, *addr, port, fib_index, proto);
712 t = is_in ? &sm->in2out : &sm->out2in;
713 if (!clib_bihash_search_8_8 (t, &kv, &value))
715 if (pool_is_free_index (tsm->sessions, value.value))
716 return VNET_API_ERROR_UNSPECIFIED;
718 s = pool_elt_at_index (tsm->sessions, value.value);
719 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
720 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
724 return VNET_API_ERROR_NO_SUCH_ENTRY;
728 nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
729 u16 l_port, u16 e_port, nat_protocol_t proto,
730 u32 sw_if_index, u32 vrf_id, u8 addr_only,
731 u8 identity_nat, u8 *tag, u8 is_add)
733 snat_main_t *sm = &snat_main;
734 snat_static_mapping_t *m = 0;
735 clib_bihash_kv_8_8_t kv, value;
736 snat_address_t *a = 0;
738 snat_interface_t *interface;
739 snat_main_per_thread_data_t *tsm;
740 snat_user_key_t u_key;
742 dlist_elt_t *head, *elt;
743 u32 elt_index, head_index;
747 snat_static_map_resolve_t *rp, *rp_match = 0;
748 nat44_lb_addr_port_t *local;
752 if (sw_if_index != ~0)
754 ip4_address_t *first_int_addr;
756 for (i = 0; i < vec_len (sm->to_resolve); i++)
758 rp = sm->to_resolve + i;
759 if (rp->sw_if_index != sw_if_index ||
760 rp->l_addr.as_u32 != l_addr.as_u32 || rp->vrf_id != vrf_id ||
761 rp->addr_only != addr_only)
766 if ((rp->l_port != l_port && rp->e_port != e_port) ||
775 /* Might be already set... */
776 first_int_addr = ip4_interface_first_address (
777 sm->ip4_main, sw_if_index, 0 /* just want the address */);
782 return VNET_API_ERROR_VALUE_EXIST;
784 nat44_ei_add_static_mapping_when_resolved (
785 l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only,
788 /* DHCP resolution required? */
792 e_addr.as_u32 = first_int_addr->as_u32;
793 /* Identity mapping? */
794 if (l_addr.as_u32 == 0)
795 l_addr.as_u32 = e_addr.as_u32;
800 return VNET_API_ERROR_NO_SUCH_ENTRY;
802 vec_del1 (sm->to_resolve, i);
807 e_addr.as_u32 = first_int_addr->as_u32;
808 /* Identity mapping? */
809 if (l_addr.as_u32 == 0)
810 l_addr.as_u32 = e_addr.as_u32;
814 init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
815 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
816 m = pool_elt_at_index (sm->static_mappings, value.value);
822 // identity mapping for second vrf
823 if (is_identity_static_mapping (m))
825 pool_foreach (local, m->locals)
827 if (local->vrf_id == vrf_id)
828 return VNET_API_ERROR_VALUE_EXIST;
830 pool_get (m->locals, local);
831 local->vrf_id = vrf_id;
832 local->fib_index = fib_table_find_or_create_and_lock (
833 FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
834 init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
835 m->proto, 0, m - sm->static_mappings);
836 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
839 return VNET_API_ERROR_VALUE_EXIST;
842 /* Convert VRF id to FIB index */
845 fib_index = fib_table_find_or_create_and_lock (
846 FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
848 /* If not specified use inside VRF id from NAT44 plugin config */
851 fib_index = sm->inside_fib_index;
852 vrf_id = sm->inside_vrf_id;
853 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
858 init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index,
859 addr_only ? 0 : proto);
860 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
862 return VNET_API_ERROR_VALUE_EXIST;
865 /* Find external address in allocated addresses and reserve port for
866 address and port pair mapping when dynamic translations enabled */
867 if (!(addr_only || sm->static_mapping_only))
869 for (i = 0; i < vec_len (sm->addresses); i++)
871 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
873 a = sm->addresses + i;
874 /* External port must be unused */
877 #define _(N, j, n, s) \
878 case NAT_PROTOCOL_##N: \
879 if (a->busy_##n##_port_refcounts[e_port]) \
880 return VNET_API_ERROR_INVALID_VALUE; \
881 ++a->busy_##n##_port_refcounts[e_port]; \
884 a->busy_##n##_ports++; \
885 a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++; \
890 default : nat_elog_info ("unknown protocol");
891 return VNET_API_ERROR_INVALID_VALUE_2;
896 /* External address must be allocated */
897 if (!a && (l_addr.as_u32 != e_addr.as_u32))
899 if (sw_if_index != ~0)
901 for (i = 0; i < vec_len (sm->to_resolve); i++)
903 rp = sm->to_resolve + i;
906 if (rp->sw_if_index != sw_if_index &&
907 rp->l_addr.as_u32 != l_addr.as_u32 &&
908 rp->vrf_id != vrf_id && rp->l_port != l_port &&
909 rp->e_port != e_port && rp->proto != proto)
912 vec_del1 (sm->to_resolve, i);
916 return VNET_API_ERROR_NO_SUCH_ENTRY;
920 pool_get (sm->static_mappings, m);
921 clib_memset (m, 0, sizeof (*m));
922 m->tag = vec_dup (tag);
923 m->local_addr = l_addr;
924 m->external_addr = e_addr;
927 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
930 m->local_port = l_port;
931 m->external_port = e_port;
937 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
938 pool_get (m->locals, local);
939 local->vrf_id = vrf_id;
940 local->fib_index = fib_index;
945 m->fib_index = fib_index;
948 if (sm->num_workers > 1)
951 .src_address = m->local_addr,
953 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
954 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
957 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
959 init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
960 m - sm->static_mappings);
961 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
963 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
964 m - sm->static_mappings);
965 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
967 /* Delete dynamic sessions matching local address (+ local port) */
968 // TODO: based on type of NAT EI/ED
969 if (!(sm->static_mapping_only))
971 u_key.addr = m->local_addr;
972 u_key.fib_index = m->fib_index;
973 kv.key = u_key.as_u64;
974 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
976 user_index = value.value;
977 u = pool_elt_at_index (tsm->users, user_index);
980 head_index = u->sessions_per_user_list_head_index;
981 head = pool_elt_at_index (tsm->list_pool, head_index);
982 elt_index = head->next;
983 elt = pool_elt_at_index (tsm->list_pool, elt_index);
984 ses_index = elt->value;
985 while (ses_index != ~0)
987 s = pool_elt_at_index (tsm->sessions, ses_index);
988 elt = pool_elt_at_index (tsm->list_pool, elt->next);
989 ses_index = elt->value;
991 if (snat_is_session_static (s))
994 if (!addr_only && s->in2out.port != m->local_port)
997 nat_free_session_data (sm, s, tsm - sm->per_thread_data,
999 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1012 if (sw_if_index != ~0)
1015 return VNET_API_ERROR_NO_SUCH_ENTRY;
1021 vrf_id = sm->inside_vrf_id;
1023 pool_foreach (local, m->locals)
1025 if (local->vrf_id == vrf_id)
1026 find = local - m->locals;
1029 return VNET_API_ERROR_NO_SUCH_ENTRY;
1031 local = pool_elt_at_index (m->locals, find);
1032 fib_index = local->fib_index;
1033 pool_put (m->locals, local);
1036 fib_index = m->fib_index;
1038 /* Free external address port */
1039 if (!(addr_only || sm->static_mapping_only))
1041 for (i = 0; i < vec_len (sm->addresses); i++)
1043 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1045 a = sm->addresses + i;
1048 #define _(N, j, n, s) \
1049 case NAT_PROTOCOL_##N: \
1050 --a->busy_##n##_port_refcounts[e_port]; \
1051 if (e_port > 1024) \
1053 a->busy_##n##_ports--; \
1054 a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--; \
1057 foreach_nat_protocol
1059 default : return VNET_API_ERROR_INVALID_VALUE_2;
1066 if (sm->num_workers > 1)
1067 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1069 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1071 init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
1072 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1074 /* Delete session(s) for static mapping if exist */
1075 if (!(sm->static_mapping_only) ||
1076 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1078 u_key.addr = m->local_addr;
1079 u_key.fib_index = fib_index;
1080 kv.key = u_key.as_u64;
1081 nat44_ei_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
1085 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1086 if (pool_elts (m->locals))
1089 init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1090 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1093 vec_free (m->workers);
1094 /* Delete static mapping from pool */
1095 pool_put (sm->static_mappings, m);
1098 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1101 /* Add/delete external address to FIB */
1102 pool_foreach (interface, sm->interfaces)
1104 if (nat_interface_is_inside (interface) || sm->out2in_dpo)
1107 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
1110 pool_foreach (interface, sm->output_feature_interfaces)
1112 if (nat_interface_is_inside (interface) || sm->out2in_dpo)
1115 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
1122 nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
1123 u32 match_fib_index,
1124 nat_protocol_t match_protocol,
1125 ip4_address_t *mapping_addr, u16 *mapping_port,
1126 u32 *mapping_fib_index, u8 by_external,
1127 u8 *is_addr_only, u8 *is_identity_nat)
1129 snat_main_t *sm = &snat_main;
1130 clib_bihash_kv_8_8_t kv, value;
1131 snat_static_mapping_t *m;
1136 init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
1137 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
1140 /* Try address only mapping */
1141 init_nat_k (&kv, match_addr, 0, 0, 0);
1142 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
1146 m = pool_elt_at_index (sm->static_mappings, value.value);
1148 *mapping_fib_index = m->fib_index;
1149 *mapping_addr = m->local_addr;
1150 port = m->local_port;
1154 init_nat_k (&kv, match_addr, match_port, match_fib_index,
1156 if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
1158 /* Try address only mapping */
1159 init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
1160 if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
1164 m = pool_elt_at_index (sm->static_mappings, value.value);
1166 *mapping_fib_index = sm->outside_fib_index;
1167 *mapping_addr = m->external_addr;
1168 port = m->external_port;
1171 /* Address only mapping doesn't change port */
1172 if (is_addr_only_static_mapping (m))
1173 *mapping_port = match_port;
1175 *mapping_port = port;
1177 if (PREDICT_FALSE (is_addr_only != 0))
1178 *is_addr_only = is_addr_only_static_mapping (m);
1180 if (PREDICT_FALSE (is_identity_nat != 0))
1181 *is_identity_nat = is_identity_static_mapping (m);
1187 nat44_ei_worker_db_free (snat_main_per_thread_data_t *tsm)
1189 pool_free (tsm->list_pool);
1190 pool_free (tsm->lru_pool);
1191 pool_free (tsm->sessions);
1192 pool_free (tsm->users);
1194 clib_bihash_free_8_8 (&tsm->user_hash);
1198 nat44_ei_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
1199 u32 translation_buckets, u32 user_buckets)
1203 pool_alloc (tsm->list_pool, translations);
1204 pool_alloc (tsm->lru_pool, translations);
1205 pool_alloc (tsm->sessions, translations);
1207 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0);
1209 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
1211 pool_get (tsm->lru_pool, head);
1212 tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
1213 clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
1215 pool_get (tsm->lru_pool, head);
1216 tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
1217 clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
1219 pool_get (tsm->lru_pool, head);
1220 tsm->udp_lru_head_index = head - tsm->lru_pool;
1221 clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
1223 pool_get (tsm->lru_pool, head);
1224 tsm->icmp_lru_head_index = head - tsm->lru_pool;
1225 clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
1227 pool_get (tsm->lru_pool, head);
1228 tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
1229 clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
1235 snat_main_t *sm = &snat_main;
1236 snat_main_per_thread_data_t *tsm;
1238 pool_free (sm->static_mappings);
1239 clib_bihash_free_8_8 (&sm->static_mapping_by_local);
1240 clib_bihash_free_8_8 (&sm->static_mapping_by_external);
1244 clib_bihash_free_8_8 (&sm->in2out);
1245 clib_bihash_free_8_8 (&sm->out2in);
1246 vec_foreach (tsm, sm->per_thread_data)
1248 nat44_ei_worker_db_free (tsm);
1254 nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
1256 snat_main_t *sm = &snat_main;
1257 snat_main_per_thread_data_t *tsm;
1259 u32 static_mapping_buckets = 1024;
1260 u32 static_mapping_memory_size = 64 << 20;
1262 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1263 "static_mapping_by_local", static_mapping_buckets,
1264 static_mapping_memory_size);
1265 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1266 "static_mapping_by_external", static_mapping_buckets,
1267 static_mapping_memory_size);
1268 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
1269 format_static_mapping_kvp);
1270 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
1271 format_static_mapping_kvp);
1275 clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, 0);
1276 clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, 0);
1277 clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
1278 clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
1279 vec_foreach (tsm, sm->per_thread_data)
1281 nat44_ei_worker_db_init (tsm, translations, translation_buckets,
1288 nat44_ei_sessions_clear ()
1290 nat44_ei_main_t *nm = &nat44_ei_main;
1292 snat_main_per_thread_data_t *tsm;
1293 snat_main_t *sm = &snat_main;
1297 clib_bihash_free_8_8 (&sm->in2out);
1298 clib_bihash_free_8_8 (&sm->out2in);
1299 clib_bihash_init_8_8 (&sm->in2out, "in2out", nm->translation_buckets, 0);
1300 clib_bihash_init_8_8 (&sm->out2in, "out2in", nm->translation_buckets, 0);
1301 clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
1302 clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
1303 vec_foreach (tsm, sm->per_thread_data)
1305 nat44_ei_worker_db_free (tsm);
1306 nat44_ei_worker_db_init (tsm, nm->translations,
1307 nm->translation_buckets, nm->user_buckets);
1311 // TODO: function for reset counters
1312 vlib_zero_simple_counter (&sm->total_users, 0);
1313 vlib_zero_simple_counter (&sm->total_sessions, 0);
1314 vlib_zero_simple_counter (&sm->user_limit_reached, 0);
1318 * fd.io coding-style-patch-verification: ON
1321 * eval: (c-set-style "gnu")