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,
1382 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1385 snat_session_key_t * k,
1386 u32 * address_indexp,
1388 u16 port_per_thread,
1389 u32 snat_thread_index);
1391 static clib_error_t * snat_init (vlib_main_t * vm)
1393 snat_main_t * sm = &snat_main;
1394 clib_error_t * error = 0;
1395 ip4_main_t * im = &ip4_main;
1396 ip_lookup_main_t * lm = &im->lookup_main;
1398 vlib_thread_registration_t *tr;
1399 vlib_thread_main_t *tm = vlib_get_thread_main ();
1402 ip4_add_del_interface_address_callback_t cb4;
1405 sm->vnet_main = vnet_get_main();
1407 sm->ip4_lookup_main = lm;
1408 sm->api_main = &api_main;
1409 sm->first_worker_index = 0;
1410 sm->next_worker = 0;
1411 sm->num_workers = 0;
1412 sm->num_snat_thread = 1;
1414 sm->port_per_thread = 0xffff - 1024;
1415 sm->fq_in2out_index = ~0;
1416 sm->fq_out2in_index = ~0;
1417 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1418 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1419 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1420 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1421 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1423 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1426 tr = (vlib_thread_registration_t *) p[0];
1429 sm->num_workers = tr->count;
1430 sm->first_worker_index = tr->first_index;
1434 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1436 /* Use all available workers by default */
1437 if (sm->num_workers > 1)
1439 for (i=0; i < sm->num_workers; i++)
1440 bitmap = clib_bitmap_set (bitmap, i, 1);
1441 snat_set_workers(bitmap);
1442 clib_bitmap_free (bitmap);
1446 sm->per_thread_data[0].snat_thread_index = 0;
1449 error = snat_api_init(vm, sm);
1453 /* Set up the interface address add/del callback */
1454 cb4.function = snat_ip4_add_del_interface_address_cb;
1455 cb4.function_opaque = 0;
1457 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1459 /* Init IPFIX logging */
1460 snat_ipfix_logging_init(vm);
1463 error = nat64_init(vm);
1469 /* Init virtual fragmenentation reassembly */
1470 return nat_reass_init(vm);
1473 VLIB_INIT_FUNCTION (snat_init);
1475 void snat_free_outside_address_and_port (snat_address_t * addresses,
1477 snat_session_key_t * k,
1481 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1483 ASSERT (address_index < vec_len (addresses));
1485 a = addresses + address_index;
1487 switch (k->protocol)
1489 #define _(N, i, n, s) \
1490 case SNAT_PROTOCOL_##N: \
1491 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1492 port_host_byte_order) == 1); \
1493 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1494 port_host_byte_order, 0); \
1495 a->busy_##n##_ports--; \
1496 a->busy_##n##_ports_per_thread[thread_index]--; \
1498 foreach_snat_protocol
1501 clib_warning("unknown_protocol");
1507 * @brief Match NAT44 static mapping.
1509 * @param sm NAT main.
1510 * @param match Address and port to match.
1511 * @param mapping External or local address and port of the matched mapping.
1512 * @param by_external If 0 match by local address otherwise match by external
1514 * @param is_addr_only If matched mapping is address only
1516 * @returns 0 if match found otherwise 1.
1518 int snat_static_mapping_match (snat_main_t * sm,
1519 snat_session_key_t match,
1520 snat_session_key_t * mapping,
1524 clib_bihash_kv_8_8_t kv, value;
1525 snat_static_mapping_t *m;
1526 snat_session_key_t m_key;
1527 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1528 u32 rand, lo = 0, hi, mid;
1531 mapping_hash = &sm->static_mapping_by_external;
1533 m_key.addr = match.addr;
1534 m_key.port = clib_net_to_host_u16 (match.port);
1535 m_key.protocol = match.protocol;
1536 m_key.fib_index = match.fib_index;
1538 kv.key = m_key.as_u64;
1540 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1542 /* Try address only mapping */
1545 kv.key = m_key.as_u64;
1546 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1550 m = pool_elt_at_index (sm->static_mappings, value.value);
1554 if (vec_len (m->locals))
1556 hi = vec_len (m->locals) - 1;
1557 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1560 mid = ((hi - lo) >> 1) + lo;
1561 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1563 if (!(m->locals[lo].prefix >= rand))
1565 mapping->addr = m->locals[lo].addr;
1566 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1570 mapping->addr = m->local_addr;
1571 /* Address only mapping doesn't change port */
1572 mapping->port = m->addr_only ? match.port
1573 : clib_host_to_net_u16 (m->local_port);
1575 mapping->fib_index = m->fib_index;
1576 mapping->protocol = m->proto;
1580 mapping->addr = m->external_addr;
1581 /* Address only mapping doesn't change port */
1582 mapping->port = m->addr_only ? match.port
1583 : clib_host_to_net_u16 (m->external_port);
1584 mapping->fib_index = sm->outside_fib_index;
1587 if (PREDICT_FALSE(is_addr_only != 0))
1588 *is_addr_only = m->addr_only;
1593 static_always_inline u16
1594 snat_random_port (u16 min, u16 max)
1596 snat_main_t *sm = &snat_main;
1597 return min + random_u32 (&sm->random_seed) /
1598 (random_u32_max() / (max - min + 1) + 1);
1602 snat_alloc_outside_address_and_port (snat_address_t * addresses,
1605 snat_session_key_t * k,
1606 u32 * address_indexp,
1608 u16 port_per_thread,
1609 u32 snat_thread_index)
1611 snat_main_t *sm = &snat_main;
1613 return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
1614 address_indexp, vrf_mode, port_per_thread,
1619 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1622 snat_session_key_t * k,
1623 u32 * address_indexp,
1625 u16 port_per_thread,
1626 u32 snat_thread_index)
1632 for (i = 0; i < vec_len (addresses); i++)
1635 if (vrf_mode && a->fib_index != ~0 && a->fib_index != fib_index)
1637 switch (k->protocol)
1639 #define _(N, j, n, s) \
1640 case SNAT_PROTOCOL_##N: \
1641 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1645 portnum = (port_per_thread * \
1646 snat_thread_index) + \
1647 snat_random_port(1, port_per_thread) + 1024; \
1648 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1650 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1651 a->busy_##n##_ports_per_thread[thread_index]++; \
1652 a->busy_##n##_ports++; \
1653 k->addr = a->addr; \
1654 k->port = clib_host_to_net_u16(portnum); \
1655 *address_indexp = i; \
1660 foreach_snat_protocol
1663 clib_warning("unknown protocol");
1668 /* Totally out of translations to use... */
1669 snat_ipfix_logging_addresses_exhausted(0);
1674 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
1677 snat_session_key_t * k,
1678 u32 * address_indexp,
1680 u16 port_per_thread,
1681 u32 snat_thread_index)
1683 snat_main_t *sm = &snat_main;
1684 snat_address_t *a = addresses;
1685 u16 m, ports, portnum, A, j;
1686 m = 16 - (sm->psid_offset + sm->psid_length);
1687 ports = (1 << (16 - sm->psid_length)) - (1 << m);
1689 if (!vec_len (addresses))
1692 switch (k->protocol)
1694 #define _(N, i, n, s) \
1695 case SNAT_PROTOCOL_##N: \
1696 if (a->busy_##n##_ports < ports) \
1700 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
1701 j = snat_random_port(0, pow2_mask(m)); \
1702 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
1703 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1705 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1706 a->busy_##n##_ports++; \
1707 k->addr = a->addr; \
1708 k->port = clib_host_to_net_u16 (portnum); \
1709 *address_indexp = i; \
1714 foreach_snat_protocol
1717 clib_warning("unknown protocol");
1722 /* Totally out of translations to use... */
1723 snat_ipfix_logging_addresses_exhausted(0);
1727 static clib_error_t *
1728 add_address_command_fn (vlib_main_t * vm,
1729 unformat_input_t * input,
1730 vlib_cli_command_t * cmd)
1732 unformat_input_t _line_input, *line_input = &_line_input;
1733 snat_main_t * sm = &snat_main;
1734 ip4_address_t start_addr, end_addr, this_addr;
1735 u32 start_host_order, end_host_order;
1740 clib_error_t *error = 0;
1742 /* Get a line of input. */
1743 if (!unformat_user (input, unformat_line_input, line_input))
1746 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1748 if (unformat (line_input, "%U - %U",
1749 unformat_ip4_address, &start_addr,
1750 unformat_ip4_address, &end_addr))
1752 else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
1754 else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1755 end_addr = start_addr;
1756 else if (unformat (line_input, "del"))
1760 error = clib_error_return (0, "unknown input '%U'",
1761 format_unformat_error, line_input);
1766 if (sm->static_mapping_only)
1768 error = clib_error_return (0, "static mapping only mode");
1772 start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1773 end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1775 if (end_host_order < start_host_order)
1777 error = clib_error_return (0, "end address less than start address");
1781 count = (end_host_order - start_host_order) + 1;
1784 clib_warning ("%U - %U, %d addresses...",
1785 format_ip4_address, &start_addr,
1786 format_ip4_address, &end_addr,
1789 this_addr = start_addr;
1791 for (i = 0; i < count; i++)
1794 snat_add_address (sm, &this_addr, vrf_id);
1796 rv = snat_del_address (sm, this_addr, 0);
1800 case VNET_API_ERROR_NO_SUCH_ENTRY:
1801 error = clib_error_return (0, "S-NAT address not exist.");
1803 case VNET_API_ERROR_UNSPECIFIED:
1804 error = clib_error_return (0, "S-NAT address used in static mapping.");
1810 increment_v4_address (&this_addr);
1814 unformat_free (line_input);
1819 VLIB_CLI_COMMAND (add_address_command, static) = {
1820 .path = "nat44 add address",
1821 .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1822 "[tenant-vrf <vrf-id>] [del]",
1823 .function = add_address_command_fn,
1826 static clib_error_t *
1827 snat_feature_command_fn (vlib_main_t * vm,
1828 unformat_input_t * input,
1829 vlib_cli_command_t * cmd)
1831 unformat_input_t _line_input, *line_input = &_line_input;
1832 vnet_main_t * vnm = vnet_get_main();
1833 clib_error_t * error = 0;
1835 u32 * inside_sw_if_indices = 0;
1836 u32 * outside_sw_if_indices = 0;
1837 u8 is_output_feature = 0;
1843 /* Get a line of input. */
1844 if (!unformat_user (input, unformat_line_input, line_input))
1847 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1849 if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1851 vec_add1 (inside_sw_if_indices, sw_if_index);
1852 else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1854 vec_add1 (outside_sw_if_indices, sw_if_index);
1855 else if (unformat (line_input, "output-feature"))
1856 is_output_feature = 1;
1857 else if (unformat (line_input, "del"))
1861 error = clib_error_return (0, "unknown input '%U'",
1862 format_unformat_error, line_input);
1867 if (vec_len (inside_sw_if_indices))
1869 for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1871 sw_if_index = inside_sw_if_indices[i];
1872 if (is_output_feature)
1874 if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
1876 error = clib_error_return (0, "%s %U failed",
1877 is_del ? "del" : "add",
1878 format_vnet_sw_interface_name, vnm,
1879 vnet_get_sw_interface (vnm,
1886 if (snat_interface_add_del (sw_if_index, 1, is_del))
1888 error = clib_error_return (0, "%s %U failed",
1889 is_del ? "del" : "add",
1890 format_vnet_sw_interface_name, vnm,
1891 vnet_get_sw_interface (vnm,
1899 if (vec_len (outside_sw_if_indices))
1901 for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1903 sw_if_index = outside_sw_if_indices[i];
1904 if (is_output_feature)
1906 if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
1908 error = clib_error_return (0, "%s %U failed",
1909 is_del ? "del" : "add",
1910 format_vnet_sw_interface_name, vnm,
1911 vnet_get_sw_interface (vnm,
1918 if (snat_interface_add_del (sw_if_index, 0, is_del))
1920 error = clib_error_return (0, "%s %U failed",
1921 is_del ? "del" : "add",
1922 format_vnet_sw_interface_name, vnm,
1923 vnet_get_sw_interface (vnm,
1932 unformat_free (line_input);
1933 vec_free (inside_sw_if_indices);
1934 vec_free (outside_sw_if_indices);
1939 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1940 .path = "set interface nat44",
1941 .function = snat_feature_command_fn,
1942 .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1947 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1949 u32 *r = va_arg (*args, u32 *);
1952 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1953 foreach_snat_protocol
1961 format_snat_protocol (u8 * s, va_list * args)
1963 u32 i = va_arg (*args, u32);
1968 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1969 foreach_snat_protocol
1972 s = format (s, "unknown");
1975 s = format (s, "%s", t);
1979 static clib_error_t *
1980 add_static_mapping_command_fn (vlib_main_t * vm,
1981 unformat_input_t * input,
1982 vlib_cli_command_t * cmd)
1984 unformat_input_t _line_input, *line_input = &_line_input;
1985 clib_error_t * error = 0;
1986 ip4_address_t l_addr, e_addr;
1987 u32 l_port = 0, e_port = 0, vrf_id = ~0;
1990 u32 sw_if_index = ~0;
1991 vnet_main_t * vnm = vnet_get_main();
1993 snat_protocol_t proto;
1996 /* Get a line of input. */
1997 if (!unformat_user (input, unformat_line_input, line_input))
2000 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2002 if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2005 else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2007 else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2010 else if (unformat (line_input, "external %U", unformat_ip4_address,
2013 else if (unformat (line_input, "external %U %u",
2014 unformat_vnet_sw_interface, vnm, &sw_if_index,
2018 else if (unformat (line_input, "external %U",
2019 unformat_vnet_sw_interface, vnm, &sw_if_index))
2021 else if (unformat (line_input, "vrf %u", &vrf_id))
2023 else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2025 else if (unformat (line_input, "del"))
2029 error = clib_error_return (0, "unknown input: '%U'",
2030 format_unformat_error, line_input);
2035 if (!addr_only && !proto_set)
2037 error = clib_error_return (0, "missing protocol");
2041 rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2042 vrf_id, addr_only, sw_if_index, proto, is_add);
2046 case VNET_API_ERROR_INVALID_VALUE:
2047 error = clib_error_return (0, "External port already in use.");
2049 case VNET_API_ERROR_NO_SUCH_ENTRY:
2051 error = clib_error_return (0, "External addres must be allocated.");
2053 error = clib_error_return (0, "Mapping not exist.");
2055 case VNET_API_ERROR_NO_SUCH_FIB:
2056 error = clib_error_return (0, "No such VRF id.");
2058 case VNET_API_ERROR_VALUE_EXIST:
2059 error = clib_error_return (0, "Mapping already exist.");
2066 unformat_free (line_input);
2073 * @cliexstart{snat add static mapping}
2074 * Static mapping allows hosts on the external network to initiate connection
2075 * to to the local network host.
2076 * To create static mapping between local host address 10.0.0.3 port 6303 and
2077 * external address 4.4.4.4 port 3606 for TCP protocol use:
2078 * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2079 * If not runnig "static mapping only" NAT plugin mode use before:
2080 * vpp# nat44 add address 4.4.4.4
2081 * To create static mapping between local and external address use:
2082 * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2085 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2086 .path = "nat44 add static mapping",
2087 .function = add_static_mapping_command_fn,
2089 "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
2092 static clib_error_t *
2093 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2094 unformat_input_t * input,
2095 vlib_cli_command_t * cmd)
2097 unformat_input_t _line_input, *line_input = &_line_input;
2098 clib_error_t * error = 0;
2099 ip4_address_t l_addr, e_addr;
2100 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2103 snat_protocol_t proto;
2105 nat44_lb_addr_port_t *locals = 0, local;
2107 /* Get a line of input. */
2108 if (!unformat_user (input, unformat_line_input, line_input))
2111 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2113 if (unformat (line_input, "local %U:%u probability %u",
2114 unformat_ip4_address, &l_addr, &l_port, &probability))
2116 memset (&local, 0, sizeof (local));
2117 local.addr = l_addr;
2118 local.port = (u16) l_port;
2119 local.probability = (u8) probability;
2120 vec_add1 (locals, local);
2122 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2125 else if (unformat (line_input, "vrf %u", &vrf_id))
2127 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2130 else if (unformat (line_input, "del"))
2134 error = clib_error_return (0, "unknown input: '%U'",
2135 format_unformat_error, line_input);
2140 if (vec_len (locals) < 2)
2142 error = clib_error_return (0, "at least two local must be set");
2148 error = clib_error_return (0, "missing protocol");
2152 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2157 case VNET_API_ERROR_INVALID_VALUE:
2158 error = clib_error_return (0, "External port already in use.");
2160 case VNET_API_ERROR_NO_SUCH_ENTRY:
2162 error = clib_error_return (0, "External addres must be allocated.");
2164 error = clib_error_return (0, "Mapping not exist.");
2166 case VNET_API_ERROR_VALUE_EXIST:
2167 error = clib_error_return (0, "Mapping already exist.");
2174 unformat_free (line_input);
2180 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2181 .path = "nat44 add load-balancing static mapping",
2182 .function = add_lb_static_mapping_command_fn,
2184 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
2187 static clib_error_t *
2188 set_workers_command_fn (vlib_main_t * vm,
2189 unformat_input_t * input,
2190 vlib_cli_command_t * cmd)
2192 unformat_input_t _line_input, *line_input = &_line_input;
2195 clib_error_t *error = 0;
2197 /* Get a line of input. */
2198 if (!unformat_user (input, unformat_line_input, line_input))
2201 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2203 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2207 error = clib_error_return (0, "unknown input '%U'",
2208 format_unformat_error, line_input);
2215 error = clib_error_return (0, "List of workers must be specified.");
2219 rv = snat_set_workers(bitmap);
2221 clib_bitmap_free (bitmap);
2225 case VNET_API_ERROR_INVALID_WORKER:
2226 error = clib_error_return (0, "Invalid worker(s).");
2228 case VNET_API_ERROR_FEATURE_DISABLED:
2229 error = clib_error_return (0,
2230 "Supported only if 2 or more workes available.");
2237 unformat_free (line_input);
2244 * @cliexstart{set snat workers}
2245 * Set NAT workers if 2 or more workers available, use:
2246 * vpp# set snat workers 0-2,5
2249 VLIB_CLI_COMMAND (set_workers_command, static) = {
2250 .path = "set nat workers",
2251 .function = set_workers_command_fn,
2253 "set nat workers <workers-list>",
2256 static clib_error_t *
2257 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2258 unformat_input_t * input,
2259 vlib_cli_command_t * cmd)
2261 unformat_input_t _line_input, *line_input = &_line_input;
2266 clib_error_t *error = 0;
2268 /* Get a line of input. */
2269 if (!unformat_user (input, unformat_line_input, line_input))
2272 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2274 if (unformat (line_input, "domain %d", &domain_id))
2276 else if (unformat (line_input, "src-port %d", &src_port))
2278 else if (unformat (line_input, "disable"))
2282 error = clib_error_return (0, "unknown input '%U'",
2283 format_unformat_error, line_input);
2288 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2292 error = clib_error_return (0, "ipfix logging enable failed");
2297 unformat_free (line_input);
2304 * @cliexstart{snat ipfix logging}
2305 * To enable NAT IPFIX logging use:
2306 * vpp# nat ipfix logging
2307 * To set IPFIX exporter use:
2308 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2311 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2312 .path = "nat ipfix logging",
2313 .function = snat_ipfix_logging_enable_disable_command_fn,
2314 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2318 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2320 snat_main_t *sm = &snat_main;
2321 u32 next_worker_index = 0;
2324 next_worker_index = sm->first_worker_index;
2325 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2326 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2328 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2329 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2331 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2333 return next_worker_index;
2337 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2339 snat_main_t *sm = &snat_main;
2342 snat_session_key_t m_key;
2343 clib_bihash_kv_8_8_t kv, value;
2344 snat_static_mapping_t *m;
2345 nat_ed_ses_key_t key;
2346 clib_bihash_kv_16_8_t s_kv, s_value;
2347 snat_main_per_thread_data_t *tsm;
2352 /* first try static mappings without port */
2353 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2355 m_key.addr = ip0->dst_address;
2358 m_key.fib_index = rx_fib_index0;
2359 kv.key = m_key.as_u64;
2360 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2362 m = pool_elt_at_index (sm->static_mappings, value.value);
2363 return m->worker_index;
2367 proto = ip_proto_to_snat_proto (ip0->protocol);
2368 udp = ip4_next_header (ip0);
2369 port = udp->dst_port;
2371 /* unknown protocol */
2372 if (PREDICT_FALSE (proto == ~0))
2374 key.l_addr = ip0->dst_address;
2375 key.r_addr = ip0->src_address;
2376 key.fib_index = rx_fib_index0;
2377 key.proto = ip0->protocol;
2380 s_kv.key[0] = key.as_u64[0];
2381 s_kv.key[1] = key.as_u64[1];
2383 if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2385 for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2387 tsm = vec_elt_at_index (sm->per_thread_data, i);
2388 if (!pool_is_free_index(tsm->sessions, s_value.value))
2390 s = pool_elt_at_index (tsm->sessions, s_value.value);
2391 if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2392 s->out2in.port == ip0->protocol &&
2393 snat_is_unk_proto_session (s))
2399 /* if no session use current thread */
2400 return vlib_get_thread_index ();
2403 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2405 icmp46_header_t * icmp = (icmp46_header_t *) udp;
2406 icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2407 if (!icmp_is_error_message (icmp))
2408 port = echo->identifier;
2411 ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2412 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2413 void *l4_header = ip4_next_header (inner_ip);
2416 case SNAT_PROTOCOL_ICMP:
2417 icmp = (icmp46_header_t*)l4_header;
2418 echo = (icmp_echo_header_t *)(icmp + 1);
2419 port = echo->identifier;
2421 case SNAT_PROTOCOL_UDP:
2422 case SNAT_PROTOCOL_TCP:
2423 port = ((tcp_udp_header_t*)l4_header)->src_port;
2426 return vlib_get_thread_index ();
2431 /* try static mappings with port */
2432 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2434 m_key.addr = ip0->dst_address;
2435 m_key.port = clib_net_to_host_u16 (port);
2436 m_key.protocol = proto;
2437 m_key.fib_index = rx_fib_index0;
2438 kv.key = m_key.as_u64;
2439 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2441 m = pool_elt_at_index (sm->static_mappings, value.value);
2442 return m->worker_index;
2446 /* worker by outside port */
2447 return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2450 static clib_error_t *
2451 snat_config (vlib_main_t * vm, unformat_input_t * input)
2453 snat_main_t * sm = &snat_main;
2454 u32 translation_buckets = 1024;
2455 u32 translation_memory_size = 128<<20;
2456 u32 user_buckets = 128;
2457 u32 user_memory_size = 64<<20;
2458 u32 max_translations_per_user = 100;
2459 u32 outside_vrf_id = 0;
2460 u32 inside_vrf_id = 0;
2461 u32 static_mapping_buckets = 1024;
2462 u32 static_mapping_memory_size = 64<<20;
2463 u8 static_mapping_only = 0;
2464 u8 static_mapping_connection_tracking = 0;
2465 snat_main_per_thread_data_t *tsm;
2467 sm->deterministic = 0;
2469 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2471 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2473 else if (unformat (input, "translation hash memory %d",
2474 &translation_memory_size));
2475 else if (unformat (input, "user hash buckets %d", &user_buckets))
2477 else if (unformat (input, "user hash memory %d",
2480 else if (unformat (input, "max translations per user %d",
2481 &max_translations_per_user))
2483 else if (unformat (input, "outside VRF id %d",
2486 else if (unformat (input, "inside VRF id %d",
2489 else if (unformat (input, "static mapping only"))
2491 static_mapping_only = 1;
2492 if (unformat (input, "connection tracking"))
2493 static_mapping_connection_tracking = 1;
2495 else if (unformat (input, "deterministic"))
2496 sm->deterministic = 1;
2498 return clib_error_return (0, "unknown input '%U'",
2499 format_unformat_error, input);
2502 /* for show commands, etc. */
2503 sm->translation_buckets = translation_buckets;
2504 sm->translation_memory_size = translation_memory_size;
2505 /* do not exceed load factor 10 */
2506 sm->max_translations = 10 * translation_buckets;
2507 sm->user_buckets = user_buckets;
2508 sm->user_memory_size = user_memory_size;
2509 sm->max_translations_per_user = max_translations_per_user;
2510 sm->outside_vrf_id = outside_vrf_id;
2511 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2513 FIB_SOURCE_PLUGIN_HI);
2514 sm->inside_vrf_id = inside_vrf_id;
2515 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2517 FIB_SOURCE_PLUGIN_HI);
2518 sm->static_mapping_only = static_mapping_only;
2519 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2521 if (sm->deterministic)
2523 sm->in2out_node_index = snat_det_in2out_node.index;
2524 sm->in2out_output_node_index = ~0;
2525 sm->out2in_node_index = snat_det_out2in_node.index;
2526 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2527 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2531 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2532 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2533 sm->in2out_node_index = snat_in2out_node.index;
2534 sm->in2out_output_node_index = snat_in2out_output_node.index;
2535 sm->out2in_node_index = snat_out2in_node.index;
2536 if (!static_mapping_only ||
2537 (static_mapping_only && static_mapping_connection_tracking))
2539 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2540 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2542 vec_foreach (tsm, sm->per_thread_data)
2544 clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2545 translation_memory_size);
2547 clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2548 translation_memory_size);
2550 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2554 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2555 translation_buckets, translation_memory_size);
2557 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2558 translation_buckets, translation_memory_size);
2562 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2563 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2565 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2566 "static_mapping_by_local", static_mapping_buckets,
2567 static_mapping_memory_size);
2569 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2570 "static_mapping_by_external", static_mapping_buckets,
2571 static_mapping_memory_size);
2577 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2579 u8 * format_snat_session_state (u8 * s, va_list * args)
2581 u32 i = va_arg (*args, u32);
2586 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2587 foreach_snat_session_state
2590 t = format (t, "unknown");
2592 s = format (s, "%s", t);
2596 u8 * format_snat_key (u8 * s, va_list * args)
2598 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2600 s = format (s, "%U proto %U port %d fib %d",
2601 format_ip4_address, &key->addr,
2602 format_snat_protocol, key->protocol,
2603 clib_net_to_host_u16 (key->port), key->fib_index);
2607 u8 * format_snat_session (u8 * s, va_list * args)
2609 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2610 snat_session_t * sess = va_arg (*args, snat_session_t *);
2612 if (snat_is_unk_proto_session (sess))
2614 s = format (s, " i2o %U proto %u fib %u\n",
2615 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2616 sess->in2out.fib_index);
2617 s = format (s, " o2i %U proto %u fib %u\n",
2618 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2619 sess->out2in.fib_index);
2623 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2624 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2626 if (sess->ext_host_addr.as_u32)
2627 s = format (s, " external host %U\n",
2628 format_ip4_address, &sess->ext_host_addr);
2629 s = format (s, " last heard %.2f\n", sess->last_heard);
2630 s = format (s, " total pkts %d, total bytes %lld\n",
2631 sess->total_pkts, sess->total_bytes);
2632 if (snat_is_session_static (sess))
2633 s = format (s, " static translation\n");
2635 s = format (s, " dynamic translation\n");
2636 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2637 s = format (s, " load-balancing\n");
2642 u8 * format_snat_user (u8 * s, va_list * args)
2644 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2645 snat_user_t * u = va_arg (*args, snat_user_t *);
2646 int verbose = va_arg (*args, int);
2647 dlist_elt_t * head, * elt;
2648 u32 elt_index, head_index;
2650 snat_session_t * sess;
2652 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2653 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2658 if (u->nsessions || u->nstaticsessions)
2660 head_index = u->sessions_per_user_list_head_index;
2661 head = pool_elt_at_index (sm->list_pool, head_index);
2663 elt_index = head->next;
2664 elt = pool_elt_at_index (sm->list_pool, elt_index);
2665 session_index = elt->value;
2667 while (session_index != ~0)
2669 sess = pool_elt_at_index (sm->sessions, session_index);
2671 s = format (s, " %U\n", format_snat_session, sm, sess);
2673 elt_index = elt->next;
2674 elt = pool_elt_at_index (sm->list_pool, elt_index);
2675 session_index = elt->value;
2682 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2684 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2685 nat44_lb_addr_port_t *local;
2688 s = format (s, "local %U external %U vrf %d",
2689 format_ip4_address, &m->local_addr,
2690 format_ip4_address, &m->external_addr,
2694 if (vec_len (m->locals))
2696 s = format (s, "%U vrf %d external %U:%d",
2697 format_snat_protocol, m->proto,
2699 format_ip4_address, &m->external_addr, m->external_port);
2700 vec_foreach (local, m->locals)
2701 s = format (s, "\n local %U:%d probability %d\%",
2702 format_ip4_address, &local->addr, local->port,
2703 local->probability);
2706 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2707 format_snat_protocol, m->proto,
2708 format_ip4_address, &m->local_addr, m->local_port,
2709 format_ip4_address, &m->external_addr, m->external_port,
2715 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2717 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2718 vnet_main_t *vnm = vnet_get_main();
2721 s = format (s, "local %U external %U vrf %d",
2722 format_ip4_address, &m->l_addr,
2723 format_vnet_sw_interface_name, vnm,
2724 vnet_get_sw_interface (vnm, m->sw_if_index),
2727 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2728 format_snat_protocol, m->proto,
2729 format_ip4_address, &m->l_addr, m->l_port,
2730 format_vnet_sw_interface_name, vnm,
2731 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2737 u8 * format_det_map_ses (u8 * s, va_list * args)
2739 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2740 ip4_address_t in_addr, out_addr;
2741 u32 in_offset, out_offset;
2742 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2743 u32 * i = va_arg (*args, u32 *);
2745 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2746 in_addr.as_u32 = clib_host_to_net_u32 (
2747 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2748 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2749 clib_net_to_host_u32(det_map->in_addr.as_u32);
2750 out_offset = in_offset / det_map->sharing_ratio;
2751 out_addr.as_u32 = clib_host_to_net_u32(
2752 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2753 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2754 format_ip4_address, &in_addr,
2755 clib_net_to_host_u16 (ses->in_port),
2756 format_ip4_address, &out_addr,
2757 clib_net_to_host_u16 (ses->out.out_port),
2758 format_ip4_address, &ses->out.ext_host_addr,
2759 clib_net_to_host_u16 (ses->out.ext_host_port),
2760 format_snat_session_state, ses->state,
2766 static clib_error_t *
2767 show_snat_command_fn (vlib_main_t * vm,
2768 unformat_input_t * input,
2769 vlib_cli_command_t * cmd)
2772 snat_main_t * sm = &snat_main;
2774 snat_static_mapping_t *m;
2775 snat_interface_t *i;
2776 snat_address_t * ap;
2777 vnet_main_t *vnm = vnet_get_main();
2778 snat_main_per_thread_data_t *tsm;
2779 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2781 snat_static_map_resolve_t *rp;
2782 snat_det_map_t * dm;
2783 snat_det_session_t * ses;
2785 if (unformat (input, "detail"))
2787 else if (unformat (input, "verbose"))
2790 if (sm->static_mapping_only)
2792 if (sm->static_mapping_connection_tracking)
2793 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2796 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2798 else if (sm->deterministic)
2800 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2804 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2809 pool_foreach (i, sm->interfaces,
2811 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2812 vnet_get_sw_interface (vnm, i->sw_if_index),
2813 (nat_interface_is_inside(i) &&
2814 nat_interface_is_outside(i)) ? "in out" :
2815 (nat_interface_is_inside(i) ? "in" : "out"));
2818 pool_foreach (i, sm->output_feature_interfaces,
2820 vlib_cli_output (vm, "%U output-feature %s",
2821 format_vnet_sw_interface_name, vnm,
2822 vnet_get_sw_interface (vnm, i->sw_if_index),
2823 (nat_interface_is_inside(i) &&
2824 nat_interface_is_outside(i)) ? "in out" :
2825 (nat_interface_is_inside(i) ? "in" : "out"));
2828 if (vec_len (sm->auto_add_sw_if_indices))
2830 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2831 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2833 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2834 vnet_get_sw_interface (vnm, *sw_if_index));
2838 vec_foreach (ap, sm->addresses)
2840 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2841 if (ap->fib_index != ~0)
2842 vlib_cli_output (vm, " tenant VRF: %u",
2843 ip4_fib_get(ap->fib_index)->table_id);
2845 vlib_cli_output (vm, " tenant VRF independent");
2846 #define _(N, i, n, s) \
2847 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2848 foreach_snat_protocol
2853 if (sm->num_workers > 1)
2855 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2858 vec_foreach (worker, sm->workers)
2860 vlib_worker_thread_t *w =
2861 vlib_worker_threads + *worker + sm->first_worker_index;
2862 vlib_cli_output (vm, " %s", w->name);
2867 if (sm->deterministic)
2869 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2870 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2871 sm->tcp_established_timeout);
2872 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2873 sm->tcp_transitory_timeout);
2874 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2875 vlib_cli_output (vm, "%d deterministic mappings",
2876 pool_elts (sm->det_maps));
2879 pool_foreach (dm, sm->det_maps,
2881 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2882 format_ip4_address, &dm->in_addr, dm->in_plen,
2883 format_ip4_address, &dm->out_addr, dm->out_plen);
2884 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2886 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2887 dm->ports_per_host);
2888 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2891 vec_foreach_index (j, dm->sessions)
2893 ses = vec_elt_at_index (dm->sessions, j);
2895 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2904 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2906 vlib_cli_output (vm, "%d static mappings",
2907 pool_elts (sm->static_mappings));
2911 pool_foreach (m, sm->static_mappings,
2913 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2919 vec_foreach (tsm, sm->per_thread_data)
2921 users_num += pool_elts (tsm->users);
2922 sessions_num += pool_elts (tsm->sessions);
2925 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2926 " %d static mappings",
2928 vec_len (sm->addresses),
2930 pool_elts (sm->static_mappings));
2934 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
2936 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
2938 vec_foreach_index (j, sm->per_thread_data)
2940 tsm = vec_elt_at_index (sm->per_thread_data, j);
2942 if (pool_elts (tsm->users) == 0)
2945 vlib_worker_thread_t *w = vlib_worker_threads + j;
2946 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2948 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
2950 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
2952 vlib_cli_output (vm, " %d list pool elements",
2953 pool_elts (tsm->list_pool));
2955 pool_foreach (u, tsm->users,
2957 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
2962 if (pool_elts (sm->static_mappings))
2964 vlib_cli_output (vm, "static mappings:");
2965 pool_foreach (m, sm->static_mappings,
2967 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2969 for (j = 0; j < vec_len (sm->to_resolve); j++)
2971 rp = sm->to_resolve + j;
2972 vlib_cli_output (vm, "%U",
2973 format_snat_static_map_to_resolve, rp);
2983 VLIB_CLI_COMMAND (show_snat_command, static) = {
2984 .path = "show nat44",
2985 .short_help = "show nat44",
2986 .function = show_snat_command_fn,
2991 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2994 ip4_address_t * address,
2996 u32 if_address_index,
2999 snat_main_t *sm = &snat_main;
3000 snat_static_map_resolve_t *rp;
3001 u32 *indices_to_delete = 0;
3005 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3007 if (sw_if_index == sm->auto_add_sw_if_indices[i])
3011 /* Don't trip over lease renewal, static config */
3012 for (j = 0; j < vec_len(sm->addresses); j++)
3013 if (sm->addresses[j].addr.as_u32 == address->as_u32)
3016 snat_add_address (sm, address, ~0);
3017 /* Scan static map resolution vector */
3018 for (j = 0; j < vec_len (sm->to_resolve); j++)
3020 rp = sm->to_resolve + j;
3021 /* On this interface? */
3022 if (rp->sw_if_index == sw_if_index)
3024 /* Add the static mapping */
3025 rv = snat_add_static_mapping (rp->l_addr,
3031 ~0 /* sw_if_index */,
3035 clib_warning ("snat_add_static_mapping returned %d",
3037 vec_add1 (indices_to_delete, j);
3040 /* If we resolved any of the outstanding static mappings */
3041 if (vec_len(indices_to_delete))
3044 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3045 vec_delete(sm->to_resolve, 1, j);
3046 vec_free(indices_to_delete);
3052 (void) snat_del_address(sm, address[0], 1);
3060 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
3062 ip4_main_t * ip4_main = sm->ip4_main;
3063 ip4_address_t * first_int_addr;
3064 snat_static_map_resolve_t *rp;
3065 u32 *indices_to_delete = 0;
3068 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3069 0 /* just want the address*/);
3071 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3073 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
3077 /* if have address remove it */
3079 (void) snat_del_address (sm, first_int_addr[0], 1);
3082 for (j = 0; j < vec_len (sm->to_resolve); j++)
3084 rp = sm->to_resolve + j;
3085 if (rp->sw_if_index == sw_if_index)
3086 vec_add1 (indices_to_delete, j);
3088 if (vec_len(indices_to_delete))
3090 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3091 vec_del1(sm->to_resolve, j);
3092 vec_free(indices_to_delete);
3095 vec_del1(sm->auto_add_sw_if_indices, i);
3098 return VNET_API_ERROR_VALUE_EXIST;
3105 return VNET_API_ERROR_NO_SUCH_ENTRY;
3107 /* add to the auto-address list */
3108 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3110 /* If the address is already bound - or static - add it now */
3112 snat_add_address (sm, first_int_addr, ~0);
3117 static clib_error_t *
3118 snat_add_interface_address_command_fn (vlib_main_t * vm,
3119 unformat_input_t * input,
3120 vlib_cli_command_t * cmd)
3122 snat_main_t *sm = &snat_main;
3123 unformat_input_t _line_input, *line_input = &_line_input;
3127 clib_error_t *error = 0;
3129 /* Get a line of input. */
3130 if (!unformat_user (input, unformat_line_input, line_input))
3133 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3135 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3136 sm->vnet_main, &sw_if_index))
3138 else if (unformat (line_input, "del"))
3142 error = clib_error_return (0, "unknown input '%U'",
3143 format_unformat_error, line_input);
3148 rv = snat_add_interface_address (sm, sw_if_index, is_del);
3156 error = clib_error_return (0, "snat_add_interface_address returned %d",
3162 unformat_free (line_input);
3167 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3168 .path = "nat44 add interface address",
3169 .short_help = "nat44 add interface address <interface> [del]",
3170 .function = snat_add_interface_address_command_fn,
3174 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3175 snat_protocol_t proto, u32 vrf_id, int is_in)
3177 snat_main_per_thread_data_t *tsm;
3178 clib_bihash_kv_8_8_t kv, value;
3180 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3181 snat_session_key_t key;
3183 clib_bihash_8_8_t *t;
3184 snat_user_key_t u_key;
3187 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3188 if (sm->num_workers)
3190 vec_elt_at_index (sm->per_thread_data,
3191 sm->worker_in2out_cb (&ip, fib_index));
3193 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3195 key.addr.as_u32 = addr->as_u32;
3196 key.port = clib_host_to_net_u16 (port);
3197 key.protocol = proto;
3198 key.fib_index = fib_index;
3199 kv.key = key.as_u64;
3200 t = is_in ? &tsm->in2out : &tsm->out2in;
3201 if (!clib_bihash_search_8_8 (t, &kv, &value))
3203 s = pool_elt_at_index (tsm->sessions, value.value);
3204 kv.key = s->in2out.as_u64;
3205 clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3206 kv.key = s->out2in.as_u64;
3207 clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3208 u_key.addr = s->in2out.addr;
3209 u_key.fib_index = s->in2out.fib_index;
3210 kv.key = u_key.as_u64;
3211 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3213 u = pool_elt_at_index (tsm->users, value.value);
3216 clib_dlist_remove (tsm->list_pool, s->per_user_index);
3217 pool_put (tsm->sessions, s);
3221 return VNET_API_ERROR_NO_SUCH_ENTRY;
3224 static clib_error_t *
3225 nat44_del_session_command_fn (vlib_main_t * vm,
3226 unformat_input_t * input,
3227 vlib_cli_command_t * cmd)
3229 snat_main_t *sm = &snat_main;
3230 unformat_input_t _line_input, *line_input = &_line_input;
3232 clib_error_t *error = 0;
3234 u32 port = 0, vrf_id = sm->outside_vrf_id;
3235 snat_protocol_t proto;
3238 /* Get a line of input. */
3239 if (!unformat_user (input, unformat_line_input, line_input))
3242 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3244 if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3245 unformat_snat_protocol, &proto))
3247 else if (unformat (line_input, "in"))
3250 vrf_id = sm->inside_vrf_id;
3252 else if (unformat (line_input, "vrf %u", &vrf_id))
3256 error = clib_error_return (0, "unknown input '%U'",
3257 format_unformat_error, line_input);
3262 rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3270 error = clib_error_return (0, "nat44_del_session returned %d", rv);
3275 unformat_free (line_input);
3280 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3281 .path = "nat44 del session",
3282 .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3283 .function = nat44_del_session_command_fn,
3286 static clib_error_t *
3287 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
3288 unformat_input_t * input,
3289 vlib_cli_command_t * cmd)
3291 snat_main_t *sm = &snat_main;
3292 unformat_input_t _line_input, *line_input = &_line_input;
3293 clib_error_t *error = 0;
3294 u32 psid, psid_offset, psid_length;
3296 /* Get a line of input. */
3297 if (!unformat_user (input, unformat_line_input, line_input))
3300 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3302 if (unformat (line_input, "default"))
3303 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3304 else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3305 &psid, &psid_offset, &psid_length))
3307 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3308 sm->psid = (u16) psid;
3309 sm->psid_offset = (u16) psid_offset;
3310 sm->psid_length = (u16) psid_length;
3314 error = clib_error_return (0, "unknown input '%U'",
3315 format_unformat_error, line_input);
3321 unformat_free (line_input);
3326 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3327 .path = "nat44 addr-port-assignment-alg",
3328 .short_help = "nat44 addr-port-assignment-alg <alg-name> [<alg-params>]",
3329 .function = nat44_set_alloc_addr_and_port_alg_command_fn,
3332 static clib_error_t *
3333 snat_det_map_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;
3340 u32 in_plen, out_plen;
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, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3352 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3354 else if (unformat (line_input, "del"))
3358 error = clib_error_return (0, "unknown input '%U'",
3359 format_unformat_error, line_input);
3364 unformat_free (line_input);
3366 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3371 error = clib_error_return (0, "snat_det_add_map return %d", rv);
3376 unformat_free (line_input);
3383 * @cliexstart{snat deterministic add}
3384 * Create bijective mapping of inside address to outside address and port range
3385 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3387 * To create deterministic mapping between inside network 10.0.0.0/18 and
3388 * outside network 1.1.1.0/30 use:
3389 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3392 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3393 .path = "nat44 deterministic add",
3394 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3395 .function = snat_det_map_command_fn,
3398 static clib_error_t *
3399 snat_det_forward_command_fn (vlib_main_t * vm,
3400 unformat_input_t * input,
3401 vlib_cli_command_t * cmd)
3403 snat_main_t *sm = &snat_main;
3404 unformat_input_t _line_input, *line_input = &_line_input;
3405 ip4_address_t in_addr, out_addr;
3407 snat_det_map_t * dm;
3408 clib_error_t *error = 0;
3410 /* Get a line of input. */
3411 if (!unformat_user (input, unformat_line_input, line_input))
3414 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3416 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3420 error = clib_error_return (0, "unknown input '%U'",
3421 format_unformat_error, line_input);
3426 unformat_free (line_input);
3428 dm = snat_det_map_by_user(sm, &in_addr);
3430 vlib_cli_output (vm, "no match");
3433 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3434 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3435 lo_port, lo_port + dm->ports_per_host - 1);
3439 unformat_free (line_input);
3446 * @cliexstart{snat deterministic forward}
3447 * Return outside address and port range from inside address for deterministic
3449 * To obtain outside address and port of inside host use:
3450 * vpp# nat44 deterministic forward 10.0.0.2
3451 * 1.1.1.0:<1054-1068>
3454 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3455 .path = "nat44 deterministic forward",
3456 .short_help = "nat44 deterministic forward <addr>",
3457 .function = snat_det_forward_command_fn,
3460 static clib_error_t *
3461 snat_det_reverse_command_fn (vlib_main_t * vm,
3462 unformat_input_t * input,
3463 vlib_cli_command_t * cmd)
3465 snat_main_t *sm = &snat_main;
3466 unformat_input_t _line_input, *line_input = &_line_input;
3467 ip4_address_t in_addr, out_addr;
3469 snat_det_map_t * dm;
3470 clib_error_t *error = 0;
3472 /* Get a line of input. */
3473 if (!unformat_user (input, unformat_line_input, line_input))
3476 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3478 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3482 error = clib_error_return (0, "unknown input '%U'",
3483 format_unformat_error, line_input);
3487 unformat_free (line_input);
3489 if (out_port < 1024 || out_port > 65535)
3491 error = clib_error_return (0, "wrong port, must be <1024-65535>");
3495 dm = snat_det_map_by_out(sm, &out_addr);
3497 vlib_cli_output (vm, "no match");
3500 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3501 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3505 unformat_free (line_input);
3512 * @cliexstart{snat deterministic reverse}
3513 * Return inside address from outside address and port for deterministic NAT.
3514 * To obtain inside host address from outside address and port use:
3515 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3519 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3520 .path = "nat44 deterministic reverse",
3521 .short_help = "nat44 deterministic reverse <addr>:<port>",
3522 .function = snat_det_reverse_command_fn,
3525 static clib_error_t *
3526 set_timeout_command_fn (vlib_main_t * vm,
3527 unformat_input_t * input,
3528 vlib_cli_command_t * cmd)
3530 snat_main_t *sm = &snat_main;
3531 unformat_input_t _line_input, *line_input = &_line_input;
3532 clib_error_t *error = 0;
3534 /* Get a line of input. */
3535 if (!unformat_user (input, unformat_line_input, line_input))
3538 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3540 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3542 else if (unformat (line_input, "tcp-established %u",
3543 &sm->tcp_established_timeout))
3545 else if (unformat (line_input, "tcp-transitory %u",
3546 &sm->tcp_transitory_timeout))
3548 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3550 else if (unformat (line_input, "reset"))
3552 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3553 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3554 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3555 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3559 error = clib_error_return (0, "unknown input '%U'",
3560 format_unformat_error, line_input);
3565 unformat_free (line_input);
3568 unformat_free (line_input);
3575 * @cliexstart{set snat deterministic timeout}
3576 * Set values of timeouts for deterministic NAT (in seconds), use:
3577 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3578 * tcp-transitory 250 icmp 90
3579 * To reset default values use:
3580 * vpp# set nat44 deterministic timeout reset
3583 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3584 .path = "set nat44 deterministic timeout",
3585 .function = set_timeout_command_fn,
3587 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3588 "tcp-transitory <sec> | icmp <sec> | reset]",
3591 static clib_error_t *
3592 snat_det_close_session_out_fn (vlib_main_t *vm,
3593 unformat_input_t * input,
3594 vlib_cli_command_t * cmd)
3596 snat_main_t *sm = &snat_main;
3597 unformat_input_t _line_input, *line_input = &_line_input;
3598 ip4_address_t out_addr, ext_addr, in_addr;
3599 u32 out_port, ext_port;
3600 snat_det_map_t * dm;
3601 snat_det_session_t * ses;
3602 snat_det_out_key_t key;
3603 clib_error_t *error = 0;
3605 /* Get a line of input. */
3606 if (!unformat_user (input, unformat_line_input, line_input))
3609 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3611 if (unformat (line_input, "%U:%d %U:%d",
3612 unformat_ip4_address, &out_addr, &out_port,
3613 unformat_ip4_address, &ext_addr, &ext_port))
3617 error = clib_error_return (0, "unknown input '%U'",
3618 format_unformat_error, line_input);
3623 unformat_free (line_input);
3625 dm = snat_det_map_by_out(sm, &out_addr);
3627 vlib_cli_output (vm, "no match");
3630 snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
3631 key.ext_host_addr = out_addr;
3632 key.ext_host_port = ntohs((u16)ext_port);
3633 key.out_port = ntohs((u16)out_port);
3634 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3636 vlib_cli_output (vm, "no match");
3638 snat_det_ses_close(dm, ses);
3642 unformat_free (line_input);
3649 * @cliexstart{snat deterministic close session out}
3650 * Close session using outside ip address and port
3651 * and external ip address and port, use:
3652 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3655 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3656 .path = "nat44 deterministic close session out",
3657 .short_help = "nat44 deterministic close session out "
3658 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3659 .function = snat_det_close_session_out_fn,
3662 static clib_error_t *
3663 snat_det_close_session_in_fn (vlib_main_t *vm,
3664 unformat_input_t * input,
3665 vlib_cli_command_t * cmd)
3667 snat_main_t *sm = &snat_main;
3668 unformat_input_t _line_input, *line_input = &_line_input;
3669 ip4_address_t in_addr, ext_addr;
3670 u32 in_port, ext_port;
3671 snat_det_map_t * dm;
3672 snat_det_session_t * ses;
3673 snat_det_out_key_t key;
3674 clib_error_t *error = 0;
3676 /* Get a line of input. */
3677 if (!unformat_user (input, unformat_line_input, line_input))
3680 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3682 if (unformat (line_input, "%U:%d %U:%d",
3683 unformat_ip4_address, &in_addr, &in_port,
3684 unformat_ip4_address, &ext_addr, &ext_port))
3688 error = clib_error_return (0, "unknown input '%U'",
3689 format_unformat_error, line_input);
3694 unformat_free (line_input);
3696 dm = snat_det_map_by_user (sm, &in_addr);
3698 vlib_cli_output (vm, "no match");
3701 key.ext_host_addr = ext_addr;
3702 key.ext_host_port = ntohs ((u16)ext_port);
3703 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
3705 vlib_cli_output (vm, "no match");
3707 snat_det_ses_close(dm, ses);
3711 unformat_free(line_input);
3718 * @cliexstart{snat deterministic close_session_in}
3719 * Close session using inside ip address and port
3720 * and external ip address and port, use:
3721 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3724 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3725 .path = "nat44 deterministic close session in",
3726 .short_help = "nat44 deterministic close session in "
3727 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3728 .function = snat_det_close_session_in_fn,