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 <nat/dslite.h>
27 #include <nat/nat_reass.h>
28 #include <vnet/fib/fib_table.h>
29 #include <vnet/fib/ip4_fib.h>
31 #include <vpp/app/version.h>
33 snat_main_t snat_main;
36 /* Hook up input features */
37 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
38 .arc_name = "ip4-unicast",
39 .node_name = "nat44-in2out",
40 .runs_before = VNET_FEATURES ("nat44-out2in"),
42 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
43 .arc_name = "ip4-unicast",
44 .node_name = "nat44-out2in",
45 .runs_before = VNET_FEATURES ("ip4-lookup"),
47 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
48 .arc_name = "ip4-unicast",
49 .node_name = "nat44-classify",
50 .runs_before = VNET_FEATURES ("ip4-lookup"),
52 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
53 .arc_name = "ip4-unicast",
54 .node_name = "nat44-det-in2out",
55 .runs_before = VNET_FEATURES ("nat44-det-out2in"),
57 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
58 .arc_name = "ip4-unicast",
59 .node_name = "nat44-det-out2in",
60 .runs_before = VNET_FEATURES ("ip4-lookup"),
62 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
63 .arc_name = "ip4-unicast",
64 .node_name = "nat44-det-classify",
65 .runs_before = VNET_FEATURES ("ip4-lookup"),
67 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
68 .arc_name = "ip4-unicast",
69 .node_name = "nat44-in2out-worker-handoff",
70 .runs_before = VNET_FEATURES ("nat44-out2in-worker-handoff"),
72 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
73 .arc_name = "ip4-unicast",
74 .node_name = "nat44-out2in-worker-handoff",
75 .runs_before = VNET_FEATURES ("ip4-lookup"),
77 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
78 .arc_name = "ip4-unicast",
79 .node_name = "nat44-handoff-classify",
80 .runs_before = VNET_FEATURES ("ip4-lookup"),
82 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
83 .arc_name = "ip4-unicast",
84 .node_name = "nat44-in2out-fast",
85 .runs_before = VNET_FEATURES ("nat44-out2in-fast"),
87 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
88 .arc_name = "ip4-unicast",
89 .node_name = "nat44-out2in-fast",
90 .runs_before = VNET_FEATURES ("ip4-lookup"),
92 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
93 .arc_name = "ip4-unicast",
94 .node_name = "nat44-hairpin-dst",
95 .runs_before = VNET_FEATURES ("ip4-lookup"),
98 /* Hook up output features */
99 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
100 .arc_name = "ip4-output",
101 .node_name = "nat44-in2out-output",
102 .runs_before = VNET_FEATURES ("interface-output"),
104 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
105 .arc_name = "ip4-output",
106 .node_name = "nat44-in2out-output-worker-handoff",
107 .runs_before = VNET_FEATURES ("interface-output"),
109 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
110 .arc_name = "ip4-output",
111 .node_name = "nat44-hairpin-src",
112 .runs_before = VNET_FEATURES ("interface-output"),
115 /* Hook up ip4-local features */
116 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
118 .arc_name = "ip4-local",
119 .node_name = "nat44-hairpinning",
120 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
125 VLIB_PLUGIN_REGISTER () = {
126 .version = VPP_BUILD_VER,
127 .description = "Network Address Translation",
131 vlib_node_registration_t nat44_classify_node;
132 vlib_node_registration_t nat44_det_classify_node;
133 vlib_node_registration_t nat44_handoff_classify_node;
136 NAT44_CLASSIFY_NEXT_IN2OUT,
137 NAT44_CLASSIFY_NEXT_OUT2IN,
138 NAT44_CLASSIFY_N_NEXT,
139 } nat44_classify_next_t;
142 nat44_classify_node_fn_inline (vlib_main_t * vm,
143 vlib_node_runtime_t * node,
144 vlib_frame_t * frame)
146 u32 n_left_from, * from, * to_next;
147 nat44_classify_next_t next_index;
148 snat_main_t *sm = &snat_main;
150 from = vlib_frame_vector_args (frame);
151 n_left_from = frame->n_vectors;
152 next_index = node->cached_next_index;
154 while (n_left_from > 0)
158 vlib_get_next_frame (vm, node, next_index,
159 to_next, n_left_to_next);
161 while (n_left_from > 0 && n_left_to_next > 0)
165 u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT;
168 snat_session_key_t m_key0;
169 clib_bihash_kv_8_8_t kv0, value0;
171 /* speculatively enqueue b0 to the current next frame */
179 b0 = vlib_get_buffer (vm, bi0);
180 ip0 = vlib_buffer_get_current (b0);
182 vec_foreach (ap, sm->addresses)
184 if (ip0->dst_address.as_u32 == ap->addr.as_u32)
186 next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
191 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
193 m_key0.addr = ip0->dst_address;
196 m_key0.fib_index = sm->outside_fib_index;
197 kv0.key = m_key0.as_u64;
198 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
200 next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
203 /* verify speculative enqueue, maybe switch current next frame */
204 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
205 to_next, n_left_to_next,
209 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
212 return frame->n_vectors;
216 nat44_classify_node_fn (vlib_main_t * vm,
217 vlib_node_runtime_t * node,
218 vlib_frame_t * frame)
220 return nat44_classify_node_fn_inline (vm, node, frame);
223 VLIB_REGISTER_NODE (nat44_classify_node) = {
224 .function = nat44_classify_node_fn,
225 .name = "nat44-classify",
226 .vector_size = sizeof (u32),
227 .type = VLIB_NODE_TYPE_INTERNAL,
228 .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
230 [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
231 [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
235 VLIB_NODE_FUNCTION_MULTIARCH (nat44_classify_node,
236 nat44_classify_node_fn);
239 nat44_det_classify_node_fn (vlib_main_t * vm,
240 vlib_node_runtime_t * node,
241 vlib_frame_t * frame)
243 return nat44_classify_node_fn_inline (vm, node, frame);
246 VLIB_REGISTER_NODE (nat44_det_classify_node) = {
247 .function = nat44_det_classify_node_fn,
248 .name = "nat44-det-classify",
249 .vector_size = sizeof (u32),
250 .type = VLIB_NODE_TYPE_INTERNAL,
251 .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
253 [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
254 [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
258 VLIB_NODE_FUNCTION_MULTIARCH (nat44_det_classify_node,
259 nat44_det_classify_node_fn);
262 nat44_handoff_classify_node_fn (vlib_main_t * vm,
263 vlib_node_runtime_t * node,
264 vlib_frame_t * frame)
266 return nat44_classify_node_fn_inline (vm, node, frame);
269 VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
270 .function = nat44_handoff_classify_node_fn,
271 .name = "nat44-handoff-classify",
272 .vector_size = sizeof (u32),
273 .type = VLIB_NODE_TYPE_INTERNAL,
274 .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
276 [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
277 [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
281 VLIB_NODE_FUNCTION_MULTIARCH (nat44_handoff_classify_node,
282 nat44_handoff_classify_node_fn);
285 * @brief Add/del NAT address to FIB.
287 * Add the external NAT address to the FIB as receive entries. This ensures
288 * that VPP will reply to ARP for this address and we don't need to enable
289 * proxy ARP on the outside interface.
291 * @param addr IPv4 address.
292 * @param plen address prefix length
293 * @param sw_if_index Interface.
294 * @param is_add If 0 delete, otherwise add.
297 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
300 fib_prefix_t prefix = {
302 .fp_proto = FIB_PROTOCOL_IP4,
304 .ip4.as_u32 = addr->as_u32,
307 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
310 fib_table_entry_update_one_path(fib_index,
312 FIB_SOURCE_PLUGIN_HI,
313 (FIB_ENTRY_FLAG_CONNECTED |
314 FIB_ENTRY_FLAG_LOCAL |
315 FIB_ENTRY_FLAG_EXCLUSIVE),
322 FIB_ROUTE_PATH_FLAG_NONE);
324 fib_table_entry_delete(fib_index,
326 FIB_SOURCE_PLUGIN_HI);
329 void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id)
333 vlib_thread_main_t *tm = vlib_get_thread_main ();
338 /* Check if address already exists */
339 vec_foreach (ap, sm->addresses)
341 if (ap->addr.as_u32 == addr->as_u32)
345 vec_add2 (sm->addresses, ap, 1);
349 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
350 FIB_SOURCE_PLUGIN_HI);
353 #define _(N, i, n, s) \
354 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
355 ap->busy_##n##_ports = 0; \
356 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
357 foreach_snat_protocol
360 /* Add external address to FIB */
361 pool_foreach (i, sm->interfaces,
363 if (nat_interface_is_inside(i))
366 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
369 pool_foreach (i, sm->output_feature_interfaces,
371 if (nat_interface_is_inside(i))
374 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
379 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
382 snat_static_mapping_t *m;
383 pool_foreach (m, sm->static_mappings,
385 if (m->external_addr.as_u32 == addr.as_u32)
392 void increment_v4_address (ip4_address_t * a)
396 v = clib_net_to_host_u32(a->as_u32) + 1;
397 a->as_u32 = clib_host_to_net_u32(v);
401 snat_add_static_mapping_when_resolved (snat_main_t * sm,
402 ip4_address_t l_addr,
407 snat_protocol_t proto,
411 snat_static_map_resolve_t *rp;
413 vec_add2 (sm->to_resolve, rp, 1);
414 rp->l_addr.as_u32 = l_addr.as_u32;
416 rp->sw_if_index = sw_if_index;
420 rp->addr_only = addr_only;
425 * @brief Add static mapping.
427 * Create static mapping between local addr+port and external addr+port.
429 * @param l_addr Local IPv4 address.
430 * @param e_addr External IPv4 address.
431 * @param l_port Local port number.
432 * @param e_port External port number.
433 * @param vrf_id VRF ID.
434 * @param addr_only If 0 address port and pair mapping, otherwise address only.
435 * @param sw_if_index External port instead of specific IP address.
436 * @param is_add If 0 delete static mapping, otherwise add.
440 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
441 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
442 u32 sw_if_index, snat_protocol_t proto, int is_add)
444 snat_main_t * sm = &snat_main;
445 snat_static_mapping_t *m;
446 snat_session_key_t m_key;
447 clib_bihash_kv_8_8_t kv, value;
448 snat_address_t *a = 0;
451 snat_interface_t *interface;
454 /* If the external address is a specific interface address */
455 if (sw_if_index != ~0)
457 ip4_address_t * first_int_addr;
459 /* Might be already set... */
460 first_int_addr = ip4_interface_first_address
461 (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
463 /* DHCP resolution required? */
464 if (first_int_addr == 0)
466 snat_add_static_mapping_when_resolved
467 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
472 e_addr.as_u32 = first_int_addr->as_u32;
476 m_key.port = addr_only ? 0 : e_port;
477 m_key.protocol = addr_only ? 0 : proto;
478 m_key.fib_index = sm->outside_fib_index;
479 kv.key = m_key.as_u64;
480 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
483 m = pool_elt_at_index (sm->static_mappings, value.value);
488 return VNET_API_ERROR_VALUE_EXIST;
490 /* Convert VRF id to FIB index */
493 p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
495 return VNET_API_ERROR_NO_SUCH_FIB;
498 /* If not specified use inside VRF id from SNAT plugin startup config */
501 fib_index = sm->inside_fib_index;
502 vrf_id = sm->inside_vrf_id;
505 /* Find external address in allocated addresses and reserve port for
506 address and port pair mapping when dynamic translations enabled */
507 if (!addr_only && !(sm->static_mapping_only))
509 for (i = 0; i < vec_len (sm->addresses); i++)
511 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
513 a = sm->addresses + i;
514 /* External port must be unused */
517 #define _(N, j, n, s) \
518 case SNAT_PROTOCOL_##N: \
519 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
520 return VNET_API_ERROR_INVALID_VALUE; \
521 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
524 a->busy_##n##_ports++; \
525 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
528 foreach_snat_protocol
531 clib_warning("unknown_protocol");
532 return VNET_API_ERROR_INVALID_VALUE_2;
537 /* External address must be allocated */
539 return VNET_API_ERROR_NO_SUCH_ENTRY;
542 pool_get (sm->static_mappings, m);
543 memset (m, 0, sizeof (*m));
544 m->local_addr = l_addr;
545 m->external_addr = e_addr;
546 m->addr_only = addr_only;
548 m->fib_index = fib_index;
551 m->local_port = l_port;
552 m->external_port = e_port;
556 m_key.addr = m->local_addr;
557 m_key.port = m->local_port;
558 m_key.protocol = m->proto;
559 m_key.fib_index = m->fib_index;
560 kv.key = m_key.as_u64;
561 kv.value = m - sm->static_mappings;
562 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
564 m_key.addr = m->external_addr;
565 m_key.port = m->external_port;
566 m_key.fib_index = sm->outside_fib_index;
567 kv.key = m_key.as_u64;
568 kv.value = m - sm->static_mappings;
569 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
574 .src_address = m->local_addr,
576 m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index);
582 return VNET_API_ERROR_NO_SUCH_ENTRY;
584 /* Free external address port */
585 if (!addr_only && !(sm->static_mapping_only))
587 for (i = 0; i < vec_len (sm->addresses); i++)
589 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
591 a = sm->addresses + i;
594 #define _(N, j, n, s) \
595 case SNAT_PROTOCOL_##N: \
596 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
599 a->busy_##n##_ports--; \
600 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
603 foreach_snat_protocol
606 clib_warning("unknown_protocol");
607 return VNET_API_ERROR_INVALID_VALUE_2;
614 m_key.addr = m->local_addr;
615 m_key.port = m->local_port;
616 m_key.protocol = m->proto;
617 m_key.fib_index = m->fib_index;
618 kv.key = m_key.as_u64;
619 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
621 m_key.addr = m->external_addr;
622 m_key.port = m->external_port;
623 m_key.fib_index = sm->outside_fib_index;
624 kv.key = m_key.as_u64;
625 clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
627 /* Delete session(s) for static mapping if exist */
628 if (!(sm->static_mapping_only) ||
629 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
631 snat_user_key_t u_key;
633 dlist_elt_t * head, * elt;
634 u32 elt_index, head_index, del_elt_index;
638 snat_main_per_thread_data_t *tsm;
640 u_key.addr = m->local_addr;
641 u_key.fib_index = m->fib_index;
642 kv.key = u_key.as_u64;
643 if (sm->num_workers > 1)
644 tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
646 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
647 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
649 user_index = value.value;
650 u = pool_elt_at_index (tsm->users, user_index);
651 if (u->nstaticsessions)
653 head_index = u->sessions_per_user_list_head_index;
654 head = pool_elt_at_index (tsm->list_pool, head_index);
655 elt_index = head->next;
656 elt = pool_elt_at_index (tsm->list_pool, elt_index);
657 ses_index = elt->value;
658 while (ses_index != ~0)
660 s = pool_elt_at_index (tsm->sessions, ses_index);
661 del_elt_index = elt_index;
662 elt_index = elt->next;
663 elt = pool_elt_at_index (tsm->list_pool, elt_index);
664 ses_index = elt->value;
668 if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
669 (clib_net_to_host_u16 (s->out2in.port) != e_port))
673 if (snat_is_unk_proto_session (s))
675 clib_bihash_kv_16_8_t up_kv;
676 nat_ed_ses_key_t up_key;
677 up_key.l_addr = s->in2out.addr;
678 up_key.r_addr = s->ext_host_addr;
679 up_key.fib_index = s->in2out.fib_index;
680 up_key.proto = s->in2out.port;
683 up_kv.key[0] = up_key.as_u64[0];
684 up_kv.key[1] = up_key.as_u64[1];
685 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
687 clib_warning ("in2out key del failed");
689 up_key.l_addr = s->out2in.addr;
690 up_key.fib_index = s->out2in.fib_index;
691 up_kv.key[0] = up_key.as_u64[0];
692 up_kv.key[1] = up_key.as_u64[1];
693 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
695 clib_warning ("out2in key del failed");
700 snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
701 s->out2in.addr.as_u32,
705 s->in2out.fib_index);
707 value.key = s->in2out.as_u64;
708 if (clib_bihash_add_del_8_8 (&tsm->in2out, &value, 0))
709 clib_warning ("in2out key del failed");
710 value.key = s->out2in.as_u64;
711 if (clib_bihash_add_del_8_8 (&tsm->out2in, &value, 0))
712 clib_warning ("out2in key del failed");
714 pool_put (tsm->sessions, s);
716 clib_dlist_remove (tsm->list_pool, del_elt_index);
717 pool_put_index (tsm->list_pool, del_elt_index);
718 u->nstaticsessions--;
725 pool_put (tsm->users, u);
726 clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
732 /* Delete static mapping from pool */
733 pool_put (sm->static_mappings, m);
739 /* Add/delete external address to FIB */
740 pool_foreach (interface, sm->interfaces,
742 if (nat_interface_is_inside(interface))
745 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
748 pool_foreach (interface, sm->output_feature_interfaces,
750 if (nat_interface_is_inside(interface))
753 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
760 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
761 snat_protocol_t proto, u32 vrf_id,
762 nat44_lb_addr_port_t *locals, u8 is_add)
764 snat_main_t * sm = &snat_main;
765 snat_static_mapping_t *m;
766 snat_session_key_t m_key;
767 clib_bihash_kv_8_8_t kv, value;
769 snat_address_t *a = 0;
771 nat44_lb_addr_port_t *local;
772 u32 worker_index = 0;
773 snat_main_per_thread_data_t *tsm;
777 m_key.protocol = proto;
778 m_key.fib_index = sm->outside_fib_index;
779 kv.key = m_key.as_u64;
780 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
783 m = pool_elt_at_index (sm->static_mappings, value.value);
788 return VNET_API_ERROR_VALUE_EXIST;
790 if (vec_len (locals) < 2)
791 return VNET_API_ERROR_INVALID_VALUE;
793 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
795 FIB_SOURCE_PLUGIN_HI);
797 /* Find external address in allocated addresses and reserve port for
798 address and port pair mapping when dynamic translations enabled */
799 if (!sm->static_mapping_only)
801 for (i = 0; i < vec_len (sm->addresses); i++)
803 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
805 a = sm->addresses + i;
806 /* External port must be unused */
809 #define _(N, j, n, s) \
810 case SNAT_PROTOCOL_##N: \
811 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
812 return VNET_API_ERROR_INVALID_VALUE; \
813 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
816 a->busy_##n##_ports++; \
817 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
820 foreach_snat_protocol
823 clib_warning("unknown_protocol");
824 return VNET_API_ERROR_INVALID_VALUE_2;
829 /* External address must be allocated */
831 return VNET_API_ERROR_NO_SUCH_ENTRY;
834 pool_get (sm->static_mappings, m);
835 memset (m, 0, sizeof (*m));
836 m->external_addr = e_addr;
839 m->fib_index = fib_index;
840 m->external_port = e_port;
843 m_key.addr = m->external_addr;
844 m_key.port = m->external_port;
845 m_key.protocol = m->proto;
846 m_key.fib_index = sm->outside_fib_index;
847 kv.key = m_key.as_u64;
848 kv.value = m - sm->static_mappings;
849 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
851 clib_warning ("static_mapping_by_external key add failed");
852 return VNET_API_ERROR_UNSPECIFIED;
858 worker_index = sm->first_worker_index +
859 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
860 tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
861 m->worker_index = worker_index;
864 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
866 m_key.port = clib_host_to_net_u16 (m->external_port);
867 kv.key = m_key.as_u64;
869 if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
871 clib_warning ("static_mapping_by_local key add failed");
872 return VNET_API_ERROR_UNSPECIFIED;
875 m_key.fib_index = m->fib_index;
876 for (i = 0; i < vec_len (locals); i++)
878 m_key.addr = locals[i].addr;
879 m_key.port = locals[i].port;
880 kv.key = m_key.as_u64;
881 kv.value = m - sm->static_mappings;
882 clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
883 locals[i].prefix = (i == 0) ? locals[i].probability :\
884 (locals[i - 1].prefix + locals[i].probability);
885 vec_add1 (m->locals, locals[i]);
887 m_key.port = clib_host_to_net_u16 (locals[i].port);
888 kv.key = m_key.as_u64;
890 if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
892 clib_warning ("in2out key add failed");
893 return VNET_API_ERROR_UNSPECIFIED;
900 return VNET_API_ERROR_NO_SUCH_ENTRY;
902 fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
904 /* Free external address port */
905 if (!sm->static_mapping_only)
907 for (i = 0; i < vec_len (sm->addresses); i++)
909 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
911 a = sm->addresses + i;
914 #define _(N, j, n, s) \
915 case SNAT_PROTOCOL_##N: \
916 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
919 a->busy_##n##_ports--; \
920 a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
923 foreach_snat_protocol
926 clib_warning("unknown_protocol");
927 return VNET_API_ERROR_INVALID_VALUE_2;
934 tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
935 m_key.addr = m->external_addr;
936 m_key.port = m->external_port;
937 m_key.protocol = m->proto;
938 m_key.fib_index = sm->outside_fib_index;
939 kv.key = m_key.as_u64;
940 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
942 clib_warning ("static_mapping_by_external key del failed");
943 return VNET_API_ERROR_UNSPECIFIED;
946 m_key.port = clib_host_to_net_u16 (m->external_port);
947 kv.key = m_key.as_u64;
948 if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
950 clib_warning ("outi2in key del failed");
951 return VNET_API_ERROR_UNSPECIFIED;
954 vec_foreach (local, m->locals)
956 m_key.addr = local->addr;
957 m_key.port = local->port;
958 m_key.fib_index = m->fib_index;
959 kv.key = m_key.as_u64;
960 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
962 clib_warning ("static_mapping_by_local key del failed");
963 return VNET_API_ERROR_UNSPECIFIED;
966 m_key.port = clib_host_to_net_u16 (local->port);
967 kv.key = m_key.as_u64;
968 if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
970 clib_warning ("in2out key del failed");
971 return VNET_API_ERROR_UNSPECIFIED;
976 pool_put (sm->static_mappings, m);
982 int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm)
984 snat_address_t *a = 0;
986 u32 *ses_to_be_removed = 0, *ses_index;
987 clib_bihash_kv_8_8_t kv, value;
988 snat_user_key_t user_key;
990 snat_main_per_thread_data_t *tsm;
991 snat_static_mapping_t *m;
992 snat_interface_t *interface;
995 /* Find SNAT address */
996 for (i=0; i < vec_len (sm->addresses); i++)
998 if (sm->addresses[i].addr.as_u32 == addr.as_u32)
1000 a = sm->addresses + i;
1005 return VNET_API_ERROR_NO_SUCH_ENTRY;
1009 pool_foreach (m, sm->static_mappings,
1011 if (m->external_addr.as_u32 == addr.as_u32)
1012 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1013 m->local_port, m->external_port,
1014 m->vrf_id, m->addr_only, ~0,
1020 /* Check if address is used in some static mapping */
1021 if (is_snat_address_used_in_static_mapping(sm, addr))
1023 clib_warning ("address used in static mapping");
1024 return VNET_API_ERROR_UNSPECIFIED;
1028 if (a->fib_index != ~0)
1029 fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
1030 FIB_SOURCE_PLUGIN_HI);
1032 /* Delete sessions using address */
1033 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1035 vec_foreach (tsm, sm->per_thread_data)
1037 pool_foreach (ses, tsm->sessions, ({
1038 if (ses->out2in.addr.as_u32 == addr.as_u32)
1040 if (snat_is_unk_proto_session (ses))
1042 clib_bihash_kv_16_8_t up_kv;
1043 nat_ed_ses_key_t up_key;
1044 up_key.l_addr = ses->in2out.addr;
1045 up_key.r_addr = ses->ext_host_addr;
1046 up_key.fib_index = ses->in2out.fib_index;
1047 up_key.proto = ses->in2out.port;
1050 up_kv.key[0] = up_key.as_u64[0];
1051 up_kv.key[1] = up_key.as_u64[1];
1052 if (clib_bihash_add_del_16_8 (&sm->in2out_ed,
1054 clib_warning ("in2out key del failed");
1056 up_key.l_addr = ses->out2in.addr;
1057 up_key.fib_index = ses->out2in.fib_index;
1058 up_kv.key[0] = up_key.as_u64[0];
1059 up_kv.key[1] = up_key.as_u64[1];
1060 if (clib_bihash_add_del_16_8 (&sm->out2in_ed,
1062 clib_warning ("out2in key del failed");
1067 snat_ipfix_logging_nat44_ses_delete(ses->in2out.addr.as_u32,
1068 ses->out2in.addr.as_u32,
1069 ses->in2out.protocol,
1072 ses->in2out.fib_index);
1073 kv.key = ses->in2out.as_u64;
1074 clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
1075 kv.key = ses->out2in.as_u64;
1076 clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
1078 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1079 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1080 user_key.addr = ses->in2out.addr;
1081 user_key.fib_index = ses->in2out.fib_index;
1082 kv.key = user_key.as_u64;
1083 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1085 u = pool_elt_at_index (tsm->users, value.value);
1091 vec_foreach (ses_index, ses_to_be_removed)
1092 pool_put_index (tsm->sessions, ses_index[0]);
1094 vec_free (ses_to_be_removed);
1098 vec_del1 (sm->addresses, i);
1100 /* Delete external address from FIB */
1101 pool_foreach (interface, sm->interfaces,
1103 if (nat_interface_is_inside(interface))
1106 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1109 pool_foreach (interface, sm->output_feature_interfaces,
1111 if (nat_interface_is_inside(interface))
1114 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1121 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1123 snat_main_t *sm = &snat_main;
1124 snat_interface_t *i;
1125 const char * feature_name, *del_feature_name;
1126 snat_address_t * ap;
1127 snat_static_mapping_t * m;
1128 snat_det_map_t * dm;
1130 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1131 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1134 if (sm->num_workers > 1 && !sm->deterministic)
1135 feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1136 else if (sm->deterministic)
1137 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1139 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1142 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1143 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
1145 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1146 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1148 pool_foreach (i, sm->interfaces,
1150 if (i->sw_if_index == sw_if_index)
1154 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1157 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1159 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1161 if (sm->num_workers > 1 && !sm->deterministic)
1162 del_feature_name = "nat44-handoff-classify";
1163 else if (sm->deterministic)
1164 del_feature_name = "nat44-det-classify";
1166 del_feature_name = "nat44-classify";
1168 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1169 sw_if_index, 0, 0, 0);
1170 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1171 sw_if_index, 1, 0, 0);
1175 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1176 sw_if_index, 0, 0, 0);
1177 pool_put (sm->interfaces, i);
1182 if ((nat_interface_is_inside(i) && is_inside) ||
1183 (nat_interface_is_outside(i) && !is_inside))
1186 if (sm->num_workers > 1 && !sm->deterministic)
1188 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1189 "nat44-out2in-worker-handoff";
1190 feature_name = "nat44-handoff-classify";
1192 else if (sm->deterministic)
1194 del_feature_name = !is_inside ? "nat44-det-in2out" :
1196 feature_name = "nat44-det-classify";
1200 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1201 feature_name = "nat44-classify";
1204 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1205 sw_if_index, 0, 0, 0);
1206 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1207 sw_if_index, 1, 0, 0);
1216 return VNET_API_ERROR_NO_SUCH_ENTRY;
1218 pool_get (sm->interfaces, i);
1219 i->sw_if_index = sw_if_index;
1221 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1225 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1227 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1229 /* Add/delete external addresses to FIB */
1233 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1234 sw_if_index, !is_del, 0, 0);
1238 vec_foreach (ap, sm->addresses)
1239 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1241 pool_foreach (m, sm->static_mappings,
1243 if (!(m->addr_only))
1246 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1249 pool_foreach (dm, sm->det_maps,
1251 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1257 int snat_interface_add_del_output_feature (u32 sw_if_index,
1261 snat_main_t *sm = &snat_main;
1262 snat_interface_t *i;
1263 snat_address_t * ap;
1264 snat_static_mapping_t * m;
1266 if (sm->deterministic ||
1267 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1268 return VNET_API_ERROR_UNSUPPORTED;
1272 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1273 sw_if_index, !is_del, 0, 0);
1274 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1275 sw_if_index, !is_del, 0, 0);
1279 if (sm->num_workers > 1)
1281 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1282 sw_if_index, !is_del, 0, 0);
1283 vnet_feature_enable_disable ("ip4-output",
1284 "nat44-in2out-output-worker-handoff",
1285 sw_if_index, !is_del, 0, 0);
1289 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1291 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1292 sw_if_index, !is_del, 0, 0);
1296 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1297 sm->fq_in2out_output_index =
1298 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1300 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1301 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1303 pool_foreach (i, sm->output_feature_interfaces,
1305 if (i->sw_if_index == sw_if_index)
1308 pool_put (sm->output_feature_interfaces, i);
1310 return VNET_API_ERROR_VALUE_EXIST;
1317 return VNET_API_ERROR_NO_SUCH_ENTRY;
1319 pool_get (sm->output_feature_interfaces, i);
1320 i->sw_if_index = sw_if_index;
1323 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1325 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1327 /* Add/delete external addresses to FIB */
1332 vec_foreach (ap, sm->addresses)
1333 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1335 pool_foreach (m, sm->static_mappings,
1337 if (!(m->addr_only))
1340 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1346 int snat_set_workers (uword * bitmap)
1348 snat_main_t *sm = &snat_main;
1351 if (sm->num_workers < 2)
1352 return VNET_API_ERROR_FEATURE_DISABLED;
1354 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1355 return VNET_API_ERROR_INVALID_WORKER;
1357 vec_free (sm->workers);
1358 clib_bitmap_foreach (i, bitmap,
1360 vec_add1(sm->workers, i);
1361 sm->per_thread_data[i].snat_thread_index = j;
1365 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1366 sm->num_snat_thread = _vec_len (sm->workers);
1373 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1376 ip4_address_t * address,
1378 u32 if_address_index,
1381 static clib_error_t * snat_init (vlib_main_t * vm)
1383 snat_main_t * sm = &snat_main;
1384 clib_error_t * error = 0;
1385 ip4_main_t * im = &ip4_main;
1386 ip_lookup_main_t * lm = &im->lookup_main;
1388 vlib_thread_registration_t *tr;
1389 vlib_thread_main_t *tm = vlib_get_thread_main ();
1392 ip4_add_del_interface_address_callback_t cb4;
1395 sm->vnet_main = vnet_get_main();
1397 sm->ip4_lookup_main = lm;
1398 sm->api_main = &api_main;
1399 sm->first_worker_index = 0;
1400 sm->next_worker = 0;
1401 sm->num_workers = 0;
1402 sm->num_snat_thread = 1;
1404 sm->port_per_thread = 0xffff - 1024;
1405 sm->fq_in2out_index = ~0;
1406 sm->fq_out2in_index = ~0;
1407 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1408 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1409 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1410 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1412 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1415 tr = (vlib_thread_registration_t *) p[0];
1418 sm->num_workers = tr->count;
1419 sm->first_worker_index = tr->first_index;
1423 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1425 /* Use all available workers by default */
1426 if (sm->num_workers > 1)
1428 for (i=0; i < sm->num_workers; i++)
1429 bitmap = clib_bitmap_set (bitmap, i, 1);
1430 snat_set_workers(bitmap);
1431 clib_bitmap_free (bitmap);
1435 sm->per_thread_data[0].snat_thread_index = 0;
1438 error = snat_api_init(vm, sm);
1442 /* Set up the interface address add/del callback */
1443 cb4.function = snat_ip4_add_del_interface_address_cb;
1444 cb4.function_opaque = 0;
1446 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1448 /* Init IPFIX logging */
1449 snat_ipfix_logging_init(vm);
1452 error = nat64_init(vm);
1458 /* Init virtual fragmenentation reassembly */
1459 return nat_reass_init(vm);
1462 VLIB_INIT_FUNCTION (snat_init);
1464 void snat_free_outside_address_and_port (snat_address_t * addresses,
1466 snat_session_key_t * k,
1470 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1472 ASSERT (address_index < vec_len (addresses));
1474 a = addresses + address_index;
1476 switch (k->protocol)
1478 #define _(N, i, n, s) \
1479 case SNAT_PROTOCOL_##N: \
1480 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1481 port_host_byte_order) == 1); \
1482 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1483 port_host_byte_order, 0); \
1484 a->busy_##n##_ports--; \
1485 a->busy_##n##_ports_per_thread[thread_index]--; \
1487 foreach_snat_protocol
1490 clib_warning("unknown_protocol");
1496 * @brief Match NAT44 static mapping.
1498 * @param sm NAT main.
1499 * @param match Address and port to match.
1500 * @param mapping External or local address and port of the matched mapping.
1501 * @param by_external If 0 match by local address otherwise match by external
1503 * @param is_addr_only If matched mapping is address only
1505 * @returns 0 if match found otherwise 1.
1507 int snat_static_mapping_match (snat_main_t * sm,
1508 snat_session_key_t match,
1509 snat_session_key_t * mapping,
1513 clib_bihash_kv_8_8_t kv, value;
1514 snat_static_mapping_t *m;
1515 snat_session_key_t m_key;
1516 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1517 u32 rand, lo = 0, hi, mid;
1520 mapping_hash = &sm->static_mapping_by_external;
1522 m_key.addr = match.addr;
1523 m_key.port = clib_net_to_host_u16 (match.port);
1524 m_key.protocol = match.protocol;
1525 m_key.fib_index = match.fib_index;
1527 kv.key = m_key.as_u64;
1529 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1531 /* Try address only mapping */
1534 kv.key = m_key.as_u64;
1535 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1539 m = pool_elt_at_index (sm->static_mappings, value.value);
1543 if (vec_len (m->locals))
1545 hi = vec_len (m->locals) - 1;
1546 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1549 mid = ((hi - lo) >> 1) + lo;
1550 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1552 if (!(m->locals[lo].prefix >= rand))
1554 mapping->addr = m->locals[lo].addr;
1555 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1559 mapping->addr = m->local_addr;
1560 /* Address only mapping doesn't change port */
1561 mapping->port = m->addr_only ? match.port
1562 : clib_host_to_net_u16 (m->local_port);
1564 mapping->fib_index = m->fib_index;
1565 mapping->protocol = m->proto;
1569 mapping->addr = m->external_addr;
1570 /* Address only mapping doesn't change port */
1571 mapping->port = m->addr_only ? match.port
1572 : clib_host_to_net_u16 (m->external_port);
1573 mapping->fib_index = sm->outside_fib_index;
1576 if (PREDICT_FALSE(is_addr_only != 0))
1577 *is_addr_only = m->addr_only;
1582 static_always_inline u16
1583 snat_random_port (u16 min, u16 max)
1585 snat_main_t *sm = &snat_main;
1586 return min + random_u32 (&sm->random_seed) /
1587 (random_u32_max() / (max - min + 1) + 1);
1590 int snat_alloc_outside_address_and_port (snat_address_t * addresses,
1593 snat_session_key_t * k,
1594 u32 * address_indexp,
1596 u16 port_per_thread,
1597 u32 snat_thread_index)
1603 for (i = 0; i < vec_len (addresses); i++)
1606 if (vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
1608 switch (k->protocol)
1610 #define _(N, j, n, s) \
1611 case SNAT_PROTOCOL_##N: \
1612 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1616 portnum = (port_per_thread * \
1617 snat_thread_index) + \
1618 snat_random_port(1, port_per_thread) + 1024; \
1619 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1621 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1622 a->busy_##n##_ports_per_thread[thread_index]++; \
1623 a->busy_##n##_ports++; \
1624 k->addr = a->addr; \
1625 k->port = clib_host_to_net_u16(portnum); \
1626 *address_indexp = i; \
1631 foreach_snat_protocol
1634 clib_warning("unknown protocol");
1639 /* Totally out of translations to use... */
1640 snat_ipfix_logging_addresses_exhausted(0);
1645 static clib_error_t *
1646 add_address_command_fn (vlib_main_t * vm,
1647 unformat_input_t * input,
1648 vlib_cli_command_t * cmd)
1650 unformat_input_t _line_input, *line_input = &_line_input;
1651 snat_main_t * sm = &snat_main;
1652 ip4_address_t start_addr, end_addr, this_addr;
1653 u32 start_host_order, end_host_order;
1658 clib_error_t *error = 0;
1660 /* Get a line of input. */
1661 if (!unformat_user (input, unformat_line_input, line_input))
1664 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1666 if (unformat (line_input, "%U - %U",
1667 unformat_ip4_address, &start_addr,
1668 unformat_ip4_address, &end_addr))
1670 else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
1672 else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1673 end_addr = start_addr;
1674 else if (unformat (line_input, "del"))
1678 error = clib_error_return (0, "unknown input '%U'",
1679 format_unformat_error, line_input);
1684 if (sm->static_mapping_only)
1686 error = clib_error_return (0, "static mapping only mode");
1690 start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1691 end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1693 if (end_host_order < start_host_order)
1695 error = clib_error_return (0, "end address less than start address");
1699 count = (end_host_order - start_host_order) + 1;
1702 clib_warning ("%U - %U, %d addresses...",
1703 format_ip4_address, &start_addr,
1704 format_ip4_address, &end_addr,
1707 this_addr = start_addr;
1709 for (i = 0; i < count; i++)
1712 snat_add_address (sm, &this_addr, vrf_id);
1714 rv = snat_del_address (sm, this_addr, 0);
1718 case VNET_API_ERROR_NO_SUCH_ENTRY:
1719 error = clib_error_return (0, "S-NAT address not exist.");
1721 case VNET_API_ERROR_UNSPECIFIED:
1722 error = clib_error_return (0, "S-NAT address used in static mapping.");
1728 increment_v4_address (&this_addr);
1732 unformat_free (line_input);
1737 VLIB_CLI_COMMAND (add_address_command, static) = {
1738 .path = "nat44 add address",
1739 .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1740 "[tenant-vrf <vrf-id>] [del]",
1741 .function = add_address_command_fn,
1744 static clib_error_t *
1745 snat_feature_command_fn (vlib_main_t * vm,
1746 unformat_input_t * input,
1747 vlib_cli_command_t * cmd)
1749 unformat_input_t _line_input, *line_input = &_line_input;
1750 vnet_main_t * vnm = vnet_get_main();
1751 clib_error_t * error = 0;
1753 u32 * inside_sw_if_indices = 0;
1754 u32 * outside_sw_if_indices = 0;
1755 u8 is_output_feature = 0;
1761 /* Get a line of input. */
1762 if (!unformat_user (input, unformat_line_input, line_input))
1765 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1767 if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1769 vec_add1 (inside_sw_if_indices, sw_if_index);
1770 else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1772 vec_add1 (outside_sw_if_indices, sw_if_index);
1773 else if (unformat (line_input, "output-feature"))
1774 is_output_feature = 1;
1775 else if (unformat (line_input, "del"))
1779 error = clib_error_return (0, "unknown input '%U'",
1780 format_unformat_error, line_input);
1785 if (vec_len (inside_sw_if_indices))
1787 for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1789 sw_if_index = inside_sw_if_indices[i];
1790 if (is_output_feature)
1792 if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
1794 error = clib_error_return (0, "%s %U failed",
1795 is_del ? "del" : "add",
1796 format_vnet_sw_interface_name, vnm,
1797 vnet_get_sw_interface (vnm,
1804 if (snat_interface_add_del (sw_if_index, 1, is_del))
1806 error = clib_error_return (0, "%s %U failed",
1807 is_del ? "del" : "add",
1808 format_vnet_sw_interface_name, vnm,
1809 vnet_get_sw_interface (vnm,
1817 if (vec_len (outside_sw_if_indices))
1819 for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1821 sw_if_index = outside_sw_if_indices[i];
1822 if (is_output_feature)
1824 if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
1826 error = clib_error_return (0, "%s %U failed",
1827 is_del ? "del" : "add",
1828 format_vnet_sw_interface_name, vnm,
1829 vnet_get_sw_interface (vnm,
1836 if (snat_interface_add_del (sw_if_index, 0, is_del))
1838 error = clib_error_return (0, "%s %U failed",
1839 is_del ? "del" : "add",
1840 format_vnet_sw_interface_name, vnm,
1841 vnet_get_sw_interface (vnm,
1850 unformat_free (line_input);
1851 vec_free (inside_sw_if_indices);
1852 vec_free (outside_sw_if_indices);
1857 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1858 .path = "set interface nat44",
1859 .function = snat_feature_command_fn,
1860 .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1865 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1867 u32 *r = va_arg (*args, u32 *);
1870 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1871 foreach_snat_protocol
1879 format_snat_protocol (u8 * s, va_list * args)
1881 u32 i = va_arg (*args, u32);
1886 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1887 foreach_snat_protocol
1890 s = format (s, "unknown");
1893 s = format (s, "%s", t);
1897 static clib_error_t *
1898 add_static_mapping_command_fn (vlib_main_t * vm,
1899 unformat_input_t * input,
1900 vlib_cli_command_t * cmd)
1902 unformat_input_t _line_input, *line_input = &_line_input;
1903 clib_error_t * error = 0;
1904 ip4_address_t l_addr, e_addr;
1905 u32 l_port = 0, e_port = 0, vrf_id = ~0;
1908 u32 sw_if_index = ~0;
1909 vnet_main_t * vnm = vnet_get_main();
1911 snat_protocol_t proto;
1914 /* Get a line of input. */
1915 if (!unformat_user (input, unformat_line_input, line_input))
1918 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1920 if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1923 else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1925 else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1928 else if (unformat (line_input, "external %U", unformat_ip4_address,
1931 else if (unformat (line_input, "external %U %u",
1932 unformat_vnet_sw_interface, vnm, &sw_if_index,
1936 else if (unformat (line_input, "external %U",
1937 unformat_vnet_sw_interface, vnm, &sw_if_index))
1939 else if (unformat (line_input, "vrf %u", &vrf_id))
1941 else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1943 else if (unformat (line_input, "del"))
1947 error = clib_error_return (0, "unknown input: '%U'",
1948 format_unformat_error, line_input);
1953 if (!addr_only && !proto_set)
1955 error = clib_error_return (0, "missing protocol");
1959 rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1960 vrf_id, addr_only, sw_if_index, proto, is_add);
1964 case VNET_API_ERROR_INVALID_VALUE:
1965 error = clib_error_return (0, "External port already in use.");
1967 case VNET_API_ERROR_NO_SUCH_ENTRY:
1969 error = clib_error_return (0, "External addres must be allocated.");
1971 error = clib_error_return (0, "Mapping not exist.");
1973 case VNET_API_ERROR_NO_SUCH_FIB:
1974 error = clib_error_return (0, "No such VRF id.");
1976 case VNET_API_ERROR_VALUE_EXIST:
1977 error = clib_error_return (0, "Mapping already exist.");
1984 unformat_free (line_input);
1991 * @cliexstart{snat add static mapping}
1992 * Static mapping allows hosts on the external network to initiate connection
1993 * to to the local network host.
1994 * To create static mapping between local host address 10.0.0.3 port 6303 and
1995 * external address 4.4.4.4 port 3606 for TCP protocol use:
1996 * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1997 * If not runnig "static mapping only" NAT plugin mode use before:
1998 * vpp# nat44 add address 4.4.4.4
1999 * To create static mapping between local and external address use:
2000 * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2003 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2004 .path = "nat44 add static mapping",
2005 .function = add_static_mapping_command_fn,
2007 "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
2010 static clib_error_t *
2011 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2012 unformat_input_t * input,
2013 vlib_cli_command_t * cmd)
2015 unformat_input_t _line_input, *line_input = &_line_input;
2016 clib_error_t * error = 0;
2017 ip4_address_t l_addr, e_addr;
2018 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2021 snat_protocol_t proto;
2023 nat44_lb_addr_port_t *locals = 0, local;
2025 /* Get a line of input. */
2026 if (!unformat_user (input, unformat_line_input, line_input))
2029 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2031 if (unformat (line_input, "local %U:%u probability %u",
2032 unformat_ip4_address, &l_addr, &l_port, &probability))
2034 memset (&local, 0, sizeof (local));
2035 local.addr = l_addr;
2036 local.port = (u16) l_port;
2037 local.probability = (u8) probability;
2038 vec_add1 (locals, local);
2040 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2043 else if (unformat (line_input, "vrf %u", &vrf_id))
2045 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2048 else if (unformat (line_input, "del"))
2052 error = clib_error_return (0, "unknown input: '%U'",
2053 format_unformat_error, line_input);
2058 if (vec_len (locals) < 2)
2060 error = clib_error_return (0, "at least two local must be set");
2066 error = clib_error_return (0, "missing protocol");
2070 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2075 case VNET_API_ERROR_INVALID_VALUE:
2076 error = clib_error_return (0, "External port already in use.");
2078 case VNET_API_ERROR_NO_SUCH_ENTRY:
2080 error = clib_error_return (0, "External addres must be allocated.");
2082 error = clib_error_return (0, "Mapping not exist.");
2084 case VNET_API_ERROR_VALUE_EXIST:
2085 error = clib_error_return (0, "Mapping already exist.");
2092 unformat_free (line_input);
2098 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2099 .path = "nat44 add load-balancing static mapping",
2100 .function = add_lb_static_mapping_command_fn,
2102 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
2105 static clib_error_t *
2106 set_workers_command_fn (vlib_main_t * vm,
2107 unformat_input_t * input,
2108 vlib_cli_command_t * cmd)
2110 unformat_input_t _line_input, *line_input = &_line_input;
2113 clib_error_t *error = 0;
2115 /* Get a line of input. */
2116 if (!unformat_user (input, unformat_line_input, line_input))
2119 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2121 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2125 error = clib_error_return (0, "unknown input '%U'",
2126 format_unformat_error, line_input);
2133 error = clib_error_return (0, "List of workers must be specified.");
2137 rv = snat_set_workers(bitmap);
2139 clib_bitmap_free (bitmap);
2143 case VNET_API_ERROR_INVALID_WORKER:
2144 error = clib_error_return (0, "Invalid worker(s).");
2146 case VNET_API_ERROR_FEATURE_DISABLED:
2147 error = clib_error_return (0,
2148 "Supported only if 2 or more workes available.");
2155 unformat_free (line_input);
2162 * @cliexstart{set snat workers}
2163 * Set NAT workers if 2 or more workers available, use:
2164 * vpp# set snat workers 0-2,5
2167 VLIB_CLI_COMMAND (set_workers_command, static) = {
2168 .path = "set nat workers",
2169 .function = set_workers_command_fn,
2171 "set nat workers <workers-list>",
2174 static clib_error_t *
2175 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2176 unformat_input_t * input,
2177 vlib_cli_command_t * cmd)
2179 unformat_input_t _line_input, *line_input = &_line_input;
2184 clib_error_t *error = 0;
2186 /* Get a line of input. */
2187 if (!unformat_user (input, unformat_line_input, line_input))
2190 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2192 if (unformat (line_input, "domain %d", &domain_id))
2194 else if (unformat (line_input, "src-port %d", &src_port))
2196 else if (unformat (line_input, "disable"))
2200 error = clib_error_return (0, "unknown input '%U'",
2201 format_unformat_error, line_input);
2206 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2210 error = clib_error_return (0, "ipfix logging enable failed");
2215 unformat_free (line_input);
2222 * @cliexstart{snat ipfix logging}
2223 * To enable NAT IPFIX logging use:
2224 * vpp# nat ipfix logging
2225 * To set IPFIX exporter use:
2226 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2229 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2230 .path = "nat ipfix logging",
2231 .function = snat_ipfix_logging_enable_disable_command_fn,
2232 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2236 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2238 snat_main_t *sm = &snat_main;
2239 u32 next_worker_index = 0;
2242 next_worker_index = sm->first_worker_index;
2243 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2244 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2246 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2247 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2249 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2251 return next_worker_index;
2255 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2257 snat_main_t *sm = &snat_main;
2260 snat_session_key_t m_key;
2261 clib_bihash_kv_8_8_t kv, value;
2262 snat_static_mapping_t *m;
2263 nat_ed_ses_key_t key;
2264 clib_bihash_kv_16_8_t s_kv, s_value;
2265 snat_main_per_thread_data_t *tsm;
2270 /* first try static mappings without port */
2271 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2273 m_key.addr = ip0->dst_address;
2276 m_key.fib_index = rx_fib_index0;
2277 kv.key = m_key.as_u64;
2278 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2280 m = pool_elt_at_index (sm->static_mappings, value.value);
2281 return m->worker_index;
2285 proto = ip_proto_to_snat_proto (ip0->protocol);
2286 udp = ip4_next_header (ip0);
2287 port = udp->dst_port;
2289 /* unknown protocol */
2290 if (PREDICT_FALSE (proto == ~0))
2292 key.l_addr = ip0->dst_address;
2293 key.r_addr = ip0->src_address;
2294 key.fib_index = rx_fib_index0;
2295 key.proto = ip0->protocol;
2298 s_kv.key[0] = key.as_u64[0];
2299 s_kv.key[1] = key.as_u64[1];
2301 if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2303 for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2305 tsm = vec_elt_at_index (sm->per_thread_data, i);
2306 if (!pool_is_free_index(tsm->sessions, s_value.value))
2308 s = pool_elt_at_index (tsm->sessions, s_value.value);
2309 if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2310 s->out2in.port == ip0->protocol &&
2311 snat_is_unk_proto_session (s))
2317 /* if no session use current thread */
2318 return vlib_get_thread_index ();
2321 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2323 icmp46_header_t * icmp = (icmp46_header_t *) udp;
2324 icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2325 if (!icmp_is_error_message (icmp))
2326 port = echo->identifier;
2329 ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2330 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2331 void *l4_header = ip4_next_header (inner_ip);
2334 case SNAT_PROTOCOL_ICMP:
2335 icmp = (icmp46_header_t*)l4_header;
2336 echo = (icmp_echo_header_t *)(icmp + 1);
2337 port = echo->identifier;
2339 case SNAT_PROTOCOL_UDP:
2340 case SNAT_PROTOCOL_TCP:
2341 port = ((tcp_udp_header_t*)l4_header)->src_port;
2344 return vlib_get_thread_index ();
2349 /* try static mappings with port */
2350 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2352 m_key.addr = ip0->dst_address;
2353 m_key.port = clib_net_to_host_u16 (port);
2354 m_key.protocol = proto;
2355 m_key.fib_index = rx_fib_index0;
2356 kv.key = m_key.as_u64;
2357 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2359 m = pool_elt_at_index (sm->static_mappings, value.value);
2360 return m->worker_index;
2364 /* worker by outside port */
2365 return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2368 static clib_error_t *
2369 snat_config (vlib_main_t * vm, unformat_input_t * input)
2371 snat_main_t * sm = &snat_main;
2372 u32 translation_buckets = 1024;
2373 u32 translation_memory_size = 128<<20;
2374 u32 user_buckets = 128;
2375 u32 user_memory_size = 64<<20;
2376 u32 max_translations_per_user = 100;
2377 u32 outside_vrf_id = 0;
2378 u32 inside_vrf_id = 0;
2379 u32 static_mapping_buckets = 1024;
2380 u32 static_mapping_memory_size = 64<<20;
2381 u8 static_mapping_only = 0;
2382 u8 static_mapping_connection_tracking = 0;
2383 snat_main_per_thread_data_t *tsm;
2385 sm->deterministic = 0;
2387 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2389 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2391 else if (unformat (input, "translation hash memory %d",
2392 &translation_memory_size));
2393 else if (unformat (input, "user hash buckets %d", &user_buckets))
2395 else if (unformat (input, "user hash memory %d",
2398 else if (unformat (input, "max translations per user %d",
2399 &max_translations_per_user))
2401 else if (unformat (input, "outside VRF id %d",
2404 else if (unformat (input, "inside VRF id %d",
2407 else if (unformat (input, "static mapping only"))
2409 static_mapping_only = 1;
2410 if (unformat (input, "connection tracking"))
2411 static_mapping_connection_tracking = 1;
2413 else if (unformat (input, "deterministic"))
2414 sm->deterministic = 1;
2416 return clib_error_return (0, "unknown input '%U'",
2417 format_unformat_error, input);
2420 /* for show commands, etc. */
2421 sm->translation_buckets = translation_buckets;
2422 sm->translation_memory_size = translation_memory_size;
2423 /* do not exceed load factor 10 */
2424 sm->max_translations = 10 * translation_buckets;
2425 sm->user_buckets = user_buckets;
2426 sm->user_memory_size = user_memory_size;
2427 sm->max_translations_per_user = max_translations_per_user;
2428 sm->outside_vrf_id = outside_vrf_id;
2429 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2431 FIB_SOURCE_PLUGIN_HI);
2432 sm->inside_vrf_id = inside_vrf_id;
2433 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2435 FIB_SOURCE_PLUGIN_HI);
2436 sm->static_mapping_only = static_mapping_only;
2437 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2439 if (sm->deterministic)
2441 sm->in2out_node_index = snat_det_in2out_node.index;
2442 sm->in2out_output_node_index = ~0;
2443 sm->out2in_node_index = snat_det_out2in_node.index;
2444 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2445 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2449 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2450 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2451 sm->in2out_node_index = snat_in2out_node.index;
2452 sm->in2out_output_node_index = snat_in2out_output_node.index;
2453 sm->out2in_node_index = snat_out2in_node.index;
2454 if (!static_mapping_only ||
2455 (static_mapping_only && static_mapping_connection_tracking))
2457 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2458 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2460 vec_foreach (tsm, sm->per_thread_data)
2462 clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2463 translation_memory_size);
2465 clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2466 translation_memory_size);
2468 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2472 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2473 translation_buckets, translation_memory_size);
2475 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2476 translation_buckets, translation_memory_size);
2480 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2481 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2483 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2484 "static_mapping_by_local", static_mapping_buckets,
2485 static_mapping_memory_size);
2487 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2488 "static_mapping_by_external", static_mapping_buckets,
2489 static_mapping_memory_size);
2495 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2497 u8 * format_snat_session_state (u8 * s, va_list * args)
2499 u32 i = va_arg (*args, u32);
2504 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2505 foreach_snat_session_state
2508 t = format (t, "unknown");
2510 s = format (s, "%s", t);
2514 u8 * format_snat_key (u8 * s, va_list * args)
2516 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2518 s = format (s, "%U proto %U port %d fib %d",
2519 format_ip4_address, &key->addr,
2520 format_snat_protocol, key->protocol,
2521 clib_net_to_host_u16 (key->port), key->fib_index);
2525 u8 * format_snat_session (u8 * s, va_list * args)
2527 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2528 snat_session_t * sess = va_arg (*args, snat_session_t *);
2530 if (snat_is_unk_proto_session (sess))
2532 s = format (s, " i2o %U proto %u fib %u\n",
2533 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2534 sess->in2out.fib_index);
2535 s = format (s, " o2i %U proto %u fib %u\n",
2536 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2537 sess->out2in.fib_index);
2541 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2542 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2544 if (sess->ext_host_addr.as_u32)
2545 s = format (s, " external host %U\n",
2546 format_ip4_address, &sess->ext_host_addr);
2547 s = format (s, " last heard %.2f\n", sess->last_heard);
2548 s = format (s, " total pkts %d, total bytes %lld\n",
2549 sess->total_pkts, sess->total_bytes);
2550 if (snat_is_session_static (sess))
2551 s = format (s, " static translation\n");
2553 s = format (s, " dynamic translation\n");
2554 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2555 s = format (s, " load-balancing\n");
2560 u8 * format_snat_user (u8 * s, va_list * args)
2562 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2563 snat_user_t * u = va_arg (*args, snat_user_t *);
2564 int verbose = va_arg (*args, int);
2565 dlist_elt_t * head, * elt;
2566 u32 elt_index, head_index;
2568 snat_session_t * sess;
2570 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2571 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2576 if (u->nsessions || u->nstaticsessions)
2578 head_index = u->sessions_per_user_list_head_index;
2579 head = pool_elt_at_index (sm->list_pool, head_index);
2581 elt_index = head->next;
2582 elt = pool_elt_at_index (sm->list_pool, elt_index);
2583 session_index = elt->value;
2585 while (session_index != ~0)
2587 sess = pool_elt_at_index (sm->sessions, session_index);
2589 s = format (s, " %U\n", format_snat_session, sm, sess);
2591 elt_index = elt->next;
2592 elt = pool_elt_at_index (sm->list_pool, elt_index);
2593 session_index = elt->value;
2600 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2602 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2603 nat44_lb_addr_port_t *local;
2606 s = format (s, "local %U external %U vrf %d",
2607 format_ip4_address, &m->local_addr,
2608 format_ip4_address, &m->external_addr,
2612 if (vec_len (m->locals))
2614 s = format (s, "%U vrf %d external %U:%d",
2615 format_snat_protocol, m->proto,
2617 format_ip4_address, &m->external_addr, m->external_port);
2618 vec_foreach (local, m->locals)
2619 s = format (s, "\n local %U:%d probability %d\%",
2620 format_ip4_address, &local->addr, local->port,
2621 local->probability);
2624 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2625 format_snat_protocol, m->proto,
2626 format_ip4_address, &m->local_addr, m->local_port,
2627 format_ip4_address, &m->external_addr, m->external_port,
2633 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2635 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2636 vnet_main_t *vnm = vnet_get_main();
2639 s = format (s, "local %U external %U vrf %d",
2640 format_ip4_address, &m->l_addr,
2641 format_vnet_sw_interface_name, vnm,
2642 vnet_get_sw_interface (vnm, m->sw_if_index),
2645 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2646 format_snat_protocol, m->proto,
2647 format_ip4_address, &m->l_addr, m->l_port,
2648 format_vnet_sw_interface_name, vnm,
2649 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2655 u8 * format_det_map_ses (u8 * s, va_list * args)
2657 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2658 ip4_address_t in_addr, out_addr;
2659 u32 in_offset, out_offset;
2660 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2661 u32 * i = va_arg (*args, u32 *);
2663 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2664 in_addr.as_u32 = clib_host_to_net_u32 (
2665 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2666 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2667 clib_net_to_host_u32(det_map->in_addr.as_u32);
2668 out_offset = in_offset / det_map->sharing_ratio;
2669 out_addr.as_u32 = clib_host_to_net_u32(
2670 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2671 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2672 format_ip4_address, &in_addr,
2673 clib_net_to_host_u16 (ses->in_port),
2674 format_ip4_address, &out_addr,
2675 clib_net_to_host_u16 (ses->out.out_port),
2676 format_ip4_address, &ses->out.ext_host_addr,
2677 clib_net_to_host_u16 (ses->out.ext_host_port),
2678 format_snat_session_state, ses->state,
2684 static clib_error_t *
2685 show_snat_command_fn (vlib_main_t * vm,
2686 unformat_input_t * input,
2687 vlib_cli_command_t * cmd)
2690 snat_main_t * sm = &snat_main;
2692 snat_static_mapping_t *m;
2693 snat_interface_t *i;
2694 snat_address_t * ap;
2695 vnet_main_t *vnm = vnet_get_main();
2696 snat_main_per_thread_data_t *tsm;
2697 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2699 snat_static_map_resolve_t *rp;
2700 snat_det_map_t * dm;
2701 snat_det_session_t * ses;
2703 if (unformat (input, "detail"))
2705 else if (unformat (input, "verbose"))
2708 if (sm->static_mapping_only)
2710 if (sm->static_mapping_connection_tracking)
2711 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2714 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2716 else if (sm->deterministic)
2718 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2722 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2727 pool_foreach (i, sm->interfaces,
2729 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2730 vnet_get_sw_interface (vnm, i->sw_if_index),
2731 (nat_interface_is_inside(i) &&
2732 nat_interface_is_outside(i)) ? "in out" :
2733 (nat_interface_is_inside(i) ? "in" : "out"));
2736 pool_foreach (i, sm->output_feature_interfaces,
2738 vlib_cli_output (vm, "%U output-feature %s",
2739 format_vnet_sw_interface_name, vnm,
2740 vnet_get_sw_interface (vnm, i->sw_if_index),
2741 (nat_interface_is_inside(i) &&
2742 nat_interface_is_outside(i)) ? "in out" :
2743 (nat_interface_is_inside(i) ? "in" : "out"));
2746 if (vec_len (sm->auto_add_sw_if_indices))
2748 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2749 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2751 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2752 vnet_get_sw_interface (vnm, *sw_if_index));
2756 vec_foreach (ap, sm->addresses)
2758 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2759 if (ap->fib_index != ~0)
2760 vlib_cli_output (vm, " tenant VRF: %u",
2761 ip4_fib_get(ap->fib_index)->table_id);
2763 vlib_cli_output (vm, " tenant VRF independent");
2764 #define _(N, i, n, s) \
2765 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2766 foreach_snat_protocol
2771 if (sm->num_workers > 1)
2773 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2776 vec_foreach (worker, sm->workers)
2778 vlib_worker_thread_t *w =
2779 vlib_worker_threads + *worker + sm->first_worker_index;
2780 vlib_cli_output (vm, " %s", w->name);
2785 if (sm->deterministic)
2787 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2788 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2789 sm->tcp_established_timeout);
2790 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2791 sm->tcp_transitory_timeout);
2792 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2793 vlib_cli_output (vm, "%d deterministic mappings",
2794 pool_elts (sm->det_maps));
2797 pool_foreach (dm, sm->det_maps,
2799 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2800 format_ip4_address, &dm->in_addr, dm->in_plen,
2801 format_ip4_address, &dm->out_addr, dm->out_plen);
2802 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2804 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2805 dm->ports_per_host);
2806 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2809 vec_foreach_index (j, dm->sessions)
2811 ses = vec_elt_at_index (dm->sessions, j);
2813 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2822 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2824 vlib_cli_output (vm, "%d static mappings",
2825 pool_elts (sm->static_mappings));
2829 pool_foreach (m, sm->static_mappings,
2831 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2837 vec_foreach (tsm, sm->per_thread_data)
2839 users_num += pool_elts (tsm->users);
2840 sessions_num += pool_elts (tsm->sessions);
2843 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2844 " %d static mappings",
2846 vec_len (sm->addresses),
2848 pool_elts (sm->static_mappings));
2852 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
2854 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
2856 vec_foreach_index (j, sm->per_thread_data)
2858 tsm = vec_elt_at_index (sm->per_thread_data, j);
2860 if (pool_elts (tsm->users) == 0)
2863 vlib_worker_thread_t *w = vlib_worker_threads + j;
2864 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2866 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
2868 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
2870 vlib_cli_output (vm, " %d list pool elements",
2871 pool_elts (tsm->list_pool));
2873 pool_foreach (u, tsm->users,
2875 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
2880 if (pool_elts (sm->static_mappings))
2882 vlib_cli_output (vm, "static mappings:");
2883 pool_foreach (m, sm->static_mappings,
2885 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2887 for (j = 0; j < vec_len (sm->to_resolve); j++)
2889 rp = sm->to_resolve + j;
2890 vlib_cli_output (vm, "%U",
2891 format_snat_static_map_to_resolve, rp);
2901 VLIB_CLI_COMMAND (show_snat_command, static) = {
2902 .path = "show nat44",
2903 .short_help = "show nat44",
2904 .function = show_snat_command_fn,
2909 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2912 ip4_address_t * address,
2914 u32 if_address_index,
2917 snat_main_t *sm = &snat_main;
2918 snat_static_map_resolve_t *rp;
2919 u32 *indices_to_delete = 0;
2923 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2925 if (sw_if_index == sm->auto_add_sw_if_indices[i])
2929 /* Don't trip over lease renewal, static config */
2930 for (j = 0; j < vec_len(sm->addresses); j++)
2931 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2934 snat_add_address (sm, address, ~0);
2935 /* Scan static map resolution vector */
2936 for (j = 0; j < vec_len (sm->to_resolve); j++)
2938 rp = sm->to_resolve + j;
2939 /* On this interface? */
2940 if (rp->sw_if_index == sw_if_index)
2942 /* Add the static mapping */
2943 rv = snat_add_static_mapping (rp->l_addr,
2949 ~0 /* sw_if_index */,
2953 clib_warning ("snat_add_static_mapping returned %d",
2955 vec_add1 (indices_to_delete, j);
2958 /* If we resolved any of the outstanding static mappings */
2959 if (vec_len(indices_to_delete))
2962 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2963 vec_delete(sm->to_resolve, 1, j);
2964 vec_free(indices_to_delete);
2970 (void) snat_del_address(sm, address[0], 1);
2978 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
2980 ip4_main_t * ip4_main = sm->ip4_main;
2981 ip4_address_t * first_int_addr;
2982 snat_static_map_resolve_t *rp;
2983 u32 *indices_to_delete = 0;
2986 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2987 0 /* just want the address*/);
2989 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2991 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2995 /* if have address remove it */
2997 (void) snat_del_address (sm, first_int_addr[0], 1);
3000 for (j = 0; j < vec_len (sm->to_resolve); j++)
3002 rp = sm->to_resolve + j;
3003 if (rp->sw_if_index == sw_if_index)
3004 vec_add1 (indices_to_delete, j);
3006 if (vec_len(indices_to_delete))
3008 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3009 vec_del1(sm->to_resolve, j);
3010 vec_free(indices_to_delete);
3013 vec_del1(sm->auto_add_sw_if_indices, i);
3016 return VNET_API_ERROR_VALUE_EXIST;
3023 return VNET_API_ERROR_NO_SUCH_ENTRY;
3025 /* add to the auto-address list */
3026 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3028 /* If the address is already bound - or static - add it now */
3030 snat_add_address (sm, first_int_addr, ~0);
3035 static clib_error_t *
3036 snat_add_interface_address_command_fn (vlib_main_t * vm,
3037 unformat_input_t * input,
3038 vlib_cli_command_t * cmd)
3040 snat_main_t *sm = &snat_main;
3041 unformat_input_t _line_input, *line_input = &_line_input;
3045 clib_error_t *error = 0;
3047 /* Get a line of input. */
3048 if (!unformat_user (input, unformat_line_input, line_input))
3051 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3053 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3054 sm->vnet_main, &sw_if_index))
3056 else if (unformat (line_input, "del"))
3060 error = clib_error_return (0, "unknown input '%U'",
3061 format_unformat_error, line_input);
3066 rv = snat_add_interface_address (sm, sw_if_index, is_del);
3074 error = clib_error_return (0, "snat_add_interface_address returned %d",
3080 unformat_free (line_input);
3085 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3086 .path = "nat44 add interface address",
3087 .short_help = "nat44 add interface address <interface> [del]",
3088 .function = snat_add_interface_address_command_fn,
3092 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3093 snat_protocol_t proto, u32 vrf_id, int is_in)
3095 snat_main_per_thread_data_t *tsm;
3096 clib_bihash_kv_8_8_t kv, value;
3098 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3099 snat_session_key_t key;
3101 clib_bihash_8_8_t *t;
3102 snat_user_key_t u_key;
3105 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3106 if (sm->num_workers)
3108 vec_elt_at_index (sm->per_thread_data,
3109 sm->worker_in2out_cb (&ip, fib_index));
3111 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3113 key.addr.as_u32 = addr->as_u32;
3114 key.port = clib_host_to_net_u16 (port);
3115 key.protocol = proto;
3116 key.fib_index = fib_index;
3117 kv.key = key.as_u64;
3118 t = is_in ? &tsm->in2out : &tsm->out2in;
3119 if (!clib_bihash_search_8_8 (t, &kv, &value))
3121 s = pool_elt_at_index (tsm->sessions, value.value);
3122 kv.key = s->in2out.as_u64;
3123 clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3124 kv.key = s->out2in.as_u64;
3125 clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3126 u_key.addr = s->in2out.addr;
3127 u_key.fib_index = s->in2out.fib_index;
3128 kv.key = u_key.as_u64;
3129 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3131 u = pool_elt_at_index (tsm->users, value.value);
3134 clib_dlist_remove (tsm->list_pool, s->per_user_index);
3135 pool_put (tsm->sessions, s);
3139 return VNET_API_ERROR_NO_SUCH_ENTRY;
3142 static clib_error_t *
3143 nat44_del_session_command_fn (vlib_main_t * vm,
3144 unformat_input_t * input,
3145 vlib_cli_command_t * cmd)
3147 snat_main_t *sm = &snat_main;
3148 unformat_input_t _line_input, *line_input = &_line_input;
3150 clib_error_t *error = 0;
3152 u32 port = 0, vrf_id = sm->outside_vrf_id;
3153 snat_protocol_t proto;
3156 /* Get a line of input. */
3157 if (!unformat_user (input, unformat_line_input, line_input))
3160 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3162 if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3163 unformat_snat_protocol, &proto))
3165 else if (unformat (line_input, "in"))
3168 vrf_id = sm->inside_vrf_id;
3170 else if (unformat (line_input, "vrf %u", &vrf_id))
3174 error = clib_error_return (0, "unknown input '%U'",
3175 format_unformat_error, line_input);
3180 rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3188 error = clib_error_return (0, "nat44_del_session returned %d", rv);
3193 unformat_free (line_input);
3198 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3199 .path = "nat44 del session",
3200 .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3201 .function = nat44_del_session_command_fn,
3204 static clib_error_t *
3205 snat_det_map_command_fn (vlib_main_t * vm,
3206 unformat_input_t * input,
3207 vlib_cli_command_t * cmd)
3209 snat_main_t *sm = &snat_main;
3210 unformat_input_t _line_input, *line_input = &_line_input;
3211 ip4_address_t in_addr, out_addr;
3212 u32 in_plen, out_plen;
3214 clib_error_t *error = 0;
3216 /* Get a line of input. */
3217 if (!unformat_user (input, unformat_line_input, line_input))
3220 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3222 if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3224 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3226 else if (unformat (line_input, "del"))
3230 error = clib_error_return (0, "unknown input '%U'",
3231 format_unformat_error, line_input);
3236 unformat_free (line_input);
3238 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3243 error = clib_error_return (0, "snat_det_add_map return %d", rv);
3248 unformat_free (line_input);
3255 * @cliexstart{snat deterministic add}
3256 * Create bijective mapping of inside address to outside address and port range
3257 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3259 * To create deterministic mapping between inside network 10.0.0.0/18 and
3260 * outside network 1.1.1.0/30 use:
3261 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3264 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3265 .path = "nat44 deterministic add",
3266 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3267 .function = snat_det_map_command_fn,
3270 static clib_error_t *
3271 snat_det_forward_command_fn (vlib_main_t * vm,
3272 unformat_input_t * input,
3273 vlib_cli_command_t * cmd)
3275 snat_main_t *sm = &snat_main;
3276 unformat_input_t _line_input, *line_input = &_line_input;
3277 ip4_address_t in_addr, out_addr;
3279 snat_det_map_t * dm;
3280 clib_error_t *error = 0;
3282 /* Get a line of input. */
3283 if (!unformat_user (input, unformat_line_input, line_input))
3286 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3288 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3292 error = clib_error_return (0, "unknown input '%U'",
3293 format_unformat_error, line_input);
3298 unformat_free (line_input);
3300 dm = snat_det_map_by_user(sm, &in_addr);
3302 vlib_cli_output (vm, "no match");
3305 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3306 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3307 lo_port, lo_port + dm->ports_per_host - 1);
3311 unformat_free (line_input);
3318 * @cliexstart{snat deterministic forward}
3319 * Return outside address and port range from inside address for deterministic
3321 * To obtain outside address and port of inside host use:
3322 * vpp# nat44 deterministic forward 10.0.0.2
3323 * 1.1.1.0:<1054-1068>
3326 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3327 .path = "nat44 deterministic forward",
3328 .short_help = "nat44 deterministic forward <addr>",
3329 .function = snat_det_forward_command_fn,
3332 static clib_error_t *
3333 snat_det_reverse_command_fn (vlib_main_t * vm,
3334 unformat_input_t * input,
3335 vlib_cli_command_t * cmd)
3337 snat_main_t *sm = &snat_main;
3338 unformat_input_t _line_input, *line_input = &_line_input;
3339 ip4_address_t in_addr, out_addr;
3341 snat_det_map_t * dm;
3342 clib_error_t *error = 0;
3344 /* Get a line of input. */
3345 if (!unformat_user (input, unformat_line_input, line_input))
3348 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3350 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3354 error = clib_error_return (0, "unknown input '%U'",
3355 format_unformat_error, line_input);
3359 unformat_free (line_input);
3361 if (out_port < 1024 || out_port > 65535)
3363 error = clib_error_return (0, "wrong port, must be <1024-65535>");
3367 dm = snat_det_map_by_out(sm, &out_addr);
3369 vlib_cli_output (vm, "no match");
3372 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3373 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3377 unformat_free (line_input);
3384 * @cliexstart{snat deterministic reverse}
3385 * Return inside address from outside address and port for deterministic NAT.
3386 * To obtain inside host address from outside address and port use:
3387 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3391 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3392 .path = "nat44 deterministic reverse",
3393 .short_help = "nat44 deterministic reverse <addr>:<port>",
3394 .function = snat_det_reverse_command_fn,
3397 static clib_error_t *
3398 set_timeout_command_fn (vlib_main_t * vm,
3399 unformat_input_t * input,
3400 vlib_cli_command_t * cmd)
3402 snat_main_t *sm = &snat_main;
3403 unformat_input_t _line_input, *line_input = &_line_input;
3404 clib_error_t *error = 0;
3406 /* Get a line of input. */
3407 if (!unformat_user (input, unformat_line_input, line_input))
3410 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3412 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3414 else if (unformat (line_input, "tcp-established %u",
3415 &sm->tcp_established_timeout))
3417 else if (unformat (line_input, "tcp-transitory %u",
3418 &sm->tcp_transitory_timeout))
3420 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3422 else if (unformat (line_input, "reset"))
3424 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3425 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3426 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3427 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3431 error = clib_error_return (0, "unknown input '%U'",
3432 format_unformat_error, line_input);
3437 unformat_free (line_input);
3440 unformat_free (line_input);
3447 * @cliexstart{set snat deterministic timeout}
3448 * Set values of timeouts for deterministic NAT (in seconds), use:
3449 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3450 * tcp-transitory 250 icmp 90
3451 * To reset default values use:
3452 * vpp# set nat44 deterministic timeout reset
3455 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3456 .path = "set nat44 deterministic timeout",
3457 .function = set_timeout_command_fn,
3459 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3460 "tcp-transitory <sec> | icmp <sec> | reset]",
3463 static clib_error_t *
3464 snat_det_close_session_out_fn (vlib_main_t *vm,
3465 unformat_input_t * input,
3466 vlib_cli_command_t * cmd)
3468 snat_main_t *sm = &snat_main;
3469 unformat_input_t _line_input, *line_input = &_line_input;
3470 ip4_address_t out_addr, ext_addr, in_addr;
3471 u32 out_port, ext_port;
3472 snat_det_map_t * dm;
3473 snat_det_session_t * ses;
3474 snat_det_out_key_t key;
3475 clib_error_t *error = 0;
3477 /* Get a line of input. */
3478 if (!unformat_user (input, unformat_line_input, line_input))
3481 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3483 if (unformat (line_input, "%U:%d %U:%d",
3484 unformat_ip4_address, &out_addr, &out_port,
3485 unformat_ip4_address, &ext_addr, &ext_port))
3489 error = clib_error_return (0, "unknown input '%U'",
3490 format_unformat_error, line_input);
3495 unformat_free (line_input);
3497 dm = snat_det_map_by_out(sm, &out_addr);
3499 vlib_cli_output (vm, "no match");
3502 snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
3503 key.ext_host_addr = out_addr;
3504 key.ext_host_port = ntohs((u16)ext_port);
3505 key.out_port = ntohs((u16)out_port);
3506 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3508 vlib_cli_output (vm, "no match");
3510 snat_det_ses_close(dm, ses);
3514 unformat_free (line_input);
3521 * @cliexstart{snat deterministic close session out}
3522 * Close session using outside ip address and port
3523 * and external ip address and port, use:
3524 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3527 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3528 .path = "nat44 deterministic close session out",
3529 .short_help = "nat44 deterministic close session out "
3530 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3531 .function = snat_det_close_session_out_fn,
3534 static clib_error_t *
3535 snat_det_close_session_in_fn (vlib_main_t *vm,
3536 unformat_input_t * input,
3537 vlib_cli_command_t * cmd)
3539 snat_main_t *sm = &snat_main;
3540 unformat_input_t _line_input, *line_input = &_line_input;
3541 ip4_address_t in_addr, ext_addr;
3542 u32 in_port, ext_port;
3543 snat_det_map_t * dm;
3544 snat_det_session_t * ses;
3545 snat_det_out_key_t key;
3546 clib_error_t *error = 0;
3548 /* Get a line of input. */
3549 if (!unformat_user (input, unformat_line_input, line_input))
3552 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3554 if (unformat (line_input, "%U:%d %U:%d",
3555 unformat_ip4_address, &in_addr, &in_port,
3556 unformat_ip4_address, &ext_addr, &ext_port))
3560 error = clib_error_return (0, "unknown input '%U'",
3561 format_unformat_error, line_input);
3566 unformat_free (line_input);
3568 dm = snat_det_map_by_user (sm, &in_addr);
3570 vlib_cli_output (vm, "no match");
3573 key.ext_host_addr = ext_addr;
3574 key.ext_host_port = ntohs ((u16)ext_port);
3575 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
3577 vlib_cli_output (vm, "no match");
3579 snat_det_ses_close(dm, ses);
3583 unformat_free(line_input);
3590 * @cliexstart{snat deterministic close_session_in}
3591 * Close session using inside ip address and port
3592 * and external ip address and port, use:
3593 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3596 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3597 .path = "nat44 deterministic close session in",
3598 .short_help = "nat44 deterministic close session in "
3599 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3600 .function = snat_det_close_session_in_fn,