From 8bf68e858a30a9c04329668d2b5dd67e9ad6f5af Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Thu, 12 Jan 2017 04:24:35 -0800 Subject: [PATCH] SNAT: add API and test for NAT pool address from interface Change-Id: I2a868f736fae8d37b438c604a9284653ea415541 Signed-off-by: Matus Fabian --- src/plugins/snat/snat.api | 51 +++++++++++++++--- src/plugins/snat/snat.c | 122 ++++++++++++++++++++++++++++++++++++++++--- src/plugins/snat/snat_test.c | 87 ++++++++++++++++++++++++++++-- test/test_snat.py | 26 ++++++++- test/vpp_papi_provider.py | 18 +++++++ 5 files changed, 287 insertions(+), 17 deletions(-) diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index a191eed5944..f046a9657e2 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -24,9 +24,9 @@ @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_ip4 - 1 if address type is IPv4 - @first_ip_address - first IP address - @last_ip_address - last IP address - @is_add - 1 if add, 0 if delete + @param first_ip_address - first IP address + @param last_ip_address - last IP address + @param is_add - 1 if add, 0 if delete */ define snat_add_address_range { u32 client_index; @@ -38,7 +38,6 @@ define snat_add_address_range { }; /** \brief Add S-NAT address range reply - @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param retval - return code */ @@ -83,7 +82,6 @@ define snat_interface_add_del_feature { }; /** \brief Enable/disable S-NAT feature on the interface reply - @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param retval - return code */ @@ -138,7 +136,6 @@ define snat_add_static_mapping { }; /** \brief Add/delete S-NAT static mapping reply - @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param retval - return code */ @@ -251,7 +248,6 @@ define snat_set_workers { }; /** \brief Set S-NAT workers reply - @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param retval - return code */ @@ -281,3 +277,44 @@ define snat_worker_details { u32 lcore_id; u8 name[64]; }; + +/** \brief Add/delete S-NAT 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 +*/ +define snat_add_del_interface_addr { + u32 client_index; + u32 context; + u8 is_add; + u8 is_inside; + u32 sw_if_index; +}; + +/** \brief Add/delete S-NAT pool address from specific interfce reply + @param context - sender context, to match reply w/ request + @param retval - return code +*/ +define snat_add_del_interface_addr_reply { + u32 context; + i32 retval; +}; + +/** \brief Dump S-NAT pool addresses interfaces + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define snat_interface_addr_dump { + u32 client_index; + u32 context; +}; + +/** \brief S-NAT pool addresses interfaces details response + @param context - sender context, to match reply w/ request + @param sw_if_index - software index of the interface +*/ +define snat_interface_addr_details { + u32 context; + u32 sw_if_index; +}; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 94e05078529..a1236cf74f4 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -1094,6 +1094,84 @@ static void *vl_api_snat_worker_dump_t_print FINISH; } +static int snat_add_interface_address(snat_main_t *sm, + u32 sw_if_index, + int is_del); + +static void +vl_api_snat_add_del_interface_addr_t_handler +(vl_api_snat_add_del_interface_addr_t * mp) +{ + snat_main_t * sm = &snat_main; + vl_api_snat_add_del_interface_addr_reply_t * rmp; + u8 is_del = mp->is_add == 0; + u32 sw_if_index = ntohl(mp->sw_if_index); + int rv = 0; + + VALIDATE_SW_IF_INDEX(mp); + + rv = snat_add_interface_address (sm, sw_if_index, is_del); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO(VL_API_SNAT_ADD_DEL_INTERFACE_ADDR_REPLY); +} + +static void *vl_api_snat_add_del_interface_addr_t_print +(vl_api_snat_add_del_interface_addr_t * mp, void *handle) +{ + u8 * s; + + s = format (0, "SCRIPT: snat_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; +} + +static void +send_snat_interface_addr_details +(u32 sw_if_index, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_snat_interface_addr_details_t *rmp; + snat_main_t * sm = &snat_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_ADDR_DETAILS+sm->msg_id_base); + rmp->sw_if_index = ntohl (sw_if_index); + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_snat_interface_addr_dump_t_handler +(vl_api_snat_interface_addr_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + snat_main_t * sm = &snat_main; + u32 * i; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + vec_foreach (i, sm->auto_add_sw_if_indices) + send_snat_interface_addr_details(*i, q, mp->context); +} + +static void *vl_api_snat_interface_addr_dump_t_print +(vl_api_snat_interface_addr_dump_t *mp, void * handle) +{ + u8 *s; + + s = format (0, "SCRIPT: snat_interface_addr_dump "); + + FINISH; +} + /* List of message types that this plugin understands */ #define foreach_snat_plugin_api_msg \ _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range) \ @@ -1105,7 +1183,9 @@ _(SNAT_SHOW_CONFIG, snat_show_config) \ _(SNAT_ADDRESS_DUMP, snat_address_dump) \ _(SNAT_INTERFACE_DUMP, snat_interface_dump) \ _(SNAT_SET_WORKERS, snat_set_workers) \ -_(SNAT_WORKER_DUMP, snat_worker_dump) +_(SNAT_WORKER_DUMP, snat_worker_dump) \ +_(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr) \ +_(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump) /* Set up the API message handling tables */ static clib_error_t * @@ -1840,7 +1920,7 @@ show_snat_command_fn (vlib_main_t * vm, snat_address_t * ap; vnet_main_t *vnm = vnet_get_main(); snat_main_per_thread_data_t *tsm; - u32 users_num = 0, sessions_num = 0, *worker; + u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index; uword j = 0; if (unformat (input, "detail")) @@ -1870,6 +1950,16 @@ show_snat_command_fn (vlib_main_t * vm, i->is_inside ? "in" : "out"); })); + if (vec_len (sm->auto_add_sw_if_indices)) + { + vlib_cli_output (vm, "SNAT pool addresses interfaces:"); + vec_foreach (sw_if_index, sm->auto_add_sw_if_indices) + { + vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, *sw_if_index)); + } + } + vec_foreach (ap, sm->addresses) { u8 * s = format (0, ""); @@ -2011,7 +2101,9 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im, } -static int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index) +static int snat_add_interface_address (snat_main_t *sm, + u32 sw_if_index, + int is_del) { ip4_main_t * ip4_main = sm->ip4_main; ip4_address_t * first_int_addr; @@ -2023,9 +2115,24 @@ static int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index) for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++) { if (sm->auto_add_sw_if_indices[i] == sw_if_index) - return 0; + { + if (is_del) + { + /* if have address remove it */ + if (first_int_addr) + (void) snat_del_address (sm, first_int_addr[0]); + vec_del1(sm->auto_add_sw_if_indices, i); + } + else + return VNET_API_ERROR_VALUE_EXIST; + + return 0; + } } + if (is_del) + return VNET_API_ERROR_NO_SUCH_ENTRY; + /* add to the auto-address list */ vec_add1(sm->auto_add_sw_if_indices, sw_if_index); @@ -2045,6 +2152,7 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u32 sw_if_index; int rv; + int is_del = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2055,12 +2163,14 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, if (unformat (line_input, "%U", unformat_vnet_sw_interface, sm->vnet_main, &sw_if_index)) ; + else if (unformat (line_input, "del")) + is_del = 1; else return clib_error_return (0, "unknown input '%U'", format_unformat_error, line_input); } - rv = snat_add_interface_address (sm, sw_if_index); + rv = snat_add_interface_address (sm, sw_if_index, is_del); switch (rv) { @@ -2076,6 +2186,6 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { .path = "snat add interface address", - .short_help = "snat add interface address ", + .short_help = "snat add interface address [del]", .function = snat_add_interface_address_command_fn, }; diff --git a/src/plugins/snat/snat_test.c b/src/plugins/snat/snat_test.c index 2a003ba60c6..6f87d80379b 100644 --- a/src/plugins/snat/snat_test.c +++ b/src/plugins/snat/snat_test.c @@ -61,7 +61,8 @@ snat_test_main_t snat_test_main; _(snat_add_address_range_reply) \ _(snat_interface_add_del_feature_reply) \ _(snat_add_static_mapping_reply) \ -_(snat_set_workers_reply) +_(snat_set_workers_reply) \ +_(snat_add_del_interface_addr_reply) #define _(n) \ static void vl_api_##n##_t_handler \ @@ -94,7 +95,10 @@ _(SNAT_SHOW_CONFIG_REPLY, snat_show_config_reply) \ _(SNAT_ADDRESS_DETAILS, snat_address_details) \ _(SNAT_INTERFACE_DETAILS, snat_interface_details) \ _(SNAT_SET_WORKERS_REPLY, snat_set_workers_reply) \ -_(SNAT_WORKER_DETAILS, snat_worker_details) +_(SNAT_WORKER_DETAILS, snat_worker_details) \ +_(SNAT_ADD_DEL_INTERFACE_ADDR_REPLY, \ + snat_add_del_interface_addr_reply) \ +_(SNAT_INTERFACE_ADDR_DETAILS, snat_interface_addr_details) /* M: construct, but don't yet send a message */ #define M(T,t) \ @@ -539,6 +543,80 @@ static int api_snat_worker_dump(vat_main_t * vam) return 0; } +static int api_snat_add_del_interface_addr (vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + unformat_input_t * i = vam->input; + f64 timeout; + vl_api_snat_add_del_interface_addr_t * mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning("unknown input '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("interface / sw_if_index required\n"); + return -99; + } + + M(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr); + mp->sw_if_index = ntohl(sw_if_index); + mp->is_add = is_add; + + S; W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_snat_interface_addr_details_t_handler + (vl_api_snat_interface_addr_details_t *mp) +{ + snat_test_main_t * sm = &snat_test_main; + vat_main_t *vam = sm->vat_main; + + fformat (vam->ofp, "sw_if_index %d\n", ntohl (mp->sw_if_index)); +} + +static int api_snat_interface_addr_dump(vat_main_t * vam) +{ + snat_test_main_t * sm = &snat_test_main; + f64 timeout; + vl_api_snat_interface_addr_dump_t * mp; + + if (vam->json_output) + { + clib_warning ("JSON output not supported for snat_address_dump"); + return -99; + } + + M(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump); + S; + /* Use a control ping for synchronization */ + { + vl_api_snat_control_ping_t *mp; + M (SNAT_CONTROL_PING, snat_control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + /* * List of messages that the api test plugin sends, * and that the data plane plugin processes @@ -554,7 +632,10 @@ _(snat_static_mapping_dump, "") \ _(snat_show_config, "") \ _(snat_address_dump, "") \ _(snat_interface_dump, "") \ -_(snat_worker_dump, "") +_(snat_worker_dump, "") \ +_(snat_add_del_interface_addr, \ + " | sw_if_index [del]") \ +_(snat_interface_addr_dump, "") void vat_api_hookup (vat_main_t *vam) { diff --git a/test/test_snat.py b/test/test_snat.py index d23becf5ce9..653496e2880 100644 --- a/test/test_snat.py +++ b/test/test_snat.py @@ -26,7 +26,7 @@ class TestSNAT(VppTestCase): cls.icmp_id_out = 6305 cls.snat_addr = '10.0.0.3' - cls.create_pg_interfaces(range(7)) + cls.create_pg_interfaces(range(8)) cls.interfaces = list(cls.pg_interfaces[0:4]) for i in cls.interfaces: @@ -48,6 +48,8 @@ class TestSNAT(VppTestCase): i.admin_up() i.resolve_arp() + cls.pg7.admin_up() + except Exception: super(TestSNAT, cls).tearDownClass() raise @@ -178,6 +180,10 @@ class TestSNAT(VppTestCase): """ Clear SNAT configuration. """ + interfaces = self.vapi.snat_interface_addr_dump() + for intf in interfaces: + self.vapi.snat_add_interface_addr(intf.sw_if_index, is_add=0) + interfaces = self.vapi.snat_interface_dump() for intf in interfaces: self.vapi.snat_interface_add_del_feature(intf.sw_if_index, @@ -623,6 +629,24 @@ class TestSNAT(VppTestCase): # verify number of translated packet self.pg1.get_capture(pkts_num) + def test_interface_addr(self): + """ Acquire SNAT addresses from interface """ + self.vapi.snat_add_interface_addr(self.pg7.sw_if_index) + + # no address in NAT pool + adresses = self.vapi.snat_address_dump() + self.assertEqual(0, len(adresses)) + + # configure interface address and check NAT address pool + self.pg7.config_ip4() + adresses = self.vapi.snat_address_dump() + self.assertEqual(1, len(adresses)) + + # remove interface address and check NAT address pool + self.pg7.unconfig_ip4() + adresses = self.vapi.snat_address_dump() + self.assertEqual(0, len(adresses)) + def tearDown(self): super(TestSNAT, self).tearDown() if not self.vpp_dead: diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index b78e861347f..73d3b564001 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -916,6 +916,24 @@ class VppPapiProvider(object): """ return self.api(self.papi.snat_show_config, {}) + def snat_add_interface_addr( + self, + sw_if_index, + is_add=1): + """Add/del S-NAT 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.snat_add_del_interface_addr, + {'is_add': is_add, 'sw_if_index': sw_if_index}) + + def snat_interface_addr_dump(self): + """Dump S-NAT addresses interfaces + :return: Dictionary of S-NAT addresses interfaces + """ + return self.api(self.papi.snat_interface_addr_dump, {}) + def control_ping(self): self.api(self.papi.control_ping) -- 2.16.6