2 * snat.c - simple nat plugin
4 * Copyright (c) 2016 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,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
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_ipfix_logging.h>
24 #include <nat/nat_det.h>
25 #include <nat/nat64.h>
26 #include <vnet/fib/fib_table.h>
27 #include <vnet/fib/ip4_fib.h>
29 #include <vpp/app/version.h>
31 snat_main_t snat_main;
34 /* Hook up input features */
35 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
36 .arc_name = "ip4-unicast",
37 .node_name = "nat44-in2out",
38 .runs_before = VNET_FEATURES ("nat44-out2in"),
40 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
41 .arc_name = "ip4-unicast",
42 .node_name = "nat44-out2in",
43 .runs_before = VNET_FEATURES ("ip4-lookup"),
45 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
46 .arc_name = "ip4-unicast",
47 .node_name = "nat44-det-in2out",
48 .runs_before = VNET_FEATURES ("nat44-det-out2in"),
50 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
51 .arc_name = "ip4-unicast",
52 .node_name = "nat44-det-out2in",
53 .runs_before = VNET_FEATURES ("ip4-lookup"),
55 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
56 .arc_name = "ip4-unicast",
57 .node_name = "nat44-in2out-worker-handoff",
58 .runs_before = VNET_FEATURES ("nat44-out2in-worker-handoff"),
60 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
61 .arc_name = "ip4-unicast",
62 .node_name = "nat44-out2in-worker-handoff",
63 .runs_before = VNET_FEATURES ("ip4-lookup"),
65 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
66 .arc_name = "ip4-unicast",
67 .node_name = "nat44-in2out-fast",
68 .runs_before = VNET_FEATURES ("nat44-out2in-fast"),
70 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
71 .arc_name = "ip4-unicast",
72 .node_name = "nat44-out2in-fast",
73 .runs_before = VNET_FEATURES ("ip4-lookup"),
75 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
76 .arc_name = "ip4-unicast",
77 .node_name = "nat44-hairpin-dst",
78 .runs_before = VNET_FEATURES ("ip4-lookup"),
81 /* Hook up output features */
82 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
83 .arc_name = "ip4-output",
84 .node_name = "nat44-in2out-output",
85 .runs_before = VNET_FEATURES ("interface-output"),
87 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
88 .arc_name = "ip4-output",
89 .node_name = "nat44-in2out-output-worker-handoff",
90 .runs_before = VNET_FEATURES ("interface-output"),
92 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
93 .arc_name = "ip4-output",
94 .node_name = "nat44-hairpin-src",
95 .runs_before = VNET_FEATURES ("interface-output"),
100 VLIB_PLUGIN_REGISTER () = {
101 .version = VPP_BUILD_VER,
102 .description = "Network Address Translation",
107 * @brief Add/del NAT address to FIB.
109 * Add the external NAT address to the FIB as receive entries. This ensures
110 * that VPP will reply to ARP for this address and we don't need to enable
111 * proxy ARP on the outside interface.
113 * @param addr IPv4 address.
114 * @param plen address prefix length
115 * @param sw_if_index Interface.
116 * @param is_add If 0 delete, otherwise add.
119 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
122 fib_prefix_t prefix = {
124 .fp_proto = FIB_PROTOCOL_IP4,
126 .ip4.as_u32 = addr->as_u32,
129 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
132 fib_table_entry_update_one_path(fib_index,
134 FIB_SOURCE_PLUGIN_HI,
135 (FIB_ENTRY_FLAG_CONNECTED |
136 FIB_ENTRY_FLAG_LOCAL |
137 FIB_ENTRY_FLAG_EXCLUSIVE),
144 FIB_ROUTE_PATH_FLAG_NONE);
146 fib_table_entry_delete(fib_index,
148 FIB_SOURCE_PLUGIN_HI);
151 void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id)
155 vlib_thread_main_t *tm = vlib_get_thread_main ();
160 /* Check if address already exists */
161 vec_foreach (ap, sm->addresses)
163 if (ap->addr.as_u32 == addr->as_u32)
167 vec_add2 (sm->addresses, ap, 1);
171 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
172 FIB_SOURCE_PLUGIN_HI);
175 #define _(N, i, n, s) \
176 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
177 ap->busy_##n##_ports = 0; \
178 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
179 foreach_snat_protocol
182 /* Add external address to FIB */
183 pool_foreach (i, sm->interfaces,
188 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
191 pool_foreach (i, sm->output_feature_interfaces,
196 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
201 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
204 snat_static_mapping_t *m;
205 pool_foreach (m, sm->static_mappings,
207 if (m->external_addr.as_u32 == addr.as_u32)
214 void increment_v4_address (ip4_address_t * a)
218 v = clib_net_to_host_u32(a->as_u32) + 1;
219 a->as_u32 = clib_host_to_net_u32(v);
223 snat_add_static_mapping_when_resolved (snat_main_t * sm,
224 ip4_address_t l_addr,
229 snat_protocol_t proto,
233 snat_static_map_resolve_t *rp;
235 vec_add2 (sm->to_resolve, rp, 1);
236 rp->l_addr.as_u32 = l_addr.as_u32;
238 rp->sw_if_index = sw_if_index;
242 rp->addr_only = addr_only;
247 * @brief Add static mapping.
249 * Create static mapping between local addr+port and external addr+port.
251 * @param l_addr Local IPv4 address.
252 * @param e_addr External IPv4 address.
253 * @param l_port Local port number.
254 * @param e_port External port number.
255 * @param vrf_id VRF ID.
256 * @param addr_only If 0 address port and pair mapping, otherwise address only.
257 * @param sw_if_index External port instead of specific IP address.
258 * @param is_add If 0 delete static mapping, otherwise add.
262 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
263 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
264 u32 sw_if_index, snat_protocol_t proto, int is_add)
266 snat_main_t * sm = &snat_main;
267 snat_static_mapping_t *m;
268 snat_session_key_t m_key;
269 clib_bihash_kv_8_8_t kv, value;
270 snat_address_t *a = 0;
273 snat_interface_t *interface;
276 /* If the external address is a specific interface address */
277 if (sw_if_index != ~0)
279 ip4_address_t * first_int_addr;
281 /* Might be already set... */
282 first_int_addr = ip4_interface_first_address
283 (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
285 /* DHCP resolution required? */
286 if (first_int_addr == 0)
288 snat_add_static_mapping_when_resolved
289 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
294 e_addr.as_u32 = first_int_addr->as_u32;
298 m_key.port = addr_only ? 0 : e_port;
299 m_key.protocol = addr_only ? 0 : proto;
300 m_key.fib_index = sm->outside_fib_index;
301 kv.key = m_key.as_u64;
302 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
305 m = pool_elt_at_index (sm->static_mappings, value.value);
310 return VNET_API_ERROR_VALUE_EXIST;
312 /* Convert VRF id to FIB index */
315 p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
317 return VNET_API_ERROR_NO_SUCH_FIB;
320 /* If not specified use inside VRF id from SNAT plugin startup config */
323 fib_index = sm->inside_fib_index;
324 vrf_id = sm->inside_vrf_id;
327 /* Find external address in allocated addresses and reserve port for
328 address and port pair mapping when dynamic translations enabled */
329 if (!addr_only && !(sm->static_mapping_only))
331 for (i = 0; i < vec_len (sm->addresses); i++)
333 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
335 a = sm->addresses + i;
336 /* External port must be unused */
339 #define _(N, j, n, s) \
340 case SNAT_PROTOCOL_##N: \
341 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
342 return VNET_API_ERROR_INVALID_VALUE; \
343 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
346 a->busy_##n##_ports++; \
347 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
350 foreach_snat_protocol
353 clib_warning("unknown_protocol");
354 return VNET_API_ERROR_INVALID_VALUE_2;
359 /* External address must be allocated */
361 return VNET_API_ERROR_NO_SUCH_ENTRY;
364 pool_get (sm->static_mappings, m);
365 memset (m, 0, sizeof (*m));
366 m->local_addr = l_addr;
367 m->external_addr = e_addr;
368 m->addr_only = addr_only;
370 m->fib_index = fib_index;
373 m->local_port = l_port;
374 m->external_port = e_port;
378 m_key.addr = m->local_addr;
379 m_key.port = m->local_port;
380 m_key.protocol = m->proto;
381 m_key.fib_index = m->fib_index;
382 kv.key = m_key.as_u64;
383 kv.value = m - sm->static_mappings;
384 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
386 m_key.addr = m->external_addr;
387 m_key.port = m->external_port;
388 m_key.fib_index = sm->outside_fib_index;
389 kv.key = m_key.as_u64;
390 kv.value = m - sm->static_mappings;
391 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
396 snat_user_key_t w_key0;
398 w_key0.addr = m->local_addr;
399 w_key0.fib_index = m->fib_index;
400 kv.key = w_key0.as_u64;
402 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
404 kv.value = sm->first_worker_index +
405 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
407 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
411 kv.value = value.value;
414 m->worker_index = kv.value;
420 return VNET_API_ERROR_NO_SUCH_ENTRY;
422 /* Free external address port */
423 if (!addr_only && !(sm->static_mapping_only))
425 for (i = 0; i < vec_len (sm->addresses); i++)
427 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
429 a = sm->addresses + i;
432 #define _(N, j, n, s) \
433 case SNAT_PROTOCOL_##N: \
434 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
437 a->busy_##n##_ports--; \
438 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
441 foreach_snat_protocol
444 clib_warning("unknown_protocol");
445 return VNET_API_ERROR_INVALID_VALUE_2;
452 m_key.addr = m->local_addr;
453 m_key.port = m->local_port;
454 m_key.protocol = m->proto;
455 m_key.fib_index = m->fib_index;
456 kv.key = m_key.as_u64;
457 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
459 m_key.addr = m->external_addr;
460 m_key.port = m->external_port;
461 m_key.fib_index = sm->outside_fib_index;
462 kv.key = m_key.as_u64;
463 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
465 /* Delete session(s) for static mapping if exist */
466 if (!(sm->static_mapping_only) ||
467 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
469 snat_user_key_t u_key;
471 dlist_elt_t * head, * elt;
472 u32 elt_index, head_index, del_elt_index;
476 snat_main_per_thread_data_t *tsm;
478 u_key.addr = m->local_addr;
479 u_key.fib_index = m->fib_index;
480 kv.key = u_key.as_u64;
481 if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
482 tsm = vec_elt_at_index (sm->per_thread_data, value.value);
484 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
485 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
487 user_index = value.value;
488 u = pool_elt_at_index (tsm->users, user_index);
489 if (u->nstaticsessions)
491 head_index = u->sessions_per_user_list_head_index;
492 head = pool_elt_at_index (tsm->list_pool, head_index);
493 elt_index = head->next;
494 elt = pool_elt_at_index (tsm->list_pool, elt_index);
495 ses_index = elt->value;
496 while (ses_index != ~0)
498 s = pool_elt_at_index (tsm->sessions, ses_index);
499 del_elt_index = elt_index;
500 elt_index = elt->next;
501 elt = pool_elt_at_index (tsm->list_pool, elt_index);
502 ses_index = elt->value;
506 if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
507 (clib_net_to_host_u16 (s->out2in.port) != e_port))
511 if (snat_is_unk_proto_session (s))
513 clib_bihash_kv_16_8_t up_kv;
514 nat_ed_ses_key_t up_key;
515 up_key.l_addr = s->in2out.addr;
516 up_key.r_addr = s->ext_host_addr;
517 up_key.fib_index = s->in2out.fib_index;
518 up_key.proto = s->in2out.port;
521 up_kv.key[0] = up_key.as_u64[0];
522 up_kv.key[1] = up_key.as_u64[1];
523 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
525 clib_warning ("in2out key del failed");
527 up_key.l_addr = s->out2in.addr;
528 up_key.fib_index = s->out2in.fib_index;
529 up_kv.key[0] = up_key.as_u64[0];
530 up_kv.key[1] = up_key.as_u64[1];
531 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
533 clib_warning ("out2in key del failed");
538 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
539 s->out2in.addr.as_u32,
543 s->in2out.fib_index);
545 value.key = s->in2out.as_u64;
546 if (clib_bihash_add_del_8_8 (&tsm->in2out, &value, 0))
547 clib_warning ("in2out key del failed");
548 value.key = s->out2in.as_u64;
549 if (clib_bihash_add_del_8_8 (&tsm->out2in, &value, 0))
550 clib_warning ("out2in key del failed");
552 pool_put (tsm->sessions, s);
554 clib_dlist_remove (tsm->list_pool, del_elt_index);
555 pool_put_index (tsm->list_pool, del_elt_index);
556 u->nstaticsessions--;
563 pool_put (tsm->users, u);
564 clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
570 /* Delete static mapping from pool */
571 pool_put (sm->static_mappings, m);
577 /* Add/delete external address to FIB */
578 pool_foreach (interface, sm->interfaces,
580 if (interface->is_inside)
583 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
586 pool_foreach (interface, sm->output_feature_interfaces,
588 if (interface->is_inside)
591 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
598 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
599 snat_protocol_t proto, u32 vrf_id,
600 nat44_lb_addr_port_t *locals, u8 is_add)
602 snat_main_t * sm = &snat_main;
603 snat_static_mapping_t *m;
604 snat_session_key_t m_key;
605 clib_bihash_kv_8_8_t kv, value;
607 snat_address_t *a = 0;
609 nat44_lb_addr_port_t *local;
610 snat_user_key_t w_key0;
611 u32 worker_index = 0;
612 snat_main_per_thread_data_t *tsm;
616 m_key.protocol = proto;
617 m_key.fib_index = sm->outside_fib_index;
618 kv.key = m_key.as_u64;
619 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
622 m = pool_elt_at_index (sm->static_mappings, value.value);
627 return VNET_API_ERROR_VALUE_EXIST;
629 if (vec_len (locals) < 2)
630 return VNET_API_ERROR_INVALID_VALUE;
632 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
634 FIB_SOURCE_PLUGIN_HI);
636 /* Find external address in allocated addresses and reserve port for
637 address and port pair mapping when dynamic translations enabled */
638 if (!sm->static_mapping_only)
640 for (i = 0; i < vec_len (sm->addresses); i++)
642 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
644 a = sm->addresses + i;
645 /* External port must be unused */
648 #define _(N, j, n, s) \
649 case SNAT_PROTOCOL_##N: \
650 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
651 return VNET_API_ERROR_INVALID_VALUE; \
652 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
655 a->busy_##n##_ports++; \
656 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
659 foreach_snat_protocol
662 clib_warning("unknown_protocol");
663 return VNET_API_ERROR_INVALID_VALUE_2;
668 /* External address must be allocated */
670 return VNET_API_ERROR_NO_SUCH_ENTRY;
673 pool_get (sm->static_mappings, m);
674 memset (m, 0, sizeof (*m));
675 m->external_addr = e_addr;
678 m->fib_index = fib_index;
679 m->external_port = e_port;
682 m_key.addr = m->external_addr;
683 m_key.port = m->external_port;
684 m_key.protocol = m->proto;
685 m_key.fib_index = sm->outside_fib_index;
686 kv.key = m_key.as_u64;
687 kv.value = m - sm->static_mappings;
688 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
690 clib_warning ("static_mapping_by_external key add failed");
691 return VNET_API_ERROR_UNSPECIFIED;
697 w_key0.addr = locals[0].addr;
698 w_key0.fib_index = fib_index;
699 kv.key = w_key0.as_u64;
701 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
702 worker_index = sm->first_worker_index +
703 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
705 worker_index = value.value;
707 tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
708 m->worker_index = worker_index;
711 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
713 m_key.port = clib_host_to_net_u16 (m->external_port);
714 kv.key = m_key.as_u64;
716 if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
718 clib_warning ("static_mapping_by_local key add failed");
719 return VNET_API_ERROR_UNSPECIFIED;
722 m_key.fib_index = m->fib_index;
723 for (i = 0; i < vec_len (locals); i++)
725 m_key.addr = locals[i].addr;
726 m_key.port = locals[i].port;
727 kv.key = m_key.as_u64;
728 kv.value = m - sm->static_mappings;
729 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
730 locals[i].prefix = (i == 0) ? locals[i].probability :\
731 (locals[i - 1].prefix + locals[i].probability);
732 vec_add1 (m->locals, locals[i]);
733 m_key.port = clib_host_to_net_u16 (locals[i].port);
734 kv.key = m_key.as_u64;
736 if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
738 clib_warning ("in2out key add failed");
739 return VNET_API_ERROR_UNSPECIFIED;
744 w_key0.addr = locals[i].addr;
745 w_key0.fib_index = fib_index;
746 kv.key = w_key0.as_u64;
747 kv.value = worker_index;
748 if (clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1))
750 clib_warning ("worker-by-in key add failed");
751 return VNET_API_ERROR_UNSPECIFIED;
759 return VNET_API_ERROR_NO_SUCH_ENTRY;
761 fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
763 /* Free external address port */
764 if (!sm->static_mapping_only)
766 for (i = 0; i < vec_len (sm->addresses); i++)
768 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
770 a = sm->addresses + i;
773 #define _(N, j, n, s) \
774 case SNAT_PROTOCOL_##N: \
775 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
778 a->busy_##n##_ports--; \
779 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
782 foreach_snat_protocol
785 clib_warning("unknown_protocol");
786 return VNET_API_ERROR_INVALID_VALUE_2;
793 tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
794 m_key.addr = m->external_addr;
795 m_key.port = m->external_port;
796 m_key.protocol = m->proto;
797 m_key.fib_index = sm->outside_fib_index;
798 kv.key = m_key.as_u64;
799 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
801 clib_warning ("static_mapping_by_external key del failed");
802 return VNET_API_ERROR_UNSPECIFIED;
804 m_key.port = clib_host_to_net_u16 (m->external_port);
805 kv.key = m_key.as_u64;
806 if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
808 clib_warning ("outi2in key del failed");
809 return VNET_API_ERROR_UNSPECIFIED;
812 vec_foreach (local, m->locals)
814 m_key.addr = local->addr;
815 m_key.port = local->port;
816 m_key.fib_index = m->fib_index;
817 kv.key = m_key.as_u64;
818 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
820 clib_warning ("static_mapping_by_local key del failed");
821 return VNET_API_ERROR_UNSPECIFIED;
823 m_key.port = clib_host_to_net_u16 (local->port);
824 kv.key = m_key.as_u64;
825 if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
827 clib_warning ("in2out key del failed");
828 return VNET_API_ERROR_UNSPECIFIED;
833 pool_put (sm->static_mappings, m);
839 int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
841 snat_address_t *a = 0;
843 u32 *ses_to_be_removed = 0, *ses_index;
844 clib_bihash_kv_8_8_t kv, value;
845 snat_user_key_t user_key;
847 snat_main_per_thread_data_t *tsm;
848 snat_static_mapping_t *m;
849 snat_interface_t *interface;
852 /* Find SNAT address */
853 for (i=0; i < vec_len (sm->addresses); i++)
855 if (sm->addresses[i].addr.as_u32 == addr.as_u32)
857 a = sm->addresses + i;
862 return VNET_API_ERROR_NO_SUCH_ENTRY;
866 pool_foreach (m, sm->static_mappings,
868 if (m->external_addr.as_u32 == addr.as_u32)
869 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
870 m->local_port, m->external_port,
871 m->vrf_id, m->addr_only, ~0,
877 /* Check if address is used in some static mapping */
878 if (is_snat_address_used_in_static_mapping(sm, addr))
880 clib_warning ("address used in static mapping");
881 return VNET_API_ERROR_UNSPECIFIED;
885 if (a->fib_index != ~0)
886 fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
887 FIB_SOURCE_PLUGIN_HI);
889 /* Delete sessions using address */
890 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
892 vec_foreach (tsm, sm->per_thread_data)
894 pool_foreach (ses, tsm->sessions, ({
895 if (ses->out2in.addr.as_u32 == addr.as_u32)
897 if (snat_is_unk_proto_session (ses))
899 clib_bihash_kv_16_8_t up_kv;
900 nat_ed_ses_key_t up_key;
901 up_key.l_addr = ses->in2out.addr;
902 up_key.r_addr = ses->ext_host_addr;
903 up_key.fib_index = ses->in2out.fib_index;
904 up_key.proto = ses->in2out.port;
907 up_kv.key[0] = up_key.as_u64[0];
908 up_kv.key[1] = up_key.as_u64[1];
909 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
911 clib_warning ("in2out key del failed");
913 up_key.l_addr = ses->out2in.addr;
914 up_key.fib_index = ses->out2in.fib_index;
915 up_kv.key[0] = up_key.as_u64[0];
916 up_kv.key[1] = up_key.as_u64[1];
917 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
919 clib_warning ("out2in key del failed");
924 snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
925 ses->out2in.addr.as_u32,
926 ses->in2out.protocol,
929 ses->in2out.fib_index);
930 kv.key = ses->in2out.as_u64;
931 clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
932 kv.key = ses->out2in.as_u64;
933 clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
935 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
936 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
937 user_key.addr = ses->in2out.addr;
938 user_key.fib_index = ses->in2out.fib_index;
939 kv.key = user_key.as_u64;
940 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
942 u = pool_elt_at_index (tsm->users, value.value);
948 vec_foreach (ses_index, ses_to_be_removed)
949 pool_put_index (tsm->sessions, ses_index[0]);
951 vec_free (ses_to_be_removed);
955 vec_del1 (sm->addresses, i);
957 /* Delete external address from FIB */
958 pool_foreach (interface, sm->interfaces,
960 if (interface->is_inside)
963 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
966 pool_foreach (interface, sm->output_feature_interfaces,
968 if (interface->is_inside)
971 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
978 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
980 snat_main_t *sm = &snat_main;
982 const char * feature_name;
984 snat_static_mapping_t * m;
987 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
988 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
991 if (sm->num_workers > 1 && !sm->deterministic)
992 feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
993 else if (sm->deterministic)
994 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
996 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
999 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
1002 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1003 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
1005 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1006 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1008 pool_foreach (i, sm->interfaces,
1010 if (i->sw_if_index == sw_if_index)
1013 pool_put (sm->interfaces, i);
1015 return VNET_API_ERROR_VALUE_EXIST;
1022 return VNET_API_ERROR_NO_SUCH_ENTRY;
1024 pool_get (sm->interfaces, i);
1025 i->sw_if_index = sw_if_index;
1026 i->is_inside = is_inside;
1028 /* Add/delete external addresses to FIB */
1033 vec_foreach (ap, sm->addresses)
1034 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1036 pool_foreach (m, sm->static_mappings,
1038 if (!(m->addr_only))
1041 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1044 pool_foreach (dm, sm->det_maps,
1046 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1052 int snat_interface_add_del_output_feature (u32 sw_if_index,
1056 snat_main_t *sm = &snat_main;
1057 snat_interface_t *i;
1058 snat_address_t * ap;
1059 snat_static_mapping_t * m;
1061 if (sm->deterministic ||
1062 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1063 return VNET_API_ERROR_UNSUPPORTED;
1067 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1068 sw_if_index, !is_del, 0, 0);
1069 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1070 sw_if_index, !is_del, 0, 0);
1074 if (sm->num_workers > 1)
1076 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1077 sw_if_index, !is_del, 0, 0);
1078 vnet_feature_enable_disable ("ip4-output",
1079 "nat44-in2out-output-worker-handoff",
1080 sw_if_index, !is_del, 0, 0);
1084 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1086 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1087 sw_if_index, !is_del, 0, 0);
1091 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1092 sm->fq_in2out_output_index =
1093 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1095 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1096 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1098 pool_foreach (i, sm->output_feature_interfaces,
1100 if (i->sw_if_index == sw_if_index)
1103 pool_put (sm->output_feature_interfaces, i);
1105 return VNET_API_ERROR_VALUE_EXIST;
1112 return VNET_API_ERROR_NO_SUCH_ENTRY;
1114 pool_get (sm->output_feature_interfaces, i);
1115 i->sw_if_index = sw_if_index;
1116 i->is_inside = is_inside;
1118 /* Add/delete external addresses to FIB */
1123 vec_foreach (ap, sm->addresses)
1124 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1126 pool_foreach (m, sm->static_mappings,
1128 if (!(m->addr_only))
1131 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1137 int snat_set_workers (uword * bitmap)
1139 snat_main_t *sm = &snat_main;
1142 if (sm->num_workers < 2)
1143 return VNET_API_ERROR_FEATURE_DISABLED;
1145 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1146 return VNET_API_ERROR_INVALID_WORKER;
1148 vec_free (sm->workers);
1149 clib_bitmap_foreach (i, bitmap,
1151 vec_add1(sm->workers, i);
1152 sm->per_thread_data[i].snat_thread_index = j;
1156 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1157 sm->num_snat_thread = _vec_len (sm->workers);
1164 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1167 ip4_address_t * address,
1169 u32 if_address_index,
1172 static clib_error_t * snat_init (vlib_main_t * vm)
1174 snat_main_t * sm = &snat_main;
1175 clib_error_t * error = 0;
1176 ip4_main_t * im = &ip4_main;
1177 ip_lookup_main_t * lm = &im->lookup_main;
1179 vlib_thread_registration_t *tr;
1180 vlib_thread_main_t *tm = vlib_get_thread_main ();
1183 ip4_add_del_interface_address_callback_t cb4;
1186 sm->vnet_main = vnet_get_main();
1188 sm->ip4_lookup_main = lm;
1189 sm->api_main = &api_main;
1190 sm->first_worker_index = 0;
1191 sm->next_worker = 0;
1192 sm->num_workers = 0;
1193 sm->num_snat_thread = 1;
1195 sm->port_per_thread = 0xffff - 1024;
1196 sm->fq_in2out_index = ~0;
1197 sm->fq_out2in_index = ~0;
1198 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1199 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1200 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1201 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1203 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1206 tr = (vlib_thread_registration_t *) p[0];
1209 sm->num_workers = tr->count;
1210 sm->first_worker_index = tr->first_index;
1214 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1216 /* Use all available workers by default */
1217 if (sm->num_workers > 1)
1219 for (i=0; i < sm->num_workers; i++)
1220 bitmap = clib_bitmap_set (bitmap, i, 1);
1221 snat_set_workers(bitmap);
1222 clib_bitmap_free (bitmap);
1226 sm->per_thread_data[0].snat_thread_index = 0;
1229 error = snat_api_init(vm, sm);
1233 /* Set up the interface address add/del callback */
1234 cb4.function = snat_ip4_add_del_interface_address_cb;
1235 cb4.function_opaque = 0;
1237 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1239 /* Init IPFIX logging */
1240 snat_ipfix_logging_init(vm);
1242 error = nat64_init(vm);
1247 VLIB_INIT_FUNCTION (snat_init);
1249 void snat_free_outside_address_and_port (snat_main_t * sm,
1251 snat_session_key_t * k,
1255 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1257 ASSERT (address_index < vec_len (sm->addresses));
1259 a = sm->addresses + address_index;
1261 switch (k->protocol)
1263 #define _(N, i, n, s) \
1264 case SNAT_PROTOCOL_##N: \
1265 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1266 port_host_byte_order) == 1); \
1267 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1268 port_host_byte_order, 0); \
1269 a->busy_##n##_ports--; \
1270 a->busy_##n##_ports_per_thread[thread_index]--; \
1272 foreach_snat_protocol
1275 clib_warning("unknown_protocol");
1281 * @brief Match NAT44 static mapping.
1283 * @param sm NAT main.
1284 * @param match Address and port to match.
1285 * @param mapping External or local address and port of the matched mapping.
1286 * @param by_external If 0 match by local address otherwise match by external
1288 * @param is_addr_only If matched mapping is address only
1290 * @returns 0 if match found otherwise 1.
1292 int snat_static_mapping_match (snat_main_t * sm,
1293 snat_session_key_t match,
1294 snat_session_key_t * mapping,
1298 clib_bihash_kv_8_8_t kv, value;
1299 snat_static_mapping_t *m;
1300 snat_session_key_t m_key;
1301 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1302 u32 rand, lo = 0, hi, mid;
1305 mapping_hash = &sm->static_mapping_by_external;
1307 m_key.addr = match.addr;
1308 m_key.port = clib_net_to_host_u16 (match.port);
1309 m_key.protocol = match.protocol;
1310 m_key.fib_index = match.fib_index;
1312 kv.key = m_key.as_u64;
1314 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1316 /* Try address only mapping */
1319 kv.key = m_key.as_u64;
1320 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1324 m = pool_elt_at_index (sm->static_mappings, value.value);
1328 if (vec_len (m->locals))
1330 hi = vec_len (m->locals) - 1;
1331 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1334 mid = ((hi - lo) >> 1) + lo;
1335 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1337 if (!(m->locals[lo].prefix >= rand))
1339 mapping->addr = m->locals[lo].addr;
1340 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1344 mapping->addr = m->local_addr;
1345 /* Address only mapping doesn't change port */
1346 mapping->port = m->addr_only ? match.port
1347 : clib_host_to_net_u16 (m->local_port);
1349 mapping->fib_index = m->fib_index;
1350 mapping->protocol = m->proto;
1354 mapping->addr = m->external_addr;
1355 /* Address only mapping doesn't change port */
1356 mapping->port = m->addr_only ? match.port
1357 : clib_host_to_net_u16 (m->external_port);
1358 mapping->fib_index = sm->outside_fib_index;
1361 if (PREDICT_FALSE(is_addr_only != 0))
1362 *is_addr_only = m->addr_only;
1367 static_always_inline u16
1368 snat_random_port (snat_main_t * sm, u16 min, u16 max)
1370 return min + random_u32 (&sm->random_seed) /
1371 (random_u32_max() / (max - min + 1) + 1);
1374 int snat_alloc_outside_address_and_port (snat_main_t * sm,
1377 snat_session_key_t * k,
1378 u32 * address_indexp)
1384 for (i = 0; i < vec_len (sm->addresses); i++)
1386 a = sm->addresses + i;
1387 if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
1389 switch (k->protocol)
1391 #define _(N, j, n, s) \
1392 case SNAT_PROTOCOL_##N: \
1393 if (a->busy_##n##_ports_per_thread[thread_index] < sm->port_per_thread) \
1397 portnum = (sm->port_per_thread * \
1398 sm->per_thread_data[thread_index].snat_thread_index) + \
1399 snat_random_port(sm, 1, sm->port_per_thread) + 1024; \
1400 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1402 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1403 a->busy_##n##_ports_per_thread[thread_index]++; \
1404 a->busy_##n##_ports++; \
1405 k->addr = a->addr; \
1406 k->port = clib_host_to_net_u16(portnum); \
1407 *address_indexp = i; \
1412 foreach_snat_protocol
1415 clib_warning("unknown protocol");
1420 /* Totally out of translations to use... */
1421 snat_ipfix_logging_addresses_exhausted(0);
1426 static clib_error_t *
1427 add_address_command_fn (vlib_main_t * vm,
1428 unformat_input_t * input,
1429 vlib_cli_command_t * cmd)
1431 unformat_input_t _line_input, *line_input = &_line_input;
1432 snat_main_t * sm = &snat_main;
1433 ip4_address_t start_addr, end_addr, this_addr;
1434 u32 start_host_order, end_host_order;
1439 clib_error_t *error = 0;
1441 /* Get a line of input. */
1442 if (!unformat_user (input, unformat_line_input, line_input))
1445 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1447 if (unformat (line_input, "%U - %U",
1448 unformat_ip4_address, &start_addr,
1449 unformat_ip4_address, &end_addr))
1451 else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
1453 else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1454 end_addr = start_addr;
1455 else if (unformat (line_input, "del"))
1459 error = clib_error_return (0, "unknown input '%U'",
1460 format_unformat_error, line_input);
1465 if (sm->static_mapping_only)
1467 error = clib_error_return (0, "static mapping only mode");
1471 start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1472 end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1474 if (end_host_order < start_host_order)
1476 error = clib_error_return (0, "end address less than start address");
1480 count = (end_host_order - start_host_order) + 1;
1483 clib_warning ("%U - %U, %d addresses...",
1484 format_ip4_address, &start_addr,
1485 format_ip4_address, &end_addr,
1488 this_addr = start_addr;
1490 for (i = 0; i < count; i++)
1493 snat_add_address (sm, &this_addr, vrf_id);
1495 rv = snat_del_address (sm, this_addr, 0);
1499 case VNET_API_ERROR_NO_SUCH_ENTRY:
1500 error = clib_error_return (0, "S-NAT address not exist.");
1502 case VNET_API_ERROR_UNSPECIFIED:
1503 error = clib_error_return (0, "S-NAT address used in static mapping.");
1509 increment_v4_address (&this_addr);
1513 unformat_free (line_input);
1518 VLIB_CLI_COMMAND (add_address_command, static) = {
1519 .path = "nat44 add address",
1520 .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1521 "[tenant-vrf <vrf-id>] [del]",
1522 .function = add_address_command_fn,
1525 static clib_error_t *
1526 snat_feature_command_fn (vlib_main_t * vm,
1527 unformat_input_t * input,
1528 vlib_cli_command_t * cmd)
1530 unformat_input_t _line_input, *line_input = &_line_input;
1531 vnet_main_t * vnm = vnet_get_main();
1532 clib_error_t * error = 0;
1534 u32 * inside_sw_if_indices = 0;
1535 u32 * outside_sw_if_indices = 0;
1536 u8 is_output_feature = 0;
1542 /* Get a line of input. */
1543 if (!unformat_user (input, unformat_line_input, line_input))
1546 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1548 if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1550 vec_add1 (inside_sw_if_indices, sw_if_index);
1551 else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1553 vec_add1 (outside_sw_if_indices, sw_if_index);
1554 else if (unformat (line_input, "output-feature"))
1555 is_output_feature = 1;
1556 else if (unformat (line_input, "del"))
1560 error = clib_error_return (0, "unknown input '%U'",
1561 format_unformat_error, line_input);
1566 if (vec_len (inside_sw_if_indices))
1568 for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1570 sw_if_index = inside_sw_if_indices[i];
1571 if (is_output_feature)
1573 if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
1575 error = clib_error_return (0, "%s %U failed",
1576 is_del ? "del" : "add",
1577 format_vnet_sw_interface_name, vnm,
1578 vnet_get_sw_interface (vnm,
1585 if (snat_interface_add_del (sw_if_index, 1, is_del))
1587 error = clib_error_return (0, "%s %U failed",
1588 is_del ? "del" : "add",
1589 format_vnet_sw_interface_name, vnm,
1590 vnet_get_sw_interface (vnm,
1598 if (vec_len (outside_sw_if_indices))
1600 for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1602 sw_if_index = outside_sw_if_indices[i];
1603 if (is_output_feature)
1605 if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
1607 error = clib_error_return (0, "%s %U failed",
1608 is_del ? "del" : "add",
1609 format_vnet_sw_interface_name, vnm,
1610 vnet_get_sw_interface (vnm,
1617 if (snat_interface_add_del (sw_if_index, 0, is_del))
1619 error = clib_error_return (0, "%s %U failed",
1620 is_del ? "del" : "add",
1621 format_vnet_sw_interface_name, vnm,
1622 vnet_get_sw_interface (vnm,
1631 unformat_free (line_input);
1632 vec_free (inside_sw_if_indices);
1633 vec_free (outside_sw_if_indices);
1638 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1639 .path = "set interface nat44",
1640 .function = snat_feature_command_fn,
1641 .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1646 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1648 u32 *r = va_arg (*args, u32 *);
1651 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1652 foreach_snat_protocol
1660 format_snat_protocol (u8 * s, va_list * args)
1662 u32 i = va_arg (*args, u32);
1667 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1668 foreach_snat_protocol
1671 s = format (s, "unknown");
1674 s = format (s, "%s", t);
1678 static clib_error_t *
1679 add_static_mapping_command_fn (vlib_main_t * vm,
1680 unformat_input_t * input,
1681 vlib_cli_command_t * cmd)
1683 unformat_input_t _line_input, *line_input = &_line_input;
1684 clib_error_t * error = 0;
1685 ip4_address_t l_addr, e_addr;
1686 u32 l_port = 0, e_port = 0, vrf_id = ~0;
1689 u32 sw_if_index = ~0;
1690 vnet_main_t * vnm = vnet_get_main();
1692 snat_protocol_t proto;
1695 /* Get a line of input. */
1696 if (!unformat_user (input, unformat_line_input, line_input))
1699 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1701 if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1704 else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1706 else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1709 else if (unformat (line_input, "external %U", unformat_ip4_address,
1712 else if (unformat (line_input, "external %U %u",
1713 unformat_vnet_sw_interface, vnm, &sw_if_index,
1717 else if (unformat (line_input, "external %U",
1718 unformat_vnet_sw_interface, vnm, &sw_if_index))
1720 else if (unformat (line_input, "vrf %u", &vrf_id))
1722 else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1724 else if (unformat (line_input, "del"))
1728 error = clib_error_return (0, "unknown input: '%U'",
1729 format_unformat_error, line_input);
1734 if (!addr_only && !proto_set)
1736 error = clib_error_return (0, "missing protocol");
1740 rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1741 vrf_id, addr_only, sw_if_index, proto, is_add);
1745 case VNET_API_ERROR_INVALID_VALUE:
1746 error = clib_error_return (0, "External port already in use.");
1748 case VNET_API_ERROR_NO_SUCH_ENTRY:
1750 error = clib_error_return (0, "External addres must be allocated.");
1752 error = clib_error_return (0, "Mapping not exist.");
1754 case VNET_API_ERROR_NO_SUCH_FIB:
1755 error = clib_error_return (0, "No such VRF id.");
1757 case VNET_API_ERROR_VALUE_EXIST:
1758 error = clib_error_return (0, "Mapping already exist.");
1765 unformat_free (line_input);
1772 * @cliexstart{snat add static mapping}
1773 * Static mapping allows hosts on the external network to initiate connection
1774 * to to the local network host.
1775 * To create static mapping between local host address 10.0.0.3 port 6303 and
1776 * external address 4.4.4.4 port 3606 for TCP protocol use:
1777 * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1778 * If not runnig "static mapping only" NAT plugin mode use before:
1779 * vpp# nat44 add address 4.4.4.4
1780 * To create static mapping between local and external address use:
1781 * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1784 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1785 .path = "nat44 add static mapping",
1786 .function = add_static_mapping_command_fn,
1788 "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1791 static clib_error_t *
1792 add_lb_static_mapping_command_fn (vlib_main_t * vm,
1793 unformat_input_t * input,
1794 vlib_cli_command_t * cmd)
1796 unformat_input_t _line_input, *line_input = &_line_input;
1797 clib_error_t * error = 0;
1798 ip4_address_t l_addr, e_addr;
1799 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1802 snat_protocol_t proto;
1804 nat44_lb_addr_port_t *locals = 0, local;
1806 /* Get a line of input. */
1807 if (!unformat_user (input, unformat_line_input, line_input))
1810 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1812 if (unformat (line_input, "local %U:%u probability %u",
1813 unformat_ip4_address, &l_addr, &l_port, &probability))
1815 memset (&local, 0, sizeof (local));
1816 local.addr = l_addr;
1817 local.port = (u16) l_port;
1818 local.probability = (u8) probability;
1819 vec_add1 (locals, local);
1821 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1824 else if (unformat (line_input, "vrf %u", &vrf_id))
1826 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
1829 else if (unformat (line_input, "del"))
1833 error = clib_error_return (0, "unknown input: '%U'",
1834 format_unformat_error, line_input);
1839 if (vec_len (locals) < 2)
1841 error = clib_error_return (0, "at least two local must be set");
1847 error = clib_error_return (0, "missing protocol");
1851 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
1856 case VNET_API_ERROR_INVALID_VALUE:
1857 error = clib_error_return (0, "External port already in use.");
1859 case VNET_API_ERROR_NO_SUCH_ENTRY:
1861 error = clib_error_return (0, "External addres must be allocated.");
1863 error = clib_error_return (0, "Mapping not exist.");
1865 case VNET_API_ERROR_VALUE_EXIST:
1866 error = clib_error_return (0, "Mapping already exist.");
1873 unformat_free (line_input);
1879 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1880 .path = "nat44 add load-balancing static mapping",
1881 .function = add_lb_static_mapping_command_fn,
1883 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
1886 static clib_error_t *
1887 set_workers_command_fn (vlib_main_t * vm,
1888 unformat_input_t * input,
1889 vlib_cli_command_t * cmd)
1891 unformat_input_t _line_input, *line_input = &_line_input;
1894 clib_error_t *error = 0;
1896 /* Get a line of input. */
1897 if (!unformat_user (input, unformat_line_input, line_input))
1900 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1902 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1906 error = clib_error_return (0, "unknown input '%U'",
1907 format_unformat_error, line_input);
1914 error = clib_error_return (0, "List of workers must be specified.");
1918 rv = snat_set_workers(bitmap);
1920 clib_bitmap_free (bitmap);
1924 case VNET_API_ERROR_INVALID_WORKER:
1925 error = clib_error_return (0, "Invalid worker(s).");
1927 case VNET_API_ERROR_FEATURE_DISABLED:
1928 error = clib_error_return (0,
1929 "Supported only if 2 or more workes available.");
1936 unformat_free (line_input);
1943 * @cliexstart{set snat workers}
1944 * Set NAT workers if 2 or more workers available, use:
1945 * vpp# set snat workers 0-2,5
1948 VLIB_CLI_COMMAND (set_workers_command, static) = {
1949 .path = "set nat workers",
1950 .function = set_workers_command_fn,
1952 "set nat workers <workers-list>",
1955 static clib_error_t *
1956 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
1957 unformat_input_t * input,
1958 vlib_cli_command_t * cmd)
1960 unformat_input_t _line_input, *line_input = &_line_input;
1965 clib_error_t *error = 0;
1967 /* Get a line of input. */
1968 if (!unformat_user (input, unformat_line_input, line_input))
1971 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1973 if (unformat (line_input, "domain %d", &domain_id))
1975 else if (unformat (line_input, "src-port %d", &src_port))
1977 else if (unformat (line_input, "disable"))
1981 error = clib_error_return (0, "unknown input '%U'",
1982 format_unformat_error, line_input);
1987 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
1991 error = clib_error_return (0, "ipfix logging enable failed");
1996 unformat_free (line_input);
2003 * @cliexstart{snat ipfix logging}
2004 * To enable NAT IPFIX logging use:
2005 * vpp# nat ipfix logging
2006 * To set IPFIX exporter use:
2007 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2010 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2011 .path = "nat ipfix logging",
2012 .function = snat_ipfix_logging_enable_disable_command_fn,
2013 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2017 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2019 snat_main_t *sm = &snat_main;
2020 snat_user_key_t key0;
2021 clib_bihash_kv_8_8_t kv0, value0;
2022 u32 next_worker_index = 0;
2024 key0.addr = ip0->src_address;
2025 key0.fib_index = rx_fib_index0;
2027 kv0.key = key0.as_u64;
2029 /* Ever heard of of the "user" before? */
2030 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0))
2032 /* No, assign next available worker (RR) */
2033 next_worker_index = sm->first_worker_index;
2034 if (vec_len (sm->workers))
2036 next_worker_index +=
2037 sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
2040 /* add non-traslated packets worker lookup */
2041 kv0.value = next_worker_index;
2042 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
2045 next_worker_index = value0.value;
2047 return next_worker_index;
2051 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2053 snat_main_t *sm = &snat_main;
2056 snat_session_key_t m_key;
2057 clib_bihash_kv_8_8_t kv, value;
2058 snat_static_mapping_t *m;
2059 nat_ed_ses_key_t key;
2060 clib_bihash_kv_16_8_t s_kv, s_value;
2061 snat_main_per_thread_data_t *tsm;
2066 /* first try static mappings without port */
2067 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2069 m_key.addr = ip0->dst_address;
2072 m_key.fib_index = rx_fib_index0;
2073 kv.key = m_key.as_u64;
2074 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2076 m = pool_elt_at_index (sm->static_mappings, value.value);
2077 return m->worker_index;
2081 proto = ip_proto_to_snat_proto (ip0->protocol);
2082 udp = ip4_next_header (ip0);
2083 port = udp->dst_port;
2085 /* unknown protocol */
2086 if (PREDICT_FALSE (proto == ~0))
2088 key.l_addr = ip0->dst_address;
2089 key.r_addr = ip0->src_address;
2090 key.fib_index = rx_fib_index0;
2091 key.proto = ip0->protocol;
2094 s_kv.key[0] = key.as_u64[0];
2095 s_kv.key[1] = key.as_u64[1];
2097 if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2099 for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2101 tsm = vec_elt_at_index (sm->per_thread_data, i);
2102 if (!pool_is_free_index(tsm->sessions, s_value.value))
2104 s = pool_elt_at_index (tsm->sessions, s_value.value);
2105 if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2106 s->out2in.port == ip0->protocol &&
2107 snat_is_unk_proto_session (s))
2113 /* if no session use current thread */
2114 return vlib_get_thread_index ();
2117 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2119 icmp46_header_t * icmp = (icmp46_header_t *) udp;
2120 icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2121 if (!icmp_is_error_message (icmp))
2122 port = echo->identifier;
2125 ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2126 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2127 void *l4_header = ip4_next_header (inner_ip);
2130 case SNAT_PROTOCOL_ICMP:
2131 icmp = (icmp46_header_t*)l4_header;
2132 echo = (icmp_echo_header_t *)(icmp + 1);
2133 port = echo->identifier;
2135 case SNAT_PROTOCOL_UDP:
2136 case SNAT_PROTOCOL_TCP:
2137 port = ((tcp_udp_header_t*)l4_header)->src_port;
2140 return vlib_get_thread_index ();
2145 /* try static mappings with port */
2146 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2148 m_key.addr = ip0->dst_address;
2149 m_key.port = clib_net_to_host_u16 (port);
2150 m_key.protocol = proto;
2151 m_key.fib_index = rx_fib_index0;
2152 kv.key = m_key.as_u64;
2153 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2155 m = pool_elt_at_index (sm->static_mappings, value.value);
2156 return m->worker_index;
2160 /* worker by outside port */
2161 return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2164 static clib_error_t *
2165 snat_config (vlib_main_t * vm, unformat_input_t * input)
2167 snat_main_t * sm = &snat_main;
2168 u32 translation_buckets = 1024;
2169 u32 translation_memory_size = 128<<20;
2170 u32 user_buckets = 128;
2171 u32 user_memory_size = 64<<20;
2172 u32 max_translations_per_user = 100;
2173 u32 outside_vrf_id = 0;
2174 u32 inside_vrf_id = 0;
2175 u32 static_mapping_buckets = 1024;
2176 u32 static_mapping_memory_size = 64<<20;
2177 u8 static_mapping_only = 0;
2178 u8 static_mapping_connection_tracking = 0;
2179 snat_main_per_thread_data_t *tsm;
2181 sm->deterministic = 0;
2183 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2185 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2187 else if (unformat (input, "translation hash memory %d",
2188 &translation_memory_size));
2189 else if (unformat (input, "user hash buckets %d", &user_buckets))
2191 else if (unformat (input, "user hash memory %d",
2194 else if (unformat (input, "max translations per user %d",
2195 &max_translations_per_user))
2197 else if (unformat (input, "outside VRF id %d",
2200 else if (unformat (input, "inside VRF id %d",
2203 else if (unformat (input, "static mapping only"))
2205 static_mapping_only = 1;
2206 if (unformat (input, "connection tracking"))
2207 static_mapping_connection_tracking = 1;
2209 else if (unformat (input, "deterministic"))
2210 sm->deterministic = 1;
2212 return clib_error_return (0, "unknown input '%U'",
2213 format_unformat_error, input);
2216 /* for show commands, etc. */
2217 sm->translation_buckets = translation_buckets;
2218 sm->translation_memory_size = translation_memory_size;
2219 /* do not exceed load factor 10 */
2220 sm->max_translations = 10 * translation_buckets;
2221 sm->user_buckets = user_buckets;
2222 sm->user_memory_size = user_memory_size;
2223 sm->max_translations_per_user = max_translations_per_user;
2224 sm->outside_vrf_id = outside_vrf_id;
2225 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2227 FIB_SOURCE_PLUGIN_HI);
2228 sm->inside_vrf_id = inside_vrf_id;
2229 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2231 FIB_SOURCE_PLUGIN_HI);
2232 sm->static_mapping_only = static_mapping_only;
2233 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2235 if (sm->deterministic)
2237 sm->in2out_node_index = snat_det_in2out_node.index;
2238 sm->in2out_output_node_index = ~0;
2239 sm->out2in_node_index = snat_det_out2in_node.index;
2240 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2241 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2245 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2246 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2247 sm->in2out_node_index = snat_in2out_node.index;
2248 sm->in2out_output_node_index = snat_in2out_output_node.index;
2249 sm->out2in_node_index = snat_out2in_node.index;
2250 if (!static_mapping_only ||
2251 (static_mapping_only && static_mapping_connection_tracking))
2253 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2254 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2256 vec_foreach (tsm, sm->per_thread_data)
2258 clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2259 translation_memory_size);
2261 clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2262 translation_memory_size);
2264 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2268 clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
2271 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2272 translation_buckets, translation_memory_size);
2274 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2275 translation_buckets, translation_memory_size);
2279 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2280 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2282 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2283 "static_mapping_by_local", static_mapping_buckets,
2284 static_mapping_memory_size);
2286 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2287 "static_mapping_by_external", static_mapping_buckets,
2288 static_mapping_memory_size);
2294 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2296 u8 * format_snat_session_state (u8 * s, va_list * args)
2298 u32 i = va_arg (*args, u32);
2303 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2304 foreach_snat_session_state
2307 t = format (t, "unknown");
2309 s = format (s, "%s", t);
2313 u8 * format_snat_key (u8 * s, va_list * args)
2315 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2317 s = format (s, "%U proto %U port %d fib %d",
2318 format_ip4_address, &key->addr,
2319 format_snat_protocol, key->protocol,
2320 clib_net_to_host_u16 (key->port), key->fib_index);
2324 u8 * format_snat_session (u8 * s, va_list * args)
2326 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2327 snat_session_t * sess = va_arg (*args, snat_session_t *);
2329 if (snat_is_unk_proto_session (sess))
2331 s = format (s, " i2o %U proto %u fib %u\n",
2332 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2333 sess->in2out.fib_index);
2334 s = format (s, " o2i %U proto %u fib %u\n",
2335 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2336 sess->out2in.fib_index);
2340 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2341 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2343 if (sess->ext_host_addr.as_u32)
2344 s = format (s, " external host %U\n",
2345 format_ip4_address, &sess->ext_host_addr);
2346 s = format (s, " last heard %.2f\n", sess->last_heard);
2347 s = format (s, " total pkts %d, total bytes %lld\n",
2348 sess->total_pkts, sess->total_bytes);
2349 if (snat_is_session_static (sess))
2350 s = format (s, " static translation\n");
2352 s = format (s, " dynamic translation\n");
2353 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2354 s = format (s, " load-balancing\n");
2359 u8 * format_snat_user (u8 * s, va_list * args)
2361 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2362 snat_user_t * u = va_arg (*args, snat_user_t *);
2363 int verbose = va_arg (*args, int);
2364 dlist_elt_t * head, * elt;
2365 u32 elt_index, head_index;
2367 snat_session_t * sess;
2369 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2370 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2375 if (u->nsessions || u->nstaticsessions)
2377 head_index = u->sessions_per_user_list_head_index;
2378 head = pool_elt_at_index (sm->list_pool, head_index);
2380 elt_index = head->next;
2381 elt = pool_elt_at_index (sm->list_pool, elt_index);
2382 session_index = elt->value;
2384 while (session_index != ~0)
2386 sess = pool_elt_at_index (sm->sessions, session_index);
2388 s = format (s, " %U\n", format_snat_session, sm, sess);
2390 elt_index = elt->next;
2391 elt = pool_elt_at_index (sm->list_pool, elt_index);
2392 session_index = elt->value;
2399 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2401 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2402 nat44_lb_addr_port_t *local;
2405 s = format (s, "local %U external %U vrf %d",
2406 format_ip4_address, &m->local_addr,
2407 format_ip4_address, &m->external_addr,
2411 if (vec_len (m->locals))
2413 s = format (s, "%U vrf %d external %U:%d",
2414 format_snat_protocol, m->proto,
2416 format_ip4_address, &m->external_addr, m->external_port);
2417 vec_foreach (local, m->locals)
2418 s = format (s, "\n local %U:%d probability %d\%",
2419 format_ip4_address, &local->addr, local->port,
2420 local->probability);
2423 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2424 format_snat_protocol, m->proto,
2425 format_ip4_address, &m->local_addr, m->local_port,
2426 format_ip4_address, &m->external_addr, m->external_port,
2432 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2434 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2435 vnet_main_t *vnm = vnet_get_main();
2438 s = format (s, "local %U external %U vrf %d",
2439 format_ip4_address, &m->l_addr,
2440 format_vnet_sw_interface_name, vnm,
2441 vnet_get_sw_interface (vnm, m->sw_if_index),
2444 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2445 format_snat_protocol, m->proto,
2446 format_ip4_address, &m->l_addr, m->l_port,
2447 format_vnet_sw_interface_name, vnm,
2448 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2454 u8 * format_det_map_ses (u8 * s, va_list * args)
2456 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2457 ip4_address_t in_addr, out_addr;
2458 u32 in_offset, out_offset;
2459 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2460 u32 * i = va_arg (*args, u32 *);
2462 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2463 in_addr.as_u32 = clib_host_to_net_u32 (
2464 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2465 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2466 clib_net_to_host_u32(det_map->in_addr.as_u32);
2467 out_offset = in_offset / det_map->sharing_ratio;
2468 out_addr.as_u32 = clib_host_to_net_u32(
2469 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2470 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2471 format_ip4_address, &in_addr,
2472 clib_net_to_host_u16 (ses->in_port),
2473 format_ip4_address, &out_addr,
2474 clib_net_to_host_u16 (ses->out.out_port),
2475 format_ip4_address, &ses->out.ext_host_addr,
2476 clib_net_to_host_u16 (ses->out.ext_host_port),
2477 format_snat_session_state, ses->state,
2483 static clib_error_t *
2484 show_snat_command_fn (vlib_main_t * vm,
2485 unformat_input_t * input,
2486 vlib_cli_command_t * cmd)
2489 snat_main_t * sm = &snat_main;
2491 snat_static_mapping_t *m;
2492 snat_interface_t *i;
2493 snat_address_t * ap;
2494 vnet_main_t *vnm = vnet_get_main();
2495 snat_main_per_thread_data_t *tsm;
2496 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2498 snat_static_map_resolve_t *rp;
2499 snat_det_map_t * dm;
2500 snat_det_session_t * ses;
2502 if (unformat (input, "detail"))
2504 else if (unformat (input, "verbose"))
2507 if (sm->static_mapping_only)
2509 if (sm->static_mapping_connection_tracking)
2510 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2513 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2515 else if (sm->deterministic)
2517 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2521 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2526 pool_foreach (i, sm->interfaces,
2528 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2529 vnet_get_sw_interface (vnm, i->sw_if_index),
2530 i->is_inside ? "in" : "out");
2533 pool_foreach (i, sm->output_feature_interfaces,
2535 vlib_cli_output (vm, "%U output-feature %s",
2536 format_vnet_sw_interface_name, vnm,
2537 vnet_get_sw_interface (vnm, i->sw_if_index),
2538 i->is_inside ? "in" : "out");
2541 if (vec_len (sm->auto_add_sw_if_indices))
2543 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2544 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2546 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2547 vnet_get_sw_interface (vnm, *sw_if_index));
2551 vec_foreach (ap, sm->addresses)
2553 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2554 if (ap->fib_index != ~0)
2555 vlib_cli_output (vm, " tenant VRF: %u",
2556 ip4_fib_get(ap->fib_index)->table_id);
2558 vlib_cli_output (vm, " tenant VRF independent");
2559 #define _(N, i, n, s) \
2560 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2561 foreach_snat_protocol
2566 if (sm->num_workers > 1)
2568 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2571 vec_foreach (worker, sm->workers)
2573 vlib_worker_thread_t *w =
2574 vlib_worker_threads + *worker + sm->first_worker_index;
2575 vlib_cli_output (vm, " %s", w->name);
2580 if (sm->deterministic)
2582 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2583 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2584 sm->tcp_established_timeout);
2585 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2586 sm->tcp_transitory_timeout);
2587 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2588 vlib_cli_output (vm, "%d deterministic mappings",
2589 pool_elts (sm->det_maps));
2592 pool_foreach (dm, sm->det_maps,
2594 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2595 format_ip4_address, &dm->in_addr, dm->in_plen,
2596 format_ip4_address, &dm->out_addr, dm->out_plen);
2597 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2599 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2600 dm->ports_per_host);
2601 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2604 vec_foreach_index (j, dm->sessions)
2606 ses = vec_elt_at_index (dm->sessions, j);
2608 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2617 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2619 vlib_cli_output (vm, "%d static mappings",
2620 pool_elts (sm->static_mappings));
2624 pool_foreach (m, sm->static_mappings,
2626 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2632 vec_foreach (tsm, sm->per_thread_data)
2634 users_num += pool_elts (tsm->users);
2635 sessions_num += pool_elts (tsm->sessions);
2638 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2639 " %d static mappings",
2641 vec_len (sm->addresses),
2643 pool_elts (sm->static_mappings));
2647 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
2649 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
2651 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
2653 vec_foreach_index (j, sm->per_thread_data)
2655 tsm = vec_elt_at_index (sm->per_thread_data, j);
2657 if (pool_elts (tsm->users) == 0)
2660 vlib_worker_thread_t *w = vlib_worker_threads + j;
2661 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2663 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
2665 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
2667 vlib_cli_output (vm, " %d list pool elements",
2668 pool_elts (tsm->list_pool));
2670 pool_foreach (u, tsm->users,
2672 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
2677 if (pool_elts (sm->static_mappings))
2679 vlib_cli_output (vm, "static mappings:");
2680 pool_foreach (m, sm->static_mappings,
2682 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2684 for (j = 0; j < vec_len (sm->to_resolve); j++)
2686 rp = sm->to_resolve + j;
2687 vlib_cli_output (vm, "%U",
2688 format_snat_static_map_to_resolve, rp);
2697 VLIB_CLI_COMMAND (show_snat_command, static) = {
2698 .path = "show nat44",
2699 .short_help = "show nat44",
2700 .function = show_snat_command_fn,
2705 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2708 ip4_address_t * address,
2710 u32 if_address_index,
2713 snat_main_t *sm = &snat_main;
2714 snat_static_map_resolve_t *rp;
2715 u32 *indices_to_delete = 0;
2719 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2721 if (sw_if_index == sm->auto_add_sw_if_indices[i])
2725 /* Don't trip over lease renewal, static config */
2726 for (j = 0; j < vec_len(sm->addresses); j++)
2727 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2730 snat_add_address (sm, address, ~0);
2731 /* Scan static map resolution vector */
2732 for (j = 0; j < vec_len (sm->to_resolve); j++)
2734 rp = sm->to_resolve + j;
2735 /* On this interface? */
2736 if (rp->sw_if_index == sw_if_index)
2738 /* Add the static mapping */
2739 rv = snat_add_static_mapping (rp->l_addr,
2745 ~0 /* sw_if_index */,
2749 clib_warning ("snat_add_static_mapping returned %d",
2751 vec_add1 (indices_to_delete, j);
2754 /* If we resolved any of the outstanding static mappings */
2755 if (vec_len(indices_to_delete))
2758 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2759 vec_delete(sm->to_resolve, 1, j);
2760 vec_free(indices_to_delete);
2766 (void) snat_del_address(sm, address[0], 1);
2774 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
2776 ip4_main_t * ip4_main = sm->ip4_main;
2777 ip4_address_t * first_int_addr;
2778 snat_static_map_resolve_t *rp;
2779 u32 *indices_to_delete = 0;
2782 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2783 0 /* just want the address*/);
2785 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2787 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2791 /* if have address remove it */
2793 (void) snat_del_address (sm, first_int_addr[0], 1);
2796 for (j = 0; j < vec_len (sm->to_resolve); j++)
2798 rp = sm->to_resolve + j;
2799 if (rp->sw_if_index == sw_if_index)
2800 vec_add1 (indices_to_delete, j);
2802 if (vec_len(indices_to_delete))
2804 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2805 vec_del1(sm->to_resolve, j);
2806 vec_free(indices_to_delete);
2809 vec_del1(sm->auto_add_sw_if_indices, i);
2812 return VNET_API_ERROR_VALUE_EXIST;
2819 return VNET_API_ERROR_NO_SUCH_ENTRY;
2821 /* add to the auto-address list */
2822 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2824 /* If the address is already bound - or static - add it now */
2826 snat_add_address (sm, first_int_addr, ~0);
2831 static clib_error_t *
2832 snat_add_interface_address_command_fn (vlib_main_t * vm,
2833 unformat_input_t * input,
2834 vlib_cli_command_t * cmd)
2836 snat_main_t *sm = &snat_main;
2837 unformat_input_t _line_input, *line_input = &_line_input;
2841 clib_error_t *error = 0;
2843 /* Get a line of input. */
2844 if (!unformat_user (input, unformat_line_input, line_input))
2847 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2849 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2850 sm->vnet_main, &sw_if_index))
2852 else if (unformat (line_input, "del"))
2856 error = clib_error_return (0, "unknown input '%U'",
2857 format_unformat_error, line_input);
2862 rv = snat_add_interface_address (sm, sw_if_index, is_del);
2870 error = clib_error_return (0, "snat_add_interface_address returned %d",
2876 unformat_free (line_input);
2881 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2882 .path = "nat44 add interface address",
2883 .short_help = "nat44 add interface address <interface> [del]",
2884 .function = snat_add_interface_address_command_fn,
2887 static clib_error_t *
2888 snat_det_map_command_fn (vlib_main_t * vm,
2889 unformat_input_t * input,
2890 vlib_cli_command_t * cmd)
2892 snat_main_t *sm = &snat_main;
2893 unformat_input_t _line_input, *line_input = &_line_input;
2894 ip4_address_t in_addr, out_addr;
2895 u32 in_plen, out_plen;
2897 clib_error_t *error = 0;
2899 /* Get a line of input. */
2900 if (!unformat_user (input, unformat_line_input, line_input))
2903 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2905 if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
2907 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
2909 else if (unformat (line_input, "del"))
2913 error = clib_error_return (0, "unknown input '%U'",
2914 format_unformat_error, line_input);
2919 unformat_free (line_input);
2921 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
2926 error = clib_error_return (0, "snat_det_add_map return %d", rv);
2931 unformat_free (line_input);
2938 * @cliexstart{snat deterministic add}
2939 * Create bijective mapping of inside address to outside address and port range
2940 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
2942 * To create deterministic mapping between inside network 10.0.0.0/18 and
2943 * outside network 1.1.1.0/30 use:
2944 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
2947 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
2948 .path = "nat44 deterministic add",
2949 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
2950 .function = snat_det_map_command_fn,
2953 static clib_error_t *
2954 snat_det_forward_command_fn (vlib_main_t * vm,
2955 unformat_input_t * input,
2956 vlib_cli_command_t * cmd)
2958 snat_main_t *sm = &snat_main;
2959 unformat_input_t _line_input, *line_input = &_line_input;
2960 ip4_address_t in_addr, out_addr;
2962 snat_det_map_t * dm;
2963 clib_error_t *error = 0;
2965 /* Get a line of input. */
2966 if (!unformat_user (input, unformat_line_input, line_input))
2969 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2971 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
2975 error = clib_error_return (0, "unknown input '%U'",
2976 format_unformat_error, line_input);
2981 unformat_free (line_input);
2983 dm = snat_det_map_by_user(sm, &in_addr);
2985 vlib_cli_output (vm, "no match");
2988 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
2989 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
2990 lo_port, lo_port + dm->ports_per_host - 1);
2994 unformat_free (line_input);
3001 * @cliexstart{snat deterministic forward}
3002 * Return outside address and port range from inside address for deterministic
3004 * To obtain outside address and port of inside host use:
3005 * vpp# nat44 deterministic forward 10.0.0.2
3006 * 1.1.1.0:<1054-1068>
3009 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3010 .path = "nat44 deterministic forward",
3011 .short_help = "nat44 deterministic forward <addr>",
3012 .function = snat_det_forward_command_fn,
3015 static clib_error_t *
3016 snat_det_reverse_command_fn (vlib_main_t * vm,
3017 unformat_input_t * input,
3018 vlib_cli_command_t * cmd)
3020 snat_main_t *sm = &snat_main;
3021 unformat_input_t _line_input, *line_input = &_line_input;
3022 ip4_address_t in_addr, out_addr;
3024 snat_det_map_t * dm;
3025 clib_error_t *error = 0;
3027 /* Get a line of input. */
3028 if (!unformat_user (input, unformat_line_input, line_input))
3031 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3033 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3037 error = clib_error_return (0, "unknown input '%U'",
3038 format_unformat_error, line_input);
3042 unformat_free (line_input);
3044 if (out_port < 1024 || out_port > 65535)
3046 error = clib_error_return (0, "wrong port, must be <1024-65535>");
3050 dm = snat_det_map_by_out(sm, &out_addr);
3052 vlib_cli_output (vm, "no match");
3055 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3056 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3060 unformat_free (line_input);
3067 * @cliexstart{snat deterministic reverse}
3068 * Return inside address from outside address and port for deterministic NAT.
3069 * To obtain inside host address from outside address and port use:
3070 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3074 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3075 .path = "nat44 deterministic reverse",
3076 .short_help = "nat44 deterministic reverse <addr>:<port>",
3077 .function = snat_det_reverse_command_fn,
3080 static clib_error_t *
3081 set_timeout_command_fn (vlib_main_t * vm,
3082 unformat_input_t * input,
3083 vlib_cli_command_t * cmd)
3085 snat_main_t *sm = &snat_main;
3086 unformat_input_t _line_input, *line_input = &_line_input;
3087 clib_error_t *error = 0;
3089 /* Get a line of input. */
3090 if (!unformat_user (input, unformat_line_input, line_input))
3093 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3095 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3097 else if (unformat (line_input, "tcp-established %u",
3098 &sm->tcp_established_timeout))
3100 else if (unformat (line_input, "tcp-transitory %u",
3101 &sm->tcp_transitory_timeout))
3103 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3105 else if (unformat (line_input, "reset"))
3107 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3108 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3109 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3110 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3114 error = clib_error_return (0, "unknown input '%U'",
3115 format_unformat_error, line_input);
3120 unformat_free (line_input);
3123 unformat_free (line_input);
3130 * @cliexstart{set snat deterministic timeout}
3131 * Set values of timeouts for deterministic NAT (in seconds), use:
3132 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3133 * tcp-transitory 250 icmp 90
3134 * To reset default values use:
3135 * vpp# set nat44 deterministic timeout reset
3138 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3139 .path = "set nat44 deterministic timeout",
3140 .function = set_timeout_command_fn,
3142 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3143 "tcp-transitory <sec> | icmp <sec> | reset]",
3146 static clib_error_t *
3147 snat_det_close_session_out_fn (vlib_main_t *vm,
3148 unformat_input_t * input,
3149 vlib_cli_command_t * cmd)
3151 snat_main_t *sm = &snat_main;
3152 unformat_input_t _line_input, *line_input = &_line_input;
3153 ip4_address_t out_addr, ext_addr, in_addr;
3154 u16 out_port, ext_port;
3155 snat_det_map_t * dm;
3156 snat_det_session_t * ses;
3157 snat_det_out_key_t key;
3158 clib_error_t *error = 0;
3160 /* Get a line of input. */
3161 if (!unformat_user (input, unformat_line_input, line_input))
3164 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3166 if (unformat (line_input, "%U:%d %U:%d",
3167 unformat_ip4_address, &out_addr, &out_port,
3168 unformat_ip4_address, &ext_addr, &ext_port))
3172 error = clib_error_return (0, "unknown input '%U'",
3173 format_unformat_error, line_input);
3178 unformat_free (line_input);
3180 dm = snat_det_map_by_out(sm, &out_addr);
3182 vlib_cli_output (vm, "no match");
3185 snat_det_reverse(dm, &ext_addr, out_port, &in_addr);
3186 key.ext_host_addr = out_addr;
3187 key.ext_host_port = ntohs(ext_port);
3188 key.out_port = ntohs(out_port);
3189 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3191 vlib_cli_output (vm, "no match");
3193 snat_det_ses_close(dm, ses);
3197 unformat_free (line_input);
3204 * @cliexstart{snat deterministic close session out}
3205 * Close session using outside ip address and port
3206 * and external ip address and port, use:
3207 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3210 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3211 .path = "nat44 deterministic close session out",
3212 .short_help = "nat44 deterministic close session out "
3213 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3214 .function = snat_det_close_session_out_fn,
3217 static clib_error_t *
3218 snat_det_close_session_in_fn (vlib_main_t *vm,
3219 unformat_input_t * input,
3220 vlib_cli_command_t * cmd)
3222 snat_main_t *sm = &snat_main;
3223 unformat_input_t _line_input, *line_input = &_line_input;
3224 ip4_address_t in_addr, ext_addr;
3225 u16 in_port, ext_port;
3226 snat_det_map_t * dm;
3227 snat_det_session_t * ses;
3228 snat_det_out_key_t key;
3229 clib_error_t *error = 0;
3231 /* Get a line of input. */
3232 if (!unformat_user (input, unformat_line_input, line_input))
3235 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3237 if (unformat (line_input, "%U:%d %U:%d",
3238 unformat_ip4_address, &in_addr, &in_port,
3239 unformat_ip4_address, &ext_addr, &ext_port))
3243 error = clib_error_return (0, "unknown input '%U'",
3244 format_unformat_error, line_input);
3249 unformat_free (line_input);
3251 dm = snat_det_map_by_user (sm, &in_addr);
3253 vlib_cli_output (vm, "no match");
3256 key.ext_host_addr = ext_addr;
3257 key.ext_host_port = ntohs (ext_port);
3258 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key);
3260 vlib_cli_output (vm, "no match");
3262 snat_det_ses_close(dm, ses);
3266 unformat_free(line_input);
3273 * @cliexstart{snat deterministic close_session_in}
3274 * Close session using inside ip address and port
3275 * and external ip address and port, use:
3276 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3279 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3280 .path = "nat44 deterministic close session in",
3281 .short_help = "nat44 deterministic close session in "
3282 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3283 .function = snat_det_close_session_in_fn,