From 0938dcf192d203dcbe89d2819d3819d2f93408bf Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Wed, 8 Nov 2017 01:59:38 -0800 Subject: NAT64 to use IPv4 address from interface (VPP-1051) Change-Id: I326429c31dea6958a342ee152ef86cb975f4b12c Signed-off-by: Matus Fabian --- src/plugins/nat/nat.api | 14 ++++++++ src/plugins/nat/nat64.c | 82 +++++++++++++++++++++++++++++++++++++++++++++ src/plugins/nat/nat64.h | 14 ++++++++ src/plugins/nat/nat64_cli.c | 68 +++++++++++++++++++++++++++++++++++++ src/plugins/nat/nat_api.c | 39 +++++++++++++++++++++ test/test_nat.py | 21 +++++++++++- test/vpp_papi_provider.py | 12 +++++++ 7 files changed, 249 insertions(+), 1 deletion(-) diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api index d8fdf7283cf..9a000d5611f 100644 --- a/src/plugins/nat/nat.api +++ b/src/plugins/nat/nat.api @@ -1649,6 +1649,20 @@ define nat64_prefix_details { u32 vrf_id; }; +/** \brief Add/delete NAT64 pool address from specific interfce + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - 1 if add, 0 if delete + @param sw_if_index - software index of the interface +*/ +autoreply define nat64_add_del_interface_addr { + u32 client_index; + u32 context; + u8 is_add; + u8 is_inside; + u32 sw_if_index; +}; + /* * DS-Lite APIs diff --git a/src/plugins/nat/nat64.c b/src/plugins/nat/nat64.c index 952ca8fb11b..936ea9e9988 100644 --- a/src/plugins/nat/nat64.c +++ b/src/plugins/nat/nat64.c @@ -47,12 +47,47 @@ static u8 well_known_prefix[] = { /* *INDENT-ON* */ +static void +nat64_ip4_add_del_interface_address_cb (ip4_main_t * im, uword opaque, + u32 sw_if_index, + ip4_address_t * address, + u32 address_length, + u32 if_address_index, u32 is_delete) +{ + nat64_main_t *nm = &nat64_main; + int i, j; + + for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++) + { + if (sw_if_index == nm->auto_add_sw_if_indices[i]) + { + if (!is_delete) + { + /* Don't trip over lease renewal, static config */ + for (j = 0; j < vec_len (nm->addr_pool); j++) + if (nm->addr_pool[j].addr.as_u32 == address->as_u32) + return; + + (void) nat64_add_del_pool_addr (address, ~0, 1); + return; + } + else + { + (void) nat64_add_del_pool_addr (address, ~0, 0); + return; + } + } + } +} + clib_error_t * nat64_init (vlib_main_t * vm) { nat64_main_t *nm = &nat64_main; clib_error_t *error = 0; vlib_thread_main_t *tm = vlib_get_thread_main (); + ip4_add_del_interface_address_callback_t cb4; + ip4_main_t *im = &ip4_main; nm->is_disabled = 0; @@ -75,6 +110,12 @@ nat64_init (vlib_main_t * vm) nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN; + /* Set up the interface address add/del callback */ + cb4.function = nat64_ip4_add_del_interface_address_cb; + cb4.function_opaque = 0; + vec_add1 (im->add_del_interface_address_callbacks, cb4); + nm->ip4_main = im; + error: return error; } @@ -162,6 +203,47 @@ nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx) /* *INDENT-ON* */ } +int +nat64_add_interface_address (u32 sw_if_index, int is_add) +{ + nat64_main_t *nm = &nat64_main; + ip4_main_t *ip4_main = nm->ip4_main; + ip4_address_t *first_int_addr; + int i; + + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); + + for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++) + { + if (nm->auto_add_sw_if_indices[i] == sw_if_index) + { + if (is_add) + return VNET_API_ERROR_VALUE_EXIST; + else + { + /* if have address remove it */ + if (first_int_addr) + (void) nat64_add_del_pool_addr (first_int_addr, ~0, 0); + + vec_del1 (nm->auto_add_sw_if_indices, i); + return 0; + } + } + } + + if (!is_add) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + /* add to the auto-address list */ + vec_add1 (nm->auto_add_sw_if_indices, sw_if_index); + + /* If the address is already bound - or static - add it now */ + if (first_int_addr) + (void) nat64_add_del_pool_addr (first_int_addr, ~0, 1); + + return 0; +} + int nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add) { diff --git a/src/plugins/nat/nat64.h b/src/plugins/nat/nat64.h index 68224cab013..118076705cc 100644 --- a/src/plugins/nat/nat64.h +++ b/src/plugins/nat/nat64.h @@ -55,6 +55,9 @@ typedef struct /** Address pool vector */ snat_address_t *addr_pool; + /** sw_if_indices whose interface addresses should be auto-added */ + u32 *auto_add_sw_if_indices; + /** Pref64 vector */ nat64_prefix_t *pref64; @@ -70,6 +73,7 @@ typedef struct u8 is_disabled; + ip4_main_t *ip4_main; snat_main_t *sm; } nat64_main_t; @@ -102,6 +106,16 @@ typedef int (*nat64_pool_addr_walk_fn_t) (snat_address_t * addr, void *ctx); */ void nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx); +/** + * @brief NAT64 pool address from specific (DHCP addressed) interface. + * + * @param sw_if_index Index of the interface. + * @param is_add 1 if add, 0 if delete. + * + * @returns 0 on success, non-zero value otherwise. + */ +int nat64_add_interface_address (u32 sw_if_index, int is_add); + /** * @brief Enable/disable NAT64 feature on the interface. * diff --git a/src/plugins/nat/nat64_cli.c b/src/plugins/nat/nat64_cli.c index 7fea6bbb983..3e15beeee3b 100644 --- a/src/plugins/nat/nat64_cli.c +++ b/src/plugins/nat/nat64_cli.c @@ -807,6 +807,61 @@ nat64_show_prefix_command_fn (vlib_main_t * vm, unformat_input_t * input, return 0; } +static clib_error_t * +nat64_add_interface_address_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + nat64_main_t *nm = &nat64_main; + vnet_main_t *vnm = vnet_get_main (); + unformat_input_t _line_input, *line_input = &_line_input; + u32 sw_if_index; + int rv; + int is_add = 1; + clib_error_t *error = 0; + + if (nm->is_disabled) + return clib_error_return (0, + "NAT64 disabled, multi thread not supported"); + /* 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", unformat_vnet_sw_interface, vnm, &sw_if_index)) + ; + else if (unformat (line_input, "del")) + is_add = 0; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + rv = nat64_add_interface_address (sw_if_index, is_add); + + switch (rv) + { + case VNET_API_ERROR_NO_SUCH_ENTRY: + error = clib_error_return (0, "entry not exist"); + break; + case VNET_API_ERROR_VALUE_EXIST: + error = clib_error_return (0, "entry exist"); + break; + default: + break; + } + +done: + unformat_free (line_input); + + return error; +} + /* *INDENT-OFF* */ /*? @@ -1017,6 +1072,19 @@ VLIB_CLI_COMMAND (show_nat64_prefix_command, static) = { .function = nat64_show_prefix_command_fn, }; +/*? + * @cliexpar + * @cliexstart{nat64 add interface address} + * Add/delete NAT64 pool address from specific (DHCP addressed) interface. + * To add NAT64 pool address from specific interface use: + * vpp# nat64 add interface address GigabitEthernet0/8/0 + * @cliexend +?*/ +VLIB_CLI_COMMAND (nat64_add_interface_address_command, static) = { + .path = "nat64 add interface address", + .short_help = "nat64 add interface address [del]", + .function = nat64_add_interface_address_command_fn, +}; /* *INDENT-ON* */ /* diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 548a9e03bc4..127a2b80bbf 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -3431,6 +3431,44 @@ vl_api_nat64_prefix_dump_t_print (vl_api_nat64_prefix_dump_t * mp, FINISH; } +static void + vl_api_nat64_add_del_interface_addr_t_handler + (vl_api_nat64_add_del_interface_addr_t * mp) +{ + nat64_main_t *nm = &nat64_main; + snat_main_t *sm = &snat_main; + vl_api_nat64_add_del_interface_addr_reply_t *rmp; + u32 sw_if_index = ntohl (mp->sw_if_index); + int rv = 0; + + if (nm->is_disabled) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto send_reply; + } + + VALIDATE_SW_IF_INDEX (mp); + + rv = nat64_add_interface_address (sw_if_index, mp->is_add); + + BAD_SW_IF_INDEX_LABEL; +send_reply: + REPLY_MACRO (VL_API_NAT64_ADD_DEL_INTERFACE_ADDR_REPLY); +} + +static void *vl_api_nat64_add_del_interface_addr_t_print + (vl_api_nat64_add_del_interface_addr_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: nat64_add_del_interface_addr "); + s = format (s, "sw_if_index %d %s", + clib_host_to_net_u32 (mp->sw_if_index), + mp->is_add ? "" : "del"); + + FINISH; +} + /***************/ /*** DS-Lite ***/ /***************/ @@ -3587,6 +3625,7 @@ _(NAT64_GET_TIMEOUTS, nat64_get_timeouts) \ _(NAT64_ST_DUMP, nat64_st_dump) \ _(NAT64_ADD_DEL_PREFIX, nat64_add_del_prefix) \ _(NAT64_PREFIX_DUMP, nat64_prefix_dump) \ +_(NAT64_ADD_DEL_INTERFACE_ADDR, nat64_add_del_interface_addr) \ _(DSLITE_ADD_DEL_POOL_ADDR_RANGE, dslite_add_del_pool_addr_range) \ _(DSLITE_SET_AFTR_ADDR, dslite_set_aftr_addr) diff --git a/test/test_nat.py b/test/test_nat.py index 3c002bb8eca..76c52828ad9 100644 --- a/test/test_nat.py +++ b/test/test_nat.py @@ -3428,7 +3428,7 @@ class TestNAT64(MethodHolder): cls.vrf1_nat_addr_n = socket.inet_pton(socket.AF_INET, cls.vrf1_nat_addr) - cls.create_pg_interfaces(range(4)) + cls.create_pg_interfaces(range(5)) cls.ip6_interfaces = list(cls.pg_interfaces[0:1]) cls.ip6_interfaces.append(cls.pg_interfaces[2]) cls.ip4_interfaces = list(cls.pg_interfaces[1:2]) @@ -4337,6 +4337,25 @@ class TestNAT64(MethodHolder): self.assertEqual(p[TCP].dport, self.tcp_port_in) self.assertEqual(data, p[Raw].load) + def test_interface_addr(self): + """ Acquire NAT64 pool addresses from interface """ + self.vapi.nat64_add_interface_addr(self.pg4.sw_if_index) + + # no address in NAT64 pool + adresses = self.vapi.nat44_address_dump() + self.assertEqual(0, len(adresses)) + + # configure interface address and check NAT64 address pool + self.pg4.config_ip4() + addresses = self.vapi.nat64_pool_addr_dump() + self.assertEqual(len(addresses), 1) + self.assertEqual(addresses[0].address, self.pg4.local_ip4n) + + # remove interface address and check NAT64 address pool + self.pg4.unconfig_ip4() + addresses = self.vapi.nat64_pool_addr_dump() + self.assertEqual(0, len(adresses)) + def nat64_get_ses_num(self): """ Return number of active NAT64 sessions. diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 63f938376ae..495db95052e 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1723,6 +1723,18 @@ class VppPapiProvider(object): """ return self.api(self.papi.nat64_prefix_dump, {}) + def nat64_add_interface_addr( + self, + sw_if_index, + is_add=1): + """Add/del NAT64 address from interface + + :param sw_if_index: Software index of the interface + :param is_add: 1 if add, 0 if delete (Default value = 1) + """ + return self.api(self.papi.nat64_add_del_interface_addr, + {'is_add': is_add, 'sw_if_index': sw_if_index}) + def dslite_set_aftr_addr(self, ip6, ip4): """Set DS-Lite AFTR addresses -- cgit 1.2.3-korg