diff options
-rw-r--r-- | src/vnet/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/vnet/ethernet/ethernet.h | 2 | ||||
-rw-r--r-- | src/vnet/ethernet/interface.c | 2 | ||||
-rw-r--r-- | src/vnet/l2/l2.api | 38 | ||||
-rw-r--r-- | src/vnet/l2/l2_api.c | 36 | ||||
-rw-r--r-- | src/vnet/l2/l2_bvi.c | 311 | ||||
-rw-r--r-- | src/vnet/l2/l2_bvi.h | 5 | ||||
-rw-r--r-- | src/vnet/l2/l2_bvi_node.c | 116 | ||||
-rw-r--r-- | test/framework.py | 15 | ||||
-rw-r--r-- | test/test_ip4_irb.py | 50 | ||||
-rw-r--r-- | test/test_l2_flood.py | 14 | ||||
-rw-r--r-- | test/vpp_bvi_interface.py | 22 |
12 files changed, 578 insertions, 35 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index b6028e90742..822ad6891fc 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -161,6 +161,7 @@ list(APPEND VNET_SOURCES l2/l2_api.c l2/l2_bd.c l2/l2_bvi.c + l2/l2_bvi_node.c l2/l2_input_classify.c l2/l2_output_classify.c l2/l2_efp_filter.c @@ -181,6 +182,7 @@ list(APPEND VNET_SOURCES ) list(APPEND VNET_MULTIARCH_SOURCES + l2/l2_bvi_node.c l2/l2_fwd.c l2/l2_learn.c l2/l2_output.c diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index 9b19143b03f..94322a715f9 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -314,7 +314,7 @@ ethernet_interface_t *ethernet_get_interface (ethernet_main_t * em, clib_error_t *ethernet_register_interface (vnet_main_t * vnm, u32 dev_class_index, u32 dev_instance, - u8 * address, + const u8 * address, u32 * hw_if_index_return, ethernet_flag_change_function_t flag_change); diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c index 1c13c405a61..0f54aa1e393 100644 --- a/src/vnet/ethernet/interface.c +++ b/src/vnet/ethernet/interface.c @@ -278,7 +278,7 @@ clib_error_t * ethernet_register_interface (vnet_main_t * vnm, u32 dev_class_index, u32 dev_instance, - u8 * address, + const u8 * address, u32 * hw_if_index_return, ethernet_flag_change_function_t flag_change) { diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index fc851e4203d..dc743763f70 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -553,6 +553,44 @@ autoreply define sw_interface_set_vpath u8 enable; }; +/** \brief Create BVI interface instance request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mac_address - mac addr to assign to the interface if none-zero + @param user_instance - requested instance, ~0 => dynamically allocate +*/ +define bvi_create +{ + u32 client_index; + u32 context; + vl_api_mac_address_t mac; + u32 user_instance; +}; + +/** \brief Create BVI interface instance response + @param context - sender context, to match reply w/ request + @param sw_if_index - sw index of the interface that was created + @param retval - return code for the request +*/ +define bvi_create_reply +{ + u32 context; + i32 retval; + u32 sw_if_index; +}; + +/** \brief Delete BVI interface request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - sw index of the interface that was created +*/ +autoreply define bvi_delete +{ + u32 client_index; + u32 context; + u32 sw_if_index; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 059f668d664..f60cd41bb39 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -27,6 +27,7 @@ #include <vnet/l2/l2_vtr.h> #include <vnet/l2/l2_learn.h> #include <vnet/l2/l2_bd.h> +#include <vnet/l2/l2_bvi.h> #include <vnet/ip/ip_types_api.h> #include <vnet/ethernet/ethernet_types_api.h> @@ -74,7 +75,9 @@ _(BRIDGE_FLAGS, bridge_flags) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \ _(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \ -_(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) +_(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \ +_(BVI_CREATE, bvi_create) \ +_(BVI_DELETE, bvi_delete) static void send_l2_xconnect_details (vl_api_registration_t * reg, u32 context, @@ -993,6 +996,37 @@ vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp) REPLY_MACRO (VL_API_SW_INTERFACE_SET_VPATH_REPLY); } +static void +vl_api_bvi_create_t_handler (vl_api_bvi_create_t * mp) +{ + vl_api_bvi_create_reply_t *rmp; + mac_address_t mac; + u32 sw_if_index; + int rv; + + mac_address_decode (mp->mac, &mac); + + rv = l2_bvi_create (ntohl (mp->user_instance), &mac, &sw_if_index); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_BVI_CREATE_REPLY, + ({ + rmp->sw_if_index = ntohl (sw_if_index); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_bvi_delete_t_handler (vl_api_bvi_delete_t * mp) +{ + vl_api_bvi_delete_reply_t *rmp; + int rv; + + rv = l2_bvi_delete (ntohl (mp->sw_if_index)); + + REPLY_MACRO (VL_API_BVI_DELETE_REPLY); +} + /* * l2_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/l2/l2_bvi.c b/src/vnet/l2/l2_bvi.c index f239743a9c4..87738fc7820 100644 --- a/src/vnet/l2/l2_bvi.c +++ b/src/vnet/l2/l2_bvi.c @@ -21,6 +21,8 @@ #include <vnet/l2/l2_flood.h> #include <vnet/l2/l2_bvi.h> +/* Allocated BVI instances */ +static uword *l2_bvi_instances; /* Call the L2 nodes that need the ethertype mapping */ void @@ -31,6 +33,315 @@ l2bvi_register_input_type (vlib_main_t * vm, l2flood_register_input_type (vm, type, node_index); } +static u8 * +format_bvi_name (u8 * s, va_list * args) +{ + u32 dev_instance = va_arg (*args, u32); + return format (s, "bvi%d", dev_instance); +} + +static clib_error_t * +bvi_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags) +{ + u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? + VNET_HW_INTERFACE_FLAG_LINK_UP : 0; + vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); + return 0; +} + +static clib_error_t * +bvi_mac_change (vnet_hw_interface_t * hi, + const u8 * old_address, const u8 * mac_address) +{ + l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address); + + return (NULL); +} + +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (bvi_device_class) = { + .name = "BVI", + .format_device_name = format_bvi_name, + .admin_up_down_function = bvi_admin_up_down, + .mac_addr_change_function = bvi_mac_change, +}; +/* *INDENT-ON* */ + +/* + * Maintain a bitmap of allocated bvi instance numbers. + */ +#define BVI_MAX_INSTANCE (16 * 1024) + +static u32 +bvi_instance_alloc (u32 want) +{ + /* + * Check for dynamically allocaetd instance number. + */ + if (~0 == want) + { + u32 bit; + + bit = clib_bitmap_first_clear (l2_bvi_instances); + if (bit >= BVI_MAX_INSTANCE) + { + return ~0; + } + l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, bit, 1); + return bit; + } + + /* + * In range? + */ + if (want >= BVI_MAX_INSTANCE) + { + return ~0; + } + + /* + * Already in use? + */ + if (clib_bitmap_get (l2_bvi_instances, want)) + { + return ~0; + } + + /* + * Grant allocation request. + */ + l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, want, 1); + + return want; +} + +static int +bvi_instance_free (u32 instance) +{ + if (instance >= BVI_MAX_INSTANCE) + { + return -1; + } + + if (clib_bitmap_get (l2_bvi_instances, instance) == 0) + { + return -1; + } + + l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, instance, 0); + return 0; +} + +int +l2_bvi_create (u32 user_instance, + const mac_address_t * mac_in, u32 * sw_if_indexp) +{ + vnet_main_t *vnm = vnet_get_main (); + vlib_main_t *vm = vlib_get_main (); + u32 instance, hw_if_index, slot; + vnet_hw_interface_t *hw_if; + clib_error_t *error; + mac_address_t mac; + + int rv = 0; + + ASSERT (sw_if_indexp); + + *sw_if_indexp = (u32) ~ 0; + + /* + * Allocate a bvi instance. Either select on dynamically + * or try to use the desired user_instance number. + */ + instance = bvi_instance_alloc (user_instance); + if (instance == ~0) + { + return VNET_API_ERROR_INVALID_REGISTRATION; + } + + /* + * Default MAC address (b0b0:0000:0000 + instance) is allocated + * if zero mac_address is configured. Otherwise, user-configurable MAC + * address is programmed on the bvi interface. + */ + if (mac_address_is_zero (mac_in)) + { + u8 bytes[] = { + [0] = 0xb0, + [1] = 0xb0, + [5] = instance, + }; + mac_address_from_bytes (&mac, bytes); + } + else + { + mac_address_copy (&mac, mac_in); + } + + error = ethernet_register_interface (vnm, + bvi_device_class.index, + instance, mac.bytes, &hw_if_index, + /* flag change */ 0); + + if (error) + { + rv = VNET_API_ERROR_INVALID_REGISTRATION; + clib_error_report (error); + return rv; + } + + hw_if = vnet_get_hw_interface (vnm, hw_if_index); + + slot = vlib_node_add_named_next_with_slot (vm, hw_if->tx_node_index, + "l2-input", 0); + ASSERT (slot == 0); + + { + vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index); + *sw_if_indexp = si->sw_if_index; + + si->flood_class = VNET_FLOOD_CLASS_BVI; + } + + return 0; +} + +int +l2_bvi_delete (u32 sw_if_index) +{ + vnet_main_t *vnm = vnet_get_main (); + + if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index)) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index); + if (hw == 0 || hw->dev_class_index != bvi_device_class.index) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + if (bvi_instance_free (hw->dev_instance) < 0) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + ethernet_delete_interface (vnm, hw->hw_if_index); + + return 0; +} + +static clib_error_t * +l2_bvi_create_cli (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u32 instance, sw_if_index; + clib_error_t *error; + mac_address_t mac; + int rv; + + error = NULL; + instance = sw_if_index = ~0; + mac_address_set_zero (&mac); + + if (unformat_user (input, unformat_line_input, line_input)) + { + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "mac %U", unformat_mac_address_t, &mac)) + ; + else if (unformat (line_input, "instance %d", &instance)) + ; + else + { + error = clib_error_return (0, "unknown input: %U", + format_unformat_error, line_input); + break; + } + } + + unformat_free (line_input); + + if (error) + return error; + } + + rv = l2_bvi_create (instance, &mac, &sw_if_index); + + if (rv) + return clib_error_return (0, "BVI create failed"); + + vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (), + sw_if_index); + return 0; +} + +/*? + * Create a BVI interface. Optionally, a MAC Address can be + * provided. If not provided, 0b:0b::00:00:00:<instance> will be used. + * + * @cliexpar + * The following two command syntaxes are equivalent: + * @cliexcmd{bvi create [mac <mac-addr>] [instance <instance>]} + * Example of how to create a bvi interface: + * @cliexcmd{bvi create} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_bvi_create_command, static) = { + .path = "bvi create", + .short_help = "bvi create [mac <mac-addr>] [instance <instance>]", + .function = l2_bvi_create_cli, +}; +/* *INDENT-ON* */ + +static clib_error_t * +l2_bvi_delete_cli (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm; + u32 sw_if_index; + int rv; + + vnm = vnet_get_main (); + sw_if_index = ~0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + ; + else + break; + } + + if (~0 != sw_if_index) + { + rv = l2_bvi_delete (sw_if_index); + + if (rv) + return clib_error_return (0, "BVI delete failed"); + } + else + return clib_error_return (0, "no such interface: %U", + format_unformat_error, input); + + return 0; +} + +/*? + * Delete a BVI interface. + * + * @cliexpar + * The following two command syntaxes are equivalent: + * @cliexcmd{bvi delete <interace> + * Example of how to create a bvi interface: + * @cliexcmd{bvi delete bvi0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_bvi_delete_command, static) = { + .path = "bvi delete", + .short_help = "bvi delete <interface>", + .function = l2_bvi_delete_cli, +}; +/* *INDENT-ON* */ + + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/l2/l2_bvi.h b/src/vnet/l2/l2_bvi.h index 51c8dac23e4..d7d410b06ab 100644 --- a/src/vnet/l2/l2_bvi.h +++ b/src/vnet/l2/l2_bvi.h @@ -97,6 +97,11 @@ l2_to_bvi (vlib_main_t * vlib_main, void l2bvi_register_input_type (vlib_main_t * vm, ethernet_type_t type, u32 node_index); + +extern int l2_bvi_create (u32 instance, const mac_address_t * mac, + u32 * sw_if_index); +extern int l2_bvi_delete (u32 sw_if_index); + #endif /* diff --git a/src/vnet/l2/l2_bvi_node.c b/src/vnet/l2/l2_bvi_node.c new file mode 100644 index 00000000000..dd7e1df46ce --- /dev/null +++ b/src/vnet/l2/l2_bvi_node.c @@ -0,0 +1,116 @@ +/* + * l2_bvi.c : layer 2 Bridged Virtual Interface + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vnet/l2/l2_bvi.h> + +/** + * send packets to l2-input. + */ +VNET_DEVICE_CLASS_TX_FN (bvi_device_class) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index; + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + u16 nexts[VLIB_FRAME_SIZE]; + u32 n_left, *from; + + n_left = frame->n_vectors; + from = vlib_frame_vector_args (frame); + + vlib_get_buffers (vm, from, bufs, n_left); + + b = bufs; + sw_if_index = sw_if_indices; + + /* It's all going to l2-input */ + clib_memset_u16 (nexts, 0, VLIB_FRAME_SIZE); + + /* + * For each packet: + * - fixup the L2 length of the packet + * - set the RX interface (which the bridge will use) to the + * TX interface (which routing has chosen) + * - Set the TX interface to the special ID so the DP knows this is a BVI + * Don't counts packets and bytes, that's done in the bviX-output node + */ + while (n_left >= 4) + { + /* Prefetch next iteration. */ + if (PREDICT_TRUE (n_left >= 8)) + { + /* LOAD pre-fetch since meta and packet data is read */ + vlib_prefetch_buffer_header (b[4], LOAD); + vlib_prefetch_buffer_header (b[5], LOAD); + vlib_prefetch_buffer_header (b[6], LOAD); + vlib_prefetch_buffer_header (b[7], LOAD); + + vlib_prefetch_buffer_data (b[4], LOAD); + vlib_prefetch_buffer_data (b[5], LOAD); + vlib_prefetch_buffer_data (b[6], LOAD); + vlib_prefetch_buffer_data (b[7], LOAD); + } + + vnet_update_l2_len (b[0]); + vnet_update_l2_len (b[1]); + vnet_update_l2_len (b[2]); + vnet_update_l2_len (b[3]); + + sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; + sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX]; + sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_TX]; + sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_TX]; + + vnet_buffer (b[0])->sw_if_index[VLIB_TX] = L2INPUT_BVI; + vnet_buffer (b[1])->sw_if_index[VLIB_TX] = L2INPUT_BVI; + vnet_buffer (b[2])->sw_if_index[VLIB_TX] = L2INPUT_BVI; + vnet_buffer (b[3])->sw_if_index[VLIB_TX] = L2INPUT_BVI; + + vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index[0]; + vnet_buffer (b[1])->sw_if_index[VLIB_RX] = sw_if_index[1]; + vnet_buffer (b[2])->sw_if_index[VLIB_RX] = sw_if_index[2]; + vnet_buffer (b[3])->sw_if_index[VLIB_RX] = sw_if_index[3]; + + b += 4; + n_left -= 4; + sw_if_index += 4; + } + while (n_left) + { + sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; + vnet_buffer (b[0])->sw_if_index[VLIB_TX] = L2INPUT_BVI; + vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index[0]; + + vnet_update_l2_len (b[0]); + + b += 1; + n_left -= 1; + sw_if_index += 1; + } + + vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); + + return frame->n_vectors; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/test/framework.py b/test/framework.py index ea989eb242d..dce477d16d2 100644 --- a/test/framework.py +++ b/test/framework.py @@ -25,6 +25,7 @@ from hook import StepHook, PollHook, VppDiedError from vpp_pg_interface import VppPGInterface from vpp_sub_interface import VppSubInterface from vpp_lo_interface import VppLoInterface +from vpp_bvi_interface import VppBviInterface from vpp_papi_provider import VppPapiProvider from vpp_papi.vpp_stats import VPPStats from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \ @@ -690,6 +691,20 @@ class VppTestCase(unittest.TestCase): cls.lo_interfaces = result return result + @classmethod + def create_bvi_interfaces(cls, count): + """ + Create BVI interfaces. + + :param count: number of interfaces created. + :returns: List of created interfaces. + """ + result = [VppBviInterface(cls) for i in range(count)] + for intf in result: + setattr(cls, intf.name, intf) + cls.bvi_interfaces = result + return result + @staticmethod def extend_packet(packet, size, padding=' '): """ diff --git a/test/test_ip4_irb.py b/test/test_ip4_irb.py index 1d55cef5d90..ef3dc1caf2b 100644 --- a/test/test_ip4_irb.py +++ b/test/test_ip4_irb.py @@ -42,10 +42,10 @@ class TestIpIrb(VppTestCase): def setUpClass(cls): """ #. Create BD with MAC learning enabled and put interfaces to this BD. - #. Configure IPv4 addresses on loopback interface and routed interface. - #. Configure MAC address binding to IPv4 neighbors on loop0. + #. Configure IPv4 addresses on BVI interface and routed interface. + #. Configure MAC address binding to IPv4 neighbors on bvi0. #. Configure MAC address on pg2. - #. Loopback BVI interface has remote hosts, one half of hosts are + #. BVI interface has remote hosts, one half of hosts are behind pg0 second behind pg1. """ super(TestIpIrb, cls).setUpClass() @@ -54,40 +54,40 @@ class TestIpIrb(VppTestCase): cls.bd_id = 10 cls.remote_hosts_count = 250 - # create 3 pg interfaces, 1 loopback interface + # create 3 pg interfaces, 1 BVI interface cls.create_pg_interfaces(range(3)) - cls.create_loopback_interfaces(1) + cls.create_bvi_interfaces(1) cls.interfaces = list(cls.pg_interfaces) - cls.interfaces.extend(cls.lo_interfaces) + cls.interfaces.extend(cls.bvi_interfaces) for i in cls.interfaces: i.admin_up() # Create BD with MAC learning enabled and put interfaces to this BD cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.loop0.sw_if_index, bd_id=cls.bd_id, + rx_sw_if_index=cls.bvi0.sw_if_index, bd_id=cls.bd_id, port_type=L2_PORT_TYPE.BVI) cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=cls.pg0.sw_if_index, bd_id=cls.bd_id) cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.bd_id) - # Configure IPv4 addresses on loopback interface and routed interface - cls.loop0.config_ip4() + # Configure IPv4 addresses on BVI interface and routed interface + cls.bvi0.config_ip4() cls.pg2.config_ip4() - # Configure MAC address binding to IPv4 neighbors on loop0 - cls.loop0.generate_remote_hosts(cls.remote_hosts_count) - cls.loop0.configure_ipv4_neighbors() + # Configure MAC address binding to IPv4 neighbors on bvi0 + cls.bvi0.generate_remote_hosts(cls.remote_hosts_count) + cls.bvi0.configure_ipv4_neighbors() # configure MAC address on pg2 cls.pg2.resolve_arp() - # Loopback BVI interface has remote hosts, one half of hosts are behind + # BVI interface has remote hosts, one half of hosts are behind # pg0 second behind pg1 half = cls.remote_hosts_count // 2 - cls.pg0.remote_hosts = cls.loop0.remote_hosts[:half] - cls.pg1.remote_hosts = cls.loop0.remote_hosts[half:] + cls.pg0.remote_hosts = cls.bvi0.remote_hosts[:half] + cls.pg1.remote_hosts = cls.bvi0.remote_hosts[half:] def tearDown(self): """Run standard test teardown and log ``show l2patch``, @@ -220,32 +220,32 @@ class TestIpIrb(VppTestCase): Test scenario: - ip traffic from pg2 interface must ends in both pg0 and pg1 - - arp entry present in loop0 interface for destination IP - - no l2 entree configured, pg0 and pg1 are same + - arp entry present in bvi0 interface for destination IP + - no l2 entry configured, pg0 and pg1 are same """ stream = self.create_stream( - self.pg2, self.loop0, self.pg_if_packet_sizes) + self.pg2, self.bvi0, self.pg_if_packet_sizes) self.pg2.add_stream(stream) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - packet_count = self.get_packet_count_for_if_idx(self.loop0.sw_if_index) + packet_count = self.get_packet_count_for_if_idx(self.bvi0.sw_if_index) rcvd1 = self.pg0.get_capture(packet_count) rcvd2 = self.pg1.get_capture(packet_count) - self.verify_capture(self.loop0, self.pg2, rcvd1) - self.verify_capture(self.loop0, self.pg2, rcvd2) + self.verify_capture(self.bvi0, self.pg2, rcvd1) + self.verify_capture(self.bvi0, self.pg2, rcvd2) self.assertListEqual(rcvd1.res, rcvd2.res) def send_and_verify_l2_to_ip(self): stream1 = self.create_stream_l2_to_ip( - self.pg0, self.loop0, self.pg2, self.pg_if_packet_sizes) + self.pg0, self.bvi0, self.pg2, self.pg_if_packet_sizes) stream2 = self.create_stream_l2_to_ip( - self.pg1, self.loop0, self.pg2, self.pg_if_packet_sizes) + self.pg1, self.bvi0, self.pg2, self.pg_if_packet_sizes) self.vapi.cli("clear trace") self.pg0.add_stream(stream1) self.pg1.add_stream(stream2) @@ -254,7 +254,7 @@ class TestIpIrb(VppTestCase): self.pg_start() rcvd = self.pg2.get_capture(514) - self.verify_capture_l2_to_ip(self.pg2, self.loop0, rcvd) + self.verify_capture_l2_to_ip(self.pg2, self.bvi0, rcvd) def test_ip4_irb_2(self): """ IPv4 IRB test 2 @@ -265,7 +265,7 @@ class TestIpIrb(VppTestCase): self.send_and_verify_l2_to_ip() # change the BVI's mac and resed traffic - self.loop0.set_mac(MACAddress("00:00:00:11:11:33")) + self.bvi0.set_mac(MACAddress("00:00:00:11:11:33")) self.send_and_verify_l2_to_ip() # check it wasn't flooded diff --git a/test/test_l2_flood.py b/test/test_l2_flood.py index 7fe5214dcde..e81daf99235 100644 --- a/test/test_l2_flood.py +++ b/test/test_l2_flood.py @@ -20,24 +20,24 @@ class TestL2Flood(VppTestCase): # 12 l2 interface and one l3 self.create_pg_interfaces(range(13)) - self.create_loopback_interfaces(1) + self.create_bvi_interfaces(1) for i in self.pg_interfaces: i.admin_up() - for i in self.lo_interfaces: + for i in self.bvi_interfaces: i.admin_up() self.pg12.config_ip4() self.pg12.resolve_arp() - self.loop0.config_ip4() + self.bvi0.config_ip4() def tearDown(self): self.pg12.unconfig_ip4() - self.loop0.unconfig_ip4() + self.bvi0.unconfig_ip4() for i in self.pg_interfaces: i.admin_down() - for i in self.lo_interfaces: + for i in self.bvi_interfaces: i.admin_down() super(TestL2Flood, self).tearDown() @@ -61,7 +61,7 @@ class TestL2Flood(VppTestCase): for i in self.pg_interfaces[8:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2) - for i in self.lo_interfaces: + for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI) @@ -142,7 +142,7 @@ class TestL2Flood(VppTestCase): for i in self.pg_interfaces[:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0) - for i in self.lo_interfaces: + for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI, diff --git a/test/vpp_bvi_interface.py b/test/vpp_bvi_interface.py new file mode 100644 index 00000000000..7039f29ca8d --- /dev/null +++ b/test/vpp_bvi_interface.py @@ -0,0 +1,22 @@ +from vpp_object import VppObject +from vpp_interface import VppInterface + + +class VppBviInterface(VppInterface, VppObject): + """VPP bvi interface.""" + + def __init__(self, test): + """ Create VPP BVI interface """ + super(VppBviInterface, self).__init__(test) + self.add_vpp_config() + + def add_vpp_config(self): + r = self.test.vapi.bvi_create(user_instance=0xffffffff, + mac="00:00:00:00:00:00") + self.set_sw_if_index(r.sw_if_index) + + def remove_vpp_config(self): + self.test.vapi.bvi_delete(sw_if_index=self.sw_if_index) + + def object_id(self): + return "bvi-%d" % self._sw_if_index |