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,
171 FIB_SOURCE_PLUGIN_HI);
174 #define _(N, i, n, s) \
175 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535);
176 foreach_snat_protocol
179 /* Add external address to FIB */
180 pool_foreach (i, sm->interfaces,
185 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
188 pool_foreach (i, sm->output_feature_interfaces,
193 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
198 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
201 snat_static_mapping_t *m;
202 pool_foreach (m, sm->static_mappings,
204 if (m->external_addr.as_u32 == addr.as_u32)
211 void increment_v4_address (ip4_address_t * a)
215 v = clib_net_to_host_u32(a->as_u32) + 1;
216 a->as_u32 = clib_host_to_net_u32(v);
220 snat_add_static_mapping_when_resolved (snat_main_t * sm,
221 ip4_address_t l_addr,
226 snat_protocol_t proto,
230 snat_static_map_resolve_t *rp;
232 vec_add2 (sm->to_resolve, rp, 1);
233 rp->l_addr.as_u32 = l_addr.as_u32;
235 rp->sw_if_index = sw_if_index;
239 rp->addr_only = addr_only;
244 * @brief Add static mapping.
246 * Create static mapping between local addr+port and external addr+port.
248 * @param l_addr Local IPv4 address.
249 * @param e_addr External IPv4 address.
250 * @param l_port Local port number.
251 * @param e_port External port number.
252 * @param vrf_id VRF ID.
253 * @param addr_only If 0 address port and pair mapping, otherwise address only.
254 * @param sw_if_index External port instead of specific IP address.
255 * @param is_add If 0 delete static mapping, otherwise add.
259 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
260 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
261 u32 sw_if_index, snat_protocol_t proto, int is_add)
263 snat_main_t * sm = &snat_main;
264 snat_static_mapping_t *m;
265 snat_session_key_t m_key;
266 clib_bihash_kv_8_8_t kv, value;
267 snat_address_t *a = 0;
270 snat_interface_t *interface;
273 /* If the external address is a specific interface address */
274 if (sw_if_index != ~0)
276 ip4_address_t * first_int_addr;
278 /* Might be already set... */
279 first_int_addr = ip4_interface_first_address
280 (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
282 /* DHCP resolution required? */
283 if (first_int_addr == 0)
285 snat_add_static_mapping_when_resolved
286 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
291 e_addr.as_u32 = first_int_addr->as_u32;
295 m_key.port = addr_only ? 0 : e_port;
296 m_key.protocol = addr_only ? 0 : proto;
297 m_key.fib_index = sm->outside_fib_index;
298 kv.key = m_key.as_u64;
299 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
302 m = pool_elt_at_index (sm->static_mappings, value.value);
307 return VNET_API_ERROR_VALUE_EXIST;
309 /* Convert VRF id to FIB index */
312 p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
314 return VNET_API_ERROR_NO_SUCH_FIB;
317 /* If not specified use inside VRF id from SNAT plugin startup config */
320 fib_index = sm->inside_fib_index;
321 vrf_id = sm->inside_vrf_id;
324 /* Find external address in allocated addresses and reserve port for
325 address and port pair mapping when dynamic translations enabled */
326 if (!addr_only && !(sm->static_mapping_only))
328 for (i = 0; i < vec_len (sm->addresses); i++)
330 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
332 a = sm->addresses + i;
333 /* External port must be unused */
336 #define _(N, j, n, s) \
337 case SNAT_PROTOCOL_##N: \
338 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
339 return VNET_API_ERROR_INVALID_VALUE; \
340 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
342 a->busy_##n##_ports++; \
344 foreach_snat_protocol
347 clib_warning("unknown_protocol");
348 return VNET_API_ERROR_INVALID_VALUE_2;
353 /* External address must be allocated */
355 return VNET_API_ERROR_NO_SUCH_ENTRY;
358 pool_get (sm->static_mappings, m);
359 memset (m, 0, sizeof (*m));
360 m->local_addr = l_addr;
361 m->external_addr = e_addr;
362 m->addr_only = addr_only;
364 m->fib_index = fib_index;
367 m->local_port = l_port;
368 m->external_port = e_port;
372 m_key.addr = m->local_addr;
373 m_key.port = m->local_port;
374 m_key.protocol = m->proto;
375 m_key.fib_index = m->fib_index;
376 kv.key = m_key.as_u64;
377 kv.value = m - sm->static_mappings;
378 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
380 m_key.addr = m->external_addr;
381 m_key.port = m->external_port;
382 m_key.fib_index = sm->outside_fib_index;
383 kv.key = m_key.as_u64;
384 kv.value = m - sm->static_mappings;
385 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
390 snat_user_key_t w_key0;
391 snat_worker_key_t w_key1;
393 w_key0.addr = m->local_addr;
394 w_key0.fib_index = m->fib_index;
395 kv.key = w_key0.as_u64;
397 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
399 kv.value = sm->first_worker_index +
400 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
402 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
406 kv.value = value.value;
409 w_key1.addr = m->external_addr;
410 w_key1.port = clib_host_to_net_u16 (m->external_port);
411 w_key1.fib_index = sm->outside_fib_index;
412 kv.key = w_key1.as_u64;
413 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1);
419 return VNET_API_ERROR_NO_SUCH_ENTRY;
421 /* Free external address port */
422 if (!addr_only && !(sm->static_mapping_only))
424 for (i = 0; i < vec_len (sm->addresses); i++)
426 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
428 a = sm->addresses + i;
431 #define _(N, j, n, s) \
432 case SNAT_PROTOCOL_##N: \
433 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
435 a->busy_##n##_ports--; \
437 foreach_snat_protocol
440 clib_warning("unknown_protocol");
441 return VNET_API_ERROR_INVALID_VALUE_2;
448 m_key.addr = m->local_addr;
449 m_key.port = m->local_port;
450 m_key.protocol = m->proto;
451 m_key.fib_index = m->fib_index;
452 kv.key = m_key.as_u64;
453 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
455 m_key.addr = m->external_addr;
456 m_key.port = m->external_port;
457 m_key.fib_index = sm->outside_fib_index;
458 kv.key = m_key.as_u64;
459 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
461 /* Delete session(s) for static mapping if exist */
462 if (!(sm->static_mapping_only) ||
463 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
465 snat_user_key_t u_key;
467 dlist_elt_t * head, * elt;
468 u32 elt_index, head_index, del_elt_index;
472 snat_main_per_thread_data_t *tsm;
474 u_key.addr = m->local_addr;
475 u_key.fib_index = m->fib_index;
476 kv.key = u_key.as_u64;
477 if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
479 user_index = value.value;
480 if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
481 tsm = vec_elt_at_index (sm->per_thread_data, value.value);
483 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
484 u = pool_elt_at_index (tsm->users, user_index);
485 if (u->nstaticsessions)
487 head_index = u->sessions_per_user_list_head_index;
488 head = pool_elt_at_index (tsm->list_pool, head_index);
489 elt_index = head->next;
490 elt = pool_elt_at_index (tsm->list_pool, elt_index);
491 ses_index = elt->value;
492 while (ses_index != ~0)
494 s = pool_elt_at_index (tsm->sessions, ses_index);
495 del_elt_index = elt_index;
496 elt_index = elt->next;
497 elt = pool_elt_at_index (tsm->list_pool, elt_index);
498 ses_index = elt->value;
502 if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
503 (clib_net_to_host_u16 (s->out2in.port) != e_port))
507 if (snat_is_unk_proto_session (s))
509 clib_bihash_kv_16_8_t up_kv;
510 nat_ed_ses_key_t up_key;
511 up_key.l_addr = s->in2out.addr;
512 up_key.r_addr = s->ext_host_addr;
513 up_key.fib_index = s->in2out.fib_index;
514 up_key.proto = s->in2out.port;
517 up_kv.key[0] = up_key.as_u64[0];
518 up_kv.key[1] = up_key.as_u64[1];
519 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
521 clib_warning ("in2out key del failed");
523 up_key.l_addr = s->out2in.addr;
524 up_key.fib_index = s->out2in.fib_index;
525 up_kv.key[0] = up_key.as_u64[0];
526 up_kv.key[1] = up_key.as_u64[1];
527 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
529 clib_warning ("out2in key del failed");
534 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
535 s->out2in.addr.as_u32,
539 s->in2out.fib_index);
541 value.key = s->in2out.as_u64;
542 if (clib_bihash_add_del_8_8 (&sm->in2out, &value, 0))
543 clib_warning ("in2out key del failed");
544 value.key = s->out2in.as_u64;
545 if (clib_bihash_add_del_8_8 (&sm->out2in, &value, 0))
546 clib_warning ("out2in key del failed");
548 pool_put (tsm->sessions, s);
550 clib_dlist_remove (tsm->list_pool, del_elt_index);
551 pool_put_index (tsm->list_pool, del_elt_index);
552 u->nstaticsessions--;
559 pool_put (tsm->users, u);
560 clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
566 /* Delete static mapping from pool */
567 pool_put (sm->static_mappings, m);
573 /* Add/delete external address to FIB */
574 pool_foreach (interface, sm->interfaces,
576 if (interface->is_inside)
579 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
582 pool_foreach (interface, sm->output_feature_interfaces,
584 if (interface->is_inside)
587 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
594 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
595 snat_protocol_t proto, u32 vrf_id,
596 nat44_lb_addr_port_t *locals, u8 is_add)
598 snat_main_t * sm = &snat_main;
599 snat_static_mapping_t *m;
600 snat_session_key_t m_key;
601 clib_bihash_kv_8_8_t kv, value;
603 snat_address_t *a = 0;
605 nat44_lb_addr_port_t *local;
606 snat_user_key_t w_key0;
607 snat_worker_key_t w_key1;
608 u32 worker_index = 0;
612 m_key.protocol = proto;
613 m_key.fib_index = sm->outside_fib_index;
614 kv.key = m_key.as_u64;
615 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
618 m = pool_elt_at_index (sm->static_mappings, value.value);
623 return VNET_API_ERROR_VALUE_EXIST;
625 if (vec_len (locals) < 2)
626 return VNET_API_ERROR_INVALID_VALUE;
628 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
630 FIB_SOURCE_PLUGIN_HI);
632 /* Find external address in allocated addresses and reserve port for
633 address and port pair mapping when dynamic translations enabled */
634 if (!sm->static_mapping_only)
636 for (i = 0; i < vec_len (sm->addresses); i++)
638 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
640 a = sm->addresses + i;
641 /* External port must be unused */
644 #define _(N, j, n, s) \
645 case SNAT_PROTOCOL_##N: \
646 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
647 return VNET_API_ERROR_INVALID_VALUE; \
648 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
650 a->busy_##n##_ports++; \
652 foreach_snat_protocol
655 clib_warning("unknown_protocol");
656 return VNET_API_ERROR_INVALID_VALUE_2;
661 /* External address must be allocated */
663 return VNET_API_ERROR_NO_SUCH_ENTRY;
666 pool_get (sm->static_mappings, m);
667 memset (m, 0, sizeof (*m));
668 m->external_addr = e_addr;
671 m->fib_index = fib_index;
672 m->external_port = e_port;
675 m_key.addr = m->external_addr;
676 m_key.port = m->external_port;
677 m_key.protocol = m->proto;
678 m_key.fib_index = sm->outside_fib_index;
679 kv.key = m_key.as_u64;
680 kv.value = m - sm->static_mappings;
681 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
683 clib_warning ("static_mapping_by_external key add failed");
684 return VNET_API_ERROR_UNSPECIFIED;
686 m_key.port = clib_host_to_net_u16 (m->external_port);
687 kv.key = m_key.as_u64;
689 if (clib_bihash_add_del_8_8(&sm->out2in, &kv, 1))
691 clib_warning ("static_mapping_by_local key add failed");
692 return VNET_API_ERROR_UNSPECIFIED;
695 m_key.fib_index = m->fib_index;
700 w_key0.addr = locals[0].addr;
701 w_key0.fib_index = fib_index;
702 kv.key = w_key0.as_u64;
704 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
705 worker_index = sm->first_worker_index +
706 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
708 worker_index = value.value;
710 w_key1.addr = m->external_addr;
711 w_key1.port = clib_host_to_net_u16 (m->external_port);
712 w_key1.fib_index = sm->outside_fib_index;
713 kv.key = w_key1.as_u64;
714 kv.value = worker_index;
715 if (clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1))
717 clib_warning ("worker-by-out add key failed");
718 return VNET_API_ERROR_UNSPECIFIED;
722 for (i = 0; i < vec_len (locals); i++)
724 m_key.addr = locals[i].addr;
725 m_key.port = locals[i].port;
726 kv.key = m_key.as_u64;
727 kv.value = m - sm->static_mappings;
728 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
729 locals[i].prefix = (i == 0) ? locals[i].probability :\
730 (locals[i - 1].prefix + locals[i].probability);
731 vec_add1 (m->locals, locals[i]);
732 m_key.port = clib_host_to_net_u16 (locals[i].port);
733 kv.key = m_key.as_u64;
735 if (clib_bihash_add_del_8_8(&sm->in2out, &kv, 1))
737 clib_warning ("in2out key add failed");
738 return VNET_API_ERROR_UNSPECIFIED;
743 w_key0.addr = locals[i].addr;
744 w_key0.fib_index = fib_index;
745 kv.key = w_key0.as_u64;
746 kv.value = worker_index;
747 if (clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1))
749 clib_warning ("worker-by-in key add failed");
750 return VNET_API_ERROR_UNSPECIFIED;
758 return VNET_API_ERROR_NO_SUCH_ENTRY;
760 fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
762 /* Free external address port */
763 if (!sm->static_mapping_only)
765 for (i = 0; i < vec_len (sm->addresses); i++)
767 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
769 a = sm->addresses + i;
772 #define _(N, j, n, s) \
773 case SNAT_PROTOCOL_##N: \
774 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
776 a->busy_##n##_ports--; \
778 foreach_snat_protocol
781 clib_warning("unknown_protocol");
782 return VNET_API_ERROR_INVALID_VALUE_2;
789 m_key.addr = m->external_addr;
790 m_key.port = m->external_port;
791 m_key.protocol = m->proto;
792 m_key.fib_index = sm->outside_fib_index;
793 kv.key = m_key.as_u64;
794 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
796 clib_warning ("static_mapping_by_external key del failed");
797 return VNET_API_ERROR_UNSPECIFIED;
799 m_key.port = clib_host_to_net_u16 (m->external_port);
800 kv.key = m_key.as_u64;
801 if (clib_bihash_add_del_8_8(&sm->out2in, &kv, 0))
803 clib_warning ("outi2in key del failed");
804 return VNET_API_ERROR_UNSPECIFIED;
807 vec_foreach (local, m->locals)
809 m_key.addr = local->addr;
810 m_key.port = local->port;
811 m_key.fib_index = m->fib_index;
812 kv.key = m_key.as_u64;
813 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
815 clib_warning ("static_mapping_by_local key del failed");
816 return VNET_API_ERROR_UNSPECIFIED;
818 m_key.port = clib_host_to_net_u16 (local->port);
819 kv.key = m_key.as_u64;
820 if (clib_bihash_add_del_8_8(&sm->in2out, &kv, 0))
822 clib_warning ("in2out key del failed");
823 return VNET_API_ERROR_UNSPECIFIED;
827 pool_put (sm->static_mappings, m);
833 int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
835 snat_address_t *a = 0;
837 u32 *ses_to_be_removed = 0, *ses_index;
838 clib_bihash_kv_8_8_t kv, value;
839 snat_user_key_t user_key;
841 snat_main_per_thread_data_t *tsm;
842 snat_static_mapping_t *m;
843 snat_interface_t *interface;
846 /* Find SNAT address */
847 for (i=0; i < vec_len (sm->addresses); i++)
849 if (sm->addresses[i].addr.as_u32 == addr.as_u32)
851 a = sm->addresses + i;
856 return VNET_API_ERROR_NO_SUCH_ENTRY;
860 pool_foreach (m, sm->static_mappings,
862 if (m->external_addr.as_u32 == addr.as_u32)
863 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
864 m->local_port, m->external_port,
865 m->vrf_id, m->addr_only, ~0,
871 /* Check if address is used in some static mapping */
872 if (is_snat_address_used_in_static_mapping(sm, addr))
874 clib_warning ("address used in static mapping");
875 return VNET_API_ERROR_UNSPECIFIED;
879 if (a->fib_index != ~0)
880 fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
881 FIB_SOURCE_PLUGIN_HI);
883 /* Delete sessions using address */
884 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
886 vec_foreach (tsm, sm->per_thread_data)
888 pool_foreach (ses, tsm->sessions, ({
889 if (ses->out2in.addr.as_u32 == addr.as_u32)
891 if (snat_is_unk_proto_session (ses))
893 clib_bihash_kv_16_8_t up_kv;
894 nat_ed_ses_key_t up_key;
895 up_key.l_addr = ses->in2out.addr;
896 up_key.r_addr = ses->ext_host_addr;
897 up_key.fib_index = ses->in2out.fib_index;
898 up_key.proto = ses->in2out.port;
901 up_kv.key[0] = up_key.as_u64[0];
902 up_kv.key[1] = up_key.as_u64[1];
903 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
905 clib_warning ("in2out key del failed");
907 up_key.l_addr = ses->out2in.addr;
908 up_key.fib_index = ses->out2in.fib_index;
909 up_kv.key[0] = up_key.as_u64[0];
910 up_kv.key[1] = up_key.as_u64[1];
911 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
913 clib_warning ("out2in key del failed");
918 snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
919 ses->out2in.addr.as_u32,
920 ses->in2out.protocol,
923 ses->in2out.fib_index);
924 kv.key = ses->in2out.as_u64;
925 clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
926 kv.key = ses->out2in.as_u64;
927 clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
929 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
930 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
931 user_key.addr = ses->in2out.addr;
932 user_key.fib_index = ses->in2out.fib_index;
933 kv.key = user_key.as_u64;
934 if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
936 u = pool_elt_at_index (tsm->users, value.value);
942 vec_foreach (ses_index, ses_to_be_removed)
943 pool_put_index (tsm->sessions, ses_index[0]);
945 vec_free (ses_to_be_removed);
949 vec_del1 (sm->addresses, i);
951 /* Delete external address from FIB */
952 pool_foreach (interface, sm->interfaces,
954 if (interface->is_inside)
957 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
960 pool_foreach (interface, sm->output_feature_interfaces,
962 if (interface->is_inside)
965 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
972 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
974 snat_main_t *sm = &snat_main;
976 const char * feature_name;
978 snat_static_mapping_t * m;
981 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
982 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
985 if (sm->num_workers > 1 && !sm->deterministic)
986 feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
987 else if (sm->deterministic)
988 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
990 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
993 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
996 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
997 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
999 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1000 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1002 pool_foreach (i, sm->interfaces,
1004 if (i->sw_if_index == sw_if_index)
1007 pool_put (sm->interfaces, i);
1009 return VNET_API_ERROR_VALUE_EXIST;
1016 return VNET_API_ERROR_NO_SUCH_ENTRY;
1018 pool_get (sm->interfaces, i);
1019 i->sw_if_index = sw_if_index;
1020 i->is_inside = is_inside;
1022 /* Add/delete external addresses to FIB */
1027 vec_foreach (ap, sm->addresses)
1028 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1030 pool_foreach (m, sm->static_mappings,
1032 if (!(m->addr_only))
1035 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1038 pool_foreach (dm, sm->det_maps,
1040 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1046 int snat_interface_add_del_output_feature (u32 sw_if_index,
1050 snat_main_t *sm = &snat_main;
1051 snat_interface_t *i;
1052 snat_address_t * ap;
1053 snat_static_mapping_t * m;
1055 if (sm->deterministic ||
1056 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1057 return VNET_API_ERROR_UNSUPPORTED;
1061 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1062 sw_if_index, !is_del, 0, 0);
1063 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1064 sw_if_index, !is_del, 0, 0);
1068 if (sm->num_workers > 1)
1070 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1071 sw_if_index, !is_del, 0, 0);
1072 vnet_feature_enable_disable ("ip4-output",
1073 "nat44-in2out-output-worker-handoff",
1074 sw_if_index, !is_del, 0, 0);
1078 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1080 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1081 sw_if_index, !is_del, 0, 0);
1085 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1086 sm->fq_in2out_output_index =
1087 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1089 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1090 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1092 pool_foreach (i, sm->output_feature_interfaces,
1094 if (i->sw_if_index == sw_if_index)
1097 pool_put (sm->output_feature_interfaces, i);
1099 return VNET_API_ERROR_VALUE_EXIST;
1106 return VNET_API_ERROR_NO_SUCH_ENTRY;
1108 pool_get (sm->output_feature_interfaces, i);
1109 i->sw_if_index = sw_if_index;
1110 i->is_inside = is_inside;
1112 /* Add/delete external addresses to FIB */
1117 vec_foreach (ap, sm->addresses)
1118 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1120 pool_foreach (m, sm->static_mappings,
1122 if (!(m->addr_only))
1125 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1131 int snat_set_workers (uword * bitmap)
1133 snat_main_t *sm = &snat_main;
1136 if (sm->num_workers < 2)
1137 return VNET_API_ERROR_FEATURE_DISABLED;
1139 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1140 return VNET_API_ERROR_INVALID_WORKER;
1142 vec_free (sm->workers);
1143 clib_bitmap_foreach (i, bitmap,
1145 vec_add1(sm->workers, i);
1146 sm->per_thread_data[i].snat_thread_index = j;
1150 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1151 sm->num_snat_thread = _vec_len (sm->workers);
1158 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1161 ip4_address_t * address,
1163 u32 if_address_index,
1166 static clib_error_t * snat_init (vlib_main_t * vm)
1168 snat_main_t * sm = &snat_main;
1169 clib_error_t * error = 0;
1170 ip4_main_t * im = &ip4_main;
1171 ip_lookup_main_t * lm = &im->lookup_main;
1173 vlib_thread_registration_t *tr;
1174 vlib_thread_main_t *tm = vlib_get_thread_main ();
1177 ip4_add_del_interface_address_callback_t cb4;
1180 sm->vnet_main = vnet_get_main();
1182 sm->ip4_lookup_main = lm;
1183 sm->api_main = &api_main;
1184 sm->first_worker_index = 0;
1185 sm->next_worker = 0;
1186 sm->num_workers = 0;
1187 sm->num_snat_thread = 1;
1189 sm->port_per_thread = 0xffff - 1024;
1190 sm->fq_in2out_index = ~0;
1191 sm->fq_out2in_index = ~0;
1192 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1193 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1194 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1195 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1197 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1200 tr = (vlib_thread_registration_t *) p[0];
1203 sm->num_workers = tr->count;
1204 sm->first_worker_index = tr->first_index;
1208 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1210 /* Use all available workers by default */
1211 if (sm->num_workers > 1)
1213 for (i=0; i < sm->num_workers; i++)
1214 bitmap = clib_bitmap_set (bitmap, i, 1);
1215 snat_set_workers(bitmap);
1216 clib_bitmap_free (bitmap);
1220 sm->per_thread_data[0].snat_thread_index = 0;
1223 error = snat_api_init(vm, sm);
1227 /* Set up the interface address add/del callback */
1228 cb4.function = snat_ip4_add_del_interface_address_cb;
1229 cb4.function_opaque = 0;
1231 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1233 /* Init IPFIX logging */
1234 snat_ipfix_logging_init(vm);
1236 error = nat64_init(vm);
1241 VLIB_INIT_FUNCTION (snat_init);
1243 void snat_free_outside_address_and_port (snat_main_t * sm,
1244 snat_session_key_t * k,
1248 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1250 ASSERT (address_index < vec_len (sm->addresses));
1252 a = sm->addresses + address_index;
1254 switch (k->protocol)
1256 #define _(N, i, n, s) \
1257 case SNAT_PROTOCOL_##N: \
1258 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1259 port_host_byte_order) == 1); \
1260 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1261 port_host_byte_order, 0); \
1262 a->busy_##n##_ports--; \
1264 foreach_snat_protocol
1267 clib_warning("unknown_protocol");
1273 * @brief Match NAT44 static mapping.
1275 * @param sm NAT main.
1276 * @param match Address and port to match.
1277 * @param mapping External or local address and port of the matched mapping.
1278 * @param by_external If 0 match by local address otherwise match by external
1280 * @param is_addr_only If matched mapping is address only
1282 * @returns 0 if match found otherwise 1.
1284 int snat_static_mapping_match (snat_main_t * sm,
1285 snat_session_key_t match,
1286 snat_session_key_t * mapping,
1290 clib_bihash_kv_8_8_t kv, value;
1291 snat_static_mapping_t *m;
1292 snat_session_key_t m_key;
1293 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1294 u32 rand, lo = 0, hi, mid;
1297 mapping_hash = &sm->static_mapping_by_external;
1299 m_key.addr = match.addr;
1300 m_key.port = clib_net_to_host_u16 (match.port);
1301 m_key.protocol = match.protocol;
1302 m_key.fib_index = match.fib_index;
1304 kv.key = m_key.as_u64;
1306 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1308 /* Try address only mapping */
1311 kv.key = m_key.as_u64;
1312 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1316 m = pool_elt_at_index (sm->static_mappings, value.value);
1320 if (vec_len (m->locals))
1322 hi = vec_len (m->locals) - 1;
1323 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1326 mid = ((hi - lo) >> 1) + lo;
1327 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1329 if (!(m->locals[lo].prefix >= rand))
1331 mapping->addr = m->locals[lo].addr;
1332 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1336 mapping->addr = m->local_addr;
1337 /* Address only mapping doesn't change port */
1338 mapping->port = m->addr_only ? match.port
1339 : clib_host_to_net_u16 (m->local_port);
1341 mapping->fib_index = m->fib_index;
1342 mapping->protocol = m->proto;
1346 mapping->addr = m->external_addr;
1347 /* Address only mapping doesn't change port */
1348 mapping->port = m->addr_only ? match.port
1349 : clib_host_to_net_u16 (m->external_port);
1350 mapping->fib_index = sm->outside_fib_index;
1353 if (PREDICT_FALSE(is_addr_only != 0))
1354 *is_addr_only = m->addr_only;
1359 static_always_inline u16
1360 snat_random_port (snat_main_t * sm, u16 min, u16 max)
1362 return min + random_u32 (&sm->random_seed) /
1363 (random_u32_max() / (max - min + 1) + 1);
1366 int snat_alloc_outside_address_and_port (snat_main_t * sm,
1369 snat_session_key_t * k,
1370 u32 * address_indexp)
1376 for (i = 0; i < vec_len (sm->addresses); i++)
1378 a = sm->addresses + i;
1379 if (sm->vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
1381 switch (k->protocol)
1383 #define _(N, j, n, s) \
1384 case SNAT_PROTOCOL_##N: \
1385 if (a->busy_##n##_ports < (sm->port_per_thread * sm->num_snat_thread)) \
1389 portnum = (sm->port_per_thread * \
1390 sm->per_thread_data[thread_index].snat_thread_index) + \
1391 snat_random_port(sm, 0, sm->port_per_thread) + 1024; \
1392 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1394 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1395 a->busy_##n##_ports++; \
1396 k->addr = a->addr; \
1397 k->port = clib_host_to_net_u16(portnum); \
1398 *address_indexp = i; \
1403 foreach_snat_protocol
1406 clib_warning("unknown protocol");
1411 /* Totally out of translations to use... */
1412 snat_ipfix_logging_addresses_exhausted(0);
1417 static clib_error_t *
1418 add_address_command_fn (vlib_main_t * vm,
1419 unformat_input_t * input,
1420 vlib_cli_command_t * cmd)
1422 unformat_input_t _line_input, *line_input = &_line_input;
1423 snat_main_t * sm = &snat_main;
1424 ip4_address_t start_addr, end_addr, this_addr;
1425 u32 start_host_order, end_host_order;
1430 clib_error_t *error = 0;
1432 /* Get a line of input. */
1433 if (!unformat_user (input, unformat_line_input, line_input))
1436 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1438 if (unformat (line_input, "%U - %U",
1439 unformat_ip4_address, &start_addr,
1440 unformat_ip4_address, &end_addr))
1442 else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
1444 else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1445 end_addr = start_addr;
1446 else if (unformat (line_input, "del"))
1450 error = clib_error_return (0, "unknown input '%U'",
1451 format_unformat_error, line_input);
1456 if (sm->static_mapping_only)
1458 error = clib_error_return (0, "static mapping only mode");
1462 start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1463 end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1465 if (end_host_order < start_host_order)
1467 error = clib_error_return (0, "end address less than start address");
1471 count = (end_host_order - start_host_order) + 1;
1474 clib_warning ("%U - %U, %d addresses...",
1475 format_ip4_address, &start_addr,
1476 format_ip4_address, &end_addr,
1479 this_addr = start_addr;
1481 for (i = 0; i < count; i++)
1484 snat_add_address (sm, &this_addr, vrf_id);
1486 rv = snat_del_address (sm, this_addr, 0);
1490 case VNET_API_ERROR_NO_SUCH_ENTRY:
1491 error = clib_error_return (0, "S-NAT address not exist.");
1493 case VNET_API_ERROR_UNSPECIFIED:
1494 error = clib_error_return (0, "S-NAT address used in static mapping.");
1500 increment_v4_address (&this_addr);
1504 unformat_free (line_input);
1509 VLIB_CLI_COMMAND (add_address_command, static) = {
1510 .path = "nat44 add address",
1511 .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1512 "[tenant-vrf <vrf-id>] [del]",
1513 .function = add_address_command_fn,
1516 static clib_error_t *
1517 snat_feature_command_fn (vlib_main_t * vm,
1518 unformat_input_t * input,
1519 vlib_cli_command_t * cmd)
1521 unformat_input_t _line_input, *line_input = &_line_input;
1522 vnet_main_t * vnm = vnet_get_main();
1523 clib_error_t * error = 0;
1525 u32 * inside_sw_if_indices = 0;
1526 u32 * outside_sw_if_indices = 0;
1527 u8 is_output_feature = 0;
1533 /* Get a line of input. */
1534 if (!unformat_user (input, unformat_line_input, line_input))
1537 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1539 if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1541 vec_add1 (inside_sw_if_indices, sw_if_index);
1542 else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1544 vec_add1 (outside_sw_if_indices, sw_if_index);
1545 else if (unformat (line_input, "output-feature"))
1546 is_output_feature = 1;
1547 else if (unformat (line_input, "del"))
1551 error = clib_error_return (0, "unknown input '%U'",
1552 format_unformat_error, line_input);
1557 if (vec_len (inside_sw_if_indices))
1559 for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1561 sw_if_index = inside_sw_if_indices[i];
1562 if (is_output_feature)
1564 if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
1566 error = clib_error_return (0, "%s %U failed",
1567 is_del ? "del" : "add",
1568 format_vnet_sw_interface_name, vnm,
1569 vnet_get_sw_interface (vnm,
1576 if (snat_interface_add_del (sw_if_index, 1, is_del))
1578 error = clib_error_return (0, "%s %U failed",
1579 is_del ? "del" : "add",
1580 format_vnet_sw_interface_name, vnm,
1581 vnet_get_sw_interface (vnm,
1589 if (vec_len (outside_sw_if_indices))
1591 for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1593 sw_if_index = outside_sw_if_indices[i];
1594 if (is_output_feature)
1596 if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
1598 error = clib_error_return (0, "%s %U failed",
1599 is_del ? "del" : "add",
1600 format_vnet_sw_interface_name, vnm,
1601 vnet_get_sw_interface (vnm,
1608 if (snat_interface_add_del (sw_if_index, 0, is_del))
1610 error = clib_error_return (0, "%s %U failed",
1611 is_del ? "del" : "add",
1612 format_vnet_sw_interface_name, vnm,
1613 vnet_get_sw_interface (vnm,
1622 unformat_free (line_input);
1623 vec_free (inside_sw_if_indices);
1624 vec_free (outside_sw_if_indices);
1629 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1630 .path = "set interface nat44",
1631 .function = snat_feature_command_fn,
1632 .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1637 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1639 u32 *r = va_arg (*args, u32 *);
1642 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1643 foreach_snat_protocol
1651 format_snat_protocol (u8 * s, va_list * args)
1653 u32 i = va_arg (*args, u32);
1658 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1659 foreach_snat_protocol
1662 s = format (s, "unknown");
1665 s = format (s, "%s", t);
1669 static clib_error_t *
1670 add_static_mapping_command_fn (vlib_main_t * vm,
1671 unformat_input_t * input,
1672 vlib_cli_command_t * cmd)
1674 unformat_input_t _line_input, *line_input = &_line_input;
1675 clib_error_t * error = 0;
1676 ip4_address_t l_addr, e_addr;
1677 u32 l_port = 0, e_port = 0, vrf_id = ~0;
1680 u32 sw_if_index = ~0;
1681 vnet_main_t * vnm = vnet_get_main();
1683 snat_protocol_t proto;
1686 /* Get a line of input. */
1687 if (!unformat_user (input, unformat_line_input, line_input))
1690 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1692 if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1695 else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1697 else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1700 else if (unformat (line_input, "external %U", unformat_ip4_address,
1703 else if (unformat (line_input, "external %U %u",
1704 unformat_vnet_sw_interface, vnm, &sw_if_index,
1708 else if (unformat (line_input, "external %U",
1709 unformat_vnet_sw_interface, vnm, &sw_if_index))
1711 else if (unformat (line_input, "vrf %u", &vrf_id))
1713 else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1715 else if (unformat (line_input, "del"))
1719 error = clib_error_return (0, "unknown input: '%U'",
1720 format_unformat_error, line_input);
1725 if (!addr_only && !proto_set)
1727 error = clib_error_return (0, "missing protocol");
1731 rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1732 vrf_id, addr_only, sw_if_index, proto, is_add);
1736 case VNET_API_ERROR_INVALID_VALUE:
1737 error = clib_error_return (0, "External port already in use.");
1739 case VNET_API_ERROR_NO_SUCH_ENTRY:
1741 error = clib_error_return (0, "External addres must be allocated.");
1743 error = clib_error_return (0, "Mapping not exist.");
1745 case VNET_API_ERROR_NO_SUCH_FIB:
1746 error = clib_error_return (0, "No such VRF id.");
1748 case VNET_API_ERROR_VALUE_EXIST:
1749 error = clib_error_return (0, "Mapping already exist.");
1756 unformat_free (line_input);
1763 * @cliexstart{snat add static mapping}
1764 * Static mapping allows hosts on the external network to initiate connection
1765 * to to the local network host.
1766 * To create static mapping between local host address 10.0.0.3 port 6303 and
1767 * external address 4.4.4.4 port 3606 for TCP protocol use:
1768 * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1769 * If not runnig "static mapping only" NAT plugin mode use before:
1770 * vpp# nat44 add address 4.4.4.4
1771 * To create static mapping between local and external address use:
1772 * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1775 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1776 .path = "nat44 add static mapping",
1777 .function = add_static_mapping_command_fn,
1779 "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1782 static clib_error_t *
1783 add_lb_static_mapping_command_fn (vlib_main_t * vm,
1784 unformat_input_t * input,
1785 vlib_cli_command_t * cmd)
1787 unformat_input_t _line_input, *line_input = &_line_input;
1788 clib_error_t * error = 0;
1789 ip4_address_t l_addr, e_addr;
1790 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1793 snat_protocol_t proto;
1795 nat44_lb_addr_port_t *locals = 0, local;
1797 /* Get a line of input. */
1798 if (!unformat_user (input, unformat_line_input, line_input))
1801 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1803 if (unformat (line_input, "local %U:%u probability %u",
1804 unformat_ip4_address, &l_addr, &l_port, &probability))
1806 memset (&local, 0, sizeof (local));
1807 local.addr = l_addr;
1808 local.port = (u16) l_port;
1809 local.probability = (u8) probability;
1810 vec_add1 (locals, local);
1812 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1815 else if (unformat (line_input, "vrf %u", &vrf_id))
1817 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
1820 else if (unformat (line_input, "del"))
1824 error = clib_error_return (0, "unknown input: '%U'",
1825 format_unformat_error, line_input);
1830 if (vec_len (locals) < 2)
1832 error = clib_error_return (0, "at least two local must be set");
1838 error = clib_error_return (0, "missing protocol");
1842 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
1847 case VNET_API_ERROR_INVALID_VALUE:
1848 error = clib_error_return (0, "External port already in use.");
1850 case VNET_API_ERROR_NO_SUCH_ENTRY:
1852 error = clib_error_return (0, "External addres must be allocated.");
1854 error = clib_error_return (0, "Mapping not exist.");
1856 case VNET_API_ERROR_VALUE_EXIST:
1857 error = clib_error_return (0, "Mapping already exist.");
1864 unformat_free (line_input);
1870 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1871 .path = "nat44 add load-balancing static mapping",
1872 .function = add_lb_static_mapping_command_fn,
1874 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
1877 static clib_error_t *
1878 set_workers_command_fn (vlib_main_t * vm,
1879 unformat_input_t * input,
1880 vlib_cli_command_t * cmd)
1882 unformat_input_t _line_input, *line_input = &_line_input;
1885 clib_error_t *error = 0;
1887 /* Get a line of input. */
1888 if (!unformat_user (input, unformat_line_input, line_input))
1891 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1893 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1897 error = clib_error_return (0, "unknown input '%U'",
1898 format_unformat_error, line_input);
1905 error = clib_error_return (0, "List of workers must be specified.");
1909 rv = snat_set_workers(bitmap);
1911 clib_bitmap_free (bitmap);
1915 case VNET_API_ERROR_INVALID_WORKER:
1916 error = clib_error_return (0, "Invalid worker(s).");
1918 case VNET_API_ERROR_FEATURE_DISABLED:
1919 error = clib_error_return (0,
1920 "Supported only if 2 or more workes available.");
1927 unformat_free (line_input);
1934 * @cliexstart{set snat workers}
1935 * Set NAT workers if 2 or more workers available, use:
1936 * vpp# set snat workers 0-2,5
1939 VLIB_CLI_COMMAND (set_workers_command, static) = {
1940 .path = "set nat workers",
1941 .function = set_workers_command_fn,
1943 "set nat workers <workers-list>",
1946 static clib_error_t *
1947 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
1948 unformat_input_t * input,
1949 vlib_cli_command_t * cmd)
1951 unformat_input_t _line_input, *line_input = &_line_input;
1956 clib_error_t *error = 0;
1958 /* Get a line of input. */
1959 if (!unformat_user (input, unformat_line_input, line_input))
1962 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1964 if (unformat (line_input, "domain %d", &domain_id))
1966 else if (unformat (line_input, "src-port %d", &src_port))
1968 else if (unformat (line_input, "disable"))
1972 error = clib_error_return (0, "unknown input '%U'",
1973 format_unformat_error, line_input);
1978 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
1982 error = clib_error_return (0, "ipfix logging enable failed");
1987 unformat_free (line_input);
1994 * @cliexstart{snat ipfix logging}
1995 * To enable NAT IPFIX logging use:
1996 * vpp# nat ipfix logging
1997 * To set IPFIX exporter use:
1998 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2001 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2002 .path = "nat ipfix logging",
2003 .function = snat_ipfix_logging_enable_disable_command_fn,
2004 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2008 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2010 snat_main_t *sm = &snat_main;
2011 snat_user_key_t key0;
2012 clib_bihash_kv_8_8_t kv0, value0;
2013 u32 next_worker_index = 0;
2015 key0.addr = ip0->src_address;
2016 key0.fib_index = rx_fib_index0;
2018 kv0.key = key0.as_u64;
2020 /* Ever heard of of the "user" before? */
2021 if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv0, &value0))
2023 /* No, assign next available worker (RR) */
2024 next_worker_index = sm->first_worker_index;
2025 if (vec_len (sm->workers))
2027 next_worker_index +=
2028 sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
2031 /* add non-traslated packets worker lookup */
2032 kv0.value = next_worker_index;
2033 clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1);
2036 next_worker_index = value0.value;
2038 return next_worker_index;
2042 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2044 snat_main_t *sm = &snat_main;
2045 snat_worker_key_t key0;
2046 clib_bihash_kv_8_8_t kv0, value0;
2047 udp_header_t * udp0;
2048 u32 next_worker_index = 0;
2050 udp0 = ip4_next_header (ip0);
2052 key0.addr = ip0->dst_address;
2053 key0.port = udp0->dst_port;
2054 key0.fib_index = rx_fib_index0;
2056 if (PREDICT_FALSE(ip0->protocol == IP_PROTOCOL_ICMP))
2058 icmp46_header_t * icmp0 = (icmp46_header_t *) udp0;
2059 icmp_echo_header_t *echo0 = (icmp_echo_header_t *)(icmp0+1);
2060 key0.port = echo0->identifier;
2063 kv0.key = key0.as_u64;
2065 /* Ever heard of of the "user" before? */
2066 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
2069 kv0.key = key0.as_u64;
2071 if (clib_bihash_search_8_8 (&sm->worker_by_out, &kv0, &value0))
2073 /* No, assign next available worker (RR) */
2074 next_worker_index = sm->first_worker_index;
2075 if (vec_len (sm->workers))
2077 next_worker_index +=
2078 sm->workers[sm->next_worker++ % _vec_len (sm->workers)];
2083 /* Static mapping without port */
2084 next_worker_index = value0.value;
2087 /* Add to translated packets worker lookup */
2088 key0.port = udp0->dst_port;
2089 kv0.key = key0.as_u64;
2090 kv0.value = next_worker_index;
2091 clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1);
2094 next_worker_index = value0.value;
2096 return next_worker_index;
2099 static clib_error_t *
2100 snat_config (vlib_main_t * vm, unformat_input_t * input)
2102 snat_main_t * sm = &snat_main;
2103 u32 translation_buckets = 1024;
2104 u32 translation_memory_size = 128<<20;
2105 u32 user_buckets = 128;
2106 u32 user_memory_size = 64<<20;
2107 u32 max_translations_per_user = 100;
2108 u32 outside_vrf_id = 0;
2109 u32 inside_vrf_id = 0;
2110 u32 static_mapping_buckets = 1024;
2111 u32 static_mapping_memory_size = 64<<20;
2112 u8 static_mapping_only = 0;
2113 u8 static_mapping_connection_tracking = 0;
2115 sm->deterministic = 0;
2117 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2119 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2121 else if (unformat (input, "translation hash memory %d",
2122 &translation_memory_size));
2123 else if (unformat (input, "user hash buckets %d", &user_buckets))
2125 else if (unformat (input, "user hash memory %d",
2128 else if (unformat (input, "max translations per user %d",
2129 &max_translations_per_user))
2131 else if (unformat (input, "outside VRF id %d",
2134 else if (unformat (input, "inside VRF id %d",
2137 else if (unformat (input, "static mapping only"))
2139 static_mapping_only = 1;
2140 if (unformat (input, "connection tracking"))
2141 static_mapping_connection_tracking = 1;
2143 else if (unformat (input, "deterministic"))
2144 sm->deterministic = 1;
2146 return clib_error_return (0, "unknown input '%U'",
2147 format_unformat_error, input);
2150 /* for show commands, etc. */
2151 sm->translation_buckets = translation_buckets;
2152 sm->translation_memory_size = translation_memory_size;
2153 sm->user_buckets = user_buckets;
2154 sm->user_memory_size = user_memory_size;
2155 sm->max_translations_per_user = max_translations_per_user;
2156 sm->outside_vrf_id = outside_vrf_id;
2157 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2159 FIB_SOURCE_PLUGIN_HI);
2160 sm->inside_vrf_id = inside_vrf_id;
2161 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2163 FIB_SOURCE_PLUGIN_HI);
2164 sm->static_mapping_only = static_mapping_only;
2165 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2167 if (sm->deterministic)
2169 sm->in2out_node_index = snat_det_in2out_node.index;
2170 sm->in2out_output_node_index = ~0;
2171 sm->out2in_node_index = snat_det_out2in_node.index;
2172 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2173 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2177 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2178 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2179 sm->in2out_node_index = snat_in2out_node.index;
2180 sm->in2out_output_node_index = snat_in2out_output_node.index;
2181 sm->out2in_node_index = snat_out2in_node.index;
2182 if (!static_mapping_only ||
2183 (static_mapping_only && static_mapping_connection_tracking))
2185 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2186 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2188 clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
2191 clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
2194 clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
2195 translation_memory_size);
2197 clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
2198 translation_memory_size);
2200 clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
2203 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2204 translation_buckets, translation_memory_size);
2206 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2207 translation_buckets, translation_memory_size);
2211 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2212 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2214 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2215 "static_mapping_by_local", static_mapping_buckets,
2216 static_mapping_memory_size);
2218 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2219 "static_mapping_by_external", static_mapping_buckets,
2220 static_mapping_memory_size);
2226 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2228 u8 * format_snat_session_state (u8 * s, va_list * args)
2230 u32 i = va_arg (*args, u32);
2235 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2236 foreach_snat_session_state
2239 t = format (t, "unknown");
2241 s = format (s, "%s", t);
2245 u8 * format_snat_key (u8 * s, va_list * args)
2247 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2249 s = format (s, "%U proto %U port %d fib %d",
2250 format_ip4_address, &key->addr,
2251 format_snat_protocol, key->protocol,
2252 clib_net_to_host_u16 (key->port), key->fib_index);
2256 u8 * format_snat_session (u8 * s, va_list * args)
2258 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2259 snat_session_t * sess = va_arg (*args, snat_session_t *);
2261 if (snat_is_unk_proto_session (sess))
2263 s = format (s, " i2o %U proto %u fib %u\n",
2264 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2265 sess->in2out.fib_index);
2266 s = format (s, " o2i %U proto %u fib %u\n",
2267 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2268 sess->out2in.fib_index);
2272 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2273 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2275 if (sess->ext_host_addr.as_u32)
2276 s = format (s, " external host %U\n",
2277 format_ip4_address, &sess->ext_host_addr);
2278 s = format (s, " last heard %.2f\n", sess->last_heard);
2279 s = format (s, " total pkts %d, total bytes %lld\n",
2280 sess->total_pkts, sess->total_bytes);
2281 if (snat_is_session_static (sess))
2282 s = format (s, " static translation\n");
2284 s = format (s, " dynamic translation\n");
2285 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2286 s = format (s, " load-balancing\n");
2291 u8 * format_snat_user (u8 * s, va_list * args)
2293 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2294 snat_user_t * u = va_arg (*args, snat_user_t *);
2295 int verbose = va_arg (*args, int);
2296 dlist_elt_t * head, * elt;
2297 u32 elt_index, head_index;
2299 snat_session_t * sess;
2301 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2302 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2307 if (u->nsessions || u->nstaticsessions)
2309 head_index = u->sessions_per_user_list_head_index;
2310 head = pool_elt_at_index (sm->list_pool, head_index);
2312 elt_index = head->next;
2313 elt = pool_elt_at_index (sm->list_pool, elt_index);
2314 session_index = elt->value;
2316 while (session_index != ~0)
2318 sess = pool_elt_at_index (sm->sessions, session_index);
2320 s = format (s, " %U\n", format_snat_session, sm, sess);
2322 elt_index = elt->next;
2323 elt = pool_elt_at_index (sm->list_pool, elt_index);
2324 session_index = elt->value;
2331 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2333 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2334 nat44_lb_addr_port_t *local;
2337 s = format (s, "local %U external %U vrf %d",
2338 format_ip4_address, &m->local_addr,
2339 format_ip4_address, &m->external_addr,
2343 if (vec_len (m->locals))
2345 s = format (s, "%U vrf %d external %U:%d",
2346 format_snat_protocol, m->proto,
2348 format_ip4_address, &m->external_addr, m->external_port);
2349 vec_foreach (local, m->locals)
2350 s = format (s, "\n local %U:%d probability %d\%",
2351 format_ip4_address, &local->addr, local->port,
2352 local->probability);
2355 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2356 format_snat_protocol, m->proto,
2357 format_ip4_address, &m->local_addr, m->local_port,
2358 format_ip4_address, &m->external_addr, m->external_port,
2364 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2366 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2367 vnet_main_t *vnm = vnet_get_main();
2370 s = format (s, "local %U external %U vrf %d",
2371 format_ip4_address, &m->l_addr,
2372 format_vnet_sw_interface_name, vnm,
2373 vnet_get_sw_interface (vnm, m->sw_if_index),
2376 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2377 format_snat_protocol, m->proto,
2378 format_ip4_address, &m->l_addr, m->l_port,
2379 format_vnet_sw_interface_name, vnm,
2380 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2386 u8 * format_det_map_ses (u8 * s, va_list * args)
2388 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2389 ip4_address_t in_addr, out_addr;
2390 u32 in_offset, out_offset;
2391 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2392 u32 * i = va_arg (*args, u32 *);
2394 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2395 in_addr.as_u32 = clib_host_to_net_u32 (
2396 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2397 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2398 clib_net_to_host_u32(det_map->in_addr.as_u32);
2399 out_offset = in_offset / det_map->sharing_ratio;
2400 out_addr.as_u32 = clib_host_to_net_u32(
2401 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2402 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2403 format_ip4_address, &in_addr,
2404 clib_net_to_host_u16 (ses->in_port),
2405 format_ip4_address, &out_addr,
2406 clib_net_to_host_u16 (ses->out.out_port),
2407 format_ip4_address, &ses->out.ext_host_addr,
2408 clib_net_to_host_u16 (ses->out.ext_host_port),
2409 format_snat_session_state, ses->state,
2415 static clib_error_t *
2416 show_snat_command_fn (vlib_main_t * vm,
2417 unformat_input_t * input,
2418 vlib_cli_command_t * cmd)
2421 snat_main_t * sm = &snat_main;
2423 snat_static_mapping_t *m;
2424 snat_interface_t *i;
2425 snat_address_t * ap;
2426 vnet_main_t *vnm = vnet_get_main();
2427 snat_main_per_thread_data_t *tsm;
2428 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2430 snat_static_map_resolve_t *rp;
2431 snat_det_map_t * dm;
2432 snat_det_session_t * ses;
2434 if (unformat (input, "detail"))
2436 else if (unformat (input, "verbose"))
2439 if (sm->static_mapping_only)
2441 if (sm->static_mapping_connection_tracking)
2442 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2445 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2447 else if (sm->deterministic)
2449 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2453 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2458 pool_foreach (i, sm->interfaces,
2460 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2461 vnet_get_sw_interface (vnm, i->sw_if_index),
2462 i->is_inside ? "in" : "out");
2465 pool_foreach (i, sm->output_feature_interfaces,
2467 vlib_cli_output (vm, "%U output-feature %s",
2468 format_vnet_sw_interface_name, vnm,
2469 vnet_get_sw_interface (vnm, i->sw_if_index),
2470 i->is_inside ? "in" : "out");
2473 if (vec_len (sm->auto_add_sw_if_indices))
2475 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2476 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2478 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2479 vnet_get_sw_interface (vnm, *sw_if_index));
2483 vec_foreach (ap, sm->addresses)
2485 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2486 if (ap->fib_index != ~0)
2487 vlib_cli_output (vm, " tenant VRF: %u",
2488 ip4_fib_get(ap->fib_index)->table_id);
2490 vlib_cli_output (vm, " tenant VRF independent");
2491 #define _(N, i, n, s) \
2492 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2493 foreach_snat_protocol
2498 if (sm->num_workers > 1)
2500 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2503 vec_foreach (worker, sm->workers)
2505 vlib_worker_thread_t *w =
2506 vlib_worker_threads + *worker + sm->first_worker_index;
2507 vlib_cli_output (vm, " %s", w->name);
2512 if (sm->deterministic)
2514 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2515 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2516 sm->tcp_established_timeout);
2517 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2518 sm->tcp_transitory_timeout);
2519 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2520 vlib_cli_output (vm, "%d deterministic mappings",
2521 pool_elts (sm->det_maps));
2524 pool_foreach (dm, sm->det_maps,
2526 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2527 format_ip4_address, &dm->in_addr, dm->in_plen,
2528 format_ip4_address, &dm->out_addr, dm->out_plen);
2529 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2531 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2532 dm->ports_per_host);
2533 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2536 vec_foreach_index (j, dm->sessions)
2538 ses = vec_elt_at_index (dm->sessions, j);
2540 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2549 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2551 vlib_cli_output (vm, "%d static mappings",
2552 pool_elts (sm->static_mappings));
2556 pool_foreach (m, sm->static_mappings,
2558 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2564 vec_foreach (tsm, sm->per_thread_data)
2566 users_num += pool_elts (tsm->users);
2567 sessions_num += pool_elts (tsm->sessions);
2570 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2571 " %d static mappings",
2573 vec_len (sm->addresses),
2575 pool_elts (sm->static_mappings));
2579 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
2581 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
2583 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
2585 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
2587 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
2589 vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
2591 vec_foreach_index (j, sm->per_thread_data)
2593 tsm = vec_elt_at_index (sm->per_thread_data, j);
2595 if (pool_elts (tsm->users) == 0)
2598 vlib_worker_thread_t *w = vlib_worker_threads + j;
2599 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2601 vlib_cli_output (vm, " %d list pool elements",
2602 pool_elts (tsm->list_pool));
2604 pool_foreach (u, tsm->users,
2606 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
2611 if (pool_elts (sm->static_mappings))
2613 vlib_cli_output (vm, "static mappings:");
2614 pool_foreach (m, sm->static_mappings,
2616 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2618 for (j = 0; j < vec_len (sm->to_resolve); j++)
2620 rp = sm->to_resolve + j;
2621 vlib_cli_output (vm, "%U",
2622 format_snat_static_map_to_resolve, rp);
2631 VLIB_CLI_COMMAND (show_snat_command, static) = {
2632 .path = "show nat44",
2633 .short_help = "show nat44",
2634 .function = show_snat_command_fn,
2639 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2642 ip4_address_t * address,
2644 u32 if_address_index,
2647 snat_main_t *sm = &snat_main;
2648 snat_static_map_resolve_t *rp;
2649 u32 *indices_to_delete = 0;
2653 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2655 if (sw_if_index == sm->auto_add_sw_if_indices[i])
2659 /* Don't trip over lease renewal, static config */
2660 for (j = 0; j < vec_len(sm->addresses); j++)
2661 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2664 snat_add_address (sm, address, ~0);
2665 /* Scan static map resolution vector */
2666 for (j = 0; j < vec_len (sm->to_resolve); j++)
2668 rp = sm->to_resolve + j;
2669 /* On this interface? */
2670 if (rp->sw_if_index == sw_if_index)
2672 /* Add the static mapping */
2673 rv = snat_add_static_mapping (rp->l_addr,
2679 ~0 /* sw_if_index */,
2683 clib_warning ("snat_add_static_mapping returned %d",
2685 vec_add1 (indices_to_delete, j);
2688 /* If we resolved any of the outstanding static mappings */
2689 if (vec_len(indices_to_delete))
2692 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2693 vec_delete(sm->to_resolve, 1, j);
2694 vec_free(indices_to_delete);
2700 (void) snat_del_address(sm, address[0], 1);
2708 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
2710 ip4_main_t * ip4_main = sm->ip4_main;
2711 ip4_address_t * first_int_addr;
2712 snat_static_map_resolve_t *rp;
2713 u32 *indices_to_delete = 0;
2716 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2717 0 /* just want the address*/);
2719 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2721 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2725 /* if have address remove it */
2727 (void) snat_del_address (sm, first_int_addr[0], 1);
2730 for (j = 0; j < vec_len (sm->to_resolve); j++)
2732 rp = sm->to_resolve + j;
2733 if (rp->sw_if_index == sw_if_index)
2734 vec_add1 (indices_to_delete, j);
2736 if (vec_len(indices_to_delete))
2738 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2739 vec_del1(sm->to_resolve, j);
2740 vec_free(indices_to_delete);
2743 vec_del1(sm->auto_add_sw_if_indices, i);
2746 return VNET_API_ERROR_VALUE_EXIST;
2753 return VNET_API_ERROR_NO_SUCH_ENTRY;
2755 /* add to the auto-address list */
2756 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2758 /* If the address is already bound - or static - add it now */
2760 snat_add_address (sm, first_int_addr, ~0);
2765 static clib_error_t *
2766 snat_add_interface_address_command_fn (vlib_main_t * vm,
2767 unformat_input_t * input,
2768 vlib_cli_command_t * cmd)
2770 snat_main_t *sm = &snat_main;
2771 unformat_input_t _line_input, *line_input = &_line_input;
2775 clib_error_t *error = 0;
2777 /* Get a line of input. */
2778 if (!unformat_user (input, unformat_line_input, line_input))
2781 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2783 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2784 sm->vnet_main, &sw_if_index))
2786 else if (unformat (line_input, "del"))
2790 error = clib_error_return (0, "unknown input '%U'",
2791 format_unformat_error, line_input);
2796 rv = snat_add_interface_address (sm, sw_if_index, is_del);
2804 error = clib_error_return (0, "snat_add_interface_address returned %d",
2810 unformat_free (line_input);
2815 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2816 .path = "nat44 add interface address",
2817 .short_help = "nat44 add interface address <interface> [del]",
2818 .function = snat_add_interface_address_command_fn,
2821 static clib_error_t *
2822 snat_det_map_command_fn (vlib_main_t * vm,
2823 unformat_input_t * input,
2824 vlib_cli_command_t * cmd)
2826 snat_main_t *sm = &snat_main;
2827 unformat_input_t _line_input, *line_input = &_line_input;
2828 ip4_address_t in_addr, out_addr;
2829 u32 in_plen, out_plen;
2831 clib_error_t *error = 0;
2833 /* Get a line of input. */
2834 if (!unformat_user (input, unformat_line_input, line_input))
2837 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2839 if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
2841 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
2843 else if (unformat (line_input, "del"))
2847 error = clib_error_return (0, "unknown input '%U'",
2848 format_unformat_error, line_input);
2853 unformat_free (line_input);
2855 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
2860 error = clib_error_return (0, "snat_det_add_map return %d", rv);
2865 unformat_free (line_input);
2872 * @cliexstart{snat deterministic add}
2873 * Create bijective mapping of inside address to outside address and port range
2874 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
2876 * To create deterministic mapping between inside network 10.0.0.0/18 and
2877 * outside network 1.1.1.0/30 use:
2878 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
2881 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
2882 .path = "nat44 deterministic add",
2883 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
2884 .function = snat_det_map_command_fn,
2887 static clib_error_t *
2888 snat_det_forward_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;
2896 snat_det_map_t * dm;
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, "%U", unformat_ip4_address, &in_addr))
2909 error = clib_error_return (0, "unknown input '%U'",
2910 format_unformat_error, line_input);
2915 unformat_free (line_input);
2917 dm = snat_det_map_by_user(sm, &in_addr);
2919 vlib_cli_output (vm, "no match");
2922 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
2923 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
2924 lo_port, lo_port + dm->ports_per_host - 1);
2928 unformat_free (line_input);
2935 * @cliexstart{snat deterministic forward}
2936 * Return outside address and port range from inside address for deterministic
2938 * To obtain outside address and port of inside host use:
2939 * vpp# nat44 deterministic forward 10.0.0.2
2940 * 1.1.1.0:<1054-1068>
2943 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
2944 .path = "nat44 deterministic forward",
2945 .short_help = "nat44 deterministic forward <addr>",
2946 .function = snat_det_forward_command_fn,
2949 static clib_error_t *
2950 snat_det_reverse_command_fn (vlib_main_t * vm,
2951 unformat_input_t * input,
2952 vlib_cli_command_t * cmd)
2954 snat_main_t *sm = &snat_main;
2955 unformat_input_t _line_input, *line_input = &_line_input;
2956 ip4_address_t in_addr, out_addr;
2958 snat_det_map_t * dm;
2959 clib_error_t *error = 0;
2961 /* Get a line of input. */
2962 if (!unformat_user (input, unformat_line_input, line_input))
2965 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2967 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
2971 error = clib_error_return (0, "unknown input '%U'",
2972 format_unformat_error, line_input);
2976 unformat_free (line_input);
2978 if (out_port < 1024 || out_port > 65535)
2980 error = clib_error_return (0, "wrong port, must be <1024-65535>");
2984 dm = snat_det_map_by_out(sm, &out_addr);
2986 vlib_cli_output (vm, "no match");
2989 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
2990 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
2994 unformat_free (line_input);
3001 * @cliexstart{snat deterministic reverse}
3002 * Return inside address from outside address and port for deterministic NAT.
3003 * To obtain inside host address from outside address and port use:
3004 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3008 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3009 .path = "nat44 deterministic reverse",
3010 .short_help = "nat44 deterministic reverse <addr>:<port>",
3011 .function = snat_det_reverse_command_fn,
3014 static clib_error_t *
3015 set_timeout_command_fn (vlib_main_t * vm,
3016 unformat_input_t * input,
3017 vlib_cli_command_t * cmd)
3019 snat_main_t *sm = &snat_main;
3020 unformat_input_t _line_input, *line_input = &_line_input;
3021 clib_error_t *error = 0;
3023 /* Get a line of input. */
3024 if (!unformat_user (input, unformat_line_input, line_input))
3027 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3029 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3031 else if (unformat (line_input, "tcp-established %u",
3032 &sm->tcp_established_timeout))
3034 else if (unformat (line_input, "tcp-transitory %u",
3035 &sm->tcp_transitory_timeout))
3037 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3039 else if (unformat (line_input, "reset"))
3041 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3042 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3043 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3044 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3048 error = clib_error_return (0, "unknown input '%U'",
3049 format_unformat_error, line_input);
3054 unformat_free (line_input);
3057 unformat_free (line_input);
3064 * @cliexstart{set snat deterministic timeout}
3065 * Set values of timeouts for deterministic NAT (in seconds), use:
3066 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3067 * tcp-transitory 250 icmp 90
3068 * To reset default values use:
3069 * vpp# set nat44 deterministic timeout reset
3072 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3073 .path = "set nat44 deterministic timeout",
3074 .function = set_timeout_command_fn,
3076 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3077 "tcp-transitory <sec> | icmp <sec> | reset]",
3080 static clib_error_t *
3081 snat_det_close_session_out_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 ip4_address_t out_addr, ext_addr, in_addr;
3088 u16 out_port, ext_port;
3089 snat_det_map_t * dm;
3090 snat_det_session_t * ses;
3091 snat_det_out_key_t key;
3092 clib_error_t *error = 0;
3094 /* Get a line of input. */
3095 if (!unformat_user (input, unformat_line_input, line_input))
3098 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3100 if (unformat (line_input, "%U:%d %U:%d",
3101 unformat_ip4_address, &out_addr, &out_port,
3102 unformat_ip4_address, &ext_addr, &ext_port))
3106 error = clib_error_return (0, "unknown input '%U'",
3107 format_unformat_error, line_input);
3112 unformat_free (line_input);
3114 dm = snat_det_map_by_out(sm, &out_addr);
3116 vlib_cli_output (vm, "no match");
3119 snat_det_reverse(dm, &ext_addr, out_port, &in_addr);
3120 key.ext_host_addr = out_addr;
3121 key.ext_host_port = ntohs(ext_port);
3122 key.out_port = ntohs(out_port);
3123 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3125 vlib_cli_output (vm, "no match");
3127 snat_det_ses_close(dm, ses);
3131 unformat_free (line_input);
3138 * @cliexstart{snat deterministic close session out}
3139 * Close session using outside ip address and port
3140 * and external ip address and port, use:
3141 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3144 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3145 .path = "nat44 deterministic close session out",
3146 .short_help = "nat44 deterministic close session out "
3147 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3148 .function = snat_det_close_session_out_fn,
3151 static clib_error_t *
3152 snat_det_close_session_in_fn (vlib_main_t *vm,
3153 unformat_input_t * input,
3154 vlib_cli_command_t * cmd)
3156 snat_main_t *sm = &snat_main;
3157 unformat_input_t _line_input, *line_input = &_line_input;
3158 ip4_address_t in_addr, ext_addr;
3159 u16 in_port, ext_port;
3160 snat_det_map_t * dm;
3161 snat_det_session_t * ses;
3162 snat_det_out_key_t key;
3163 clib_error_t *error = 0;
3165 /* Get a line of input. */
3166 if (!unformat_user (input, unformat_line_input, line_input))
3169 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3171 if (unformat (line_input, "%U:%d %U:%d",
3172 unformat_ip4_address, &in_addr, &in_port,
3173 unformat_ip4_address, &ext_addr, &ext_port))
3177 error = clib_error_return (0, "unknown input '%U'",
3178 format_unformat_error, line_input);
3183 unformat_free (line_input);
3185 dm = snat_det_map_by_user (sm, &in_addr);
3187 vlib_cli_output (vm, "no match");
3190 key.ext_host_addr = ext_addr;
3191 key.ext_host_port = ntohs (ext_port);
3192 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs(in_port), key);
3194 vlib_cli_output (vm, "no match");
3196 snat_det_ses_close(dm, ses);
3200 unformat_free(line_input);
3207 * @cliexstart{snat deterministic close_session_in}
3208 * Close session using inside ip address and port
3209 * and external ip address and port, use:
3210 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3213 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3214 .path = "nat44 deterministic close session in",
3215 .short_help = "nat44 deterministic close session in "
3216 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3217 .function = snat_det_close_session_in_fn,