From: Matus Fabian Date: Thu, 26 Oct 2017 10:37:38 +0000 (-0700) Subject: NAT: delete session API/CLI (VPP-1041) X-Git-Tag: v18.04-rc0~394 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=5ba86f72439a627f2084bcafb221ad77f4990168 NAT: delete session API/CLI (VPP-1041) Administratively delete NAT44 session for specific inside/outside addresses and port pair. Change-Id: If5ab500ac3592c7153d6d8f2cc0297df7309fbc3 Signed-off-by: Matus Fabian --- diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api index fe408211d83..98a6f0673e4 100644 --- a/src/plugins/nat/nat.api +++ b/src/plugins/nat/nat.api @@ -1061,6 +1061,26 @@ manual_endian define nat44_lb_static_mapping_details { vl_api_nat44_lb_addr_port_t locals[local_num]; }; +/** \brief Delete NAT44 session + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_in - 1 if inside network addres and port pari, 0 if outside + @param ip_address - IPv4 address + @param protocol - IP protocol + @param port - port number + @param vfr_id - VRF ID +*/ +autoreply define nat44_del_session { + u32 client_index; + u32 context; + u8 is_in; + u8 address[4]; + u8 protocol; + u16 port; + u32 vrf_id; +}; + + /* * Deterministic NAT (CGN) APIs */ diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 50ab317759e..189c5940d9c 100644 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -3075,6 +3075,119 @@ VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { .function = snat_add_interface_address_command_fn, }; +int +nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + snat_protocol_t proto, u32 vrf_id, int is_in) +{ + snat_main_per_thread_data_t *tsm; + clib_bihash_kv_8_8_t kv, value; + ip4_header_t ip; + u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); + snat_session_key_t key; + snat_session_t *s; + clib_bihash_8_8_t *t; + snat_user_key_t u_key; + snat_user_t *u; + + ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; + if (sm->num_workers) + tsm = + vec_elt_at_index (sm->per_thread_data, + sm->worker_in2out_cb (&ip, fib_index)); + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + key.addr.as_u32 = addr->as_u32; + key.port = clib_host_to_net_u16 (port); + key.protocol = proto; + key.fib_index = fib_index; + kv.key = key.as_u64; + t = is_in ? &tsm->in2out : &tsm->out2in; + if (!clib_bihash_search_8_8 (t, &kv, &value)) + { + s = pool_elt_at_index (tsm->sessions, value.value); + kv.key = s->in2out.as_u64; + clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0); + kv.key = s->out2in.as_u64; + clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0); + u_key.addr = s->in2out.addr; + u_key.fib_index = s->in2out.fib_index; + kv.key = u_key.as_u64; + if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) + { + u = pool_elt_at_index (tsm->users, value.value); + u->nsessions--; + } + clib_dlist_remove (tsm->list_pool, s->per_user_index); + pool_put (tsm->sessions, s); + return 0; + } + + return VNET_API_ERROR_NO_SUCH_ENTRY; +} + +static clib_error_t * +nat44_del_session_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + snat_main_t *sm = &snat_main; + unformat_input_t _line_input, *line_input = &_line_input; + int is_in = 0; + clib_error_t *error = 0; + ip4_address_t addr; + u32 port = 0, vrf_id = sm->outside_vrf_id; + snat_protocol_t proto; + int rv; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port, + unformat_snat_protocol, &proto)) + ; + else if (unformat (line_input, "in")) + { + is_in = 1; + vrf_id = sm->inside_vrf_id; + } + else if (unformat (line_input, "vrf %u", &vrf_id)) + ; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in); + + switch (rv) + { + case 0: + break; + + default: + error = clib_error_return (0, "nat44_del_session returned %d", rv); + goto done; + } + +done: + unformat_free (line_input); + + return error; +} + +VLIB_CLI_COMMAND (nat44_del_session_command, static) = { + .path = "nat44 del session", + .short_help = "nat44 del session in|out : tcp|udp|icmp [vrf ]", + .function = nat44_del_session_command_fn, +}; + static clib_error_t * snat_det_map_command_fn (vlib_main_t * vm, unformat_input_t * input, diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index d4ad72520da..9c50a0b77ec 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -507,6 +507,8 @@ u8 * format_snat_protocol(u8 * s, va_list * args); int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add); +int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + snat_protocol_t proto, u32 vrf_id, int is_in); static_always_inline u8 icmp_is_error_message (icmp46_header_t * icmp) diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 96f69eba186..f80a5067a43 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -2277,6 +2277,42 @@ static void *vl_api_nat44_lb_static_mapping_dump_t_print FINISH; } +static void +vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp) +{ + snat_main_t *sm = &snat_main; + vl_api_nat44_del_session_reply_t *rmp; + ip4_address_t addr; + u16 port; + u32 vrf_id; + int rv = 0; + snat_protocol_t proto; + + memcpy (&addr.as_u8, mp->address, 4); + port = clib_net_to_host_u16 (mp->port); + vrf_id = clib_net_to_host_u32 (mp->vrf_id); + proto = ip_proto_to_snat_proto (mp->protocol); + + rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in); + + REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY); +} + +static void * +vl_api_nat44_del_session_t_print (vl_api_nat44_del_session_t * mp, + void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: nat44_add_del_static_mapping "); + s = format (s, "addr %U port %d protocol %d vrf_id %d is_in %d", + format_ip4_address, mp->address, + clib_net_to_host_u16 (mp->port), + mp->protocol, clib_net_to_host_u32 (mp->vrf_id), mp->is_in); + + FINISH; +} + /*******************************/ /*** Deterministic NAT (CGN) ***/ /*******************************/ @@ -3304,6 +3340,7 @@ _(NAT44_INTERFACE_OUTPUT_FEATURE_DUMP, \ nat44_interface_output_feature_dump) \ _(NAT44_ADD_DEL_LB_STATIC_MAPPING, nat44_add_del_lb_static_mapping) \ _(NAT44_LB_STATIC_MAPPING_DUMP, nat44_lb_static_mapping_dump) \ +_(NAT44_DEL_SESSION, nat44_del_session) \ _(NAT_DET_ADD_DEL_MAP, nat_det_add_del_map) \ _(NAT_DET_FORWARD, nat_det_forward) \ _(NAT_DET_REVERSE, nat_det_reverse) \ diff --git a/test/test_nat.py b/test/test_nat.py index 792b21b418f..37e1b1e7b75 100644 --- a/test/test_nat.py +++ b/test/test_nat.py @@ -2452,6 +2452,33 @@ class TestNAT44(MethodHolder): self.logger.error(ppp("Unexpected or invalid packet:", p)) raise + def test_del_session(self): + """ Delete NAT44 session """ + self.nat44_add_address(self.nat_addr) + self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) + self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, + is_inside=0) + + pkts = self.create_stream_in(self.pg0, self.pg1) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(len(pkts)) + + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) + nsessions = len(sessions) + + self.vapi.nat44_del_session(sessions[0].inside_ip_address, + sessions[0].inside_port, + sessions[0].protocol) + self.vapi.nat44_del_session(sessions[1].outside_ip_address, + sessions[1].outside_port, + sessions[1].protocol, + is_in=0) + + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) + self.assertEqual(nsessions - len(sessions), 2) + def tearDown(self): super(TestNAT44, self).tearDown() if not self.vpp_dead: diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 68b2bd0b514..8e7235659be 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1346,6 +1346,29 @@ class VppPapiProvider(object): """ return self.api(self.papi.nat44_lb_static_mapping_dump, {}) + def nat44_del_session( + self, + addr, + port, + protocol, + vrf_id=0, + is_in=1): + """Delete NAT44 session + + :param addr: IPv4 address + :param por: port number + :param protocol: IP protocol number + :param vrf_id: VRF ID + :param is_in: 1 if inside network addres and port pari, 0 if outside + """ + return self.api( + self.papi.nat44_del_session, + {'address': addr, + 'port': port, + 'protocol': protocol, + 'vrf_id': vrf_id, + 'is_in': is_in}) + def nat_det_add_del_map( self, in_addr,