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);
126 nat44_ei_plugin_disable ()
128 nat44_ei_main_t *nm = &nat44_ei_main;
129 snat_main_t *sm = &snat_main;
130 snat_interface_t *i, *vec;
133 // first unregister all nodes from interfaces
134 vec = vec_dup (sm->interfaces);
137 if (nat_interface_is_inside (i))
138 error = snat_interface_add_del (i->sw_if_index, 1, 1);
139 if (nat_interface_is_outside (i))
140 error = snat_interface_add_del (i->sw_if_index, 0, 1);
144 nat_log_err ("error occurred while removing interface %u",
151 vec = vec_dup (sm->output_feature_interfaces);
154 if (nat_interface_is_inside (i))
155 error = snat_interface_add_del_output_feature (i->sw_if_index, 1, 1);
156 if (nat_interface_is_outside (i))
157 error = snat_interface_add_del_output_feature (i->sw_if_index, 0, 1);
161 nat_log_err ("error occurred while removing interface %u",
166 sm->output_feature_interfaces = 0;
171 nat44_addresses_free (&sm->addresses);
172 nat44_addresses_free (&sm->twice_nat_addresses);
174 vec_free (sm->to_resolve);
175 vec_free (sm->auto_add_sw_if_indices);
176 vec_free (sm->auto_add_sw_if_indices_twice_nat);
179 sm->auto_add_sw_if_indices = 0;
180 sm->auto_add_sw_if_indices_twice_nat = 0;
182 sm->forwarding_enabled = 0;
185 clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
186 clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig));
192 nat44_ei_free_session_data (snat_main_t *sm, snat_session_t *s,
193 u32 thread_index, u8 is_ha)
195 clib_bihash_kv_8_8_t kv;
197 init_nat_i2o_k (&kv, s);
198 if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0))
199 nat_elog_warn ("in2out key del failed");
201 init_nat_o2i_k (&kv, s);
202 if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0))
203 nat_elog_warn ("out2in key del failed");
207 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
208 &s->in2out.addr, s->in2out.port,
209 &s->out2in.addr, s->out2in.port, s->nat_proto);
211 nat_ipfix_logging_nat44_ses_delete (
212 thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
213 s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
215 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
216 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
220 if (snat_is_session_static (s))
223 snat_free_outside_address_and_port (sm->addresses, thread_index,
224 &s->out2in.addr, s->out2in.port,
228 static_always_inline void
229 nat44_ei_user_del_sessions (snat_user_t *u, u32 thread_index)
234 snat_main_t *sm = &snat_main;
235 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
239 pool_elt_at_index (tsm->list_pool, u->sessions_per_user_list_head_index);
241 elt = pool_elt_at_index (tsm->list_pool, elt->next);
243 while (elt->value != ~0)
245 s = pool_elt_at_index (tsm->sessions, elt->value);
246 elt = pool_elt_at_index (tsm->list_pool, elt->next);
248 nat44_ei_free_session_data (sm, s, thread_index, 0);
249 nat44_delete_session (sm, s, thread_index);
254 nat44_ei_user_del (ip4_address_t *addr, u32 fib_index)
258 snat_main_t *sm = &snat_main;
259 snat_main_per_thread_data_t *tsm;
261 snat_user_key_t user_key;
262 clib_bihash_kv_8_8_t kv, value;
264 if (sm->endpoint_dependent)
267 user_key.addr.as_u32 = addr->as_u32;
268 user_key.fib_index = fib_index;
269 kv.key = user_key.as_u64;
271 if (sm->num_workers > 1)
273 vec_foreach (tsm, sm->per_thread_data)
275 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
277 nat44_ei_user_del_sessions (
278 pool_elt_at_index (tsm->users, value.value),
287 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
288 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
290 nat44_ei_user_del_sessions (
291 pool_elt_at_index (tsm->users, value.value), tsm->thread_index);
299 nat44_ei_static_mapping_del_sessions (snat_main_t *sm,
300 snat_main_per_thread_data_t *tsm,
301 snat_user_key_t u_key, int addr_only,
302 ip4_address_t e_addr, u16 e_port)
304 clib_bihash_kv_8_8_t kv, value;
305 kv.key = u_key.as_u64;
307 dlist_elt_t *head, *elt;
310 u32 elt_index, head_index, ses_index;
312 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
314 user_index = value.value;
315 u = pool_elt_at_index (tsm->users, user_index);
316 if (u->nstaticsessions)
318 head_index = u->sessions_per_user_list_head_index;
319 head = pool_elt_at_index (tsm->list_pool, head_index);
320 elt_index = head->next;
321 elt = pool_elt_at_index (tsm->list_pool, elt_index);
322 ses_index = elt->value;
323 while (ses_index != ~0)
325 s = pool_elt_at_index (tsm->sessions, ses_index);
326 elt = pool_elt_at_index (tsm->list_pool, elt->next);
327 ses_index = elt->value;
331 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
332 (s->out2in.port != e_port))
336 if (is_lb_session (s))
339 if (!snat_is_session_static (s))
342 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
343 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
353 nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
356 snat_main_t *sm = &snat_main;
357 u32 next_worker_index = 0;
360 next_worker_index = sm->first_worker_index;
361 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
362 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
364 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
365 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
367 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
369 return next_worker_index;
373 nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
374 u32 rx_fib_index0, u8 is_output)
376 snat_main_t *sm = &snat_main;
379 clib_bihash_kv_8_8_t kv, value;
380 snat_static_mapping_t *m;
382 u32 next_worker_index = 0;
384 /* first try static mappings without port */
385 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
387 init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
388 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
391 m = pool_elt_at_index (sm->static_mappings, value.value);
392 return m->workers[0];
396 proto = ip_proto_to_nat_proto (ip0->protocol);
397 udp = ip4_next_header (ip0);
398 port = udp->dst_port;
400 /* unknown protocol */
401 if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
403 /* use current thread */
404 return vlib_get_thread_index ();
407 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
409 icmp46_header_t *icmp = (icmp46_header_t *) udp;
410 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
411 if (!icmp_type_is_error_message (
412 vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
413 port = vnet_buffer (b)->ip.reass.l4_src_port;
416 /* if error message, then it's not fragmented and we can access it */
417 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
418 proto = ip_proto_to_nat_proto (inner_ip->protocol);
419 void *l4_header = ip4_next_header (inner_ip);
422 case NAT_PROTOCOL_ICMP:
423 icmp = (icmp46_header_t *) l4_header;
424 echo = (icmp_echo_header_t *) (icmp + 1);
425 port = echo->identifier;
427 case NAT_PROTOCOL_UDP:
428 case NAT_PROTOCOL_TCP:
429 port = ((tcp_udp_header_t *) l4_header)->src_port;
432 return vlib_get_thread_index ();
437 /* try static mappings with port */
438 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
440 init_nat_k (&kv, ip0->dst_address, port, rx_fib_index0, proto);
441 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
444 m = pool_elt_at_index (sm->static_mappings, value.value);
445 return m->workers[0];
449 /* worker by outside port */
450 next_worker_index = sm->first_worker_index;
452 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
453 return next_worker_index;
457 nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
458 u32 thread_index, nat_protocol_t proto,
459 ip4_address_t *addr, u16 *port, u16 port_per_thread,
460 u32 snat_thread_index)
463 snat_address_t *a, *ga = 0;
466 for (i = 0; i < vec_len (addresses); i++)
471 #define _(N, j, n, s) \
472 case NAT_PROTOCOL_##N: \
473 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
475 if (a->fib_index == fib_index) \
479 portnum = (port_per_thread * snat_thread_index) + \
480 snat_random_port (0, port_per_thread - 1) + 1024; \
481 if (a->busy_##n##_port_refcounts[portnum]) \
483 --a->busy_##n##_port_refcounts[portnum]; \
484 a->busy_##n##_ports_per_thread[thread_index]++; \
485 a->busy_##n##_ports++; \
487 *port = clib_host_to_net_u16 (portnum); \
491 else if (a->fib_index == ~0) \
499 default : nat_elog_info ("unknown protocol");
509 #define _(N, j, n, s) \
510 case NAT_PROTOCOL_##N: \
513 portnum = (port_per_thread * snat_thread_index) + \
514 snat_random_port (0, port_per_thread - 1) + 1024; \
515 if (a->busy_##n##_port_refcounts[portnum]) \
517 ++a->busy_##n##_port_refcounts[portnum]; \
518 a->busy_##n##_ports_per_thread[thread_index]++; \
519 a->busy_##n##_ports++; \
521 *port = clib_host_to_net_u16 (portnum); \
527 default : nat_elog_info ("unknown protocol");
532 /* Totally out of translations to use... */
533 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
538 nat44_ei_alloc_range_cb (snat_address_t *addresses, u32 fib_index,
539 u32 thread_index, nat_protocol_t proto,
540 ip4_address_t *addr, u16 *port, u16 port_per_thread,
541 u32 snat_thread_index)
543 snat_main_t *sm = &snat_main;
544 snat_address_t *a = addresses;
547 ports = sm->end_port - sm->start_port + 1;
549 if (!vec_len (addresses))
554 #define _(N, i, n, s) \
555 case NAT_PROTOCOL_##N: \
556 if (a->busy_##n##_ports < ports) \
560 portnum = snat_random_port (sm->start_port, sm->end_port); \
561 if (a->busy_##n##_port_refcounts[portnum]) \
563 ++a->busy_##n##_port_refcounts[portnum]; \
564 a->busy_##n##_ports++; \
566 *port = clib_host_to_net_u16 (portnum); \
573 default : nat_elog_info ("unknown protocol");
578 /* Totally out of translations to use... */
579 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
584 nat44_ei_alloc_mape_cb (snat_address_t *addresses, u32 fib_index,
585 u32 thread_index, nat_protocol_t proto,
586 ip4_address_t *addr, u16 *port, u16 port_per_thread,
587 u32 snat_thread_index)
589 snat_main_t *sm = &snat_main;
590 snat_address_t *a = addresses;
591 u16 m, ports, portnum, A, j;
592 m = 16 - (sm->psid_offset + sm->psid_length);
593 ports = (1 << (16 - sm->psid_length)) - (1 << m);
595 if (!vec_len (addresses))
600 #define _(N, i, n, s) \
601 case NAT_PROTOCOL_##N: \
602 if (a->busy_##n##_ports < ports) \
606 A = snat_random_port (1, pow2_mask (sm->psid_offset)); \
607 j = snat_random_port (0, pow2_mask (m)); \
608 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
609 if (a->busy_##n##_port_refcounts[portnum]) \
611 ++a->busy_##n##_port_refcounts[portnum]; \
612 a->busy_##n##_ports++; \
614 *port = clib_host_to_net_u16 (portnum); \
621 default : nat_elog_info ("unknown protocol");
626 /* Totally out of translations to use... */
627 nat_ipfix_logging_addresses_exhausted (thread_index, 0);
632 nat44_ei_set_alloc_default ()
634 snat_main_t *sm = &snat_main;
636 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
637 sm->alloc_addr_and_port = nat44_ei_alloc_default_cb;
641 nat44_ei_set_alloc_range (u16 start_port, u16 end_port)
643 snat_main_t *sm = &snat_main;
645 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
646 sm->alloc_addr_and_port = nat44_ei_alloc_range_cb;
647 sm->start_port = start_port;
648 sm->end_port = end_port;
652 nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
654 snat_main_t *sm = &snat_main;
656 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
657 sm->alloc_addr_and_port = nat44_ei_alloc_mape_cb;
659 sm->psid_offset = psid_offset;
660 sm->psid_length = psid_length;
664 nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port,
665 u16 e_port, nat_protocol_t proto,
666 u32 sw_if_index, u32 vrf_id,
667 int addr_only, int identity_nat,
670 snat_main_t *sm = &snat_main;
671 snat_static_map_resolve_t *rp;
673 vec_add2 (sm->to_resolve, rp, 1);
674 clib_memset (rp, 0, sizeof (*rp));
676 rp->l_addr.as_u32 = l_addr.as_u32;
679 rp->sw_if_index = sw_if_index;
682 rp->addr_only = addr_only;
683 rp->identity_nat = identity_nat;
684 rp->tag = vec_dup (tag);
688 nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
689 nat_protocol_t proto, u32 vrf_id, int is_in)
691 snat_main_per_thread_data_t *tsm;
692 clib_bihash_kv_8_8_t kv, value;
694 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
696 clib_bihash_8_8_t *t;
698 if (sm->endpoint_dependent)
699 return VNET_API_ERROR_UNSUPPORTED;
701 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
702 if (sm->num_workers > 1)
703 tsm = vec_elt_at_index (sm->per_thread_data,
704 sm->worker_in2out_cb (&ip, fib_index, 0));
706 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
708 init_nat_k (&kv, *addr, port, fib_index, proto);
709 t = is_in ? &sm->in2out : &sm->out2in;
710 if (!clib_bihash_search_8_8 (t, &kv, &value))
712 if (pool_is_free_index (tsm->sessions, value.value))
713 return VNET_API_ERROR_UNSPECIFIED;
715 s = pool_elt_at_index (tsm->sessions, value.value);
716 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
717 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
721 return VNET_API_ERROR_NO_SUCH_ENTRY;
725 nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
726 u16 l_port, u16 e_port, nat_protocol_t proto,
727 u32 sw_if_index, u32 vrf_id, u8 addr_only,
728 u8 identity_nat, u8 *tag, u8 is_add)
730 snat_main_t *sm = &snat_main;
731 snat_static_mapping_t *m = 0;
732 clib_bihash_kv_8_8_t kv, value;
733 snat_address_t *a = 0;
735 snat_interface_t *interface;
736 snat_main_per_thread_data_t *tsm;
737 snat_user_key_t u_key;
739 dlist_elt_t *head, *elt;
740 u32 elt_index, head_index;
744 snat_static_map_resolve_t *rp, *rp_match = 0;
745 nat44_lb_addr_port_t *local;
749 if (sw_if_index != ~0)
751 ip4_address_t *first_int_addr;
753 for (i = 0; i < vec_len (sm->to_resolve); i++)
755 rp = sm->to_resolve + i;
756 if (rp->sw_if_index != sw_if_index ||
757 rp->l_addr.as_u32 != l_addr.as_u32 || rp->vrf_id != vrf_id ||
758 rp->addr_only != addr_only)
763 if ((rp->l_port != l_port && rp->e_port != e_port) ||
772 /* Might be already set... */
773 first_int_addr = ip4_interface_first_address (
774 sm->ip4_main, sw_if_index, 0 /* just want the address */);
779 return VNET_API_ERROR_VALUE_EXIST;
781 nat44_ei_add_static_mapping_when_resolved (
782 l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only,
785 /* DHCP resolution required? */
789 e_addr.as_u32 = first_int_addr->as_u32;
790 /* Identity mapping? */
791 if (l_addr.as_u32 == 0)
792 l_addr.as_u32 = e_addr.as_u32;
797 return VNET_API_ERROR_NO_SUCH_ENTRY;
799 vec_del1 (sm->to_resolve, i);
804 e_addr.as_u32 = first_int_addr->as_u32;
805 /* Identity mapping? */
806 if (l_addr.as_u32 == 0)
807 l_addr.as_u32 = e_addr.as_u32;
811 init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
812 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
813 m = pool_elt_at_index (sm->static_mappings, value.value);
819 // identity mapping for second vrf
820 if (is_identity_static_mapping (m))
822 pool_foreach (local, m->locals)
824 if (local->vrf_id == vrf_id)
825 return VNET_API_ERROR_VALUE_EXIST;
827 pool_get (m->locals, local);
828 local->vrf_id = vrf_id;
829 local->fib_index = fib_table_find_or_create_and_lock (
830 FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
831 init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
832 m->proto, 0, m - sm->static_mappings);
833 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
836 return VNET_API_ERROR_VALUE_EXIST;
839 /* Convert VRF id to FIB index */
842 fib_index = fib_table_find_or_create_and_lock (
843 FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
845 /* If not specified use inside VRF id from NAT44 plugin config */
848 fib_index = sm->inside_fib_index;
849 vrf_id = sm->inside_vrf_id;
850 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
855 init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index,
856 addr_only ? 0 : proto);
857 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
859 return VNET_API_ERROR_VALUE_EXIST;
862 /* Find external address in allocated addresses and reserve port for
863 address and port pair mapping when dynamic translations enabled */
864 if (!(addr_only || sm->static_mapping_only))
866 for (i = 0; i < vec_len (sm->addresses); i++)
868 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
870 a = sm->addresses + i;
871 /* External port must be unused */
874 #define _(N, j, n, s) \
875 case NAT_PROTOCOL_##N: \
876 if (a->busy_##n##_port_refcounts[e_port]) \
877 return VNET_API_ERROR_INVALID_VALUE; \
878 ++a->busy_##n##_port_refcounts[e_port]; \
881 a->busy_##n##_ports++; \
882 a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++; \
887 default : nat_elog_info ("unknown protocol");
888 return VNET_API_ERROR_INVALID_VALUE_2;
893 /* External address must be allocated */
894 if (!a && (l_addr.as_u32 != e_addr.as_u32))
896 if (sw_if_index != ~0)
898 for (i = 0; i < vec_len (sm->to_resolve); i++)
900 rp = sm->to_resolve + i;
903 if (rp->sw_if_index != sw_if_index &&
904 rp->l_addr.as_u32 != l_addr.as_u32 &&
905 rp->vrf_id != vrf_id && rp->l_port != l_port &&
906 rp->e_port != e_port && rp->proto != proto)
909 vec_del1 (sm->to_resolve, i);
913 return VNET_API_ERROR_NO_SUCH_ENTRY;
917 pool_get (sm->static_mappings, m);
918 clib_memset (m, 0, sizeof (*m));
919 m->tag = vec_dup (tag);
920 m->local_addr = l_addr;
921 m->external_addr = e_addr;
924 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
927 m->local_port = l_port;
928 m->external_port = e_port;
934 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
935 pool_get (m->locals, local);
936 local->vrf_id = vrf_id;
937 local->fib_index = fib_index;
942 m->fib_index = fib_index;
945 if (sm->num_workers > 1)
948 .src_address = m->local_addr,
950 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
951 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
954 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
956 init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
957 m - sm->static_mappings);
958 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
960 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
961 m - sm->static_mappings);
962 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
964 /* Delete dynamic sessions matching local address (+ local port) */
965 // TODO: based on type of NAT EI/ED
966 if (!(sm->static_mapping_only))
968 u_key.addr = m->local_addr;
969 u_key.fib_index = m->fib_index;
970 kv.key = u_key.as_u64;
971 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
973 user_index = value.value;
974 u = pool_elt_at_index (tsm->users, user_index);
977 head_index = u->sessions_per_user_list_head_index;
978 head = pool_elt_at_index (tsm->list_pool, head_index);
979 elt_index = head->next;
980 elt = pool_elt_at_index (tsm->list_pool, elt_index);
981 ses_index = elt->value;
982 while (ses_index != ~0)
984 s = pool_elt_at_index (tsm->sessions, ses_index);
985 elt = pool_elt_at_index (tsm->list_pool, elt->next);
986 ses_index = elt->value;
988 if (snat_is_session_static (s))
991 if (!addr_only && s->in2out.port != m->local_port)
994 nat_free_session_data (sm, s, tsm - sm->per_thread_data,
996 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1009 if (sw_if_index != ~0)
1012 return VNET_API_ERROR_NO_SUCH_ENTRY;
1018 vrf_id = sm->inside_vrf_id;
1020 pool_foreach (local, m->locals)
1022 if (local->vrf_id == vrf_id)
1023 find = local - m->locals;
1026 return VNET_API_ERROR_NO_SUCH_ENTRY;
1028 local = pool_elt_at_index (m->locals, find);
1029 fib_index = local->fib_index;
1030 pool_put (m->locals, local);
1033 fib_index = m->fib_index;
1035 /* Free external address port */
1036 if (!(addr_only || sm->static_mapping_only))
1038 for (i = 0; i < vec_len (sm->addresses); i++)
1040 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1042 a = sm->addresses + i;
1045 #define _(N, j, n, s) \
1046 case NAT_PROTOCOL_##N: \
1047 --a->busy_##n##_port_refcounts[e_port]; \
1048 if (e_port > 1024) \
1050 a->busy_##n##_ports--; \
1051 a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--; \
1054 foreach_nat_protocol
1056 default : return VNET_API_ERROR_INVALID_VALUE_2;
1063 if (sm->num_workers > 1)
1064 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1066 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1068 init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
1069 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1071 /* Delete session(s) for static mapping if exist */
1072 if (!(sm->static_mapping_only) ||
1073 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1075 u_key.addr = m->local_addr;
1076 u_key.fib_index = fib_index;
1077 kv.key = u_key.as_u64;
1078 nat44_ei_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
1082 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1083 if (pool_elts (m->locals))
1086 init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1087 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1090 vec_free (m->workers);
1091 /* Delete static mapping from pool */
1092 pool_put (sm->static_mappings, m);
1095 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1098 /* Add/delete external address to FIB */
1099 pool_foreach (interface, sm->interfaces)
1101 if (nat_interface_is_inside (interface) || sm->out2in_dpo)
1104 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
1107 pool_foreach (interface, sm->output_feature_interfaces)
1109 if (nat_interface_is_inside (interface) || sm->out2in_dpo)
1112 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
1119 nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
1120 u32 match_fib_index,
1121 nat_protocol_t match_protocol,
1122 ip4_address_t *mapping_addr, u16 *mapping_port,
1123 u32 *mapping_fib_index, u8 by_external,
1124 u8 *is_addr_only, u8 *is_identity_nat)
1126 snat_main_t *sm = &snat_main;
1127 clib_bihash_kv_8_8_t kv, value;
1128 snat_static_mapping_t *m;
1133 init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
1134 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
1137 /* Try address only mapping */
1138 init_nat_k (&kv, match_addr, 0, 0, 0);
1139 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
1143 m = pool_elt_at_index (sm->static_mappings, value.value);
1145 *mapping_fib_index = m->fib_index;
1146 *mapping_addr = m->local_addr;
1147 port = m->local_port;
1151 init_nat_k (&kv, match_addr, match_port, match_fib_index,
1153 if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
1155 /* Try address only mapping */
1156 init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
1157 if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
1161 m = pool_elt_at_index (sm->static_mappings, value.value);
1163 *mapping_fib_index = sm->outside_fib_index;
1164 *mapping_addr = m->external_addr;
1165 port = m->external_port;
1168 /* Address only mapping doesn't change port */
1169 if (is_addr_only_static_mapping (m))
1170 *mapping_port = match_port;
1172 *mapping_port = port;
1174 if (PREDICT_FALSE (is_addr_only != 0))
1175 *is_addr_only = is_addr_only_static_mapping (m);
1177 if (PREDICT_FALSE (is_identity_nat != 0))
1178 *is_identity_nat = is_identity_static_mapping (m);
1184 nat44_ei_worker_db_free (snat_main_per_thread_data_t *tsm)
1186 pool_free (tsm->list_pool);
1187 pool_free (tsm->lru_pool);
1188 pool_free (tsm->sessions);
1189 pool_free (tsm->users);
1191 clib_bihash_free_8_8 (&tsm->user_hash);
1195 nat44_ei_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
1196 u32 translation_buckets, u32 user_buckets)
1200 pool_alloc (tsm->list_pool, translations);
1201 pool_alloc (tsm->lru_pool, translations);
1202 pool_alloc (tsm->sessions, translations);
1204 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0);
1206 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
1208 pool_get (tsm->lru_pool, head);
1209 tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
1210 clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
1212 pool_get (tsm->lru_pool, head);
1213 tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
1214 clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
1216 pool_get (tsm->lru_pool, head);
1217 tsm->udp_lru_head_index = head - tsm->lru_pool;
1218 clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
1220 pool_get (tsm->lru_pool, head);
1221 tsm->icmp_lru_head_index = head - tsm->lru_pool;
1222 clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
1224 pool_get (tsm->lru_pool, head);
1225 tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
1226 clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
1232 snat_main_t *sm = &snat_main;
1233 snat_main_per_thread_data_t *tsm;
1235 pool_free (sm->static_mappings);
1236 clib_bihash_free_8_8 (&sm->static_mapping_by_local);
1237 clib_bihash_free_8_8 (&sm->static_mapping_by_external);
1241 clib_bihash_free_8_8 (&sm->in2out);
1242 clib_bihash_free_8_8 (&sm->out2in);
1243 vec_foreach (tsm, sm->per_thread_data)
1245 nat44_ei_worker_db_free (tsm);
1251 nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
1253 snat_main_t *sm = &snat_main;
1254 snat_main_per_thread_data_t *tsm;
1256 u32 static_mapping_buckets = 1024;
1257 u32 static_mapping_memory_size = 64 << 20;
1259 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1260 "static_mapping_by_local", static_mapping_buckets,
1261 static_mapping_memory_size);
1262 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1263 "static_mapping_by_external", static_mapping_buckets,
1264 static_mapping_memory_size);
1265 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
1266 format_static_mapping_kvp);
1267 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
1268 format_static_mapping_kvp);
1272 clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, 0);
1273 clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, 0);
1274 clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
1275 clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
1276 vec_foreach (tsm, sm->per_thread_data)
1278 nat44_ei_worker_db_init (tsm, translations, translation_buckets,
1285 nat44_ei_sessions_clear ()
1287 nat44_ei_main_t *nm = &nat44_ei_main;
1289 snat_main_per_thread_data_t *tsm;
1290 snat_main_t *sm = &snat_main;
1294 clib_bihash_free_8_8 (&sm->in2out);
1295 clib_bihash_free_8_8 (&sm->out2in);
1296 clib_bihash_init_8_8 (&sm->in2out, "in2out", nm->translation_buckets, 0);
1297 clib_bihash_init_8_8 (&sm->out2in, "out2in", nm->translation_buckets, 0);
1298 clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
1299 clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
1300 vec_foreach (tsm, sm->per_thread_data)
1302 nat44_ei_worker_db_free (tsm);
1303 nat44_ei_worker_db_init (tsm, nm->translations,
1304 nm->translation_buckets, nm->user_buckets);
1308 // TODO: function for reset counters
1309 vlib_zero_simple_counter (&sm->total_users, 0);
1310 vlib_zero_simple_counter (&sm->total_sessions, 0);
1311 vlib_zero_simple_counter (&sm->user_limit_reached, 0);
1315 * fd.io coding-style-patch-verification: ON
1318 * eval: (c-set-style "gnu")