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);
736 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
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) || (m->local_addr.as_u32 == m->external_addr.as_u32))
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 = ~0;
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_identity_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;
2100 u32 port = 0, vrf_id = ~0;
2103 u32 sw_if_index = ~0;
2104 vnet_main_t * vnm = vnet_get_main();
2106 snat_protocol_t proto;
2110 /* Get a line of input. */
2111 if (!unformat_user (input, unformat_line_input, line_input))
2114 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2116 if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2118 else if (unformat (line_input, "external %U",
2119 unformat_vnet_sw_interface, vnm, &sw_if_index))
2121 else if (unformat (line_input, "vrf %u", &vrf_id))
2123 else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2126 else if (unformat (line_input, "del"))
2130 error = clib_error_return (0, "unknown input: '%U'",
2131 format_unformat_error, line_input);
2136 rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2137 vrf_id, addr_only, sw_if_index, proto, is_add);
2141 case VNET_API_ERROR_INVALID_VALUE:
2142 error = clib_error_return (0, "External port already in use.");
2144 case VNET_API_ERROR_NO_SUCH_ENTRY:
2146 error = clib_error_return (0, "External addres must be allocated.");
2148 error = clib_error_return (0, "Mapping not exist.");
2150 case VNET_API_ERROR_NO_SUCH_FIB:
2151 error = clib_error_return (0, "No such VRF id.");
2153 case VNET_API_ERROR_VALUE_EXIST:
2154 error = clib_error_return (0, "Mapping already exist.");
2161 unformat_free (line_input);
2168 * @cliexstart{snat add identity mapping}
2169 * Identity mapping translate an IP address to itself.
2170 * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2172 * vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2173 * To create identity mapping for address 10.0.0.3 use:
2174 * vpp# nat44 add identity mapping 10.0.0.3
2175 * To create identity mapping for DHCP addressed interface use:
2176 * vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2179 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2180 .path = "nat44 add identity mapping",
2181 .function = add_identity_mapping_command_fn,
2182 .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2183 "[<protocol> <port>] [vrf <table-id>] [del]",
2186 static clib_error_t *
2187 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2188 unformat_input_t * input,
2189 vlib_cli_command_t * cmd)
2191 unformat_input_t _line_input, *line_input = &_line_input;
2192 clib_error_t * error = 0;
2193 ip4_address_t l_addr, e_addr;
2194 u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2197 snat_protocol_t proto;
2199 nat44_lb_addr_port_t *locals = 0, local;
2201 /* Get a line of input. */
2202 if (!unformat_user (input, unformat_line_input, line_input))
2205 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2207 if (unformat (line_input, "local %U:%u probability %u",
2208 unformat_ip4_address, &l_addr, &l_port, &probability))
2210 memset (&local, 0, sizeof (local));
2211 local.addr = l_addr;
2212 local.port = (u16) l_port;
2213 local.probability = (u8) probability;
2214 vec_add1 (locals, local);
2216 else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2219 else if (unformat (line_input, "vrf %u", &vrf_id))
2221 else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2224 else if (unformat (line_input, "del"))
2228 error = clib_error_return (0, "unknown input: '%U'",
2229 format_unformat_error, line_input);
2234 if (vec_len (locals) < 2)
2236 error = clib_error_return (0, "at least two local must be set");
2242 error = clib_error_return (0, "missing protocol");
2246 rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2251 case VNET_API_ERROR_INVALID_VALUE:
2252 error = clib_error_return (0, "External port already in use.");
2254 case VNET_API_ERROR_NO_SUCH_ENTRY:
2256 error = clib_error_return (0, "External addres must be allocated.");
2258 error = clib_error_return (0, "Mapping not exist.");
2260 case VNET_API_ERROR_VALUE_EXIST:
2261 error = clib_error_return (0, "Mapping already exist.");
2268 unformat_free (line_input);
2274 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2275 .path = "nat44 add load-balancing static mapping",
2276 .function = add_lb_static_mapping_command_fn,
2278 "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
2281 static clib_error_t *
2282 set_workers_command_fn (vlib_main_t * vm,
2283 unformat_input_t * input,
2284 vlib_cli_command_t * cmd)
2286 unformat_input_t _line_input, *line_input = &_line_input;
2289 clib_error_t *error = 0;
2291 /* Get a line of input. */
2292 if (!unformat_user (input, unformat_line_input, line_input))
2295 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2297 if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2301 error = clib_error_return (0, "unknown input '%U'",
2302 format_unformat_error, line_input);
2309 error = clib_error_return (0, "List of workers must be specified.");
2313 rv = snat_set_workers(bitmap);
2315 clib_bitmap_free (bitmap);
2319 case VNET_API_ERROR_INVALID_WORKER:
2320 error = clib_error_return (0, "Invalid worker(s).");
2322 case VNET_API_ERROR_FEATURE_DISABLED:
2323 error = clib_error_return (0,
2324 "Supported only if 2 or more workes available.");
2331 unformat_free (line_input);
2338 * @cliexstart{set snat workers}
2339 * Set NAT workers if 2 or more workers available, use:
2340 * vpp# set snat workers 0-2,5
2343 VLIB_CLI_COMMAND (set_workers_command, static) = {
2344 .path = "set nat workers",
2345 .function = set_workers_command_fn,
2347 "set nat workers <workers-list>",
2350 static clib_error_t *
2351 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2352 unformat_input_t * input,
2353 vlib_cli_command_t * cmd)
2355 unformat_input_t _line_input, *line_input = &_line_input;
2360 clib_error_t *error = 0;
2362 /* Get a line of input. */
2363 if (!unformat_user (input, unformat_line_input, line_input))
2366 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2368 if (unformat (line_input, "domain %d", &domain_id))
2370 else if (unformat (line_input, "src-port %d", &src_port))
2372 else if (unformat (line_input, "disable"))
2376 error = clib_error_return (0, "unknown input '%U'",
2377 format_unformat_error, line_input);
2382 rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2386 error = clib_error_return (0, "ipfix logging enable failed");
2391 unformat_free (line_input);
2398 * @cliexstart{snat ipfix logging}
2399 * To enable NAT IPFIX logging use:
2400 * vpp# nat ipfix logging
2401 * To set IPFIX exporter use:
2402 * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2405 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2406 .path = "nat ipfix logging",
2407 .function = snat_ipfix_logging_enable_disable_command_fn,
2408 .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2412 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2414 snat_main_t *sm = &snat_main;
2415 u32 next_worker_index = 0;
2418 next_worker_index = sm->first_worker_index;
2419 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2420 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2422 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2423 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2425 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2427 return next_worker_index;
2431 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2433 snat_main_t *sm = &snat_main;
2436 snat_session_key_t m_key;
2437 clib_bihash_kv_8_8_t kv, value;
2438 snat_static_mapping_t *m;
2439 nat_ed_ses_key_t key;
2440 clib_bihash_kv_16_8_t s_kv, s_value;
2441 snat_main_per_thread_data_t *tsm;
2446 /* first try static mappings without port */
2447 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2449 m_key.addr = ip0->dst_address;
2452 m_key.fib_index = rx_fib_index0;
2453 kv.key = m_key.as_u64;
2454 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2456 m = pool_elt_at_index (sm->static_mappings, value.value);
2457 return m->worker_index;
2461 proto = ip_proto_to_snat_proto (ip0->protocol);
2462 udp = ip4_next_header (ip0);
2463 port = udp->dst_port;
2465 /* unknown protocol */
2466 if (PREDICT_FALSE (proto == ~0))
2468 key.l_addr = ip0->dst_address;
2469 key.r_addr = ip0->src_address;
2470 key.fib_index = rx_fib_index0;
2471 key.proto = ip0->protocol;
2474 s_kv.key[0] = key.as_u64[0];
2475 s_kv.key[1] = key.as_u64[1];
2477 if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2479 for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2481 tsm = vec_elt_at_index (sm->per_thread_data, i);
2482 if (!pool_is_free_index(tsm->sessions, s_value.value))
2484 s = pool_elt_at_index (tsm->sessions, s_value.value);
2485 if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2486 s->out2in.port == ip0->protocol &&
2487 snat_is_unk_proto_session (s))
2493 /* if no session use current thread */
2494 return vlib_get_thread_index ();
2497 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2499 icmp46_header_t * icmp = (icmp46_header_t *) udp;
2500 icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2501 if (!icmp_is_error_message (icmp))
2502 port = echo->identifier;
2505 ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2506 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2507 void *l4_header = ip4_next_header (inner_ip);
2510 case SNAT_PROTOCOL_ICMP:
2511 icmp = (icmp46_header_t*)l4_header;
2512 echo = (icmp_echo_header_t *)(icmp + 1);
2513 port = echo->identifier;
2515 case SNAT_PROTOCOL_UDP:
2516 case SNAT_PROTOCOL_TCP:
2517 port = ((tcp_udp_header_t*)l4_header)->src_port;
2520 return vlib_get_thread_index ();
2525 /* try static mappings with port */
2526 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2528 m_key.addr = ip0->dst_address;
2529 m_key.port = clib_net_to_host_u16 (port);
2530 m_key.protocol = proto;
2531 m_key.fib_index = rx_fib_index0;
2532 kv.key = m_key.as_u64;
2533 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2535 m = pool_elt_at_index (sm->static_mappings, value.value);
2536 return m->worker_index;
2540 /* worker by outside port */
2541 return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2544 static clib_error_t *
2545 snat_config (vlib_main_t * vm, unformat_input_t * input)
2547 snat_main_t * sm = &snat_main;
2548 u32 translation_buckets = 1024;
2549 u32 translation_memory_size = 128<<20;
2550 u32 user_buckets = 128;
2551 u32 user_memory_size = 64<<20;
2552 u32 max_translations_per_user = 100;
2553 u32 outside_vrf_id = 0;
2554 u32 inside_vrf_id = 0;
2555 u32 static_mapping_buckets = 1024;
2556 u32 static_mapping_memory_size = 64<<20;
2557 u8 static_mapping_only = 0;
2558 u8 static_mapping_connection_tracking = 0;
2559 snat_main_per_thread_data_t *tsm;
2561 sm->deterministic = 0;
2563 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2565 if (unformat (input, "translation hash buckets %d", &translation_buckets))
2567 else if (unformat (input, "translation hash memory %d",
2568 &translation_memory_size));
2569 else if (unformat (input, "user hash buckets %d", &user_buckets))
2571 else if (unformat (input, "user hash memory %d",
2574 else if (unformat (input, "max translations per user %d",
2575 &max_translations_per_user))
2577 else if (unformat (input, "outside VRF id %d",
2580 else if (unformat (input, "inside VRF id %d",
2583 else if (unformat (input, "static mapping only"))
2585 static_mapping_only = 1;
2586 if (unformat (input, "connection tracking"))
2587 static_mapping_connection_tracking = 1;
2589 else if (unformat (input, "deterministic"))
2590 sm->deterministic = 1;
2592 return clib_error_return (0, "unknown input '%U'",
2593 format_unformat_error, input);
2596 /* for show commands, etc. */
2597 sm->translation_buckets = translation_buckets;
2598 sm->translation_memory_size = translation_memory_size;
2599 /* do not exceed load factor 10 */
2600 sm->max_translations = 10 * translation_buckets;
2601 sm->user_buckets = user_buckets;
2602 sm->user_memory_size = user_memory_size;
2603 sm->max_translations_per_user = max_translations_per_user;
2604 sm->outside_vrf_id = outside_vrf_id;
2605 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2607 FIB_SOURCE_PLUGIN_HI);
2608 sm->inside_vrf_id = inside_vrf_id;
2609 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2611 FIB_SOURCE_PLUGIN_HI);
2612 sm->static_mapping_only = static_mapping_only;
2613 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2615 if (sm->deterministic)
2617 sm->in2out_node_index = snat_det_in2out_node.index;
2618 sm->in2out_output_node_index = ~0;
2619 sm->out2in_node_index = snat_det_out2in_node.index;
2620 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2621 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2625 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2626 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2627 sm->in2out_node_index = snat_in2out_node.index;
2628 sm->in2out_output_node_index = snat_in2out_output_node.index;
2629 sm->out2in_node_index = snat_out2in_node.index;
2630 if (!static_mapping_only ||
2631 (static_mapping_only && static_mapping_connection_tracking))
2633 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2634 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2636 vec_foreach (tsm, sm->per_thread_data)
2638 clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2639 translation_memory_size);
2641 clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2642 translation_memory_size);
2644 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2648 clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2649 translation_buckets, translation_memory_size);
2651 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2652 translation_buckets, translation_memory_size);
2656 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2657 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2659 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2660 "static_mapping_by_local", static_mapping_buckets,
2661 static_mapping_memory_size);
2663 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2664 "static_mapping_by_external", static_mapping_buckets,
2665 static_mapping_memory_size);
2671 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2673 u8 * format_snat_session_state (u8 * s, va_list * args)
2675 u32 i = va_arg (*args, u32);
2680 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2681 foreach_snat_session_state
2684 t = format (t, "unknown");
2686 s = format (s, "%s", t);
2690 u8 * format_snat_key (u8 * s, va_list * args)
2692 snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2694 s = format (s, "%U proto %U port %d fib %d",
2695 format_ip4_address, &key->addr,
2696 format_snat_protocol, key->protocol,
2697 clib_net_to_host_u16 (key->port), key->fib_index);
2701 u8 * format_snat_session (u8 * s, va_list * args)
2703 snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2704 snat_session_t * sess = va_arg (*args, snat_session_t *);
2706 if (snat_is_unk_proto_session (sess))
2708 s = format (s, " i2o %U proto %u fib %u\n",
2709 format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2710 sess->in2out.fib_index);
2711 s = format (s, " o2i %U proto %u fib %u\n",
2712 format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2713 sess->out2in.fib_index);
2717 s = format (s, " i2o %U\n", format_snat_key, &sess->in2out);
2718 s = format (s, " o2i %U\n", format_snat_key, &sess->out2in);
2720 if (sess->ext_host_addr.as_u32)
2721 s = format (s, " external host %U\n",
2722 format_ip4_address, &sess->ext_host_addr);
2723 s = format (s, " last heard %.2f\n", sess->last_heard);
2724 s = format (s, " total pkts %d, total bytes %lld\n",
2725 sess->total_pkts, sess->total_bytes);
2726 if (snat_is_session_static (sess))
2727 s = format (s, " static translation\n");
2729 s = format (s, " dynamic translation\n");
2730 if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2731 s = format (s, " load-balancing\n");
2736 u8 * format_snat_user (u8 * s, va_list * args)
2738 snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2739 snat_user_t * u = va_arg (*args, snat_user_t *);
2740 int verbose = va_arg (*args, int);
2741 dlist_elt_t * head, * elt;
2742 u32 elt_index, head_index;
2744 snat_session_t * sess;
2746 s = format (s, "%U: %d dynamic translations, %d static translations\n",
2747 format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2752 if (u->nsessions || u->nstaticsessions)
2754 head_index = u->sessions_per_user_list_head_index;
2755 head = pool_elt_at_index (sm->list_pool, head_index);
2757 elt_index = head->next;
2758 elt = pool_elt_at_index (sm->list_pool, elt_index);
2759 session_index = elt->value;
2761 while (session_index != ~0)
2763 sess = pool_elt_at_index (sm->sessions, session_index);
2765 s = format (s, " %U\n", format_snat_session, sm, sess);
2767 elt_index = elt->next;
2768 elt = pool_elt_at_index (sm->list_pool, elt_index);
2769 session_index = elt->value;
2776 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2778 snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2779 nat44_lb_addr_port_t *local;
2782 s = format (s, "local %U external %U vrf %d",
2783 format_ip4_address, &m->local_addr,
2784 format_ip4_address, &m->external_addr,
2788 if (vec_len (m->locals))
2790 s = format (s, "%U vrf %d external %U:%d",
2791 format_snat_protocol, m->proto,
2793 format_ip4_address, &m->external_addr, m->external_port);
2794 vec_foreach (local, m->locals)
2795 s = format (s, "\n local %U:%d probability %d\%",
2796 format_ip4_address, &local->addr, local->port,
2797 local->probability);
2800 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2801 format_snat_protocol, m->proto,
2802 format_ip4_address, &m->local_addr, m->local_port,
2803 format_ip4_address, &m->external_addr, m->external_port,
2809 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2811 snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2812 vnet_main_t *vnm = vnet_get_main();
2815 s = format (s, "local %U external %U vrf %d",
2816 format_ip4_address, &m->l_addr,
2817 format_vnet_sw_interface_name, vnm,
2818 vnet_get_sw_interface (vnm, m->sw_if_index),
2821 s = format (s, "%U local %U:%d external %U:%d vrf %d",
2822 format_snat_protocol, m->proto,
2823 format_ip4_address, &m->l_addr, m->l_port,
2824 format_vnet_sw_interface_name, vnm,
2825 vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2831 u8 * format_det_map_ses (u8 * s, va_list * args)
2833 snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2834 ip4_address_t in_addr, out_addr;
2835 u32 in_offset, out_offset;
2836 snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2837 u32 * i = va_arg (*args, u32 *);
2839 u32 user_index = *i / SNAT_DET_SES_PER_USER;
2840 in_addr.as_u32 = clib_host_to_net_u32 (
2841 clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2842 in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2843 clib_net_to_host_u32(det_map->in_addr.as_u32);
2844 out_offset = in_offset / det_map->sharing_ratio;
2845 out_addr.as_u32 = clib_host_to_net_u32(
2846 clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2847 s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2848 format_ip4_address, &in_addr,
2849 clib_net_to_host_u16 (ses->in_port),
2850 format_ip4_address, &out_addr,
2851 clib_net_to_host_u16 (ses->out.out_port),
2852 format_ip4_address, &ses->out.ext_host_addr,
2853 clib_net_to_host_u16 (ses->out.ext_host_port),
2854 format_snat_session_state, ses->state,
2860 static clib_error_t *
2861 show_snat_command_fn (vlib_main_t * vm,
2862 unformat_input_t * input,
2863 vlib_cli_command_t * cmd)
2866 snat_main_t * sm = &snat_main;
2868 snat_static_mapping_t *m;
2869 snat_interface_t *i;
2870 snat_address_t * ap;
2871 vnet_main_t *vnm = vnet_get_main();
2872 snat_main_per_thread_data_t *tsm;
2873 u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2875 snat_static_map_resolve_t *rp;
2876 snat_det_map_t * dm;
2877 snat_det_session_t * ses;
2879 if (unformat (input, "detail"))
2881 else if (unformat (input, "verbose"))
2884 if (sm->static_mapping_only)
2886 if (sm->static_mapping_connection_tracking)
2887 vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2890 vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2892 else if (sm->deterministic)
2894 vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2898 vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2903 pool_foreach (i, sm->interfaces,
2905 vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2906 vnet_get_sw_interface (vnm, i->sw_if_index),
2907 (nat_interface_is_inside(i) &&
2908 nat_interface_is_outside(i)) ? "in out" :
2909 (nat_interface_is_inside(i) ? "in" : "out"));
2912 pool_foreach (i, sm->output_feature_interfaces,
2914 vlib_cli_output (vm, "%U output-feature %s",
2915 format_vnet_sw_interface_name, vnm,
2916 vnet_get_sw_interface (vnm, i->sw_if_index),
2917 (nat_interface_is_inside(i) &&
2918 nat_interface_is_outside(i)) ? "in out" :
2919 (nat_interface_is_inside(i) ? "in" : "out"));
2922 if (vec_len (sm->auto_add_sw_if_indices))
2924 vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2925 vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2927 vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2928 vnet_get_sw_interface (vnm, *sw_if_index));
2932 vec_foreach (ap, sm->addresses)
2934 vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2935 if (ap->fib_index != ~0)
2936 vlib_cli_output (vm, " tenant VRF: %u",
2937 ip4_fib_get(ap->fib_index)->table_id);
2939 vlib_cli_output (vm, " tenant VRF independent");
2940 #define _(N, i, n, s) \
2941 vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s);
2942 foreach_snat_protocol
2947 if (sm->num_workers > 1)
2949 vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2952 vec_foreach (worker, sm->workers)
2954 vlib_worker_thread_t *w =
2955 vlib_worker_threads + *worker + sm->first_worker_index;
2956 vlib_cli_output (vm, " %s", w->name);
2961 if (sm->deterministic)
2963 vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2964 vlib_cli_output (vm, "tcp-established timeout: %dsec",
2965 sm->tcp_established_timeout);
2966 vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2967 sm->tcp_transitory_timeout);
2968 vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2969 vlib_cli_output (vm, "%d deterministic mappings",
2970 pool_elts (sm->det_maps));
2973 pool_foreach (dm, sm->det_maps,
2975 vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2976 format_ip4_address, &dm->in_addr, dm->in_plen,
2977 format_ip4_address, &dm->out_addr, dm->out_plen);
2978 vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2980 vlib_cli_output (vm, " number of ports per inside host: %d\n",
2981 dm->ports_per_host);
2982 vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2985 vec_foreach_index (j, dm->sessions)
2987 ses = vec_elt_at_index (dm->sessions, j);
2989 vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses,
2998 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
3000 vlib_cli_output (vm, "%d static mappings",
3001 pool_elts (sm->static_mappings));
3005 pool_foreach (m, sm->static_mappings,
3007 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3013 vec_foreach (tsm, sm->per_thread_data)
3015 users_num += pool_elts (tsm->users);
3016 sessions_num += pool_elts (tsm->sessions);
3019 vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3020 " %d static mappings",
3022 vec_len (sm->addresses),
3024 pool_elts (sm->static_mappings));
3028 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3030 vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3032 vec_foreach_index (j, sm->per_thread_data)
3034 tsm = vec_elt_at_index (sm->per_thread_data, j);
3036 if (pool_elts (tsm->users) == 0)
3039 vlib_worker_thread_t *w = vlib_worker_threads + j;
3040 vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3042 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out,
3044 vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in,
3046 vlib_cli_output (vm, " %d list pool elements",
3047 pool_elts (tsm->list_pool));
3049 pool_foreach (u, tsm->users,
3051 vlib_cli_output (vm, " %U", format_snat_user, tsm, u,
3056 if (pool_elts (sm->static_mappings))
3058 vlib_cli_output (vm, "static mappings:");
3059 pool_foreach (m, sm->static_mappings,
3061 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3063 for (j = 0; j < vec_len (sm->to_resolve); j++)
3065 rp = sm->to_resolve + j;
3066 vlib_cli_output (vm, "%U",
3067 format_snat_static_map_to_resolve, rp);
3077 VLIB_CLI_COMMAND (show_snat_command, static) = {
3078 .path = "show nat44",
3079 .short_help = "show nat44",
3080 .function = show_snat_command_fn,
3085 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3088 ip4_address_t * address,
3090 u32 if_address_index,
3093 snat_main_t *sm = &snat_main;
3094 snat_static_map_resolve_t *rp;
3095 u32 *indices_to_delete = 0;
3096 ip4_address_t l_addr;
3100 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3102 if (sw_if_index == sm->auto_add_sw_if_indices[i])
3106 /* Don't trip over lease renewal, static config */
3107 for (j = 0; j < vec_len(sm->addresses); j++)
3108 if (sm->addresses[j].addr.as_u32 == address->as_u32)
3111 snat_add_address (sm, address, ~0);
3112 /* Scan static map resolution vector */
3113 for (j = 0; j < vec_len (sm->to_resolve); j++)
3115 rp = sm->to_resolve + j;
3116 /* On this interface? */
3117 if (rp->sw_if_index == sw_if_index)
3119 /* Indetity mapping? */
3120 if (rp->l_addr.as_u32 == 0)
3121 l_addr.as_u32 = address[0].as_u32;
3123 l_addr.as_u32 = rp->l_addr.as_u32;
3124 /* Add the static mapping */
3125 rv = snat_add_static_mapping (l_addr,
3131 ~0 /* sw_if_index */,
3135 clib_warning ("snat_add_static_mapping returned %d",
3137 vec_add1 (indices_to_delete, j);
3140 /* If we resolved any of the outstanding static mappings */
3141 if (vec_len(indices_to_delete))
3144 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3145 vec_delete(sm->to_resolve, 1, j);
3146 vec_free(indices_to_delete);
3152 (void) snat_del_address(sm, address[0], 1);
3160 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
3162 ip4_main_t * ip4_main = sm->ip4_main;
3163 ip4_address_t * first_int_addr;
3164 snat_static_map_resolve_t *rp;
3165 u32 *indices_to_delete = 0;
3168 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3169 0 /* just want the address*/);
3171 for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3173 if (sm->auto_add_sw_if_indices[i] == sw_if_index)
3177 /* if have address remove it */
3179 (void) snat_del_address (sm, first_int_addr[0], 1);
3182 for (j = 0; j < vec_len (sm->to_resolve); j++)
3184 rp = sm->to_resolve + j;
3185 if (rp->sw_if_index == sw_if_index)
3186 vec_add1 (indices_to_delete, j);
3188 if (vec_len(indices_to_delete))
3190 for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3191 vec_del1(sm->to_resolve, j);
3192 vec_free(indices_to_delete);
3195 vec_del1(sm->auto_add_sw_if_indices, i);
3198 return VNET_API_ERROR_VALUE_EXIST;
3205 return VNET_API_ERROR_NO_SUCH_ENTRY;
3207 /* add to the auto-address list */
3208 vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3210 /* If the address is already bound - or static - add it now */
3212 snat_add_address (sm, first_int_addr, ~0);
3217 static clib_error_t *
3218 snat_add_interface_address_command_fn (vlib_main_t * vm,
3219 unformat_input_t * input,
3220 vlib_cli_command_t * cmd)
3222 snat_main_t *sm = &snat_main;
3223 unformat_input_t _line_input, *line_input = &_line_input;
3227 clib_error_t *error = 0;
3229 /* Get a line of input. */
3230 if (!unformat_user (input, unformat_line_input, line_input))
3233 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3235 if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3236 sm->vnet_main, &sw_if_index))
3238 else if (unformat (line_input, "del"))
3242 error = clib_error_return (0, "unknown input '%U'",
3243 format_unformat_error, line_input);
3248 rv = snat_add_interface_address (sm, sw_if_index, is_del);
3256 error = clib_error_return (0, "snat_add_interface_address returned %d",
3262 unformat_free (line_input);
3267 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3268 .path = "nat44 add interface address",
3269 .short_help = "nat44 add interface address <interface> [del]",
3270 .function = snat_add_interface_address_command_fn,
3274 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3275 snat_protocol_t proto, u32 vrf_id, int is_in)
3277 snat_main_per_thread_data_t *tsm;
3278 clib_bihash_kv_8_8_t kv, value;
3280 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3281 snat_session_key_t key;
3283 clib_bihash_8_8_t *t;
3284 snat_user_key_t u_key;
3287 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3288 if (sm->num_workers)
3290 vec_elt_at_index (sm->per_thread_data,
3291 sm->worker_in2out_cb (&ip, fib_index));
3293 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3295 key.addr.as_u32 = addr->as_u32;
3296 key.port = clib_host_to_net_u16 (port);
3297 key.protocol = proto;
3298 key.fib_index = fib_index;
3299 kv.key = key.as_u64;
3300 t = is_in ? &tsm->in2out : &tsm->out2in;
3301 if (!clib_bihash_search_8_8 (t, &kv, &value))
3303 s = pool_elt_at_index (tsm->sessions, value.value);
3304 kv.key = s->in2out.as_u64;
3305 clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3306 kv.key = s->out2in.as_u64;
3307 clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3308 u_key.addr = s->in2out.addr;
3309 u_key.fib_index = s->in2out.fib_index;
3310 kv.key = u_key.as_u64;
3311 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3313 u = pool_elt_at_index (tsm->users, value.value);
3316 clib_dlist_remove (tsm->list_pool, s->per_user_index);
3317 pool_put (tsm->sessions, s);
3321 return VNET_API_ERROR_NO_SUCH_ENTRY;
3324 static clib_error_t *
3325 nat44_del_session_command_fn (vlib_main_t * vm,
3326 unformat_input_t * input,
3327 vlib_cli_command_t * cmd)
3329 snat_main_t *sm = &snat_main;
3330 unformat_input_t _line_input, *line_input = &_line_input;
3332 clib_error_t *error = 0;
3334 u32 port = 0, vrf_id = sm->outside_vrf_id;
3335 snat_protocol_t proto;
3338 /* Get a line of input. */
3339 if (!unformat_user (input, unformat_line_input, line_input))
3342 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3344 if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3345 unformat_snat_protocol, &proto))
3347 else if (unformat (line_input, "in"))
3350 vrf_id = sm->inside_vrf_id;
3352 else if (unformat (line_input, "vrf %u", &vrf_id))
3356 error = clib_error_return (0, "unknown input '%U'",
3357 format_unformat_error, line_input);
3362 rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3370 error = clib_error_return (0, "nat44_del_session returned %d", rv);
3375 unformat_free (line_input);
3380 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3381 .path = "nat44 del session",
3382 .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3383 .function = nat44_del_session_command_fn,
3386 static clib_error_t *
3387 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
3388 unformat_input_t * input,
3389 vlib_cli_command_t * cmd)
3391 snat_main_t *sm = &snat_main;
3392 unformat_input_t _line_input, *line_input = &_line_input;
3393 clib_error_t *error = 0;
3394 u32 psid, psid_offset, psid_length;
3396 /* Get a line of input. */
3397 if (!unformat_user (input, unformat_line_input, line_input))
3400 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3402 if (unformat (line_input, "default"))
3403 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3404 else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3405 &psid, &psid_offset, &psid_length))
3407 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3408 sm->psid = (u16) psid;
3409 sm->psid_offset = (u16) psid_offset;
3410 sm->psid_length = (u16) psid_length;
3414 error = clib_error_return (0, "unknown input '%U'",
3415 format_unformat_error, line_input);
3421 unformat_free (line_input);
3426 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3427 .path = "nat44 addr-port-assignment-alg",
3428 .short_help = "nat44 addr-port-assignment-alg <alg-name> [<alg-params>]",
3429 .function = nat44_set_alloc_addr_and_port_alg_command_fn,
3432 static clib_error_t *
3433 snat_det_map_command_fn (vlib_main_t * vm,
3434 unformat_input_t * input,
3435 vlib_cli_command_t * cmd)
3437 snat_main_t *sm = &snat_main;
3438 unformat_input_t _line_input, *line_input = &_line_input;
3439 ip4_address_t in_addr, out_addr;
3440 u32 in_plen, out_plen;
3442 clib_error_t *error = 0;
3444 /* Get a line of input. */
3445 if (!unformat_user (input, unformat_line_input, line_input))
3448 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3450 if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3452 else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3454 else if (unformat (line_input, "del"))
3458 error = clib_error_return (0, "unknown input '%U'",
3459 format_unformat_error, line_input);
3464 unformat_free (line_input);
3466 rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3471 error = clib_error_return (0, "snat_det_add_map return %d", rv);
3476 unformat_free (line_input);
3483 * @cliexstart{snat deterministic add}
3484 * Create bijective mapping of inside address to outside address and port range
3485 * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3487 * To create deterministic mapping between inside network 10.0.0.0/18 and
3488 * outside network 1.1.1.0/30 use:
3489 * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3492 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3493 .path = "nat44 deterministic add",
3494 .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3495 .function = snat_det_map_command_fn,
3498 static clib_error_t *
3499 snat_det_forward_command_fn (vlib_main_t * vm,
3500 unformat_input_t * input,
3501 vlib_cli_command_t * cmd)
3503 snat_main_t *sm = &snat_main;
3504 unformat_input_t _line_input, *line_input = &_line_input;
3505 ip4_address_t in_addr, out_addr;
3507 snat_det_map_t * dm;
3508 clib_error_t *error = 0;
3510 /* Get a line of input. */
3511 if (!unformat_user (input, unformat_line_input, line_input))
3514 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3516 if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3520 error = clib_error_return (0, "unknown input '%U'",
3521 format_unformat_error, line_input);
3526 unformat_free (line_input);
3528 dm = snat_det_map_by_user(sm, &in_addr);
3530 vlib_cli_output (vm, "no match");
3533 snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3534 vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3535 lo_port, lo_port + dm->ports_per_host - 1);
3539 unformat_free (line_input);
3546 * @cliexstart{snat deterministic forward}
3547 * Return outside address and port range from inside address for deterministic
3549 * To obtain outside address and port of inside host use:
3550 * vpp# nat44 deterministic forward 10.0.0.2
3551 * 1.1.1.0:<1054-1068>
3554 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3555 .path = "nat44 deterministic forward",
3556 .short_help = "nat44 deterministic forward <addr>",
3557 .function = snat_det_forward_command_fn,
3560 static clib_error_t *
3561 snat_det_reverse_command_fn (vlib_main_t * vm,
3562 unformat_input_t * input,
3563 vlib_cli_command_t * cmd)
3565 snat_main_t *sm = &snat_main;
3566 unformat_input_t _line_input, *line_input = &_line_input;
3567 ip4_address_t in_addr, out_addr;
3569 snat_det_map_t * dm;
3570 clib_error_t *error = 0;
3572 /* Get a line of input. */
3573 if (!unformat_user (input, unformat_line_input, line_input))
3576 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3578 if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3582 error = clib_error_return (0, "unknown input '%U'",
3583 format_unformat_error, line_input);
3587 unformat_free (line_input);
3589 if (out_port < 1024 || out_port > 65535)
3591 error = clib_error_return (0, "wrong port, must be <1024-65535>");
3595 dm = snat_det_map_by_out(sm, &out_addr);
3597 vlib_cli_output (vm, "no match");
3600 snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3601 vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3605 unformat_free (line_input);
3612 * @cliexstart{snat deterministic reverse}
3613 * Return inside address from outside address and port for deterministic NAT.
3614 * To obtain inside host address from outside address and port use:
3615 * #vpp nat44 deterministic reverse 1.1.1.1:1276
3619 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3620 .path = "nat44 deterministic reverse",
3621 .short_help = "nat44 deterministic reverse <addr>:<port>",
3622 .function = snat_det_reverse_command_fn,
3625 static clib_error_t *
3626 set_timeout_command_fn (vlib_main_t * vm,
3627 unformat_input_t * input,
3628 vlib_cli_command_t * cmd)
3630 snat_main_t *sm = &snat_main;
3631 unformat_input_t _line_input, *line_input = &_line_input;
3632 clib_error_t *error = 0;
3634 /* Get a line of input. */
3635 if (!unformat_user (input, unformat_line_input, line_input))
3638 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3640 if (unformat (line_input, "udp %u", &sm->udp_timeout))
3642 else if (unformat (line_input, "tcp-established %u",
3643 &sm->tcp_established_timeout))
3645 else if (unformat (line_input, "tcp-transitory %u",
3646 &sm->tcp_transitory_timeout))
3648 else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3650 else if (unformat (line_input, "reset"))
3652 sm->udp_timeout = SNAT_UDP_TIMEOUT;
3653 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3654 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3655 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3659 error = clib_error_return (0, "unknown input '%U'",
3660 format_unformat_error, line_input);
3665 unformat_free (line_input);
3668 unformat_free (line_input);
3675 * @cliexstart{set snat deterministic timeout}
3676 * Set values of timeouts for deterministic NAT (in seconds), use:
3677 * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3678 * tcp-transitory 250 icmp 90
3679 * To reset default values use:
3680 * vpp# set nat44 deterministic timeout reset
3683 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3684 .path = "set nat44 deterministic timeout",
3685 .function = set_timeout_command_fn,
3687 "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3688 "tcp-transitory <sec> | icmp <sec> | reset]",
3691 static clib_error_t *
3692 snat_det_close_session_out_fn (vlib_main_t *vm,
3693 unformat_input_t * input,
3694 vlib_cli_command_t * cmd)
3696 snat_main_t *sm = &snat_main;
3697 unformat_input_t _line_input, *line_input = &_line_input;
3698 ip4_address_t out_addr, ext_addr, in_addr;
3699 u32 out_port, ext_port;
3700 snat_det_map_t * dm;
3701 snat_det_session_t * ses;
3702 snat_det_out_key_t key;
3703 clib_error_t *error = 0;
3705 /* Get a line of input. */
3706 if (!unformat_user (input, unformat_line_input, line_input))
3709 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3711 if (unformat (line_input, "%U:%d %U:%d",
3712 unformat_ip4_address, &out_addr, &out_port,
3713 unformat_ip4_address, &ext_addr, &ext_port))
3717 error = clib_error_return (0, "unknown input '%U'",
3718 format_unformat_error, line_input);
3723 unformat_free (line_input);
3725 dm = snat_det_map_by_out(sm, &out_addr);
3727 vlib_cli_output (vm, "no match");
3730 snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
3731 key.ext_host_addr = out_addr;
3732 key.ext_host_port = ntohs((u16)ext_port);
3733 key.out_port = ntohs((u16)out_port);
3734 ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3736 vlib_cli_output (vm, "no match");
3738 snat_det_ses_close(dm, ses);
3742 unformat_free (line_input);
3749 * @cliexstart{snat deterministic close session out}
3750 * Close session using outside ip address and port
3751 * and external ip address and port, use:
3752 * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3755 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3756 .path = "nat44 deterministic close session out",
3757 .short_help = "nat44 deterministic close session out "
3758 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3759 .function = snat_det_close_session_out_fn,
3762 static clib_error_t *
3763 snat_det_close_session_in_fn (vlib_main_t *vm,
3764 unformat_input_t * input,
3765 vlib_cli_command_t * cmd)
3767 snat_main_t *sm = &snat_main;
3768 unformat_input_t _line_input, *line_input = &_line_input;
3769 ip4_address_t in_addr, ext_addr;
3770 u32 in_port, ext_port;
3771 snat_det_map_t * dm;
3772 snat_det_session_t * ses;
3773 snat_det_out_key_t key;
3774 clib_error_t *error = 0;
3776 /* Get a line of input. */
3777 if (!unformat_user (input, unformat_line_input, line_input))
3780 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3782 if (unformat (line_input, "%U:%d %U:%d",
3783 unformat_ip4_address, &in_addr, &in_port,
3784 unformat_ip4_address, &ext_addr, &ext_port))
3788 error = clib_error_return (0, "unknown input '%U'",
3789 format_unformat_error, line_input);
3794 unformat_free (line_input);
3796 dm = snat_det_map_by_user (sm, &in_addr);
3798 vlib_cli_output (vm, "no match");
3801 key.ext_host_addr = ext_addr;
3802 key.ext_host_port = ntohs ((u16)ext_port);
3803 ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
3805 vlib_cli_output (vm, "no match");
3807 snat_det_ses_close(dm, ses);
3811 unformat_free(line_input);
3818 * @cliexstart{snat deterministic close_session_in}
3819 * Close session using inside ip address and port
3820 * and external ip address and port, use:
3821 * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3824 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3825 .path = "nat44 deterministic close session in",
3826 .short_help = "nat44 deterministic close session in "
3827 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3828 .function = snat_det_close_session_in_fn,