From 09d96f4a611fa989bfbbfb7e683d668dbe73ac1a Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Thu, 2 Feb 2017 01:43:00 -0800 Subject: [PATCH 1/1] SNAT: Port allocation per protocol Ports are allocated per protocol (UDP, TCP, ICMP) 1:1 NAT with port is configured for specific protocol Change-Id: I37ae5eed3715b223d0620d4fdaed7a482bb7a834 Signed-off-by: Matus Fabian --- src/plugins/snat/in2out.c | 37 ++----- src/plugins/snat/out2in.c | 34 +----- src/plugins/snat/snat.api | 4 + src/plugins/snat/snat.c | 196 +++++++++++++++++++++++++--------- src/plugins/snat/snat.h | 46 ++++++-- src/plugins/snat/snat_ipfix_logging.c | 4 +- src/plugins/snat/snat_test.c | 29 +++-- test/test_snat.py | 27 +++-- test/vpp_papi_provider.py | 5 +- 9 files changed, 242 insertions(+), 140 deletions(-) diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c index fba852c6fe1..b0047737121 100644 --- a/src/plugins/snat/in2out.c +++ b/src/plugins/snat/in2out.c @@ -224,7 +224,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, u32 address_index = ~0; u32 outside_fib_index; uword * p; - snat_static_mapping_key_t worker_by_out_key; + snat_worker_key_t worker_by_out_key; p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id); if (! p) @@ -234,6 +234,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, } outside_fib_index = p[0]; + key1.protocol = key0->protocol; user_key.addr = ip0->src_address; user_key.fib_index = rx_fib_index0; kv0.key = user_key.as_u64; @@ -520,7 +521,7 @@ snat_hairpinning (snat_main_t *sm, u32 proto0) { snat_session_key_t key0, sm0; - snat_static_mapping_key_t k0; + snat_worker_key_t k0; snat_session_t * s0; clib_bihash_kv_8_8_t kv0, value0; ip_csum_t sum0; @@ -682,13 +683,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP; - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); /* Next configured feature, probably ip4-lookup */ if (is_slow_path) @@ -818,13 +813,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, sw_if_index1); - proto1 = ~0; - proto1 = (ip1->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto1; + proto1 = ip_proto_to_snat_proto (ip1->protocol); /* Next configured feature, probably ip4-lookup */ if (is_slow_path) @@ -989,13 +978,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, sw_if_index0); - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); /* Next configured feature, probably ip4-lookup */ if (is_slow_path) @@ -1497,13 +1480,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm, sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); if (PREDICT_FALSE (proto0 == ~0)) goto trace0; diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c index f08e16d3c51..4f3322a3231 100644 --- a/src/plugins/snat/out2in.c +++ b/src/plugins/snat/out2in.c @@ -405,13 +405,7 @@ snat_out2in_node_fn (vlib_main_t * vm, rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, sw_if_index0); - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); if (PREDICT_FALSE (proto0 == ~0)) goto trace0; @@ -536,13 +530,7 @@ snat_out2in_node_fn (vlib_main_t * vm, rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, sw_if_index1); - proto1 = ~0; - proto1 = (ip1->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto1; - proto1 = (ip1->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto1; + proto1 = ip_proto_to_snat_proto (ip1->protocol); if (PREDICT_FALSE (proto1 == ~0)) goto trace1; @@ -701,13 +689,7 @@ snat_out2in_node_fn (vlib_main_t * vm, rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index, sw_if_index0); - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); if (PREDICT_FALSE (proto0 == ~0)) goto trace00; @@ -901,7 +883,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, u32 rx_fib_index0; ip4_header_t * ip0; udp_header_t * udp0; - snat_static_mapping_key_t key0; + snat_worker_key_t key0; clib_bihash_kv_8_8_t kv0, value0; u8 do_handoff; @@ -1196,13 +1178,7 @@ snat_out2in_fast_node_fn (vlib_main_t * vm, vnet_feature_next (sw_if_index0, &next0, b0); - proto0 = ~0; - proto0 = (ip0->protocol == IP_PROTOCOL_UDP) - ? SNAT_PROTOCOL_UDP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_TCP) - ? SNAT_PROTOCOL_TCP : proto0; - proto0 = (ip0->protocol == IP_PROTOCOL_ICMP) - ? SNAT_PROTOCOL_ICMP : proto0; + proto0 = ip_proto_to_snat_proto (ip0->protocol); if (PREDICT_FALSE (proto0 == ~0)) goto trace00; diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index b562e7a08e1..decbacf5c2f 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -118,6 +118,7 @@ define snat_interface_details { @param addr_only - 1 if address only mapping @param local_ip_address - local IP address @param external_ip_address - external IP address + @param protocol - IP protocol @param local_port - local port number @param external_port - external port number @param external_sw_if_index - external interface (if set @@ -132,6 +133,7 @@ define snat_add_static_mapping { u8 addr_only; u8 local_ip_address[16]; u8 external_ip_address[16]; + u8 protocol; u16 local_port; u16 external_port; u32 external_sw_if_index; @@ -162,6 +164,7 @@ define snat_static_mapping_dump { @param addr_only - 1 if address only mapping @param local_ip_address - local IP address @param external_ip_address - external IP address + @param protocol - IP protocol @param local_port - local port number @param external_port - external port number @param vfr_id - VRF ID @@ -172,6 +175,7 @@ define snat_static_mapping_details { u8 addr_only; u8 local_ip_address[16]; u8 external_ip_address[16]; + u8 protocol; u16 local_port; u16 external_port; u32 vrf_id; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 5ee6647576a..0fcd6ce8606 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -270,7 +270,10 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr) vec_add2 (sm->addresses, ap, 1); ap->addr = *addr; - clib_bitmap_alloc (ap->busy_port_bitmap, 65535); +#define _(N, i, n, s) \ + clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); + foreach_snat_protocol +#undef _ /* Add external address to FIB */ pool_foreach (i, sm->interfaces, @@ -311,6 +314,7 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, u32 sw_if_index, u16 e_port, u32 vrf_id, + snat_protocol_t proto, int addr_only, int is_add) { @@ -322,6 +326,7 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, rp->sw_if_index = sw_if_index; rp->e_port = e_port; rp->vrf_id = vrf_id; + rp->proto = proto; rp->addr_only = addr_only; rp->is_add = is_add; } @@ -344,11 +349,11 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, */ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, - u32 sw_if_index, int is_add) + u32 sw_if_index, snat_protocol_t proto, int is_add) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; - snat_static_mapping_key_t m_key; + snat_session_key_t m_key; clib_bihash_kv_8_8_t kv, value; snat_address_t *a = 0; u32 fib_index = ~0; @@ -378,7 +383,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (first_int_addr == 0) { snat_add_static_mapping_when_resolved - (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, + (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, addr_only, is_add); return 0; } @@ -388,6 +393,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, m_key.addr = e_addr; m_key.port = addr_only ? 0 : e_port; + m_key.protocol = addr_only ? 0 : proto; m_key.fib_index = sm->outside_fib_index; kv.key = m_key.as_u64; if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) @@ -435,12 +441,22 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, { a = sm->addresses + i; /* External port must be unused */ - if (clib_bitmap_get_no_check (a->busy_port_bitmap, e_port)) - return VNET_API_ERROR_INVALID_VALUE; - clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 1); - if (e_port > 1024) - a->busy_ports++; - + switch (proto) + { +#define _(N, j, n, s) \ + case SNAT_PROTOCOL_##N: \ + if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \ + return VNET_API_ERROR_INVALID_VALUE; \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \ + if (e_port > 1024) \ + a->busy_##n##_ports++; \ + break; + foreach_snat_protocol +#undef _ + default: + clib_warning("unknown_protocol"); + return VNET_API_ERROR_INVALID_VALUE_2; + } break; } } @@ -460,10 +476,12 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, { m->local_port = l_port; m->external_port = e_port; + m->proto = proto; } m_key.addr = m->local_addr; m_key.port = m->local_port; + m_key.protocol = m->proto; m_key.fib_index = m->fib_index; kv.key = m_key.as_u64; kv.value = m - sm->static_mappings; @@ -480,7 +498,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (sm->workers) { snat_user_key_t w_key0; - snat_static_mapping_key_t w_key1; + snat_worker_key_t w_key1; w_key0.addr = m->local_addr; w_key0.fib_index = m->fib_index; @@ -518,9 +536,20 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) { a = sm->addresses + i; - clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 0); - a->busy_ports--; - + switch (proto) + { +#define _(N, j, n, s) \ + case SNAT_PROTOCOL_##N: \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \ + if (e_port > 1024) \ + a->busy_##n##_ports--; \ + break; + foreach_snat_protocol +#undef _ + default: + clib_warning("unknown_protocol"); + return VNET_API_ERROR_INVALID_VALUE_2; + } break; } } @@ -528,6 +557,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, m_key.addr = m->local_addr; m_key.port = m->local_port; + m_key.protocol = m->proto; m_key.fib_index = m->fib_index; kv.key = m_key.as_u64; clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0); @@ -666,7 +696,8 @@ int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm) if (m->external_addr.as_u32 == addr.as_u32) (void) snat_add_static_mapping (m->local_addr, m->external_addr, m->local_port, m->external_port, - m->vrf_id, m->addr_only, ~0, 0); + m->vrf_id, m->addr_only, ~0, + m->proto, 0); })); } else @@ -680,7 +711,7 @@ int snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm) } /* Delete sessions using address */ - if (a->busy_ports) + if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) { vec_foreach (tsm, sm->per_thread_data) { @@ -1019,6 +1050,7 @@ vl_api_snat_add_static_mapping_t_handler u16 local_port = 0, external_port = 0; u32 vrf_id, external_sw_if_index; int rv = 0; + snat_protocol_t proto; if (mp->is_ip4 != 1) { @@ -1035,11 +1067,11 @@ vl_api_snat_add_static_mapping_t_handler } vrf_id = clib_net_to_host_u32 (mp->vrf_id); external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); + proto = ip_proto_to_snat_proto (mp->protocol); rv = snat_add_static_mapping(local_addr, external_addr, local_port, external_port, vrf_id, mp->addr_only, - external_sw_if_index, - mp->is_add); + external_sw_if_index, proto, mp->is_add); send_reply: REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY); @@ -1051,7 +1083,8 @@ static void *vl_api_snat_add_static_mapping_t_print u8 * s; s = format (0, "SCRIPT: snat_add_static_mapping "); - s = format (s, "local_addr %U external_addr %U ", + s = format (s, "protocol %d local_addr %U external_addr %U ", + mp->protocol, format_ip4_address, mp->local_ip_address, format_ip4_address, mp->external_ip_address); @@ -1086,6 +1119,7 @@ send_snat_static_mapping_details rmp->local_port = htons (m->local_port); rmp->external_port = htons (m->external_port); rmp->vrf_id = htonl (m->vrf_id); + rmp->protocol = snat_proto_to_ip_proto (m->proto); rmp->context = context; vl_msg_api_send_shmem (q, (u8 *) & rmp); @@ -1532,11 +1566,22 @@ void snat_free_outside_address_and_port (snat_main_t * sm, a = sm->addresses + address_index; - ASSERT (clib_bitmap_get_no_check (a->busy_port_bitmap, - port_host_byte_order) == 1); - - clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0); - a->busy_ports--; + switch (k->protocol) + { +#define _(N, i, n, s) \ + case SNAT_PROTOCOL_##N: \ + ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ + port_host_byte_order) == 1); \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ + port_host_byte_order, 0); \ + a->busy_##n##_ports--; \ + break; + foreach_snat_protocol +#undef _ + default: + clib_warning("unknown_protocol"); + return; + } } /** @@ -1557,7 +1602,7 @@ int snat_static_mapping_match (snat_main_t * sm, { clib_bihash_kv_8_8_t kv, value; snat_static_mapping_t *m; - snat_static_mapping_key_t m_key; + snat_session_key_t m_key; clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; if (by_external) @@ -1565,6 +1610,7 @@ int snat_static_mapping_match (snat_main_t * sm, m_key.addr = match.addr; m_key.port = clib_net_to_host_u16 (match.port); + m_key.protocol = match.protocol; m_key.fib_index = match.fib_index; kv.key = m_key.as_u64; @@ -1573,6 +1619,7 @@ int snat_static_mapping_match (snat_main_t * sm, { /* Try address only mapping */ m_key.port = 0; + m_key.protocol = 0; kv.key = m_key.as_u64; if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) return 1; @@ -1610,27 +1657,37 @@ int snat_alloc_outside_address_and_port (snat_main_t * sm, for (i = 0; i < vec_len (sm->addresses); i++) { - if (sm->addresses[i].busy_ports < (65535-1024)) + a = sm->addresses + i; + switch (k->protocol) { - a = sm->addresses + i; - - while (1) - { - portnum = random_u32 (&sm->random_seed); - portnum &= 0xFFFF; - if (portnum < 1024) - continue; - if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum)) - continue; - clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1); - a->busy_ports++; - /* Caller sets protocol and fib index */ - k->addr = a->addr; - k->port = clib_host_to_net_u16(portnum); - *address_indexp = i; - return 0; - } +#define _(N, j, n, s) \ + case SNAT_PROTOCOL_##N: \ + if (a->busy_##n##_ports < (65535-1024)) \ + { \ + while (1) \ + { \ + portnum = random_u32 (&sm->random_seed); \ + portnum &= 0xFFFF; \ + if (portnum < 1024) \ + continue; \ + if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ + continue; \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ + a->busy_##n##_ports++; \ + k->addr = a->addr; \ + k->port = clib_host_to_net_u16(portnum); \ + *address_indexp = i; \ + return 0; \ + } \ + } \ + break; + foreach_snat_protocol +#undef _ + default: + clib_warning("unknown protocol"); + return 1; } + } /* Totally out of translations to use... */ snat_ipfix_logging_addresses_exhausted(0); @@ -1787,6 +1844,38 @@ VLIB_CLI_COMMAND (set_interface_snat_command, static) = { .short_help = "set interface snat in out [del]", }; +uword +unformat_snat_protocol (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N; + foreach_snat_protocol +#undef _ + else + return 0; + return 1; +} + +u8 * +format_snat_protocol (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break; + foreach_snat_protocol +#undef _ + default: + s = format (s, "unknown"); + } + s = format (s, "%s", t); + return s; +} + static clib_error_t * add_static_mapping_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -1801,6 +1890,7 @@ add_static_mapping_command_fn (vlib_main_t * vm, u32 sw_if_index = ~0; vnet_main_t * vnm = vnet_get_main(); int rv; + snat_protocol_t proto; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1829,6 +1919,8 @@ add_static_mapping_command_fn (vlib_main_t * vm, ; else if (unformat (line_input, "vrf %u", &vrf_id)) ; + else if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) + ; else if (unformat (line_input, "del")) is_add = 0; else @@ -1838,7 +1930,7 @@ add_static_mapping_command_fn (vlib_main_t * vm, unformat_free (line_input); rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, - vrf_id, addr_only, sw_if_index, is_add); + vrf_id, addr_only, sw_if_index, proto, is_add); switch (rv) { @@ -2175,7 +2267,8 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) format_ip4_address, &m->external_addr, m->vrf_id); else - s = format (s, "local %U:%d external %U:%d vrf %d", + s = format (s, "%U local %U:%d external %U:%d vrf %d", + format_snat_protocol, m->proto, format_ip4_address, &m->local_addr, m->local_port, format_ip4_address, &m->external_addr, m->external_port, m->vrf_id); @@ -2238,13 +2331,11 @@ show_snat_command_fn (vlib_main_t * vm, vec_foreach (ap, sm->addresses) { - u8 * s = format (0, ""); vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); - clib_bitmap_foreach (j, ap->busy_port_bitmap, - ({ - s = format (s, " %d", j); - })); - vlib_cli_output (vm, " %d busy ports:%s", ap->busy_ports, s); +#define _(N, i, n, s) \ + vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); + foreach_snat_protocol +#undef _ } } @@ -2383,6 +2474,7 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im, rp->vrf_id, rp->addr_only, ~0 /* sw_if_index */, + rp->proto, rp->is_add); if (rv) clib_warning ("snat_add_static_mapping returned %d", diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index fc379dfa3ed..32dc9f9e0a6 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -66,13 +66,18 @@ typedef struct { }; u64 as_u64; }; -} snat_static_mapping_key_t; +} snat_worker_key_t; +#define foreach_snat_protocol \ + _(UDP, 0, udp, "udp") \ + _(TCP, 1, tcp, "tcp") \ + _(ICMP, 2, icmp, "icmp") + typedef enum { - SNAT_PROTOCOL_UDP = 0, - SNAT_PROTOCOL_TCP, - SNAT_PROTOCOL_ICMP, +#define _(N, i, n, s) SNAT_PROTOCOL_##N = i, + foreach_snat_protocol +#undef _ } snat_protocol_t; @@ -112,8 +117,11 @@ typedef struct { typedef struct { ip4_address_t addr; - u32 busy_ports; - uword * busy_port_bitmap; +#define _(N, i, n, s) \ + u32 busy_##n##_ports; \ + uword * busy_##n##_port_bitmap; + foreach_snat_protocol +#undef _ } snat_address_t; typedef struct { @@ -124,6 +132,7 @@ typedef struct { u8 addr_only; u32 vrf_id; u32 fib_index; + snat_protocol_t proto; } snat_static_mapping_t; typedef struct { @@ -137,6 +146,7 @@ typedef struct { u16 e_port; u32 sw_if_index; u32 vrf_id; + snat_protocol_t proto; int addr_only; int is_add; } snat_static_map_resolve_t; @@ -272,4 +282,28 @@ typedef struct { u16 sequence; } icmp_echo_header_t; +always_inline snat_protocol_t +ip_proto_to_snat_proto (u8 ip_proto) +{ + snat_protocol_t snat_proto = ~0; + + snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto; + snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto; + snat_proto = (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto; + + return snat_proto; +} + +always_inline u8 +snat_proto_to_ip_proto (snat_protocol_t snat_proto) +{ + u8 ip_proto = ~0; + + ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto; + ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto; + ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto; + + return ip_proto; +} + #endif /* __included_snat_h__ */ diff --git a/src/plugins/snat/snat_ipfix_logging.c b/src/plugins/snat/snat_ipfix_logging.c index d72eb226675..9f1abb7d9f4 100644 --- a/src/plugins/snat/snat_ipfix_logging.c +++ b/src/plugins/snat/snat_ipfix_logging.c @@ -295,9 +295,7 @@ snat_ipfix_logging_nat44_ses (u8 nat_event, u32 src_ip, u32 nat_src_ip, if (!silm->enabled) return; - proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : proto; - proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : proto; - proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : proto; + proto = snat_proto_to_ip_proto (snat_proto); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c index 50e81eaec46..85f9d57a35e 100644 --- a/src/plugins/snat/snat_test.c +++ b/src/plugins/snat/snat_test.c @@ -214,13 +214,14 @@ static int api_snat_add_static_mapping(vat_main_t * vam) unformat_input_t * i = vam->input; vl_api_snat_add_static_mapping_t * mp; u8 external_addr_set = 0; - u8 local_addr_set; + u8 local_addr_set = 0; u8 is_add = 1; u8 addr_only = 1; ip4_address_t local_addr, external_addr; u32 local_port = 0, external_port = 0, vrf_id = ~0; u32 sw_if_index = ~0; u8 sw_if_index_set = 0; + u32 proto = ~0; int ret; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) @@ -239,7 +240,9 @@ static int api_snat_add_static_mapping(vat_main_t * vam) sw_if_index_set = 1; else if (unformat (i, "external_sw_if_index %d", &sw_if_index)) sw_if_index_set = 1; - else if (unformat (i, "vrf %u", &vrf_id)) + else if (unformat (i, "vrf %u", &vrf_id)) + ; + else if (unformat (i, "protocol %u", &proto)) ; else if (unformat (i, "del")) is_add = 0; @@ -269,6 +272,7 @@ static int api_snat_add_static_mapping(vat_main_t * vam) mp->external_port = ntohs ((u16) external_port); mp->external_sw_if_index = ntohl (sw_if_index); mp->vrf_id = ntohl (vrf_id); + mp->protocol = (u8) proto; memcpy (mp->local_ip_address, &local_addr, 4); memcpy (mp->external_ip_address, &external_addr, 4); @@ -300,17 +304,19 @@ static void vl_api_snat_static_mapping_details_t_handler vat_main_t *vam = sm->vat_main; if (mp->addr_only) - fformat (vam->ofp, "%15U%6s%15U%6s%11d\n", + fformat (vam->ofp, "%15U%6s%15U%6s%11d%6d\n", format_ip4_address, &mp->local_ip_address, "", format_ip4_address, &mp->external_ip_address, "", - ntohl (mp->vrf_id)); + ntohl (mp->vrf_id), + mp->protocol); else - fformat (vam->ofp, "%15U%6d%15U%6d%11d\n", + fformat (vam->ofp, "%15U%6d%15U%6d%11d%6d\n", format_ip4_address, &mp->local_ip_address, ntohs (mp->local_port), format_ip4_address, &mp->external_ip_address, ntohs (mp->external_port), - ntohl (mp->vrf_id)); + ntohl (mp->vrf_id), + mp->protocol); } @@ -327,8 +333,8 @@ static int api_snat_static_mapping_dump(vat_main_t * vam) } fformat (vam->ofp, "%21s%21s\n", "local", "external"); - fformat (vam->ofp, "%15s%6s%15s%6s%11s\n", "address", "port", "address", - "port", "vrf"); + fformat (vam->ofp, "%15s%6s%15s%6s%11s%6s\n", "address", "port", "address", + "port", "vrf", "proto"); M(SNAT_STATIC_MAPPING_DUMP, mp); S(mp); @@ -626,9 +632,10 @@ static int api_snat_add_del_interface_addr (vat_main_t * vam) _(snat_add_address_range, " [- | sw_if_index [in] [out] [del]") \ -_(snat_add_static_mapping, "local_addr external_addr " \ - "| external_if | external_sw_if_ndex ) " \ - "[local_port ] [external_port ] [vrf ] [del]") \ +_(snat_add_static_mapping, "local_addr (external_addr " \ + " | external_if | external_sw_if_ndex ) " \ + "[local_port ] [external_port ] [vrf ] [del] " \ + "protocol ") \ _(snat_set_workers, "") \ _(snat_static_mapping_dump, "") \ _(snat_show_config, "") \ diff --git a/test/test_snat.py b/test/test_snat.py index a67deede7a5..967d4b37c71 100644 --- a/test/test_snat.py +++ b/test/test_snat.py @@ -292,6 +292,7 @@ class TestSNAT(VppTestCase): external_port=sm.external_port, addr_only=sm.addr_only, vrf_id=sm.vrf_id, + protocol=sm.protocol, is_add=0) adresses = self.vapi.snat_address_dump() @@ -302,7 +303,8 @@ class TestSNAT(VppTestCase): def snat_add_static_mapping(self, local_ip, external_ip='0.0.0.0', local_port=0, external_port=0, vrf_id=0, - is_add=1, external_sw_if_index=0xFFFFFFFF): + is_add=1, external_sw_if_index=0xFFFFFFFF, + proto=0): """ Add/delete S-NAT static mapping @@ -313,6 +315,7 @@ class TestSNAT(VppTestCase): :param vrf_id: VRF ID (Default 0) :param is_add: 1 if add, 0 if delete (Default add) :param external_sw_if_index: External interface instead of IP address + :param proto: IP protocol (Mandatory if port specified) """ addr_only = 1 if local_port and external_port: @@ -327,6 +330,7 @@ class TestSNAT(VppTestCase): external_port, addr_only, vrf_id, + proto, is_add) def snat_add_address(self, ip, is_add=1): @@ -430,11 +434,14 @@ class TestSNAT(VppTestCase): self.snat_add_address(self.snat_addr) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.tcp_port_in, self.tcp_port_out) + self.tcp_port_in, self.tcp_port_out, + proto=IP_PROTOS.tcp) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.udp_port_in, self.udp_port_out) + self.udp_port_in, self.udp_port_out, + proto=IP_PROTOS.udp) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.icmp_id_in, self.icmp_id_out) + self.icmp_id_in, self.icmp_id_out, + proto=IP_PROTOS.icmp) self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index, is_inside=0) @@ -464,11 +471,14 @@ class TestSNAT(VppTestCase): self.snat_add_address(self.snat_addr) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.tcp_port_in, self.tcp_port_out) + self.tcp_port_in, self.tcp_port_out, + proto=IP_PROTOS.tcp) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.udp_port_in, self.udp_port_out) + self.udp_port_in, self.udp_port_out, + proto=IP_PROTOS.udp) self.snat_add_static_mapping(self.pg0.remote_ip4, self.snat_addr, - self.icmp_id_in, self.icmp_id_out) + self.icmp_id_in, self.icmp_id_out, + proto=IP_PROTOS.icmp) self.vapi.snat_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.snat_interface_add_del_feature(self.pg1.sw_if_index, is_inside=0) @@ -685,7 +695,8 @@ class TestSNAT(VppTestCase): is_inside=0) # add static mapping for server self.snat_add_static_mapping(server.ip4, self.snat_addr, - server_in_port, server_out_port) + server_in_port, server_out_port, + proto=IP_PROTOS.tcp) # send packet from host to server p = (Ether(src=host.mac, dst=self.pg0.local_mac) / diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 72c18e6cef7..2cd02cc7954 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -883,6 +883,7 @@ class VppPapiProvider(object): external_port=0, addr_only=1, vrf_id=0, + protocol=0, is_add=1, is_ip4=1): """Add/delete S-NAT static mapping @@ -894,6 +895,7 @@ class VppPapiProvider(object): :param external_port: External port number (Default value = 0) :param addr_only: 1 if address only mapping, 0 if address and port :param vrf_id: VRF ID + :param protocol: IP protocol (Default value = 0) :param is_add: 1 if add, 0 if delete (Default value = 1) :param is_ip4: 1 if address type is IPv4 (Default value = 1) """ @@ -907,7 +909,8 @@ class VppPapiProvider(object): 'local_port': local_port, 'external_port': external_port, 'external_sw_if_index': external_sw_if_index, - 'vrf_id': vrf_id}) + 'vrf_id': vrf_id, + 'protocol': protocol}) def snat_add_address_range( self, -- 2.16.6