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)
159 /* Check if address already exists */
160 vec_foreach (ap, sm->addresses)
162 if (ap->addr.as_u32 == addr->as_u32)
166 vec_add2 (sm->addresses, ap, 1);
170 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id);
173 #define _(N, i, n, s) \
174 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535);
175 foreach_snat_protocol
178 /* Add external address to FIB */
179 pool_foreach (i, sm->interfaces,
184 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
187 pool_foreach (i, sm->output_feature_interfaces,
192 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
197 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
200 snat_static_mapping_t *m;
201 pool_foreach (m, sm->static_mappings,
203 if (m->external_addr.as_u32 == addr.as_u32)
210 void increment_v4_address (ip4_address_t * a)
214 v = clib_net_to_host_u32(a->as_u32) + 1;
215 a->as_u32 = clib_host_to_net_u32(v);
219 snat_add_static_mapping_when_resolved (snat_main_t * sm,
220 ip4_address_t l_addr,
225 snat_protocol_t proto,
229 snat_static_map_resolve_t *rp;
231 vec_add2 (sm->to_resolve, rp, 1);
232 rp->l_addr.as_u32 = l_addr.as_u32;
234 rp->sw_if_index = sw_if_index;
238 rp->addr_only = addr_only;
243 * @brief Add static mapping.
245 * Create static mapping between local addr+port and external addr+port.
247 * @param l_addr Local IPv4 address.
248 * @param e_addr External IPv4 address.
249 * @param l_port Local port number.
250 * @param e_port External port number.
251 * @param vrf_id VRF ID.
252 * @param addr_only If 0 address port and pair mapping, otherwise address only.
253 * @param sw_if_index External port instead of specific IP address.
254 * @param is_add If 0 delete static mapping, otherwise add.
258 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
259 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
260 u32 sw_if_index, snat_protocol_t proto, int is_add)
262 snat_main_t * sm = &snat_main;
263 snat_static_mapping_t *m;
264 snat_session_key_t m_key;
265 clib_bihash_kv_8_8_t kv, value;
266 snat_address_t *a = 0;
269 snat_interface_t *interface;
272 /* If the external address is a specific interface address */
273 if (sw_if_index != ~0)
275 ip4_address_t * first_int_addr;
277 /* Might be already set... */
278 first_int_addr = ip4_interface_first_address
279 (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
281 /* DHCP resolution required? */
282 if (first_int_addr == 0)
284 snat_add_static_mapping_when_resolved
285 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
290 e_addr.as_u32 = first_int_addr->as_u32;
294 m_key.port = addr_only ? 0 : e_port;
295 m_key.protocol = addr_only ? 0 : proto;
296 m_key.fib_index = sm->outside_fib_index;
297 kv.key = m_key.as_u64;
298 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
301 m = pool_elt_at_index (sm->static_mappings, value.value);
306 return VNET_API_ERROR_VALUE_EXIST;
308 /* Convert VRF id to FIB index */
311 p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
313 return VNET_API_ERROR_NO_SUCH_FIB;
316 /* If not specified use inside VRF id from SNAT plugin startup config */
319 fib_index = sm->inside_fib_index;
320 vrf_id = sm->inside_vrf_id;
323 /* Find external address in allocated addresses and reserve port for
324 address and port pair mapping when dynamic translations enabled */
325 if (!addr_only && !(sm->static_mapping_only))
327 for (i = 0; i < vec_len (sm->addresses); i++)
329 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
331 a = sm->addresses + i;
332 /* External port must be unused */
335 #define _(N, j, n, s) \
336 case SNAT_PROTOCOL_##N: \
337 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
338 return VNET_API_ERROR_INVALID_VALUE; \
339 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
341 a->busy_##n##_ports++; \
343 foreach_snat_protocol
346 clib_warning("unknown_protocol");
347 return VNET_API_ERROR_INVALID_VALUE_2;
352 /* External address must be allocated */
354 return VNET_API_ERROR_NO_SUCH_ENTRY;
357 pool_get (sm->static_mappings, m);
358 memset (m, 0, sizeof (*m));
359 m->local_addr = l_addr;
360 m->external_addr = e_addr;
361 m->addr_only = addr_only;
363 m->fib_index = fib_index;
366 m->local_port = l_port;
367 m->external_port = e_port;
371 m_key.addr = m->local_addr;
372 m_key.port = m->local_port;
373 m_key.protocol = m->proto;
374 m_key.fib_index = m->fib_index;
375 kv.key = m_key.as_u64;
376 kv.value = m - sm->static_mappings;
377 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
379 m_key.addr = m->external_addr;
380 m_key.port = m->external_port;
381 m_key.fib_index = sm->outside_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_external, &kv, 1);
389 snat_user_key_t w_key0;
390 snat_worker_key_t w_key1;
392 w_key0.addr = m->local_addr;
393 w_key0.fib_index = m->fib_index;
394 kv.key = w_key0.as_u64;
396 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
398 kv.value = sm->first_worker_index +
399 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
401 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
405 kv.value = value.value;
408 w_key1.addr = m->external_addr;
409 w_key1.port = clib_host_to_net_u16 (m->external_port);
410 w_key1.fib_index = sm->outside_fib_index;
411 kv.key = w_key1.as_u64;
412 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1);
418 return VNET_API_ERROR_NO_SUCH_ENTRY;
420 /* Free external address port */
421 if (!addr_only && !(sm->static_mapping_only))
423 for (i = 0; i < vec_len (sm->addresses); i++)
425 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
427 a = sm->addresses + i;
430 #define _(N, j, n, s) \
431 case SNAT_PROTOCOL_##N: \
432 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
434 a->busy_##n##_ports--; \
436 foreach_snat_protocol
439 clib_warning("unknown_protocol");
440 return VNET_API_ERROR_INVALID_VALUE_2;
447 m_key.addr = m->local_addr;
448 m_key.port = m->local_port;
449 m_key.protocol = m->proto;
450 m_key.fib_index = m->fib_index;
451 kv.key = m_key.as_u64;
452 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
454 m_key.addr = m->external_addr;
455 m_key.port = m->external_port;
456 m_key.fib_index = sm->outside_fib_index;
457 kv.key = m_key.as_u64;
458 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
460 /* Delete session(s) for static mapping if exist */
461 if (!(sm->static_mapping_only) ||
462 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
464 snat_user_key_t u_key;
466 dlist_elt_t * head, * elt;
467 u32 elt_index, head_index, del_elt_index;
471 snat_main_per_thread_data_t *tsm;
473 u_key.addr = m->local_addr;
474 u_key.fib_index = m->fib_index;
475 kv.key = u_key.as_u64;
476 if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
478 user_index = value.value;
479 if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
480 tsm = vec_elt_at_index (sm->per_thread_data, value.value);
482 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
483 u = pool_elt_at_index (tsm->users, user_index);
484 if (u->nstaticsessions)
486 head_index = u->sessions_per_user_list_head_index;
487 head = pool_elt_at_index (tsm->list_pool, head_index);
488 elt_index = head->next;
489 elt = pool_elt_at_index (tsm->list_pool, elt_index);
490 ses_index = elt->value;
491 while (ses_index != ~0)
493 s = pool_elt_at_index (tsm->sessions, ses_index);
494 del_elt_index = elt_index;
495 elt_index = elt->next;
496 elt = pool_elt_at_index (tsm->list_pool, elt_index);
497 ses_index = elt->value;
501 if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
502 (clib_net_to_host_u16 (s->out2in.port) != e_port))
506 if (snat_is_unk_proto_session (s))
508 clib_bihash_kv_16_8_t up_kv;
509 nat_ed_ses_key_t up_key;
510 up_key.l_addr = s->in2out.addr;
511 up_key.r_addr = s->ext_host_addr;
512 up_key.fib_index = s->in2out.fib_index;
513 up_key.proto = s->in2out.port;
516 up_kv.key[0] = up_key.as_u64[0];
517 up_kv.key[1] = up_key.as_u64[1];
518 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
520 clib_warning ("in2out key del failed");
522 up_key.l_addr = s->out2in.addr;
523 up_key.fib_index = s->out2in.fib_index;
524 up_kv.key[0] = up_key.as_u64[0];
525 up_kv.key[1] = up_key.as_u64[1];
526 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
528 clib_warning ("out2in key del failed");
533 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
534 s->out2in.addr.as_u32,
538 s->in2out.fib_index);
540 value.key = s->in2out.as_u64;
541 if (clib_bihash_add_del_8_8 (&sm->in2out, &value, 0))
542 clib_warning ("in2out key del failed");
543 value.key = s->out2in.as_u64;
544 if (clib_bihash_add_del_8_8 (&sm->out2in, &value, 0))
545 clib_warning ("out2in key del failed");
547 pool_put (tsm->sessions, s);
549 clib_dlist_remove (tsm->list_pool, del_elt_index);
550 pool_put_index (tsm->list_pool, del_elt_index);
551 u->nstaticsessions--;
558 pool_put (tsm->users, u);
559 clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
565 /* Delete static mapping from pool */
566 pool_put (sm->static_mappings, m);
572 /* Add/delete external address to FIB */
573 pool_foreach (interface, sm->interfaces,
575 if (interface->is_inside)
578 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
581 pool_foreach (interface, sm->output_feature_interfaces,
583 if (interface->is_inside)
586 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
593 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
594 snat_protocol_t proto, u32 vrf_id,
595 nat44_lb_addr_port_t *locals, u8 is_add)
597 snat_main_t * sm = &snat_main;
598 snat_static_mapping_t *m;
599 snat_session_key_t m_key;
600 clib_bihash_kv_8_8_t kv, value;
602 snat_address_t *a = 0;
604 nat44_lb_addr_port_t *local;
605 snat_user_key_t w_key0;
606 snat_worker_key_t w_key1;
607 u32 worker_index = 0;
611 m_key.protocol = proto;
612 m_key.fib_index = sm->outside_fib_index;
613 kv.key = m_key.as_u64;
614 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
617 m = pool_elt_at_index (sm->static_mappings, value.value);
622 return VNET_API_ERROR_VALUE_EXIST;
624 if (vec_len (locals) < 2)
625 return VNET_API_ERROR_INVALID_VALUE;
627 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
630 /* Find external address in allocated addresses and reserve port for
631 address and port pair mapping when dynamic translations enabled */
632 if (!sm->static_mapping_only)
634 for (i = 0; i < vec_len (sm->addresses); i++)
636 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
638 a = sm->addresses + i;
639 /* External port must be unused */
642 #define _(N, j, n, s) \
643 case SNAT_PROTOCOL_##N: \
644 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
645 return VNET_API_ERROR_INVALID_VALUE; \
646 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
648 a->busy_##n##_ports++; \
650 foreach_snat_protocol
653 clib_warning("unknown_protocol");
654 return VNET_API_ERROR_INVALID_VALUE_2;
659 /* External address must be allocated */
661 return VNET_API_ERROR_NO_SUCH_ENTRY;
664 pool_get (sm->static_mappings, m);
665 memset (m, 0, sizeof (*m));
666 m->external_addr = e_addr;
669 m->fib_index = fib_index;
670 m->external_port = e_port;
673 m_key.addr = m->external_addr;
674 m_key.port = m->external_port;
675 m_key.protocol = m->proto;
676 m_key.fib_index = sm->outside_fib_index;
677 kv.key = m_key.as_u64;
678 kv.value = m - sm->static_mappings;
679 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
681 clib_warning ("static_mapping_by_external key add failed");
682 return VNET_API_ERROR_UNSPECIFIED;
684 m_key.port = clib_host_to_net_u16 (m->external_port);
685 kv.key = m_key.as_u64;
687 if (clib_bihash_add_del_8_8(&sm->out2in, &kv, 1))
689 clib_warning ("static_mapping_by_local key add failed");
690 return VNET_API_ERROR_UNSPECIFIED;
693 m_key.fib_index = m->fib_index;
698 w_key0.addr = locals[0].addr;
699 w_key0.fib_index = fib_index;
700 kv.key = w_key0.as_u64;
702 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
703 worker_index = sm->first_worker_index +
704 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
706 worker_index = value.value;
708 w_key1.addr = m->external_addr;
709 w_key1.port = clib_host_to_net_u16 (m->external_port);
710 w_key1.fib_index = sm->outside_fib_index;
711 kv.key = w_key1.as_u64;
712 kv.value = worker_index;
713 if (clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1))
715 clib_warning ("worker-by-out add key failed");
716 return VNET_API_ERROR_UNSPECIFIED;
720 for (i = 0; i < vec_len (locals); i++)
722 m_key.addr = locals[i].addr;
723 m_key.port = locals[i].port;
724 kv.key = m_key.as_u64;
725 kv.value = m - sm->static_mappings;
726 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
727 locals[i].prefix = locals[i - 1].prefix + locals[i].probability;
728 vec_add1 (m->locals, locals[i]);
729 m_key.port = clib_host_to_net_u16 (locals[i].port);
730 kv.key = m_key.as_u64;
732 if (clib_bihash_add_del_8_8(&sm->in2out, &kv, 1))
734 clib_warning ("in2out key add failed");
735 return VNET_API_ERROR_UNSPECIFIED;
740 w_key0.addr = locals[i].addr;
741 w_key0.fib_index = fib_index;
742 kv.key = w_key0.as_u64;
743 kv.value = worker_index;
744 if (clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1))
746 clib_warning ("worker-by-in key add failed");
747 return VNET_API_ERROR_UNSPECIFIED;
755 return VNET_API_ERROR_NO_SUCH_ENTRY;
757 fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4);
759 /* Free external address port */
760 if (!sm->static_mapping_only)
762 for (i = 0; i < vec_len (sm->addresses); i++)
764 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
766 a = sm->addresses + i;
769 #define _(N, j, n, s) \
770 case SNAT_PROTOCOL_##N: \
771 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
773 a->busy_##n##_ports--; \
775 foreach_snat_protocol
778 clib_warning("unknown_protocol");
779 return VNET_API_ERROR_INVALID_VALUE_2;
786 m_key.addr = m->external_addr;
787 m_key.port = m->external_port;
788 m_key.protocol = m->proto;
789 m_key.fib_index = sm->outside_fib_index;
790 kv.key = m_key.as_u64;
791 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
793 clib_warning ("static_mapping_by_external key del failed");
794 return VNET_API_ERROR_UNSPECIFIED;
796 m_key.port = clib_host_to_net_u16 (m->external_port);
797 kv.key = m_key.as_u64;
798 if (clib_bihash_add_del_8_8(&sm->out2in, &kv, 0))
800 clib_warning ("outi2in key del failed");
801 return VNET_API_ERROR_UNSPECIFIED;
804 vec_foreach (local, m->locals)
806 m_key.addr = local->addr;
807 m_key.port = local->port;
808 m_key.fib_index = m->fib_index;
809 kv.key = m_key.as_u64;
810 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
812 clib_warning ("static_mapping_by_local key del failed");
813 return VNET_API_ERROR_UNSPECIFIED;
815 m_key.port = clib_host_to_net_u16 (local->port);
816 kv.key = m_key.as_u64;
817 if (clib_bihash_add_del_8_8(&sm->in2out, &kv, 0))
819 clib_warning ("in2out key del failed");
820 return VNET_API_ERROR_UNSPECIFIED;
824 pool_put (sm->static_mappings, m);
830 int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
832 snat_address_t *a = 0;
834 u32 *ses_to_be_removed = 0, *ses_index;
835 clib_bihash_kv_8_8_t kv, value;
836 snat_user_key_t user_key;
838 snat_main_per_thread_data_t *tsm;
839 snat_static_mapping_t *m;
840 snat_interface_t *interface;
843 /* Find SNAT address */
844 for (i=0; i < vec_len (sm->addresses); i++)
846 if (sm->addresses[i].addr.as_u32 == addr.as_u32)
848 a = sm->addresses + i;
853 return VNET_API_ERROR_NO_SUCH_ENTRY;
857 pool_foreach (m, sm->static_mappings,
859 if (m->external_addr.as_u32 == addr.as_u32)
860 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
861 m->local_port, m->external_port,
862 m->vrf_id, m->addr_only, ~0,
868 /* Check if address is used in some static mapping */
869 if (is_snat_address_used_in_static_mapping(sm, addr))
871 clib_warning ("address used in static mapping");
872 return VNET_API_ERROR_UNSPECIFIED;
876 if (a->fib_index != ~0)
877 fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4);
879 /* Delete sessions using address */
880 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
882 vec_foreach (tsm, sm->per_thread_data)
884 pool_foreach (ses, tsm->sessions, ({
885 if (ses->out2in.addr.as_u32 == addr.as_u32)
887 if (snat_is_unk_proto_session (ses))
889 clib_bihash_kv_16_8_t up_kv;
890 nat_ed_ses_key_t up_key;
891 up_key.l_addr = ses->in2out.addr;
892 up_key.r_addr = ses->ext_host_addr;
893 up_key.fib_index = ses->in2out.fib_index;
894 up_key.proto = ses->in2out.port;
897 up_kv.key[0] = up_key.as_u64[0];
898 up_kv.key[1] = up_key.as_u64[1];
899 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
901 clib_warning ("in2out key del failed");
903 up_key.l_addr = ses->out2in.addr;
904 up_key.fib_index = ses->out2in.fib_index;
905 up_kv.key[0] = up_key.as_u64[0];
906 up_kv.key[1] = up_key.as_u64[1];
907 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
909 clib_warning ("out2in key del failed");
914 snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
915 ses->out2in.addr.as_u32,
916 ses->in2out.protocol,
919 ses->in2out.fib_index);
920 kv.key = ses->in2out.as_u64;
921 clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
922 kv.key = ses->out2in.as_u64;
923 clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
925 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
926 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
927 user_key.addr = ses->in2out.addr;
928 user_key.fib_index = ses->in2out.fib_index;
929 kv.key = user_key.as_u64;
930 if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
932 u = pool_elt_at_index (tsm->users, value.value);
938 vec_foreach (ses_index, ses_to_be_removed)
939 pool_put_index (tsm->sessions, ses_index[0]);
941 vec_free (ses_to_be_removed);
945 vec_del1 (sm->addresses, i);
947 /* Delete external address from FIB */
948 pool_foreach (interface, sm->interfaces,
950 if (interface->is_inside)
953 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
956 pool_foreach (interface, sm->output_feature_interfaces,
958 if (interface->is_inside)
961 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
968 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
970 snat_main_t *sm = &snat_main;
972 const char * feature_name;
974 snat_static_mapping_t * m;
977 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
978 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
981 if (sm->num_workers > 1 && !sm->deterministic)
982 feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
983 else if (sm->deterministic)
984 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
986 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
989 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
992 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
993 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
995 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
996 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
998 pool_foreach (i, sm->interfaces,
1000 if (i->sw_if_index == sw_if_index)
1003 pool_put (sm->interfaces, i);
1005 return VNET_API_ERROR_VALUE_EXIST;
1012 return VNET_API_ERROR_NO_SUCH_ENTRY;
1014 pool_get (sm->interfaces, i);
1015 i->sw_if_index = sw_if_index;
1016 i->is_inside = is_inside;
1018 /* Add/delete external addresses to FIB */
1023 vec_foreach (ap, sm->addresses)
1024 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1026 pool_foreach (m, sm->static_mappings,
1028 if (!(m->addr_only))
1031 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1034 pool_foreach (dm, sm->det_maps,
1036 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1042 int snat_interface_add_del_output_feature (u32 sw_if_index,
1046 snat_main_t *sm = &snat_main;
1047 snat_interface_t *i;
1048 snat_address_t * ap;
1049 snat_static_mapping_t * m;
1051 if (sm->deterministic ||
1052 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1053 return VNET_API_ERROR_UNSUPPORTED;
1057 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1058 sw_if_index, !is_del, 0, 0);
1059 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1060 sw_if_index, !is_del, 0, 0);
1064 if (sm->num_workers > 1)
1066 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1067 sw_if_index, !is_del, 0, 0);
1068 vnet_feature_enable_disable ("ip4-output",
1069 "nat44-in2out-output-worker-handoff",
1070 sw_if_index, !is_del, 0, 0);
1074 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1076 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1077 sw_if_index, !is_del, 0, 0);
1081 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1082 sm->fq_in2out_output_index =
1083 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1085 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1086 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1088 pool_foreach (i, sm->output_feature_interfaces,
1090 if (i->sw_if_index == sw_if_index)
1093 pool_put (sm->output_feature_interfaces, i);
1095 return VNET_API_ERROR_VALUE_EXIST;
1102 return VNET_API_ERROR_NO_SUCH_ENTRY;
1104 pool_get (sm->output_feature_interfaces, i);
1105 i->sw_if_index = sw_if_index;
1106 i->is_inside = is_inside;
1108 /* Add/delete external addresses to FIB */
1113 vec_foreach (ap, sm->addresses)
1114 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1116 pool_foreach (m, sm->static_mappings,
1118 if (!(m->addr_only))
1121 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1127 int snat_set_workers (uword * bitmap)
1129 snat_main_t *sm = &snat_main;
1132 if (sm->num_workers < 2)
1133 return VNET_API_ERROR_FEATURE_DISABLED;
1135 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1136 return VNET_API_ERROR_INVALID_WORKER;
1138 vec_free (sm->workers);
1139 clib_bitmap_foreach (i, bitmap,
1141 vec_add1(sm->workers, i);
1142 sm->per_thread_data[i].snat_thread_index = j;
1146 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1147 sm->num_snat_thread = _vec_len (sm->workers);
1154 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1157 ip4_address_t * address,
1159 u32 if_address_index,
1162 static clib_error_t * snat_init (vlib_main_t * vm)
1164 snat_main_t * sm = &snat_main;
1165 clib_error_t * error = 0;
1166 ip4_main_t * im = &ip4_main;
1167 ip_lookup_main_t * lm = &im->lookup_main;
1169 vlib_thread_registration_t *tr;
1170 vlib_thread_main_t *tm = vlib_get_thread_main ();
1173 ip4_add_del_interface_address_callback_t cb4;
1176 sm->vnet_main = vnet_get_main();
1178 sm->ip4_lookup_main = lm;
1179 sm->api_main = &api_main;
1180 sm->first_worker_index = 0;
1181 sm->next_worker = 0;
1182 sm->num_workers = 0;
1183 sm->num_snat_thread = 1;
1185 sm->port_per_thread = 0xffff - 1024;
1186 sm->fq_in2out_index = ~0;
1187 sm->fq_out2in_index = ~0;
1188 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1189 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1190 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1191 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1193 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1196 tr = (vlib_thread_registration_t *) p[0];
1199 sm->num_workers = tr->count;
1200 sm->first_worker_index = tr->first_index;
1204 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1206 /* Use all available workers by default */
1207 if (sm->num_workers > 1)
1209 for (i=0; i < sm->num_workers; i++)
1210 bitmap = clib_bitmap_set (bitmap, i, 1);
1211 snat_set_workers(bitmap);
1212 clib_bitmap_free (bitmap);
1216 sm->per_thread_data[0].snat_thread_index = 0;
1219 error = snat_api_init(vm, sm);
1223 /* Set up the interface address add/del callback */
1224 cb4.function = snat_ip4_add_del_interface_address_cb;
1225 cb4.function_opaque = 0;
1227 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1229 /* Init IPFIX logging */
1230 snat_ipfix_logging_init(vm);
1232 error = nat64_init(vm);
1237 VLIB_INIT_FUNCTION (snat_init);
1239 void snat_free_outside_address_and_port (snat_main_t * sm,
1240 snat_session_key_t * k,
1244 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1246 ASSERT (address_index < vec_len (sm->addresses));
1248 a = sm->addresses + address_index;
1250 switch (k->protocol)
1252 #define _(N, i, n, s) \
1253 case SNAT_PROTOCOL_##N: \
1254 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1255 port_host_byte_order) == 1); \
1256 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1257 port_host_byte_order, 0); \
1258 a->busy_##n##_ports--; \
1260 foreach_snat_protocol
1263 clib_warning("unknown_protocol");
1269 * @brief Match NAT44 static mapping.
1271 * @param sm NAT main.
1272 * @param match Address and port to match.
1273 * @param mapping External or local address and port of the matched mapping.
1274 * @param by_external If 0 match by local address otherwise match by external
1276 * @param is_addr_only If matched mapping is address only
1278 * @returns 0 if match found otherwise 1.
1280 int snat_static_mapping_match (snat_main_t * sm,
1281 snat_session_key_t match,
1282 snat_session_key_t * mapping,
1286 clib_bihash_kv_8_8_t kv, value;
1287 snat_static_mapping_t *m;
1288 snat_session_key_t m_key;
1289 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1290 u32 rand, lo = 0, hi, mid;
1293 mapping_hash = &sm->static_mapping_by_external;
1295 m_key.addr = match.addr;
1296 m_key.port = clib_net_to_host_u16 (match.port);
1297 m_key.protocol = match.protocol;
1298 m_key.fib_index = match.fib_index;
1300 kv.key = m_key.as_u64;
1302 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1304 /* Try address only mapping */
1307 kv.key = m_key.as_u64;
1308 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1312 m = pool_elt_at_index (sm->static_mappings, value.value);
1316 if (vec_len (m->locals))
1318 hi = vec_len (m->locals) - 1;
1319 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1322 mid = ((hi - 1) >> 1) + lo;
1323 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1325 if (!(m->locals[lo].prefix >= rand))
1327 mapping->addr = m->locals[lo].addr;
1328 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1332 mapping->addr = m->local_addr;
1333 /* Address only mapping doesn't change port */
1334 mapping->port = m->addr_only ? match.port
1335 : clib_host_to_net_u16 (m->local_port);
1337 mapping->fib_index = m->fib_index;
1338 mapping->protocol = m->proto;
1342 mapping->addr = m->external_addr;
1343 /* Address only mapping doesn't change port */
1344 mapping->port = m->addr_only ? match.port
1345 : clib_host_to_net_u16 (m->external_port);
1346 mapping->fib_index = sm->outside_fib_index;
1349 if (PREDICT_FALSE(is_addr_only != 0))
1350 *is_addr_only = m->addr_only;
1355 static_always_inline u16
1356 snat_random_port (snat_main_t * sm, u16 min, u16 max)
1358 return min + random_u32 (&sm->random_seed) /
1359 (random_u32_max() / (max - min + 1) + 1);
1362 int snat_alloc_outside_address_and_port (snat_main_t * sm,
1365 snat_session_key_t * k,
1366 u32 * address_indexp)
1372 for (i = 0; i < vec_len (sm->addresses); i++)
1374 a = sm->addresses + i;
1375 if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
1377 switch (k->protocol)
1379 #define _(N, j, n, s) \
1380 case SNAT_PROTOCOL_##N: \
1381 if (a->busy_##n##_ports < (sm->port_per_thread * sm->num_snat_thread)) \
1385 portnum = (sm->port_per_thread * \
1386 sm->per_thread_data[thread_index].snat_thread_index) + \
1387 snat_random_port(sm, 0, sm->port_per_thread) + 1024; \
1388 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1390 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1391 a->busy_##n##_ports++; \
1392 k->addr = a->addr; \
1393 k->port = clib_host_to_net_u16(portnum); \
1394 *address_indexp = i; \
1399 foreach_snat_protocol
1402 clib_warning("unknown protocol");
1407 /* Totally out of translations to use... */
1408 snat_ipfix_logging_addresses_exhausted(0);
1413 static clib_error_t *
1414 add_address_command_fn (vlib_main_t * vm,
1415 unformat_input_t * input,
1416 vlib_cli_command_t * cmd)
1418 unformat_input_t _line_input, *line_input = &_line_input;
1419 snat_main_t * sm = &snat_main;
1420 ip4_address_t start_addr, end_addr, this_addr;
1421 u32 start_host_order, end_host_order;
1426 clib_error_t *error = 0;
1428 /* Get a line of input. */
1429 if (!unformat_user (input, unformat_line_input, line_input))
1432 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1434 if (unformat (line_input, "%U - %U",
1435 unformat_ip4_address, &start_addr,
1436 unformat_ip4_address, &end_addr))
1438 else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
1440 else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1441 end_addr = start_addr;
1442 else if (unformat (line_input, "del"))
1446 error = clib_error_return (0, "unknown input '%U'",
1447 format_unformat_error, line_input);
1452 if (sm->static_mapping_only)
1454 error = clib_error_return (0, "static mapping only mode");
1458 start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1459 end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1461 if (end_host_order < start_host_order)
1463 error = clib_error_return (0, "end address less than start address");
1467 count = (end_host_order - start_host_order) + 1;
1470 clib_warning ("%U - %U, %d addresses...",
1471 format_ip4_address, &start_addr,
1472 format_ip4_address, &end_addr,
1475 this_addr = start_addr;
1477 for (i = 0; i < count; i++)
1480 snat_add_address (sm, &this_addr, vrf_id);
1482 rv = snat_del_address (sm, this_addr, 0);
1486 case VNET_API_ERROR_NO_SUCH_ENTRY:
1487 error = clib_error_return (0, "S-NAT address not exist.");
1489 case VNET_API_ERROR_UNSPECIFIED:
1490 error = clib_error_return (0, "S-NAT address used in static mapping.");
1496 increment_v4_address (&this_addr);
1500 unformat_free (line_input);
1505 VLIB_CLI_COMMAND (add_address_command, static) = {
1506 .path = "nat44 add address",
1507 .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1508 "[tenant-vrf <vrf-id>] [del]",
1509 .function = add_address_command_fn,
1512 static clib_error_t *
1513 snat_feature_command_fn (vlib_main_t * vm,
1514 unformat_input_t * input,
1515 vlib_cli_command_t * cmd)
1517 unformat_input_t _line_input, *line_input = &_line_input;
1518 vnet_main_t * vnm = vnet_get_main();
1519 clib_error_t * error = 0;
1521 u32 * inside_sw_if_indices = 0;
1522 u32 * outside_sw_if_indices = 0;
1523 u8 is_output_feature = 0;
1529 /* Get a line of input. */
1530 if (!unformat_user (input, unformat_line_input, line_input))
1533 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1535 if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1537 vec_add1 (inside_sw_if_indices, sw_if_index);
1538 else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1540 vec_add1 (outside_sw_if_indices, sw_if_index);
1541 else if (unformat (line_input, "output-feature"))
1542 is_output_feature = 1;
1543 else if (unformat (line_input, "del"))
1547 error = clib_error_return (0, "unknown input '%U'",
1548 format_unformat_error, line_input);
1553 if (vec_len (inside_sw_if_indices))
1555 for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1557 sw_if_index = inside_sw_if_indices[i];
1558 if (is_output_feature)
1560 if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
1562 error = clib_error_return (0, "%s %U failed",
1563 is_del ? "del" : "add",
1564 format_vnet_sw_interface_name, vnm,
1565 vnet_get_sw_interface (vnm,
1572 if (snat_interface_add_del (sw_if_index, 1, is_del))
1574 error = clib_error_return (0, "%s %U failed",
1575 is_del ? "del" : "add",
1576 format_vnet_sw_interface_name, vnm,
1577 vnet_get_sw_interface (vnm,
1585 if (vec_len (outside_sw_if_indices))
1587 for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1589 sw_if_index = outside_sw_if_indices[i];
1590 if (is_output_feature)
1592 if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
1594 error = clib_error_return (0, "%s %U failed",
1595 is_del ? "del" : "add",
1596 format_vnet_sw_interface_name, vnm,
1597 vnet_get_sw_interface (vnm,
1604 if (snat_interface_add_del (sw_if_index, 0, is_del))
1606 error = clib_error_return (0, "%s %U failed",
1607 is_del ? "del" : "add",
1608 format_vnet_sw_interface_name, vnm,
1609 vnet_get_sw_interface (vnm,
1618 unformat_free (line_input);
1619 vec_free (inside_sw_if_indices);
1620 vec_free (outside_sw_if_indices);
1625 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1626 .path = "set interface nat44",
1627 .function = snat_feature_command_fn,
1628 .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1633 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1635 u32 *r = va_arg (*args, u32 *);
1638 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1639 foreach_snat_protocol
1647 format_snat_protocol (u8 * s, va_list * args)
1649 u32 i = va_arg (*args, u32);
1654 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1655 foreach_snat_protocol
1658 s = format (s, "unknown");
1661 s = format (s, "%s", t);
1665 static clib_error_t *
1666 add_static_mapping_command_fn (vlib_main_t * vm,
1667 unformat_input_t * input,
1668 vlib_cli_command_t * cmd)
1670 unformat_input_t _line_input, *line_input = &_line_input;
1671 clib_error_t * error = 0;
1672 ip4_address_t l_addr, e_addr;
1673 u32 l_port = 0, e_port = 0, vrf_id = ~0;
1676 u32 sw_if_index = ~0;
1677 vnet_main_t * vnm = vnet_get_main();
1679 snat_protocol_t proto;
1682 /* Get a line of input. */
1683 if (!unformat_user (input, unformat_line_input, line_input))
1686 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1688 if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1691 else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1693 else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1696 else if (unformat (line_input, "external %U", unformat_ip4_address,
1699 else if (unformat (line_input, "external %U %u",
1700 unformat_vnet_sw_interface, vnm, &sw_if_index,
1704 else if (unformat (line_input, "external %U",
1705 unformat_vnet_sw_interface, vnm, &sw_if_index))
1707 else if (unformat (line_input, "vrf %u", &vrf_id))
1709 else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1711 else if (unformat (line_input, "del"))
1715 error = clib_error_return (0, "unknown input: '%U'",
1716 format_unformat_error, line_input);
1721 if (!addr_only && !proto_set)
1723 error = clib_error_return (0, "missing protocol");
1727 rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1728 vrf_id, addr_only, sw_if_index, proto, is_add);
1732 case VNET_API_ERROR_INVALID_VALUE:
1733 error = clib_error_return (0, "External port already in use.");
1735 case VNET_API_ERROR_NO_SUCH_ENTRY:
1737 error = clib_error_return (0, "External addres must be allocated.");
1739 error = clib_error_return (0, "Mapping not exist.");
1741 case VNET_API_ERROR_NO_SUCH_FIB:
1742 error = clib_error_return (0, "No such VRF id.");
1744 case VNET_API_ERROR_VALUE_EXIST:
1745 error = clib_error_return (0, "Mapping already exist.");
1752 unformat_free (line_input);
1759 * @cliexstart{snat add static mapping}
1760 * Static mapping allows hosts on the external network to initiate connection
1761 * to to the local network host.
1762 * To create static mapping between local host address 10.0.0.3 port 6303 and
1763 * external address 4.4.4.4 port 3606 for TCP protocol use:
1764 * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1765 * If not runnig "static mapping only" NAT plugin mode use before:
1766 * vpp# nat44 add address 4.4.4.4
1767 * To create static mapping between local and external address use:
1768 * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1771 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1772 .path = "nat44 add static mapping",
1773 .function = add_static_mapping_command_fn,
1775 "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1778 static clib_error_t *
1779 add_lb_static_mapping_command_fn (vlib_main_t * vm,
1780 unformat_input_t * input,
1781 vlib_cli_command_t * cmd)
1783 unformat_input_t _line_input, *line_input = &_line_input;
1784 clib_error_t * error = 0;
1785 ip4_address_t l_addr, e_addr;
1786 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1789 snat_protocol_t proto;
1791 nat44_lb_addr_port_t *locals = 0, local;
1793 /* Get a line of input. */
1794 if (!unformat_user (input, unformat_line_input, line_input))
1797 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1799 if (unformat (line_input, "local %U:%u probability %u",
1800 unformat_ip4_address, &l_addr, &l_port, &probability))
1802 memset (&local, 0, sizeof (local));
1803 local.addr = l_addr;
1804 local.port = (u16) l_port;
1805 local.probability = (u8) probability;
1806 vec_add1 (locals, local);
1808 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1811 else if (unformat (line_input, "vrf %u", &vrf_id))
1813 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
1816 else if (unformat (line_input, "del"))
1820 error = clib_error_return (0, "unknown input: '%U'",
1821 format_unformat_error, line_input);
1826 if (vec_len (locals) < 2)
1828 error = clib_error_return (0, "at least two local must be set");
1834 error = clib_error_return (0, "missing protocol");
1838 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
1843 case VNET_API_ERROR_INVALID_VALUE:
1844 error = clib_error_return (0, "External port already in use.");
1846 case VNET_API_ERROR_NO_SUCH_ENTRY:
1848 error = clib_error_return (0, "External addres must be allocated.");
1850 error = clib_error_return (0, "Mapping not exist.");
1852 case VNET_API_ERROR_VALUE_EXIST:
1853 error = clib_error_return (0, "Mapping already exist.");
1860 unformat_free (line_input);
1866 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1867 .path = "nat44 add load-balancing static mapping",
1868 .function = add_lb_static_mapping_command_fn,
1870 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
1873 static clib_error_t *
1874 set_workers_command_fn (vlib_main_t * vm,
1875 unformat_input_t * input,
1876 vlib_cli_command_t * cmd)
1878 unformat_input_t _line_input, *line_input = &_line_input;
1881 clib_error_t *error = 0;
1883 /* Get a line of input. */
1884 if (!unformat_user (input, unformat_line_input, line_input))
1887 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1889 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1893 error = clib_error_return (0, "unknown input '%U'",
1894 format_unformat_error, line_input);
1901 error = clib_error_return (0, "List of workers must be specified.");
1905 rv = snat_set_workers(bitmap);
1907 clib_bitmap_free (bitmap);
1911 case VNET_API_ERROR_INVALID_WORKER:
1912 error = clib_error_return (0, "Invalid worker(s).");
1914 case VNET_API_ERROR_FEATURE_DISABLED:
1915 error = clib_error_return (0,
1916 "Supported only if 2 or more workes available.");
1923 unformat_free (line_input);
1930 * @cliexstart{set snat workers}
1931 * Set NAT workers if 2 or more workers available, use:
1932 * vpp# set snat workers 0-2,5
1935 VLIB_CLI_COMMAND (set_workers_command, static) = {
1936 .path = "set nat workers",
1937 .function = set_workers_command_fn,
1939 "set nat workers <workers-list>",
1942 static clib_error_t *
1943 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
1944 unformat_input_t * input,
1945 vlib_cli_command_t * cmd)
1947 unformat_input_t _line_input, *line_input = &_line_input;
1952 clib_error_t *error = 0;
1954 /* Get a line of input. */
1955 if (!unformat_user (input, unformat_line_input, line_input))
1958 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1960 if (unformat (line_input, "domain %d", &domain_id))
1962 else if (unformat (line_input, "src-port %d", &src_port))
1964 else if (unformat (line_input, "disable"))
1968 error = clib_error_return (0, "unknown input '%U'",
1969 format_unformat_error, line_input);
1974 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
1978 error = clib_error_return (0, "ipfix logging enable failed");
1983 unformat_free (line_input);
1990 * @cliexstart{snat ipfix logging}
1991 * To enable NAT IPFIX logging use:
1992 * vpp# nat ipfix logging
1993 * To set IPFIX exporter use:
1994 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
1997 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
1998 .path = "nat ipfix logging",
1999 .function = snat_ipfix_logging_enable_disable_command_fn,
2000 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2004 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2006 snat_main_t *sm = &snat_main;
2007 snat_user_key_t key0;
2008 clib_bihash_kv_8_8_t kv0, value0;
2009 u32 next_worker_index = 0;
2011 key0.addr = ip0->src_address;
2012 key0.fib_index = rx_fib_index0;
2014 kv0.key = key0.as_u64;
2016 /* Ever heard of of the "user" before? */
2017 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0))
2019 /* No, assign next available worker (RR) */
2020 next_worker_index = sm->first_worker_index;
2021 if (vec_len (sm->workers))
2023 next_worker_index +=
2024 sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
2027 /* add non-traslated packets worker lookup */
2028 kv0.value = next_worker_index;
2029 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
2032 next_worker_index = value0.value;
2034 return next_worker_index;
2038 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2040 snat_main_t *sm = &snat_main;
2041 snat_worker_key_t key0;
2042 clib_bihash_kv_8_8_t kv0, value0;
2043 udp_header_t * udp0;
2044 u32 next_worker_index = 0;
2046 udp0 = ip4_next_header (ip0);
2048 key0.addr = ip0->dst_address;
2049 key0.port = udp0->dst_port;
2050 key0.fib_index = rx_fib_index0;
2052 if (PREDICT_FALSE(ip0->protocol == IP_PROTOCOL_ICMP))
2054 icmp46_header_t * icmp0 = (icmp46_header_t *) udp0;
2055 icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1);
2056 key0.port = echo0->identifier;
2059 kv0.key = key0.as_u64;
2061 /* Ever heard of of the "user" before? */
2062 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
2065 kv0.key = key0.as_u64;
2067 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
2069 /* No, assign next available worker (RR) */
2070 next_worker_index = sm->first_worker_index;
2071 if (vec_len (sm->workers))
2073 next_worker_index +=
2074 sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
2079 /* Static mapping without port */
2080 next_worker_index = value0.value;
2083 /* Add to translated packets worker lookup */
2084 key0.port = udp0->dst_port;
2085 kv0.key = key0.as_u64;
2086 kv0.value = next_worker_index;
2087 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
2090 next_worker_index = value0.value;
2092 return next_worker_index;
2095 static clib_error_t *
2096 snat_config (vlib_main_t * vm, unformat_input_t * input)
2098 snat_main_t * sm = &snat_main;
2099 u32 translation_buckets = 1024;
2100 u32 translation_memory_size = 128<<20;
2101 u32 user_buckets = 128;
2102 u32 user_memory_size = 64<<20;
2103 u32 max_translations_per_user = 100;
2104 u32 outside_vrf_id = 0;
2105 u32 inside_vrf_id = 0;
2106 u32 static_mapping_buckets = 1024;
2107 u32 static_mapping_memory_size = 64<<20;
2108 u8 static_mapping_only = 0;
2109 u8 static_mapping_connection_tracking = 0;
2111 sm->deterministic = 0;
2113 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2115 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2117 else if (unformat (input, "translation hash memory %d",
2118 &translation_memory_size));
2119 else if (unformat (input, "user hash buckets %d", &user_buckets))
2121 else if (unformat (input, "user hash memory %d",
2124 else if (unformat (input, "max translations per user %d",
2125 &max_translations_per_user))
2127 else if (unformat (input, "outside VRF id %d",
2130 else if (unformat (input, "inside VRF id %d",
2133 else if (unformat (input, "static mapping only"))
2135 static_mapping_only = 1;
2136 if (unformat (input, "connection tracking"))
2137 static_mapping_connection_tracking = 1;
2139 else if (unformat (input, "deterministic"))
2140 sm->deterministic = 1;
2142 return clib_error_return (0, "unknown input '%U'",
2143 format_unformat_error, input);
2146 /* for show commands, etc. */
2147 sm->translation_buckets = translation_buckets;
2148 sm->translation_memory_size = translation_memory_size;
2149 sm->user_buckets = user_buckets;
2150 sm->user_memory_size = user_memory_size;
2151 sm->max_translations_per_user = max_translations_per_user;
2152 sm->outside_vrf_id = outside_vrf_id;
2153 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2155 sm->inside_vrf_id = inside_vrf_id;
2156 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2158 sm->static_mapping_only = static_mapping_only;
2159 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2161 if (sm->deterministic)
2163 sm->in2out_node_index = snat_det_in2out_node.index;
2164 sm->in2out_output_node_index = ~0;
2165 sm->out2in_node_index = snat_det_out2in_node.index;
2166 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2167 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2171 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2172 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2173 sm->in2out_node_index = snat_in2out_node.index;
2174 sm->in2out_output_node_index = snat_in2out_output_node.index;
2175 sm->out2in_node_index = snat_out2in_node.index;
2176 if (!static_mapping_only ||
2177 (static_mapping_only && static_mapping_connection_tracking))
2179 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2180 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2182 clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
2185 clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
2188 clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
2189 translation_memory_size);
2191 clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
2192 translation_memory_size);
2194 clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
2197 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2198 translation_buckets, translation_memory_size);
2200 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2201 translation_buckets, translation_memory_size);
2205 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2206 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2208 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2209 "static_mapping_by_local", static_mapping_buckets,
2210 static_mapping_memory_size);
2212 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2213 "static_mapping_by_external", static_mapping_buckets,
2214 static_mapping_memory_size);
2220 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2222 u8 * format_snat_session_state (u8 * s, va_list * args)
2224 u32 i = va_arg (*args, u32);
2229 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2230 foreach_snat_session_state
2233 t = format (t, "unknown");
2235 s = format (s, "%s", t);
2239 u8 * format_snat_key (u8 * s, va_list * args)
2241 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2243 s = format (s, "%U proto %U port %d fib %d",
2244 format_ip4_address, &key->addr,
2245 format_snat_protocol, key->protocol,
2246 clib_net_to_host_u16 (key->port), key->fib_index);
2250 u8 * format_snat_session (u8 * s, va_list * args)
2252 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2253 snat_session_t * sess = va_arg (*args, snat_session_t *);
2255 if (snat_is_unk_proto_session (sess))
2257 s = format (s, " i2o %U proto %u fib %u\n",
2258 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2259 sess->in2out.fib_index);
2260 s = format (s, " o2i %U proto %u fib %u\n",
2261 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2262 sess->out2in.fib_index);
2266 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2267 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2269 if (sess->ext_host_addr.as_u32)
2270 s = format (s, " external host %U\n",
2271 format_ip4_address, &sess->ext_host_addr);
2272 s = format (s, " last heard %.2f\n", sess->last_heard);
2273 s = format (s, " total pkts %d, total bytes %lld\n",
2274 sess->total_pkts, sess->total_bytes);
2275 if (snat_is_session_static (sess))
2276 s = format (s, " static translation\n");
2278 s = format (s, " dynamic translation\n");
2279 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2280 s = format (s, " load-balancing\n");
2285 u8 * format_snat_user (u8 * s, va_list * args)
2287 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2288 snat_user_t * u = va_arg (*args, snat_user_t *);
2289 int verbose = va_arg (*args, int);
2290 dlist_elt_t * head, * elt;
2291 u32 elt_index, head_index;
2293 snat_session_t * sess;
2295 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2296 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2301 if (u->nsessions || u->nstaticsessions)
2303 head_index = u->sessions_per_user_list_head_index;
2304 head = pool_elt_at_index (sm->list_pool, head_index);
2306 elt_index = head->next;
2307 elt = pool_elt_at_index (sm->list_pool, elt_index);
2308 session_index = elt->value;
2310 while (session_index != ~0)
2312 sess = pool_elt_at_index (sm->sessions, session_index);
2314 s = format (s, " %U\n", format_snat_session, sm, sess);
2316 elt_index = elt->next;
2317 elt = pool_elt_at_index (sm->list_pool, elt_index);
2318 session_index = elt->value;
2325 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2327 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2328 nat44_lb_addr_port_t *local;
2331 s = format (s, "local %U external %U vrf %d",
2332 format_ip4_address, &m->local_addr,
2333 format_ip4_address, &m->external_addr,
2337 if (vec_len (m->locals))
2339 s = format (s, "%U vrf %d external %U:%d",
2340 format_snat_protocol, m->proto,
2342 format_ip4_address, &m->external_addr, m->external_port);
2343 vec_foreach (local, m->locals)
2344 s = format (s, "\n local %U:%d probability %d\%",
2345 format_ip4_address, &local->addr, local->port,
2346 local->probability);
2349 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2350 format_snat_protocol, m->proto,
2351 format_ip4_address, &m->local_addr, m->local_port,
2352 format_ip4_address, &m->external_addr, m->external_port,
2358 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2360 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2361 vnet_main_t *vnm = vnet_get_main();
2364 s = format (s, "local %U external %U vrf %d",
2365 format_ip4_address, &m->l_addr,
2366 format_vnet_sw_interface_name, vnm,
2367 vnet_get_sw_interface (vnm, m->sw_if_index),
2370 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2371 format_snat_protocol, m->proto,
2372 format_ip4_address, &m->l_addr, m->l_port,
2373 format_vnet_sw_interface_name, vnm,
2374 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2380 u8 * format_det_map_ses (u8 * s, va_list * args)
2382 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2383 ip4_address_t in_addr, out_addr;
2384 u32 in_offset, out_offset;
2385 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2386 u32 * i = va_arg (*args, u32 *);
2388 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2389 in_addr.as_u32 = clib_host_to_net_u32 (
2390 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2391 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2392 clib_net_to_host_u32(det_map->in_addr.as_u32);
2393 out_offset = in_offset / det_map->sharing_ratio;
2394 out_addr.as_u32 = clib_host_to_net_u32(
2395 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2396 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2397 format_ip4_address, &in_addr,
2398 clib_net_to_host_u16 (ses->in_port),
2399 format_ip4_address, &out_addr,
2400 clib_net_to_host_u16 (ses->out.out_port),
2401 format_ip4_address, &ses->out.ext_host_addr,
2402 clib_net_to_host_u16 (ses->out.ext_host_port),
2403 format_snat_session_state, ses->state,
2409 static clib_error_t *
2410 show_snat_command_fn (vlib_main_t * vm,
2411 unformat_input_t * input,
2412 vlib_cli_command_t * cmd)
2415 snat_main_t * sm = &snat_main;
2417 snat_static_mapping_t *m;
2418 snat_interface_t *i;
2419 snat_address_t * ap;
2420 vnet_main_t *vnm = vnet_get_main();
2421 snat_main_per_thread_data_t *tsm;
2422 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2424 snat_static_map_resolve_t *rp;
2425 snat_det_map_t * dm;
2426 snat_det_session_t * ses;
2428 if (unformat (input, "detail"))
2430 else if (unformat (input, "verbose"))
2433 if (sm->static_mapping_only)
2435 if (sm->static_mapping_connection_tracking)
2436 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2439 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2441 else if (sm->deterministic)
2443 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2447 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2452 pool_foreach (i, sm->interfaces,
2454 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2455 vnet_get_sw_interface (vnm, i->sw_if_index),
2456 i->is_inside ? "in" : "out");
2459 pool_foreach (i, sm->output_feature_interfaces,
2461 vlib_cli_output (vm, "%U output-feature %s",
2462 format_vnet_sw_interface_name, vnm,
2463 vnet_get_sw_interface (vnm, i->sw_if_index),
2464 i->is_inside ? "in" : "out");
2467 if (vec_len (sm->auto_add_sw_if_indices))
2469 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2470 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2472 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2473 vnet_get_sw_interface (vnm, *sw_if_index));
2477 vec_foreach (ap, sm->addresses)
2479 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2480 if (ap->fib_index != ~0)
2481 vlib_cli_output (vm, " tenant VRF: %u",
2482 ip4_fib_get(ap->fib_index)->table_id);
2484 vlib_cli_output (vm, " tenant VRF independent");
2485 #define _(N, i, n, s) \
2486 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2487 foreach_snat_protocol
2492 if (sm->num_workers > 1)
2494 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2497 vec_foreach (worker, sm->workers)
2499 vlib_worker_thread_t *w =
2500 vlib_worker_threads + *worker + sm->first_worker_index;
2501 vlib_cli_output (vm, " %s", w->name);
2506 if (sm->deterministic)
2508 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2509 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2510 sm->tcp_established_timeout);
2511 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2512 sm->tcp_transitory_timeout);
2513 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2514 vlib_cli_output (vm, "%d deterministic mappings",
2515 pool_elts (sm->det_maps));
2518 pool_foreach (dm, sm->det_maps,
2520 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2521 format_ip4_address, &dm->in_addr, dm->in_plen,
2522 format_ip4_address, &dm->out_addr, dm->out_plen);
2523 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2525 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2526 dm->ports_per_host);
2527 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2530 vec_foreach_index (j, dm->sessions)
2532 ses = vec_elt_at_index (dm->sessions, j);
2534 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2543 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2545 vlib_cli_output (vm, "%d static mappings",
2546 pool_elts (sm->static_mappings));
2550 pool_foreach (m, sm->static_mappings,
2552 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2558 vec_foreach (tsm, sm->per_thread_data)
2560 users_num += pool_elts (tsm->users);
2561 sessions_num += pool_elts (tsm->sessions);
2564 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2565 " %d static mappings",
2567 vec_len (sm->addresses),
2569 pool_elts (sm->static_mappings));
2573 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
2575 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
2577 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
2579 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
2581 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
2583 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
2585 vec_foreach_index (j, sm->per_thread_data)
2587 tsm = vec_elt_at_index (sm->per_thread_data, j);
2589 if (pool_elts (tsm->users) == 0)
2592 vlib_worker_thread_t *w = vlib_worker_threads + j;
2593 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2595 vlib_cli_output (vm, " %d list pool elements",
2596 pool_elts (tsm->list_pool));
2598 pool_foreach (u, tsm->users,
2600 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
2605 if (pool_elts (sm->static_mappings))
2607 vlib_cli_output (vm, "static mappings:");
2608 pool_foreach (m, sm->static_mappings,
2610 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2612 for (j = 0; j < vec_len (sm->to_resolve); j++)
2614 rp = sm->to_resolve + j;
2615 vlib_cli_output (vm, "%U",
2616 format_snat_static_map_to_resolve, rp);
2625 VLIB_CLI_COMMAND (show_snat_command, static) = {
2626 .path = "show nat44",
2627 .short_help = "show nat44",
2628 .function = show_snat_command_fn,
2633 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2636 ip4_address_t * address,
2638 u32 if_address_index,
2641 snat_main_t *sm = &snat_main;
2642 snat_static_map_resolve_t *rp;
2643 u32 *indices_to_delete = 0;
2647 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2649 if (sw_if_index == sm->auto_add_sw_if_indices[i])
2653 /* Don't trip over lease renewal, static config */
2654 for (j = 0; j < vec_len(sm->addresses); j++)
2655 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2658 snat_add_address (sm, address, ~0);
2659 /* Scan static map resolution vector */
2660 for (j = 0; j < vec_len (sm->to_resolve); j++)
2662 rp = sm->to_resolve + j;
2663 /* On this interface? */
2664 if (rp->sw_if_index == sw_if_index)
2666 /* Add the static mapping */
2667 rv = snat_add_static_mapping (rp->l_addr,
2673 ~0 /* sw_if_index */,
2677 clib_warning ("snat_add_static_mapping returned %d",
2679 vec_add1 (indices_to_delete, j);
2682 /* If we resolved any of the outstanding static mappings */
2683 if (vec_len(indices_to_delete))
2686 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2687 vec_delete(sm->to_resolve, 1, j);
2688 vec_free(indices_to_delete);
2694 (void) snat_del_address(sm, address[0], 1);
2702 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
2704 ip4_main_t * ip4_main = sm->ip4_main;
2705 ip4_address_t * first_int_addr;
2706 snat_static_map_resolve_t *rp;
2707 u32 *indices_to_delete = 0;
2710 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2711 0 /* just want the address*/);
2713 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2715 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2719 /* if have address remove it */
2721 (void) snat_del_address (sm, first_int_addr[0], 1);
2724 for (j = 0; j < vec_len (sm->to_resolve); j++)
2726 rp = sm->to_resolve + j;
2727 if (rp->sw_if_index == sw_if_index)
2728 vec_add1 (indices_to_delete, j);
2730 if (vec_len(indices_to_delete))
2732 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2733 vec_del1(sm->to_resolve, j);
2734 vec_free(indices_to_delete);
2737 vec_del1(sm->auto_add_sw_if_indices, i);
2740 return VNET_API_ERROR_VALUE_EXIST;
2747 return VNET_API_ERROR_NO_SUCH_ENTRY;
2749 /* add to the auto-address list */
2750 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2752 /* If the address is already bound - or static - add it now */
2754 snat_add_address (sm, first_int_addr, ~0);
2759 static clib_error_t *
2760 snat_add_interface_address_command_fn (vlib_main_t * vm,
2761 unformat_input_t * input,
2762 vlib_cli_command_t * cmd)
2764 snat_main_t *sm = &snat_main;
2765 unformat_input_t _line_input, *line_input = &_line_input;
2769 clib_error_t *error = 0;
2771 /* Get a line of input. */
2772 if (!unformat_user (input, unformat_line_input, line_input))
2775 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2777 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2778 sm->vnet_main, &sw_if_index))
2780 else if (unformat (line_input, "del"))
2784 error = clib_error_return (0, "unknown input '%U'",
2785 format_unformat_error, line_input);
2790 rv = snat_add_interface_address (sm, sw_if_index, is_del);
2798 error = clib_error_return (0, "snat_add_interface_address returned %d",
2804 unformat_free (line_input);
2809 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2810 .path = "nat44 add interface address",
2811 .short_help = "nat44 add interface address <interface> [del]",
2812 .function = snat_add_interface_address_command_fn,
2815 static clib_error_t *
2816 snat_det_map_command_fn (vlib_main_t * vm,
2817 unformat_input_t * input,
2818 vlib_cli_command_t * cmd)
2820 snat_main_t *sm = &snat_main;
2821 unformat_input_t _line_input, *line_input = &_line_input;
2822 ip4_address_t in_addr, out_addr;
2823 u32 in_plen, out_plen;
2825 clib_error_t *error = 0;
2827 /* Get a line of input. */
2828 if (!unformat_user (input, unformat_line_input, line_input))
2831 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2833 if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
2835 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
2837 else if (unformat (line_input, "del"))
2841 error = clib_error_return (0, "unknown input '%U'",
2842 format_unformat_error, line_input);
2847 unformat_free (line_input);
2849 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
2854 error = clib_error_return (0, "snat_det_add_map return %d", rv);
2859 unformat_free (line_input);
2866 * @cliexstart{snat deterministic add}
2867 * Create bijective mapping of inside address to outside address and port range
2868 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
2870 * To create deterministic mapping between inside network 10.0.0.0/18 and
2871 * outside network 1.1.1.0/30 use:
2872 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
2875 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
2876 .path = "nat44 deterministic add",
2877 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
2878 .function = snat_det_map_command_fn,
2881 static clib_error_t *
2882 snat_det_forward_command_fn (vlib_main_t * vm,
2883 unformat_input_t * input,
2884 vlib_cli_command_t * cmd)
2886 snat_main_t *sm = &snat_main;
2887 unformat_input_t _line_input, *line_input = &_line_input;
2888 ip4_address_t in_addr, out_addr;
2890 snat_det_map_t * dm;
2891 clib_error_t *error = 0;
2893 /* Get a line of input. */
2894 if (!unformat_user (input, unformat_line_input, line_input))
2897 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2899 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
2903 error = clib_error_return (0, "unknown input '%U'",
2904 format_unformat_error, line_input);
2909 unformat_free (line_input);
2911 dm = snat_det_map_by_user(sm, &in_addr);
2913 vlib_cli_output (vm, "no match");
2916 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
2917 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
2918 lo_port, lo_port + dm->ports_per_host - 1);
2922 unformat_free (line_input);
2929 * @cliexstart{snat deterministic forward}
2930 * Return outside address and port range from inside address for deterministic
2932 * To obtain outside address and port of inside host use:
2933 * vpp# nat44 deterministic forward 10.0.0.2
2934 * 1.1.1.0:<1054-1068>
2937 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
2938 .path = "nat44 deterministic forward",
2939 .short_help = "nat44 deterministic forward <addr>",
2940 .function = snat_det_forward_command_fn,
2943 static clib_error_t *
2944 snat_det_reverse_command_fn (vlib_main_t * vm,
2945 unformat_input_t * input,
2946 vlib_cli_command_t * cmd)
2948 snat_main_t *sm = &snat_main;
2949 unformat_input_t _line_input, *line_input = &_line_input;
2950 ip4_address_t in_addr, out_addr;
2952 snat_det_map_t * dm;
2953 clib_error_t *error = 0;
2955 /* Get a line of input. */
2956 if (!unformat_user (input, unformat_line_input, line_input))
2959 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2961 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
2965 error = clib_error_return (0, "unknown input '%U'",
2966 format_unformat_error, line_input);
2970 unformat_free (line_input);
2972 if (out_port < 1024 || out_port > 65535)
2974 error = clib_error_return (0, "wrong port, must be <1024-65535>");
2978 dm = snat_det_map_by_out(sm, &out_addr);
2980 vlib_cli_output (vm, "no match");
2983 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
2984 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
2988 unformat_free (line_input);
2995 * @cliexstart{snat deterministic reverse}
2996 * Return inside address from outside address and port for deterministic NAT.
2997 * To obtain inside host address from outside address and port use:
2998 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3002 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3003 .path = "nat44 deterministic reverse",
3004 .short_help = "nat44 deterministic reverse <addr>:<port>",
3005 .function = snat_det_reverse_command_fn,
3008 static clib_error_t *
3009 set_timeout_command_fn (vlib_main_t * vm,
3010 unformat_input_t * input,
3011 vlib_cli_command_t * cmd)
3013 snat_main_t *sm = &snat_main;
3014 unformat_input_t _line_input, *line_input = &_line_input;
3015 clib_error_t *error = 0;
3017 /* Get a line of input. */
3018 if (!unformat_user (input, unformat_line_input, line_input))
3021 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3023 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3025 else if (unformat (line_input, "tcp-established %u",
3026 &sm->tcp_established_timeout))
3028 else if (unformat (line_input, "tcp-transitory %u",
3029 &sm->tcp_transitory_timeout))
3031 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3033 else if (unformat (line_input, "reset"))
3035 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3036 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3037 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3038 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3042 error = clib_error_return (0, "unknown input '%U'",
3043 format_unformat_error, line_input);
3048 unformat_free (line_input);
3051 unformat_free (line_input);
3058 * @cliexstart{set snat deterministic timeout}
3059 * Set values of timeouts for deterministic NAT (in seconds), use:
3060 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3061 * tcp-transitory 250 icmp 90
3062 * To reset default values use:
3063 * vpp# set nat44 deterministic timeout reset
3066 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3067 .path = "set nat44 deterministic timeout",
3068 .function = set_timeout_command_fn,
3070 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3071 "tcp-transitory <sec> | icmp <sec> | reset]",
3074 static clib_error_t *
3075 snat_det_close_session_out_fn (vlib_main_t *vm,
3076 unformat_input_t * input,
3077 vlib_cli_command_t * cmd)
3079 snat_main_t *sm = &snat_main;
3080 unformat_input_t _line_input, *line_input = &_line_input;
3081 ip4_address_t out_addr, ext_addr, in_addr;
3082 u16 out_port, ext_port;
3083 snat_det_map_t * dm;
3084 snat_det_session_t * ses;
3085 snat_det_out_key_t key;
3086 clib_error_t *error = 0;
3088 /* Get a line of input. */
3089 if (!unformat_user (input, unformat_line_input, line_input))
3092 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3094 if (unformat (line_input, "%U:%d %U:%d",
3095 unformat_ip4_address, &out_addr, &out_port,
3096 unformat_ip4_address, &ext_addr, &ext_port))
3100 error = clib_error_return (0, "unknown input '%U'",
3101 format_unformat_error, line_input);
3106 unformat_free (line_input);
3108 dm = snat_det_map_by_out(sm, &out_addr);
3110 vlib_cli_output (vm, "no match");
3113 snat_det_reverse(dm, &ext_addr, out_port, &in_addr);
3114 key.ext_host_addr = out_addr;
3115 key.ext_host_port = ntohs(ext_port);
3116 key.out_port = ntohs(out_port);
3117 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3119 vlib_cli_output (vm, "no match");
3121 snat_det_ses_close(dm, ses);
3125 unformat_free (line_input);
3132 * @cliexstart{snat deterministic close session out}
3133 * Close session using outside ip address and port
3134 * and external ip address and port, use:
3135 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3138 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3139 .path = "nat44 deterministic close session out",
3140 .short_help = "nat44 deterministic close session out "
3141 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3142 .function = snat_det_close_session_out_fn,
3145 static clib_error_t *
3146 snat_det_close_session_in_fn (vlib_main_t *vm,
3147 unformat_input_t * input,
3148 vlib_cli_command_t * cmd)
3150 snat_main_t *sm = &snat_main;
3151 unformat_input_t _line_input, *line_input = &_line_input;
3152 ip4_address_t in_addr, ext_addr;
3153 u16 in_port, ext_port;
3154 snat_det_map_t * dm;
3155 snat_det_session_t * ses;
3156 snat_det_out_key_t key;
3157 clib_error_t *error = 0;
3159 /* Get a line of input. */
3160 if (!unformat_user (input, unformat_line_input, line_input))
3163 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3165 if (unformat (line_input, "%U:%d %U:%d",
3166 unformat_ip4_address, &in_addr, &in_port,
3167 unformat_ip4_address, &ext_addr, &ext_port))
3171 error = clib_error_return (0, "unknown input '%U'",
3172 format_unformat_error, line_input);
3177 unformat_free (line_input);
3179 dm = snat_det_map_by_user (sm, &in_addr);
3181 vlib_cli_output (vm, "no match");
3184 key.ext_host_addr = ext_addr;
3185 key.ext_host_port = ntohs (ext_port);
3186 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key);
3188 vlib_cli_output (vm, "no match");
3190 snat_det_ses_close(dm, ses);
3194 unformat_free(line_input);
3201 * @cliexstart{snat deterministic close_session_in}
3202 * Close session using inside ip address and port
3203 * and external ip address and port, use:
3204 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3207 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3208 .path = "nat44 deterministic close session in",
3209 .short_help = "nat44 deterministic close session in "
3210 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3211 .function = snat_det_close_session_in_fn,