From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/l2/l2_bd.c | 1079 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1079 insertions(+) create mode 100644 src/vnet/l2/l2_bd.c (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c new file mode 100644 index 00000000..22f83d0b --- /dev/null +++ b/src/vnet/l2/l2_bd.c @@ -0,0 +1,1079 @@ +/* + * l2_bd.c : layer 2 bridge domain + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + * @file + * @brief Ethernet Bridge Domain. + * + * Code in this file manages Layer 2 bridge domains. + * + */ + +bd_main_t bd_main; + +/** + Init bridge domain if not done already. + For feature bitmap, set all bits except ARP termination +*/ +void +bd_validate (l2_bridge_domain_t * bd_config) +{ + if (!bd_is_valid (bd_config)) + { + bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; + bd_config->bvi_sw_if_index = ~0; + bd_config->members = 0; + bd_config->flood_count = 0; + bd_config->tun_master_count = 0; + bd_config->tun_normal_count = 0; + bd_config->mac_by_ip4 = 0; + bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), + sizeof (uword)); + } +} + +u32 +bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + uword *p; + u32 rv; + + if (bd_id == ~0) + { + bd_id = 0; + while (hash_get (bdm->bd_index_by_bd_id, bd_id)) + bd_id++; + } + else + { + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + return (p[0]); + } + + rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); + + /* mark this index busy */ + bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1); + + hash_set (bdm->bd_index_by_bd_id, bd_id, rv); + + vec_validate (l2input_main.bd_configs, rv); + l2input_main.bd_configs[rv].bd_id = bd_id; + + return rv; +} + +int +bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) +{ + uword *p; + u32 bd_index; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + return -1; + + bd_index = p[0]; + + /* mark this index clear */ + bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); + hash_unset (bdm->bd_index_by_bd_id, bd_id); + + l2input_main.bd_configs[bd_index].bd_id = ~0; + l2input_main.bd_configs[bd_index].feature_bitmap = 0; + + return 0; +} + +static void +update_flood_count (l2_bridge_domain_t * bd_config) +{ + bd_config->flood_count = vec_len (bd_config->members) - + (bd_config->tun_master_count ? bd_config->tun_normal_count : 0); +} + +void +bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member) +{ + u32 ix; + vnet_sw_interface_t *sw_if = vnet_get_sw_interface + (vnet_get_main (), member->sw_if_index); + + /* + * Add one element to the vector + * vector is ordered [ bvi, normal/tun_masters..., tun_normals... ] + * When flooding, the bvi interface (if present) must be the last member + * processed due to how BVI processing can change the packet. To enable + * this order, we make the bvi interface the first in the vector and + * flooding walks the vector in reverse. + */ + switch (sw_if->flood_class) + { + case VNET_FLOOD_CLASS_TUNNEL_MASTER: + bd_config->tun_master_count++; + /* Fall through */ + default: + /* Fall through */ + case VNET_FLOOD_CLASS_NORMAL: + ix = (member->flags & L2_FLOOD_MEMBER_BVI) ? 0 : + vec_len (bd_config->members) - bd_config->tun_normal_count; + break; + case VNET_FLOOD_CLASS_TUNNEL_NORMAL: + ix = vec_len (bd_config->members); + bd_config->tun_normal_count++; + break; + } + + vec_insert_elts (bd_config->members, member, 1, ix); + update_flood_count (bd_config); +} + +#define BD_REMOVE_ERROR_OK 0 +#define BD_REMOVE_ERROR_NOT_FOUND 1 + +u32 +bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index) +{ + u32 ix; + + /* Find and delete the member */ + vec_foreach_index (ix, bd_config->members) + { + l2_flood_member_t *m = vec_elt_at_index (bd_config->members, ix); + if (m->sw_if_index == sw_if_index) + { + vnet_sw_interface_t *sw_if = vnet_get_sw_interface + (vnet_get_main (), sw_if_index); + + if (sw_if->flood_class != VNET_FLOOD_CLASS_NORMAL) + { + if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_MASTER) + bd_config->tun_master_count--; + else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL) + bd_config->tun_normal_count--; + } + vec_del1 (bd_config->members, ix); + update_flood_count (bd_config); + + return BD_REMOVE_ERROR_OK; + } + } + + return BD_REMOVE_ERROR_NOT_FOUND; +} + + +clib_error_t * +l2bd_init (vlib_main_t * vm) +{ + bd_main_t *bdm = &bd_main; + u32 bd_index; + bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword)); + /* + * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set + * to packet drop only. Thus, packets received from any L2 interface with + * uninitialized bd_index of 0 can be dropped safely. + */ + bd_index = bd_find_or_add_bd_index (bdm, 0); + ASSERT (bd_index == 0); + l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; + return 0; +} + +VLIB_INIT_FUNCTION (l2bd_init); + + +/** + Set the learn/forward/flood flags for the bridge domain. + Return 0 if ok, non-zero if for an error. +*/ +u32 +bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) +{ + + l2_bridge_domain_t *bd_config; + u32 feature_bitmap = 0; + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + + bd_validate (bd_config); + + if (flags & L2_LEARN) + { + feature_bitmap |= L2INPUT_FEAT_LEARN; + } + if (flags & L2_FWD) + { + feature_bitmap |= L2INPUT_FEAT_FWD; + } + if (flags & L2_FLOOD) + { + feature_bitmap |= L2INPUT_FEAT_FLOOD; + } + if (flags & L2_UU_FLOOD) + { + feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + } + if (flags & L2_ARP_TERM) + { + feature_bitmap |= L2INPUT_FEAT_ARP_TERM; + } + + if (enable) + { + bd_config->feature_bitmap |= feature_bitmap; + } + else + { + bd_config->feature_bitmap &= ~feature_bitmap; + } + + return 0; +} + +/** + Set the mac age for the bridge domain. +*/ +void +bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) +{ + l2_bridge_domain_t *bd_config; + int enable = 0; + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config->mac_age = age; + + /* check if there is at least one bd with mac aging enabled */ + vec_foreach (bd_config, l2input_main.bd_configs) + if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) + enable = 1; + + vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, + enable ? L2_MAC_AGE_PROCESS_EVENT_START : + L2_MAC_AGE_PROCESS_EVENT_STOP, 0); +} + +/** + Set bridge-domain learn enable/disable. + The CLI format is: + set bridge-domain learn [disable] +*/ +static clib_error_t * +bd_learn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_LEARN, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 learning can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable learning (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain learn 200} + * Example of how to disable learning (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain learn 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_learn_cli, static) = { + .path = "set bridge-domain learn", + .short_help = "set bridge-domain learn [disable]", + .function = bd_learn, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain forward enable/disable. + The CLI format is: + set bridge-domain forward [disable] +*/ +static clib_error_t * +bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_FWD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + + +/*? + * Layer 2 unicast forwarding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable forwarding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain forward 200} + * Example of how to disable forwarding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain forward 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_fwd_cli, static) = { + .path = "set bridge-domain forward", + .short_help = "set bridge-domain forward [disable]", + .function = bd_fwd, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain flood enable/disable. + The CLI format is: + set bridge-domain flood [disable] +*/ +static clib_error_t * +bd_flood (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_FLOOD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 flooding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200} + * Example of how to disable flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_flood_cli, static) = { + .path = "set bridge-domain flood", + .short_help = "set bridge-domain flood [disable]", + .function = bd_flood, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain unkown-unicast flood enable/disable. + The CLI format is: + set bridge-domain uu-flood [disable] +*/ +static clib_error_t * +bd_uu_flood (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 unknown-unicast flooding can be enabled and disabled on each + * bridge-domain. It is enabled by default. + * + * @cliexpar + * Example of how to enable unknown-unicast flooding (where 200 is the + * bridge-domain-id): + * @cliexcmd{set bridge-domain uu-flood 200} + * Example of how to disable unknown-unicast flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain uu-flood 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = { + .path = "set bridge-domain uu-flood", + .short_help = "set bridge-domain uu-flood [disable]", + .function = bd_uu_flood, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain arp term enable/disable. + The CLI format is: + set bridge-domain arp term [disable] +*/ +static clib_error_t * +bd_arp_term (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + enable = 1; + if (unformat (input, "disable")) + enable = 0; + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +static clib_error_t * +bd_mac_age (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 age; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + if (!unformat (input, "%u", &age)) + { + error = + clib_error_return (0, "expecting ageing time in minutes but got `%U'", + format_unformat_error, input); + goto done; + } + + /* set the bridge domain flag */ + if (age > 255) + { + error = + clib_error_return (0, "mac aging time cannot be bigger than 255"); + goto done; + } + bd_set_mac_age (vm, bd_index, (u8) age); + +done: + return error; +} + +/*? + * Layer 2 mac aging can be enabled and disabled on each + * bridge-domain. Use this command to set or disable mac aging + * on specific bridge-domains. It is disabled by default. + * + * @cliexpar + * Example of how to set mac aging (where 200 is the bridge-domain-id and + * 5 is aging time in minutes): + * @cliexcmd{set bridge-domain mac-age 200 5} + * Example of how to disable mac aging (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200 0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_mac_age_cli, static) = { + .path = "set bridge-domain mac-age", + .short_help = "set bridge-domain mac-age ", + .function = bd_mac_age, +}; +/* *INDENT-ON* */ + +/*? + * Modify whether or not an existing bridge-domain should terminate and respond + * to ARP Requests. ARP Termination is disabled by default. + * + * @cliexpar + * Example of how to enable ARP termination (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp term 200} + * Example of how to disable ARP termination (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp term 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_arp_term_cli, static) = { + .path = "set bridge-domain arp term", + .short_help = "set bridge-domain arp term [disable]", + .function = bd_arp_term, +}; +/* *INDENT-ON* */ + + +/** + * Add/delete IP address to MAC address mapping. + * + * The clib hash implementation stores uword entries in the hash table. + * The hash table mac_by_ip4 is keyed via IP4 address and store the + * 6-byte MAC address directly in the hash table entry uword. + * + * @warning This only works for 64-bit processor with 8-byte uword; + * which means this code *WILL NOT WORK* for a 32-bit prcessor with + * 4-byte uword. + */ +u32 +bd_add_del_ip_mac (u32 bd_index, + u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add) +{ + l2input_main_t *l2im = &l2input_main; + l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index); + u64 new_mac = *(u64 *) mac_addr; + u64 *old_mac; + u16 *mac16 = (u16 *) & new_mac; + + ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */ + + mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */ + if (is_ip6) + { + ip6_address_t *ip6_addr_key; + hash_pair_t *hp; + old_mac = (u64 *) hash_get_mem (bd_cfg->mac_by_ip6, ip_addr); + if (is_add) + { + if (old_mac == 0) + { /* new entry - allocate and craete ip6 address key */ + ip6_addr_key = clib_mem_alloc (sizeof (ip6_address_t)); + clib_memcpy (ip6_addr_key, ip_addr, sizeof (ip6_address_t)); + } + else if (*old_mac == new_mac) + { /* same mac entry already exist for ip6 address */ + return 0; + } + else + { /* updat mac for ip6 address */ + hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr); + ip6_addr_key = (ip6_address_t *) hp->key; + } + hash_set_mem (bd_cfg->mac_by_ip6, ip6_addr_key, new_mac); + } + else + { + if (old_mac && (*old_mac == new_mac)) + { + hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr); + ip6_addr_key = (ip6_address_t *) hp->key; + hash_unset_mem (bd_cfg->mac_by_ip6, ip_addr); + clib_mem_free (ip6_addr_key); + } + else + return 1; + } + } + else + { + ip4_address_t ip4_addr = *(ip4_address_t *) ip_addr; + old_mac = (u64 *) hash_get (bd_cfg->mac_by_ip4, ip4_addr.as_u32); + if (is_add) + { + if (old_mac && (*old_mac == new_mac)) + return 0; /* mac entry already exist */ + hash_set (bd_cfg->mac_by_ip4, ip4_addr.as_u32, new_mac); + } + else + { + if (old_mac && (*old_mac == new_mac)) + hash_unset (bd_cfg->mac_by_ip4, ip4_addr.as_u32); + else + return 1; + } + } + return 0; +} + +/** + Set bridge-domain arp entry add/delete. + The CLI format is: + set bridge-domain arp entry [del] +*/ +static clib_error_t * +bd_arp_entry (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u8 is_add = 1; + u8 is_ip6 = 0; + u8 ip_addr[16]; + u8 mac_addr[6]; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + if (unformat (input, "%U", unformat_ip4_address, ip_addr)) + { + is_ip6 = 0; + } + else if (unformat (input, "%U", unformat_ip6_address, ip_addr)) + { + is_ip6 = 1; + } + else + { + error = clib_error_return (0, "expecting IP address but got `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%U", unformat_ethernet_address, mac_addr)) + { + error = clib_error_return (0, "expecting MAC address but got `%U'", + format_unformat_error, input); + goto done; + } + + if (unformat (input, "del")) + { + is_add = 0; + } + + /* set the bridge domain flagAdd IP-MAC entry into bridge domain */ + if (bd_add_del_ip_mac (bd_index, ip_addr, mac_addr, is_ip6, is_add)) + { + error = clib_error_return (0, "MAC %s for IP %U and MAC %U failed", + is_add ? "add" : "del", + is_ip6 ? + format_ip4_address : format_ip6_address, + ip_addr, format_ethernet_address, mac_addr); + } + +done: + return error; +} + +/*? + * Add an ARP entry to an existing bridge-domain. + * + * @cliexpar + * Example of how to add an ARP entry (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a} + * Example of how to delete an ARP entry (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a del} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_arp_entry_cli, static) = { + .path = "set bridge-domain arp entry", + .short_help = "set bridge-domain arp entry [del]", + .function = bd_arp_entry, +}; +/* *INDENT-ON* */ + +u8 * +format_vtr (u8 * s, va_list * args) +{ + u32 vtr_op = va_arg (*args, u32); + u32 dot1q = va_arg (*args, u32); + u32 tag1 = va_arg (*args, u32); + u32 tag2 = va_arg (*args, u32); + switch (vtr_op) + { + case L2_VTR_DISABLED: + return format (s, "none"); + case L2_VTR_PUSH_1: + return format (s, "push-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_PUSH_2: + return format (s, "push-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", tag1, + tag2); + case L2_VTR_POP_1: + return format (s, "pop-1"); + case L2_VTR_POP_2: + return format (s, "pop-2"); + case L2_VTR_TRANSLATE_1_1: + return format (s, "trans-1-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_TRANSLATE_1_2: + return format (s, "trans-1-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", + tag1, tag2); + case L2_VTR_TRANSLATE_2_1: + return format (s, "trans-2-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_TRANSLATE_2_2: + return format (s, "trans-2-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", + tag1, tag2); + default: + return format (s, "none"); + } +} + +/** + Show bridge-domain state. + The CLI format is: + show bridge-domain [] +*/ +static clib_error_t * +bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index = ~0; + l2_bridge_domain_t *bd_config; + u32 start, end; + u32 printed; + u32 detail = 0; + u32 intf = 0; + u32 arp = 0; + u32 bd_id = ~0; + uword *p; + + start = 0; + end = vec_len (l2input_main.bd_configs); + + if (unformat (input, "%d", &bd_id)) + { + if (unformat (input, "detail")) + detail = 1; + else if (unformat (input, "det")) + detail = 1; + if (unformat (input, "int")) + intf = 1; + if (unformat (input, "arp")) + arp = 1; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + if (bd_is_valid (bd_config)) + { + start = bd_index; + end = start + 1; + } + else + { + vlib_cli_output (vm, "bridge-domain %d not in use", bd_id); + goto done; + } + } + + /* Show all bridge-domains that have been initialized */ + printed = 0; + for (bd_index = start; bd_index < end; bd_index++) + { + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + if (bd_is_valid (bd_config)) + { + if (!printed) + { + printed = 1; + vlib_cli_output (vm, + "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s", + "ID", "Index", "Learning", "U-Forwrd", + "UU-Flood", "Flooding", "ARP-Term", + "BVI-Intf"); + } + + vlib_cli_output (vm, + "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U", + bd_config->bd_id, bd_index, + bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on" + : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ? + "on" : "off", format_vnet_sw_if_index_name_with_NA, + vnm, bd_config->bvi_sw_if_index); + + if (detail || intf) + { + /* Show all member interfaces */ + int i; + vec_foreach_index (i, bd_config->members) + { + l2_flood_member_t *member = + vec_elt_at_index (bd_config->members, i); + u32 vtr_opr, dot1q, tag1, tag2; + if (i == 0) + { + vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=9s%=30s", + "Interface", "Index", "SHG", "BVI", + "TxFlood", "VLAN-Tag-Rewrite"); + } + l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q, + &tag1, &tag2); + vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=9s%=30U", + format_vnet_sw_if_index_name, vnm, + member->sw_if_index, member->sw_if_index, + member->shg, + member->flags & L2_FLOOD_MEMBER_BVI ? "*" : + "-", i < bd_config->flood_count ? "*" : "-", + format_vtr, vtr_opr, dot1q, tag1, tag2); + } + } + + if ((detail || arp) && + (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM)) + { + u32 ip4_addr; + ip6_address_t *ip6_addr; + u64 mac_addr; + vlib_cli_output (vm, + "\n IP4/IP6 to MAC table for ARP Termination"); + + /* *INDENT-OFF* */ + hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4, + ({ + vlib_cli_output (vm, "%=40U => %=20U", + format_ip4_address, &ip4_addr, + format_ethernet_address, &mac_addr); + })); + + hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6, + ({ + vlib_cli_output (vm, "%=40U => %=20U", + format_ip6_address, ip6_addr, + format_ethernet_address, &mac_addr); + })); + /* *INDENT-ON* */ + } + } + } + + if (!printed) + { + vlib_cli_output (vm, "no bridge-domains in use"); + } + +done: + return error; +} + +/*? + * Show a summary of all the bridge-domain instances or detailed view of a + * single bridge-domain. Bridge-domains are created by adding an interface + * to a bridge using the 'set interface l2 bridge' command. + * + * @cliexpar + * @parblock + * Example of displaying all bridge-domains: + * @cliexstart{show bridge-domain} + * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 0 0 off off off off off local0 + * 200 1 on on on on off N/A + * @cliexend + * + * Example of displaying details of a single bridge-domains: + * @cliexstart{show bridge-domain 200 detail} + * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 200 1 on on on on off N/A + * + * Interface Index SHG BVI VLAN-Tag-Rewrite + * GigabitEthernet0/8/0.200 3 0 - none + * GigabitEthernet0/9/0.200 4 0 - none + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_show_cli, static) = { + .path = "show bridge-domain", + .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]", + .function = bd_show, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 25b36674f7e9072084f8f149067450f5eb6a5841 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Thu, 2 Mar 2017 10:43:19 +0200 Subject: bridge domain: fix members reordered when removing since adding support for multicast vxlan flooding (flood class tunnel master) correct flood functionality depends on the order of the memebers vector solved by using vec_delete instead of vec_del1 which swaps members before deleting the last element Change-Id: I234f218d49172b4142c567db9699a5cb274e4a66 Signed-off-by: Eyal Bari --- src/vnet/l2/l2_bd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 22f83d0b..f741b643 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -185,7 +185,7 @@ bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index) else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL) bd_config->tun_normal_count--; } - vec_del1 (bd_config->members, ix); + vec_delete (bd_config->members, 1, ix); update_flood_count (bd_config); return BD_REMOVE_ERROR_OK; -- cgit 1.2.3-korg From da1f2c7cffb0de4ef05a48ffd107214eb11fa45f Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 24 Mar 2017 20:11:15 -0400 Subject: Implement MAC Flush for BD or Interface from the L2FIB Allow non-static MACs in the L2FIB which is associated with an interface or a bridge domain (BD) be flushed. MAC flush are initiated automatically when an interface is removed from a BD or when a BD is deleted. MAC flush can also be invoked manually via the following CLI: l2fib mac-flush interface l2fib mac-flush bridge-domain Change-Id: Ie33243622834810a765f48ebcd22bdb8e8fc87a4 Signed-off-by: John Lo --- src/vnet/buffer.h | 8 ++- src/vnet/l2/l2_bd.c | 41 +++++++---- src/vnet/l2/l2_bd.h | 3 + src/vnet/l2/l2_fib.c | 188 +++++++++++++++++++++++++++++++++++++++++++++---- src/vnet/l2/l2_fib.h | 39 +++++----- src/vnet/l2/l2_input.c | 14 ++++ src/vnet/l2/l2_input.h | 3 + src/vnet/l2/l2_learn.c | 10 ++- src/vnet/l2/l2_learn.h | 1 + 9 files changed, 258 insertions(+), 49 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index f08b4fc1..ea3ce093 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -169,9 +169,11 @@ typedef struct struct { u32 feature_bitmap; - u16 bd_index; // bridge-domain index - u8 l2_len; // ethernet header length - u8 shg; // split-horizon group + u16 bd_index; /* bridge-domain index */ + u8 l2_len; /* ethernet header length */ + u8 shg; /* split-horizon group */ + u8 bd_sn; /* bridge domain seq# */ + u8 int_sn; /* interface seq# */ } l2; /* l2tpv3 softwire encap, only valid there */ diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index f741b643..6c01368b 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -115,6 +115,8 @@ bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) l2input_main.bd_configs[bd_index].bd_id = ~0; l2input_main.bd_configs[bd_index].feature_bitmap = 0; + l2fib_flush_bd_mac (vlib_get_main (), bd_index); + return 0; } @@ -900,7 +902,6 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 bd_index = ~0; l2_bridge_domain_t *bd_config; u32 start, end; - u32 printed; u32 detail = 0; u32 intf = 0; u32 arp = 0; @@ -942,7 +943,8 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } /* Show all bridge-domains that have been initialized */ - printed = 0; + u32 printed = 0; + u8 *as = 0; for (bd_index = start; bd_index < end; bd_index++) { bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); @@ -952,26 +954,32 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { printed = 1; vlib_cli_output (vm, - "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s", - "ID", "Index", "Learning", "U-Forwrd", - "UU-Flood", "Flooding", "ARP-Term", + "%=5s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", + "ID", "Index", "BSN", "Age(min)", "Learning", + "U-Forwrd", "UU-Flood", "Flooding", "ARP-Term", "BVI-Intf"); } + if (bd_config->mac_age) + as = format (as, "%d", bd_config->mac_age); + else + as = format (as, "off"); vlib_cli_output (vm, - "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U", - bd_config->bd_id, bd_index, + "%=5d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", + bd_config->bd_id, bd_index, bd_config->seq_num, as, bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? "on" : "off", - bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on" - : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? + "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ? "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ? "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ? - "on" : "off", format_vnet_sw_if_index_name_with_NA, + "on" : "off", + format_vnet_sw_if_index_name_with_NA, vnm, bd_config->bvi_sw_if_index); + vec_reset_length (as); if (detail || intf) { @@ -981,19 +989,21 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { l2_flood_member_t *member = vec_elt_at_index (bd_config->members, i); + l2_input_config_t *int_config = + l2input_intf_config (member->sw_if_index); u32 vtr_opr, dot1q, tag1, tag2; if (i == 0) { - vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=9s%=30s", - "Interface", "Index", "SHG", "BVI", - "TxFlood", "VLAN-Tag-Rewrite"); + vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=5s%=9s%=30s", + "Interface", "If-idx", "ISN", "SHG", + "BVI", "TxFlood", "VLAN-Tag-Rewrite"); } l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q, &tag1, &tag2); - vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=9s%=30U", + vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U", format_vnet_sw_if_index_name, vnm, member->sw_if_index, member->sw_if_index, - member->shg, + int_config->seq_num, member->shg, member->flags & L2_FLOOD_MEMBER_BVI ? "*" : "-", i < bd_config->flood_count ? "*" : "-", format_vtr, vtr_opr, dot1q, tag1, tag2); @@ -1027,6 +1037,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } } } + vec_free (as); if (!printed) { diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 4bb9bc9b..5c2502d9 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -86,6 +86,9 @@ typedef struct /* mac aging */ u8 mac_age; + /* sequence number for bridge domain based flush of MACs */ + u8 seq_num; + } l2_bridge_domain_t; /* Return 1 if bridge domain has been initialized */ diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index d34836e3..fadd79eb 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -168,10 +168,10 @@ show_l2fib (vlib_main_t * vm, { first_entry = 0; vlib_cli_output (vm, - "%=19s%=7s%=30s%=7s%=8s%=8s%=5s%=16s", - "Mac Address", "BD Idx", "Interface", - "Index", "static", "filter", "bvi", - "Mac Age (min)"); + "%=19s%=7s%=7s%=8s%=9s%=7s%=7s%=5s%=30s", + "Mac-Address", "BD-Idx", "If-Idx", + "BSN-ISN", "Age(min)", "static", "filter", + "bvi", "Interface-Name"); } key.raw = v->kvp[k].key; @@ -183,26 +183,27 @@ show_l2fib (vlib_main_t * vm, bd_config = vec_elt_at_index (l2input_main.bd_configs, key.fields.bd_index); - if (bd_config->mac_age) + if (bd_config->mac_age && !result.fields.static_mac) { i16 delta = now - result.fields.timestamp; delta += delta < 0 ? 256 : 0; s = format (s, "%d", delta); } else - s = format (s, "disabled"); + s = format (s, "-"); vlib_cli_output (vm, - "%=19U%=7d%=30U%=7d%=8d%=8d%=5d%=16v", + "%=19U%=7d%=7d %3d/%-3d%=9v%=7s%=7s%=5s%=30U", format_ethernet_address, key.fields.mac, key.fields.bd_index, - format_vnet_sw_if_index_name_with_NA, - msm->vnet_main, result.fields.sw_if_index, result.fields.sw_if_index == ~0 ? -1 : result.fields.sw_if_index, - result.fields.static_mac, - result.fields.filter, - result.fields.bvi, s); + result.fields.bd_sn, result.fields.int_sn, + s, result.fields.static_mac ? "*" : "-", + result.fields.filter ? "*" : "-", + result.fields.bvi ? "*" : "-", + format_vnet_sw_if_index_name_with_NA, + msm->vnet_main, result.fields.sw_if_index); vec_reset_length (s); } total_entries++; @@ -330,6 +331,15 @@ l2fib_add_entry (u64 mac, result.fields.static_mac = static_mac; result.fields.filter = filter_mac; result.fields.bvi = bvi_mac; + if (!static_mac) + { + l2_input_config_t *int_config = l2input_intf_config (sw_if_index); + l2_bridge_domain_t *bd_config = + vec_elt_at_index (l2input_main.bd_configs, + bd_index); + result.fields.int_sn = int_config->seq_num; + result.fields.bd_sn = bd_config->seq_num; + } kv.key = key.raw; kv.value = result.raw; @@ -703,6 +713,141 @@ VLIB_CLI_COMMAND (l2fib_del_cli, static) = { }; /* *INDENT-ON* */ +/** + Kick off ager to scan MACs to age/delete MAC entries +*/ +void +l2fib_start_ager_scan (vlib_main_t * vm) +{ + l2_bridge_domain_t *bd_config; + int enable = 0; + + /* check if there is at least one bd with mac aging enabled */ + vec_foreach (bd_config, l2input_main.bd_configs) + if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) + enable = 1; + + vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, + enable ? L2_MAC_AGE_PROCESS_EVENT_START : + L2_MAC_AGE_PROCESS_EVENT_ONE_PASS, 0); +} + +/** + Flush all learned MACs from an interface +*/ +void +l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index) +{ + l2_input_config_t *int_config; + int_config = l2input_intf_config (sw_if_index); + int_config->seq_num += 1; + l2fib_start_ager_scan (vm); +} + +/** + Flush all learned MACs in a bridge domain +*/ +void +l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index) +{ + l2_bridge_domain_t *bd_config; + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config->seq_num += 1; + l2fib_start_ager_scan (vm); +} + +/** + Flush MACs, except static ones, associated with an interface + The CLI format is: + l2fib flush-mac interface +*/ +static clib_error_t * +l2fib_flush_mac_int (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + l2fib_flush_int_mac (vm, sw_if_index); + +done: + return error; +} + +/*? + * This command kick off ager to delete all existing MAC Address entries, + * except static ones, associated with an interface from the L2 FIB table. + * + * @cliexpar + * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table: + * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli, static) = { + .path = "l2fib flush-mac interface", + .short_help = "l2fib flush-mac interface ", + .function = l2fib_flush_mac_int, +}; +/* *INDENT-ON* */ + +/** + Flush bridge-domain MACs except static ones. + The CLI format is: + l2fib flush-mac bridge-domain +*/ +static clib_error_t * +l2fib_flush_mac_bd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + l2fib_flush_bd_mac (vm, bd_index); + +done: + return error; +} + +/*? + * This command kick off ager to delete all existing MAC Address entries, + * except static ones, in a bridge domain from the L2 FIB table. + * + * @cliexpar + * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table: + * @cliexcmd{l2fib flush-mac bridge-domain 1000} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = { + .path = "l2fib flush-mac bridge-domain", + .short_help = "l2fib flush-mac bridge-domain ", + .function = l2fib_flush_mac_bd, +}; +/* *INDENT-ON* */ + BVT (clib_bihash) * get_mac_table (void) { @@ -716,6 +861,7 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, { uword event_type, *event_data = 0; l2fib_main_t *msm = &l2fib_main; + l2_input_config_t *int_config; l2_bridge_domain_t *bd_config; BVT (clib_bihash) * h = &msm->mac_table; clib_bihash_bucket_t *b; @@ -747,6 +893,9 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, case L2_MAC_AGE_PROCESS_EVENT_STOP: enabled = 0; continue; + case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS: + enabled = 0; + break; default: ASSERT (0); } @@ -790,8 +939,19 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (result.fields.static_mac) continue; - bd_config = vec_elt_at_index (l2input_main.bd_configs, - key.fields.bd_index); + int_config = + l2input_intf_config (result.fields.sw_if_index); + bd_config = + vec_elt_at_index (l2input_main.bd_configs, + key.fields.bd_index); + + if ((result.fields.int_sn != int_config->seq_num) || + (result.fields.bd_sn != bd_config->seq_num)) + { + void *p = &key.fields.mac; + l2fib_del_entry (*(u64 *) p, key.fields.bd_index); + continue; + } if (bd_config->mac_age == 0) continue; diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 4a2da59b..7e49d74b 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -66,7 +66,8 @@ typedef struct u8 filter:1; /* drop packets to/from this mac */ u8 unused1:5; u8 timestamp; /* timestamp for aging */ - u16 unused2; + u8 int_sn; /* interface seq num */ + u8 bd_sn; /* bridge domain seq num */ } fields; u64 raw; }; @@ -313,22 +314,28 @@ l2fib_lookup_4 (BVT (clib_bihash) * mac_table, } } +void l2fib_clear_table (uint keep_static); + +void +l2fib_add_entry (u64 mac, + u32 bd_index, + u32 sw_if_index, u32 static_mac, u32 drop_mac, u32 bvi_mac); + +u32 l2fib_del_entry (u64 mac, u32 bd_index); + +void l2fib_start_ager_scan (vlib_main_t * vm); + +void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index); + +void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index); + +void +l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, + l2fib_entry_result_t ** l2fe_res); + +u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); + BVT (clib_bihash) * get_mac_table (void); - void - l2fib_clear_table (uint keep_static); - void - l2fib_add_entry (u64 mac, - u32 bd_index, - u32 sw_if_index, - u32 static_mac, u32 drop_mac, u32 bvi_mac); -u32 -l2fib_del_entry (u64 mac, u32 bd_index); - - void - l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, - l2fib_entry_result_t ** l2fe_res); - - u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); #endif diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 3aa5331b..041ff38d 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,9 @@ classify_and_dispatch (vlib_main_t * vm, /* Get config for the bridge domain interface */ bd_config = vec_elt_at_index (msm->bd_configs, bd_index0); + /* Save bridge domain seq_num */ + vnet_buffer (b0)->l2.bd_sn = bd_config->seq_num; + /* * Process bridge domain feature enables. * To perform learning/flooding/forwarding, the corresponding bit @@ -214,6 +218,9 @@ classify_and_dispatch (vlib_main_t * vm, /* mask out features from bitmap using packet type and bd config */ feature_bitmap = config->feature_bitmap & feat_mask; + /* Save interface seq_num */ + vnet_buffer (b0)->l2.int_sn = config->seq_num; + /* save for next feature graph nodes */ vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; @@ -561,6 +568,12 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); } + + /* Clear MACs learned on the interface */ + if ((config->feature_bitmap | L2INPUT_FEAT_LEARN) || + (bd_config->feature_bitmap | L2INPUT_FEAT_LEARN)) + l2fib_flush_int_mac (vm, sw_if_index); + l2_if_adjust--; } else if (config->xconnect) @@ -632,6 +645,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->xconnect = 0; config->bridge = 1; config->bd_index = bd_index; + config->seq_num += 1; /* * Enable forwarding, flooding, learning and ARP termination by default diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index f3fada6a..262f75c7 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -53,6 +53,9 @@ typedef struct /* split horizon group */ u8 shg; + /* sequence number for interface based flush of MACs */ + u8 seq_num; + } l2_input_config_t; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index afe7f478..faed0d66 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -140,7 +140,11 @@ l2learn_process (vlib_node_runtime_t * node, counter_base[L2LEARN_ERROR_HIT] += 1; if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) result0->fields.timestamp = timestamp; - + if (PREDICT_FALSE + (result0->fields.int_sn != vnet_buffer (b0)->l2.int_sn)) + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; + if (PREDICT_FALSE (result0->fields.bd_sn != vnet_buffer (b0)->l2.bd_sn)) + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; } else if (result0->raw == ~0) { @@ -167,6 +171,8 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; kv.key = key0->raw; kv.value = result0->raw; @@ -204,6 +210,8 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; kv.key = key0->raw; kv.value = result0->raw; diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index 5bb1130b..0d95de04 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -51,6 +51,7 @@ enum { L2_MAC_AGE_PROCESS_EVENT_START = 1, L2_MAC_AGE_PROCESS_EVENT_STOP = 2, + L2_MAC_AGE_PROCESS_EVENT_ONE_PASS = 3, } l2_mac_age_process_event_t; #endif -- cgit 1.2.3-korg From 054807960a92e477563321720cf8750909d72d7e Mon Sep 17 00:00:00 2001 From: Choonho Son Date: Wed, 29 Mar 2017 20:07:45 +0900 Subject: CLI: create/delete bridge-domain Added new CLI command - create bridge-domain - create bridge-domain del Change-Id: I1a7d632c7daa3c37b7f424a184e8fabd489518e9 Signed-off-by: Choonho Son --- src/vnet/l2/l2_bd.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/vnet/l2/l2_bd.h | 12 ++++ 2 files changed, 201 insertions(+), 1 deletion(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 6c01368b..0375998c 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -104,7 +104,7 @@ bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) - return -1; + return VNET_API_ERROR_NO_SUCH_ENTRY; bd_index = p[0]; @@ -212,6 +212,8 @@ l2bd_init (vlib_main_t * vm) bd_index = bd_find_or_add_bd_index (bdm, 0); ASSERT (bd_index == 0); l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; + + bdm->vlib_main = vm; return 0; } @@ -1081,6 +1083,192 @@ VLIB_CLI_COMMAND (bd_show_cli, static) = { }; /* *INDENT-ON* */ +int +bd_add_del (l2_bridge_domain_add_del_args_t * a) +{ + bd_main_t *bdm = &bd_main; + vlib_main_t *vm = bdm->vlib_main; + u32 enable_flags = 0, disable_flags = 0; + u32 bd_index = ~0; + int rv = 0; + + if (a->is_add) + { + bd_index = bd_find_or_add_bd_index (bdm, a->bd_id); + if (bd_index == ~0) + return bd_index; + + if (a->flood) + enable_flags |= L2_FLOOD; + else + disable_flags |= L2_FLOOD; + + if (a->uu_flood) + enable_flags |= L2_UU_FLOOD; + else + disable_flags |= L2_UU_FLOOD; + + if (a->forward) + enable_flags |= L2_FWD; + else + disable_flags |= L2_FWD; + + if (a->learn) + enable_flags |= L2_LEARN; + else + disable_flags |= L2_LEARN; + + if (a->arp_term) + enable_flags |= L2_ARP_TERM; + else + disable_flags |= L2_ARP_TERM; + + if (enable_flags) + bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); + + if (disable_flags) + bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); + + bd_set_mac_age (vm, bd_index, a->mac_age); + } + else + rv = bd_delete_bd_index (bdm, a->bd_id); + + return rv; +} + +/** + Create or delete bridge-domain. + The CLI format is: + create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] + [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] +*/ + +static clib_error_t * +bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + u8 is_add = 1; + u32 bd_id = ~0; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 0, arp_term = 0; + u32 mac_age = 0; + l2_bridge_domain_add_del_args_t _a, *a = &_a; + 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, "%d", &bd_id)) + ; + else if (unformat (line_input, "flood %d", &flood)) + ; + else if (unformat (line_input, "uu-flood %d", &uu_flood)) + ; + else if (unformat (line_input, "forward %d", &forward)) + ; + else if (unformat (line_input, "arp-term %d", &arp_term)) + ; + else if (unformat (line_input, "mac-age %d", &mac_age)) + ; + else if (unformat (line_input, "del")) + { + is_add = 0; + flood = uu_flood = forward = learn = 0; + } + else + break; + } + + if (bd_id == ~0) + { + error = clib_error_return (0, "bridge-domain-id not specified"); + goto done; + } + + if (mac_age > 255) + { + error = clib_error_return (0, "mac age must be less than 256"); + goto done; + } + + memset (a, 0, sizeof (*a)); + a->is_add = is_add; + a->bd_id = bd_id; + a->flood = (u8) flood; + a->uu_flood = (u8) uu_flood; + a->forward = (u8) forward; + a->learn = (u8) learn; + a->arp_term = (u8) arp_term; + a->mac_age = (u8) mac_age; + + rv = bd_add_del (a); + + switch (rv) + { + case 0: + if (is_add) + vlib_cli_output (vm, "bridge-domain %d", bd_id); + break; + case VNET_API_ERROR_NO_SUCH_ENTRY: + error = clib_error_return (0, "bridge domain id does not exist"); + goto done; + default: + error = clib_error_return (0, "bd_add_del returned %d", rv); + goto done; + } + +done: + unformat_free (line_input); + + return error; +} + + +/*? + * Create/Delete bridge-domain instance + * + * @cliexpar + * @parblock + * Example of creating bridge-domain 1: + * @cliexstart{create bridge-domain 1} + * bridge-domain 1 + * @cliexend + * + * Example of creating bridge-domain 2 with enabling arp-term, mac-age 60: + * @cliexstart{create bridge-domain 2 arp-term 1 mac-age 60} + * bridge-domain 2 + * + * vpp# show bridge-domain + * ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 0 0 0 off off off off off off local0 + * 1 1 0 off on on off on off N/A + * 2 2 0 60 on on off on on N/A + * + * @cliexend + * + * Example of delete bridge-domain 1: + * @cliexstart{create bridge-domain 1 del} + * @cliexend + * @endparblock +?*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_create_cli, static) = { + .path = "create bridge-domain", + .short_help = "create bridge-domain " + " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]" + " [mac-age ] [del]", + .function = bd_add_del_command_fn, +}; +/* *INDENT-ON* */ + + + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 5c2502d9..83733411 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -91,6 +91,18 @@ typedef struct } l2_bridge_domain_t; +typedef struct +{ + u32 bd_id; + u8 flood; + u8 uu_flood; + u8 forward; + u8 learn; + u8 arp_term; + u8 mac_age; + u8 is_add; +} l2_bridge_domain_add_del_args_t; + /* Return 1 if bridge domain has been initialized */ always_inline u32 bd_is_valid (l2_bridge_domain_t * bd_config) -- cgit 1.2.3-korg From fead670ae0a8323d8cd14e2cfad1fb8c25a48a99 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Tue, 4 Apr 2017 04:46:32 +0300 Subject: BD/API:add bridge_domain_set_mac_age api Change-Id: Ic2d33b31ba88f6d9602a22439865637d98cf4a33 Signed-off-by: Eyal Bari --- src/vat/api_format.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++- src/vnet/l2/l2.api | 24 +++++++++++++++ src/vnet/l2/l2_api.c | 33 +++++++++++++++----- src/vnet/l2/l2_bd.c | 3 +- src/vnet/l2/l2_input.h | 5 +++ src/vpp/api/custom_dump.c | 23 +++++++++++--- 6 files changed, 150 insertions(+), 15 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index fca2b37a..06884eb1 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1458,6 +1458,39 @@ static void vl_api_control_ping_reply_t_handler_json vam->result_ready = 1; } +static void + vl_api_bridge_domain_set_mac_age_reply_t_handler + (vl_api_bridge_domain_set_mac_age_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_bridge_domain_set_mac_age_reply_t_handler_json + (vl_api_bridge_domain_set_mac_age_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_l2_flags_reply_t_handler (vl_api_l2_flags_reply_t * mp) { @@ -4285,6 +4318,7 @@ _(SW_INTERFACE_SET_L2_BRIDGE_REPLY, \ _(BRIDGE_DOMAIN_ADD_DEL_REPLY, bridge_domain_add_del_reply) \ _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ _(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE_REPLY, bridge_domain_set_mac_age_reply) \ _(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ _(L2_FLAGS_REPLY, l2_flags_reply) \ _(BRIDGE_FLAGS_REPLY, bridge_flags_reply) \ @@ -6030,6 +6064,46 @@ api_l2fib_add_del (vat_main_t * vam) return (vam->retval); } +static int +api_bridge_domain_set_mac_age (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_set_mac_age_t *mp; + u32 bd_id = ~0; + u32 mac_age = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)); + else if (unformat (i, "mac-age %d", &mac_age)); + else + break; + } + + if (bd_id == ~0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (mac_age > 255) + { + errmsg ("mac age must be less than 256 "); + return -99; + } + + M (BRIDGE_DOMAIN_SET_MAC_AGE, mp); + + mp->bd_id = htonl (bd_id); + mp->mac_age = (u8) mac_age; + + S (mp); + W (ret); + return ret; +} + static int api_l2_flags (vat_main_t * vam) { @@ -18419,8 +18493,9 @@ _(sw_interface_set_l2_bridge, \ " | sw_if_index bd_id \n" \ "[shg ] [bvi]\n" \ "enable | disable") \ +_(bridge_domain_set_mac_age, "bd_id mac-age 0-255\n")\ _(bridge_domain_add_del, \ - "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [del]\n") \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 061990c0..81b75858 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -146,6 +146,30 @@ define l2_flags_reply u32 resulting_feature_bitmap; }; +/** \brief L2 bridge domain set mac age + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the bridge domain to create + @param mac_age - mac aging time in min, 0 for disabled +*/ +define bridge_domain_set_mac_age +{ + u32 client_index; + u32 context; + u32 bd_id; + u8 mac_age; +}; + +/** \brief Set bridge domain response + @param context - sender context, to match reply w/ request + @param retval - return code for the set l2 bits request +*/ +define bridge_domain_set_mac_age_reply +{ + u32 context; + i32 retval; +}; + /** \brief L2 bridge domain add or delete request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a985852c..ffcc7901 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -54,7 +54,8 @@ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ _(BRIDGE_FLAGS, bridge_flags) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ -_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) +_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) static void send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context, @@ -244,17 +245,13 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) { vl_api_l2_flags_reply_t *rmp; int rv = 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 flags = ntohl (mp->feature_bitmap); u32 rbm = 0; VALIDATE_SW_IF_INDEX (mp); -#define _(a,b) \ - if (flags & L2INPUT_FEAT_ ## a) \ - rbm = l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ ## a, mp->is_set); - foreach_l2input_feat; -#undef _ + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 flags = ntohl (mp->feature_bitmap) & L2INPUT_VALID_MASK; + rbm = l2input_intf_bitmap_enable (sw_if_index, flags, mp->is_set); BAD_SW_IF_INDEX_LABEL; @@ -266,6 +263,26 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) /* *INDENT-ON* */ } +static void +vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t + * mp) +{ + vlib_main_t *vm = vlib_get_main (); + bd_main_t *bdm = &bd_main; + vl_api_bridge_domain_set_mac_age_reply_t *rmp; + int rv = 0; + u32 bd_id = ntohl (mp->bd_id); + uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + { + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; + } + bd_set_mac_age (vm, *p, mp->mac_age); +out: + REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY); +} + static void vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 0375998c..a222fec9 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -284,8 +284,7 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) /* check if there is at least one bd with mac aging enabled */ vec_foreach (bd_config, l2input_main.bd_configs) - if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) - enable = 1; + enable |= bd_config->bd_id != ~0 && bd_config->mac_age != 0; vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, enable ? L2_MAC_AGE_PROCESS_EVENT_START : diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index 262f75c7..a2ade8d8 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -117,6 +117,11 @@ typedef enum foreach_l2input_feat #undef _ L2INPUT_N_FEAT, + L2INPUT_VALID_MASK = +#define _(sym,str) L2INPUT_FEAT_##sym##_BIT | + foreach_l2input_feat +#undef _ + 0, } l2input_feat_t; /* Feature bit masks */ diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index fd4f7fef..b3fd781e 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -200,7 +200,7 @@ static void *vl_api_sw_interface_set_vxlan_bypass_t_print s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); if (mp->is_ipv6) - s = format (s, "ip6"); + s = format (s, "ip6 "); if (mp->enable) s = format (s, "enable "); @@ -260,9 +260,9 @@ static void *vl_api_bridge_domain_add_del_t_print if (mp->is_add) { - s = format (s, "flood %d uu-flood %d forward %d learn %d arp-term %d", - mp->flood, mp->uu_flood, mp->forward, mp->learn, - mp->arp_term); + s = format (s, "flood %d uu-flood %d ", mp->flood, mp->uu_flood); + s = format (s, "forward %d learn %d ", mp->forward, mp->learn); + s = format (s, "arp-term %d mac-age %d", mp->arp_term, mp->mac_age); } else s = format (s, "del "); @@ -270,6 +270,20 @@ static void *vl_api_bridge_domain_add_del_t_print FINISH; } +static void *vl_api_bridge_domain_set_mac_age_t_print + (vl_api_bridge_domain_set_mac_age_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: bridge_domain_set_mac_age "); + + s = format (s, "bd_id %d ", ntohl (mp->bd_id)); + + s = format (s, "mac-age %d", mp->mac_age); + + FINISH; +} + static void *vl_api_bridge_domain_dump_t_print (vl_api_bridge_domain_dump_t * mp, void *handle) { @@ -2948,6 +2962,7 @@ _(CLASSIFY_ADD_DEL_SESSION, classify_add_del_session) \ _(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(ADD_NODE_NEXT, add_node_next) \ -- cgit 1.2.3-korg From 5ee51f8ed616f14f3b32ae8857d383fefa02d861 Mon Sep 17 00:00:00 2001 From: Choonho Son Date: Wed, 5 Apr 2017 19:09:52 +0900 Subject: VPP-686: create bridge-domain - update default flags - add missing flag learn Change-Id: I50a1a001848769836468838775b59d3414d27710 Signed-off-by: Choonho Son --- src/vnet/l2/l2_bd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index a222fec9..9d7a43d3 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -1138,7 +1138,7 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) /** Create or delete bridge-domain. - The CLI format is: + The CLI format: create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] */ @@ -1151,7 +1151,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, clib_error_t *error = 0; u8 is_add = 1; u32 bd_id = ~0; - u32 flood = 1, forward = 1, learn = 1, uu_flood = 0, arp_term = 0; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; u32 mac_age = 0; l2_bridge_domain_add_del_args_t _a, *a = &_a; int rv; @@ -1170,6 +1170,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, ; else if (unformat (line_input, "forward %d", &forward)) ; + else if (unformat (line_input, "learn %d", &learn)) + ; else if (unformat (line_input, "arp-term %d", &arp_term)) ; else if (unformat (line_input, "mac-age %d", &mac_age)) -- cgit 1.2.3-korg From b1352ed0ac39aaa7be7542275d1d43fa64ab28ac Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Fri, 7 Apr 2017 23:14:17 +0300 Subject: BD:unify bridge domain creation code Change-Id: I29082e7a0c556069180a157e55b3698cf8cd38c7 Signed-off-by: Eyal Bari --- src/vnet/api_errno.h | 4 +- src/vnet/l2/l2_api.c | 63 +++++++---------------------- src/vnet/l2/l2_bd.c | 92 ++++++++++++++++++++----------------------- src/vnet/l2/l2_bd.h | 37 ++++++++++++----- src/vnet/lisp-gpe/interface.c | 7 ++-- src/vpp/api/api.c | 12 +++--- 6 files changed, 97 insertions(+), 118 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index e939404b..0d5b2227 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -107,7 +107,9 @@ _(ADDRESS_FOUND_FOR_INTERFACE, -114, "Address found for interface") \ _(SESSION_CONNECT_FAIL, -115, "Session failed to connect") \ _(ENTRY_ALREADY_EXISTS, -116, "Entry already exists") \ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ -_(APPLICATION_NOT_ATTACHED, -118, "application not attached") +_(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ +_(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ +_(BD_IN_USE, -120, "Bridge domain has member interfaces") typedef enum { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 026f1706..5a3c8dc2 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -324,54 +324,20 @@ out: static void vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) { - vlib_main_t *vm = vlib_get_main (); - bd_main_t *bdm = &bd_main; - vl_api_bridge_domain_add_del_reply_t *rmp; - int rv = 0; - u32 enable_flags = 0, disable_flags = 0; - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - - if (mp->is_add) - { - bd_index = bd_find_or_add_bd_index (bdm, bd_id); - - if (mp->flood) - enable_flags |= L2_FLOOD; - else - disable_flags |= L2_FLOOD; - - if (mp->uu_flood) - enable_flags |= L2_UU_FLOOD; - else - disable_flags |= L2_UU_FLOOD; - - if (mp->forward) - enable_flags |= L2_FWD; - else - disable_flags |= L2_FWD; - - if (mp->arp_term) - enable_flags |= L2_ARP_TERM; - else - disable_flags |= L2_ARP_TERM; - - if (mp->learn) - enable_flags |= L2_LEARN; - else - disable_flags |= L2_LEARN; - - if (enable_flags) - bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); - - if (disable_flags) - bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); - - bd_set_mac_age (vm, bd_index, mp->mac_age); - } - else - rv = bd_delete_bd_index (bdm, bd_id); + l2_bridge_domain_add_del_args_t a = { + .is_add = mp->is_add, + .flood = mp->flood, + .uu_flood = mp->uu_flood, + .forward = mp->forward, + .learn = mp->learn, + .arp_term = mp->arp_term, + .mac_age = mp->mac_age, + .bd_id = ntohl (mp->bd_id), + }; + + int rv = bd_add_del (&a); + vl_api_bridge_domain_add_del_reply_t *rmp; REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); } @@ -436,7 +402,8 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) bd_id = ntohl (mp->bd_id); - bd_index = (bd_id == ~0) ? 0 : bd_find_or_add_bd_index (bdm, bd_id); + bd_index = (bd_id == ~0) ? 0 : bd_find_index (bdm, bd_id); + ASSERT (bd_index != ~0); end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; for (; bd_index < end; bd_index++) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 9d7a43d3..cfaf4c99 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -50,42 +50,35 @@ bd_main_t bd_main; void bd_validate (l2_bridge_domain_t * bd_config) { - if (!bd_is_valid (bd_config)) - { - bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; - bd_config->bvi_sw_if_index = ~0; - bd_config->members = 0; - bd_config->flood_count = 0; - bd_config->tun_master_count = 0; - bd_config->tun_normal_count = 0; - bd_config->mac_by_ip4 = 0; - bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), - sizeof (uword)); - } + if (bd_is_valid (bd_config)) + return; + bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; + bd_config->bvi_sw_if_index = ~0; + bd_config->members = 0; + bd_config->flood_count = 0; + bd_config->tun_master_count = 0; + bd_config->tun_normal_count = 0; + bd_config->mac_by_ip4 = 0; + bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), + sizeof (uword)); } u32 -bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +bd_find_index (bd_main_t * bdm, u32 bd_id) { - uword *p; - u32 rv; - - if (bd_id == ~0) - { - bd_id = 0; - while (hash_get (bdm->bd_index_by_bd_id, bd_id)) - bd_id++; - } - else - { - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p) - return (p[0]); - } + u32 *p = (u32 *) hash_get (bdm->bd_index_by_bd_id, bd_id); + if (!p) + return ~0; + return p[0]; +} - rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); +u32 +bd_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + ASSERT (!hash_get (bdm->bd_index_by_bd_id, bd_id)); + u32 rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); - /* mark this index busy */ + /* mark this index taken */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1); hash_set (bdm->bd_index_by_bd_id, bd_id, rv); @@ -96,21 +89,14 @@ bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) return rv; } -int -bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) +static int +bd_delete (bd_main_t * bdm, u32 bd_index) { - uword *p; - u32 bd_index; - - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p == 0) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - bd_index = p[0]; + u32 bd_id = l2input_main.bd_configs[bd_index].bd_id; + hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); - hash_unset (bdm->bd_index_by_bd_id, bd_id); l2input_main.bd_configs[bd_index].bd_id = ~0; l2input_main.bd_configs[bd_index].feature_bitmap = 0; @@ -202,14 +188,13 @@ clib_error_t * l2bd_init (vlib_main_t * vm) { bd_main_t *bdm = &bd_main; - u32 bd_index; bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword)); /* * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set * to packet drop only. Thus, packets received from any L2 interface with * uninitialized bd_index of 0 can be dropped safely. */ - bd_index = bd_find_or_add_bd_index (bdm, 0); + u32 bd_index = bd_add_bd_index (bdm, 0); ASSERT (bd_index == 0); l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; @@ -1087,16 +1072,16 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { bd_main_t *bdm = &bd_main; vlib_main_t *vm = bdm->vlib_main; - u32 enable_flags = 0, disable_flags = 0; - u32 bd_index = ~0; int rv = 0; + u32 bd_index = bd_find_index (bdm, a->bd_id); if (a->is_add) { - bd_index = bd_find_or_add_bd_index (bdm, a->bd_id); - if (bd_index == ~0) - return bd_index; + if (bd_index != ~0) + return VNET_API_ERROR_BD_ALREADY_EXISTS; + bd_index = bd_add_bd_index (bdm, a->bd_id); + u32 enable_flags = 0, disable_flags = 0; if (a->flood) enable_flags |= L2_FLOOD; else @@ -1131,7 +1116,13 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) bd_set_mac_age (vm, bd_index, a->mac_age); } else - rv = bd_delete_bd_index (bdm, a->bd_id); + { + if (bd_index == ~0) + return VNET_API_ERROR_NO_SUCH_ENTRY; + if (vec_len (l2input_main.bd_configs[bd_index].members)) + return VNET_API_ERROR_BD_IN_USE; + rv = bd_delete (bdm, bd_index); + } return rv; } @@ -1215,6 +1206,9 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, if (is_add) vlib_cli_output (vm, "bridge-domain %d", bd_id); break; + case VNET_API_ERROR_BD_IN_USE: + error = clib_error_return (0, "bridge domain in use - remove members"); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: error = clib_error_return (0, "bridge domain id does not exist"); goto done; diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 83733411..e502d497 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -128,28 +128,47 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); +int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** - * \brief Get or create a bridge domain. + * \brief Get a bridge domain. + * + * Get a bridge domain with the given bridge domain ID. + * + * \param bdm bd_main pointer. + * \param bd_id The bridge domain ID + * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. + */ +u32 bd_find_index (bd_main_t * bdm, u32 bd_id); + +/** + * \brief Create a bridge domain. * - * Get or create a bridge domain with the given bridge domain ID. + * Create a bridge domain with the given bridge domain ID * * \param bdm bd_main pointer. - * \param bd_id The bridge domain ID or ~0 if an arbitrary unused bridge domain should be used. * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. */ -u32 bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id); +u32 bd_add_bd_index (bd_main_t * bdm, u32 bd_id); /** - * \brief Delete a bridge domain. + * \brief Get or create a bridge domain. * - * Delete an existing bridge domain with the given bridge domain ID. + * Get a bridge domain with the given bridge domain ID, if one exists, otherwise + * create one with the given ID, or the first unused ID if the given ID is ~0.. * * \param bdm bd_main pointer. - * \param bd_id The bridge domain ID. - * \return 0 on success and -1 if the bridge domain does not exist. + * \param bd_id The bridge domain ID + * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. */ -int bd_delete_bd_index (bd_main_t * bdm, u32 bd_id); +static inline u32 +bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + u32 bd_index = bd_find_index (bdm, bd_id); + if (bd_index == ~0) + return bd_add_bd_index (bdm, bd_id); + return bd_index; +} u32 bd_add_del_ip_mac (u32 bd_index, u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add); diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 4760f448..0598c048 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -705,11 +705,10 @@ void lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) { tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces; - u16 bd_index; - uword *hip; - bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); - hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); + u32 bd_index = bd_find_index (&bd_main, bd_id); + ASSERT (bd_index != ~0); + uword *hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); if (hip == 0) { diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 22410fcc..f1b6877f 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -410,21 +410,19 @@ static void bd_main_t *bdm = &bd_main; vl_api_sw_interface_set_l2_bridge_reply_t *rmp; int rv = 0; - u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index); - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 bvi = mp->bvi; - u8 shg = mp->shg; vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); VALIDATE_RX_SW_IF_INDEX (mp); + u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index); - bd_index = bd_find_or_add_bd_index (bdm, bd_id); if (mp->enable) { - //VALIDATE_TX_SW_IF_INDEX(mp); + u32 bd_id = ntohl (mp->bd_id); + u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id); + u32 bvi = mp->bvi; + u8 shg = mp->shg; rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, rx_sw_if_index, bd_index, bvi, shg, 0); } -- cgit 1.2.3-korg From d77630adaf48f05766c33ec60ef19ed50acae161 Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 28 Apr 2017 00:33:36 -0400 Subject: Fix memory leak on deletion of BD (bridge domain) On BD deletion, free memory used by members vector and mac_by_ip4 and mac_by_ip6 hash tables. Change-Id: Ied467e79bb6636fd8788bdeddee660c66391bb7e Signed-off-by: John Lo --- src/vnet/l2/l2_bd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index cfaf4c99..7c55789b 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -92,15 +92,21 @@ bd_add_bd_index (bd_main_t * bdm, u32 bd_id) static int bd_delete (bd_main_t * bdm, u32 bd_index) { - u32 bd_id = l2input_main.bd_configs[bd_index].bd_id; + l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; + u32 bd_id = bd->bd_id; hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); - l2input_main.bd_configs[bd_index].bd_id = ~0; - l2input_main.bd_configs[bd_index].feature_bitmap = 0; + /* clear BD config for reuse: bd_id to -1 and clear feature_bitmap */ + bd->bd_id = ~0; + bd->feature_bitmap = 0; + /* free memory used by BD and flush non-static MACs in BD */ + vec_free (bd->members); + hash_free (bd->mac_by_ip4); + hash_free (bd->mac_by_ip6); l2fib_flush_bd_mac (vlib_get_main (), bd_index); return 0; -- cgit 1.2.3-korg From 1c7d4858369881ac4cc287c4fa16eff2e9890c1c Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Tue, 2 May 2017 11:06:23 -0500 Subject: Prevent Bridge Domain operations on BD 0. The default bridge domain, 0, is created automatically with static features. It should be modified by neither the CLI nor the API. So add tests for, and reject any operation on BD 0. The new API error message BD_NOT_MODIFIABLE is returned in such cases. Change-Id: Iaf3dd80c4f43cf41689ca55756a0a3525420cd12 Signed-off-by: Jon Loeliger --- src/vnet/api_errno.h | 3 ++- src/vnet/l2/l2_api.c | 19 ++++++++++++++++++- src/vnet/l2/l2_bd.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/vpp/api/api.c | 6 ++++++ 4 files changed, 70 insertions(+), 3 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index b87c197f..e694fbf1 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -110,7 +110,8 @@ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ _(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ -_(UNSUPPORTED, -121, "Unsupported") +_(BD_NOT_MODIFIABLE, -121, "Default bridge domain 0 can be neither deleted nor modified") \ +_(UNSUPPORTED, -122, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 5a3c8dc2..8cc7c794 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -310,7 +310,15 @@ vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t vl_api_bridge_domain_set_mac_age_reply_t *rmp; int rv = 0; u32 bd_id = ntohl (mp->bd_id); - uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + uword *p; + + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { rv = VNET_API_ERROR_NO_SUCH_ENTRY; @@ -401,10 +409,13 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) return; bd_id = ntohl (mp->bd_id); + if (bd_id == 0) + return; bd_index = (bd_id == ~0) ? 0 : bd_find_index (bdm, bd_id); ASSERT (bd_index != ~0); end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; + for (; bd_index < end; bd_index++) { bd_config = l2input_bd_config_from_index (l2im, bd_index); @@ -437,6 +448,12 @@ vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) u32 flags = ntohl (mp->feature_bitmap); uword *p; + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 7c55789b..4ebbb547 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -304,6 +304,10 @@ bd_learn (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -369,6 +373,10 @@ bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -436,6 +444,10 @@ bd_flood (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -502,6 +514,10 @@ bd_uu_flood (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -568,6 +584,10 @@ bd_arp_term (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) bd_index = *p; @@ -607,6 +627,10 @@ bd_mac_age (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -780,6 +804,10 @@ bd_arp_entry (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) @@ -900,7 +928,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 bd_id = ~0; uword *p; - start = 0; + start = 1; end = vec_len (l2input_main.bd_configs); if (unformat (input, "%d", &bd_id)) @@ -914,6 +942,10 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) if (unformat (input, "arp")) arp = 1; + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) bd_index = *p; @@ -1125,6 +1157,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { if (bd_index == ~0) return VNET_API_ERROR_NO_SUCH_ENTRY; + if (bd_index == 0) + return VNET_API_ERROR_BD_NOT_MODIFIABLE; if (vec_len (l2input_main.bd_configs[bd_index].members)) return VNET_API_ERROR_BD_IN_USE; rv = bd_delete (bdm, bd_index); @@ -1188,6 +1222,12 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, goto done; } + if (bd_id == 0) + { + error = clib_error_return (0, "bridge domain 0 can not be modified"); + goto done; + } + if (mac_age > 255) { error = clib_error_return (0, "mac age must be less than 256"); @@ -1218,6 +1258,9 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, case VNET_API_ERROR_NO_SUCH_ENTRY: error = clib_error_return (0, "bridge domain id does not exist"); goto done; + case VNET_API_ERROR_BD_NOT_MODIFIABLE: + error = clib_error_return (0, "bridge domain 0 can not be modified"); + goto done; default: error = clib_error_return (0, "bd_add_del returned %d", rv); goto done; diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 9c230574..baf45d5c 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -446,6 +446,12 @@ vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp) u32 bd_index; uword *p; + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { -- cgit 1.2.3-korg From afc47aa36f44d3f865c6e1e48f41eded366a85ac Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Thu, 20 Apr 2017 14:45:17 +0300 Subject: L2FIB:flush interface learned macs on down Change-Id: I80a723f55fcf2ecc3209a35e8297c88b45b1abfb Signed-off-by: Eyal Bari --- src/vnet/l2/l2_bd.c | 15 ++++++--------- src/vnet/l2/l2_fib.c | 13 +++++++++++-- src/vnet/l2/l2_input.c | 42 ++++++++++++++---------------------------- src/vnet/l2/l2_input.h | 11 +++++++++++ 4 files changed, 42 insertions(+), 39 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 4ebbb547..4d540220 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -94,6 +94,8 @@ bd_delete (bd_main_t * bdm, u32 bd_index) { l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; u32 bd_id = bd->bd_id; + l2fib_flush_bd_mac (vlib_get_main (), bd_index); + hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ @@ -107,7 +109,6 @@ bd_delete (bd_main_t * bdm, u32 bd_index) vec_free (bd->members); hash_free (bd->mac_by_ip4); hash_free (bd->mac_by_ip6); - l2fib_flush_bd_mac (vlib_get_main (), bd_index); return 0; } @@ -219,13 +220,9 @@ u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) { - l2_bridge_domain_t *bd_config; - u32 feature_bitmap = 0; - - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); - + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); bd_validate (bd_config); + u32 feature_bitmap = 0; if (flags & L2_LEARN) { @@ -713,13 +710,13 @@ u32 bd_add_del_ip_mac (u32 bd_index, u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add) { - l2input_main_t *l2im = &l2input_main; - l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index); + l2_bridge_domain_t *bd_cfg = l2input_bd_config (bd_index); u64 new_mac = *(u64 *) mac_addr; u64 *old_mac; u16 *mac16 = (u16 *) & new_mac; ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */ + ASSERT (bd_is_valid (bd_cfg)); mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */ if (is_ip6) diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index fadd79eb..d8fcc319 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -751,8 +751,7 @@ void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index) { l2_bridge_domain_t *bd_config; - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config = l2input_bd_config (bd_index); bd_config->seq_num += 1; l2fib_start_ager_scan (vm); } @@ -848,6 +847,16 @@ VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = { }; /* *INDENT-ON* */ +clib_error_t * +l2fib_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) +{ + l2_input_config_t *config = l2input_intf_config (sw_if_index); + if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0 && config->bridge) + l2fib_flush_int_mac (vnm->vlib_main, sw_if_index); + return 0; +} + +VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2fib_sw_interface_up_down); BVT (clib_bihash) * get_mac_table (void) { diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index e5d6878a..fe65e694 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -481,20 +481,12 @@ l2input_intf_config (u32 sw_if_index) u32 l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) { - l2input_main_t *mp = &l2input_main; - l2_input_config_t *config; - - vec_validate (mp->configs, sw_if_index); - config = vec_elt_at_index (mp->configs, sw_if_index); + l2_input_config_t *config = l2input_intf_config (sw_if_index); if (enable) - { - config->feature_bitmap |= feature_bitmap; - } + config->feature_bitmap |= feature_bitmap; else - { - config->feature_bitmap &= ~feature_bitmap; - } + config->feature_bitmap &= ~feature_bitmap; return config->feature_bitmap; } @@ -502,9 +494,7 @@ l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) u32 l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value) { - l2_bridge_domain_t *bd_config; - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);; bd_validate (bd_config); bd_config->feature_bitmap = (bd_config->feature_bitmap & ~feat_mask) | feat_value; @@ -535,7 +525,6 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ l2_output_config_t *out_config; l2_input_config_t *config; l2_bridge_domain_t *bd_config; - l2_flood_member_t member; u64 mac; i32 l2_if_adjust = 0; u32 slot; @@ -570,8 +559,8 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ } /* Clear MACs learned on the interface */ - if ((config->feature_bitmap | L2INPUT_FEAT_LEARN) || - (bd_config->feature_bitmap | L2INPUT_FEAT_LEARN)) + if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) || + (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN)) l2fib_flush_int_mac (vm, sw_if_index); l2_if_adjust--; @@ -661,8 +650,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT; /* Set up bridge domain */ - vec_validate (mp->bd_configs, bd_index); - bd_config = vec_elt_at_index (mp->bd_configs, bd_index); + bd_config = l2input_bd_config (bd_index); bd_validate (bd_config); /* TODO: think: add l2fib entry even for non-bvi interface? */ @@ -694,9 +682,11 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ } /* Add interface to bridge-domain flood vector */ - member.sw_if_index = sw_if_index; - member.flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL; - member.shg = shg; + l2_flood_member_t member = { + .sw_if_index = sw_if_index, + .flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL, + .shg = shg, + }; bd_add_member (bd_config, &member); } @@ -997,10 +987,8 @@ show_int_mode (vlib_main_t * vm, char *mode; u8 *args; vnet_interface_main_t *im = &vnm->interface_main; - vnet_sw_interface_t *si, *sis = 0; - l2input_main_t *mp = &l2input_main; - l2_input_config_t *config; + vnet_sw_interface_t *si, *sis = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { u32 sw_if_index; @@ -1018,7 +1006,6 @@ show_int_mode (vlib_main_t * vm, format_unformat_error, input); goto done; } - } if (vec_len (sis) == 0) /* Get all interfaces */ @@ -1033,8 +1020,7 @@ show_int_mode (vlib_main_t * vm, vec_foreach (si, sis) { - vec_validate (mp->configs, si->sw_if_index); - config = vec_elt_at_index (mp->configs, si->sw_if_index); + l2_input_config_t *config = l2input_intf_config (si->sw_if_index); if (config->bridge) { u32 bd_id; diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index a2ade8d8..cb67cb9d 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -89,6 +89,17 @@ l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index) return bd_is_valid (bd_config) ? bd_config : NULL; } +static_always_inline l2_bridge_domain_t * +l2input_bd_config (u32 bd_index) +{ + l2input_main_t *mp = &l2input_main; + l2_bridge_domain_t *bd_config; + + vec_validate (mp->bd_configs, bd_index); + bd_config = vec_elt_at_index (mp->bd_configs, bd_index); + return bd_config; +} + /* L2 input indication packet is from BVI, using -2 */ #define L2INPUT_BVI ((u32) (~0-1)) -- cgit 1.2.3-korg From d48c8eb7354c6c8b5b875dc70d616d11c17e9fb8 Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 5 May 2017 12:35:25 -0400 Subject: Fix L2FIB learn counter and memory cleanup of mac_by_ip6 hash table Fix global_learn_count to be incremented or decremented by add and deletion of non-static MAC entries from L2FIB only. Without this fix, the counter may reach the threshold of 1M and stop MAC leanring even though number of MAC entries in L2FIB is less than the threshold. Cleanup indirect hash key memory used by mac_by_ip6 hash table on BD deletion. Change-Id: I13986c4e6304c7956122520dd3f83d6bb6e65a15 Signed-off-by: John Lo --- src/vnet/l2/l2_bd.c | 13 +++++++++++-- src/vnet/l2/l2_fib.c | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 4d540220..351e6987 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -94,8 +94,11 @@ bd_delete (bd_main_t * bdm, u32 bd_index) { l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; u32 bd_id = bd->bd_id; - l2fib_flush_bd_mac (vlib_get_main (), bd_index); + u64 mac_addr; + ip6_address_t *ip6_addr_key; + /* flush non-static MACs in BD and removed bd_id from hash table */ + l2fib_flush_bd_mac (vlib_get_main (), bd_index); hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ @@ -105,9 +108,15 @@ bd_delete (bd_main_t * bdm, u32 bd_index) bd->bd_id = ~0; bd->feature_bitmap = 0; - /* free memory used by BD and flush non-static MACs in BD */ + /* free memory used by BD */ vec_free (bd->members); hash_free (bd->mac_by_ip4); + /* *INDENT-OFF* */ + hash_foreach_mem (ip6_addr_key, mac_addr, bd->mac_by_ip6, + ({ + clib_mem_free (ip6_addr_key); /* free memory used for ip6 addr key */ + })); + /* *INDENT-ON* */ hash_free (bd->mac_by_ip6); return 0; diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index d8fcc319..028a7326 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -215,7 +215,9 @@ show_l2fib (vlib_main_t * vm, if (total_entries == 0) vlib_cli_output (vm, "no l2fib entries"); else - vlib_cli_output (vm, "%lld l2fib entries", total_entries); + vlib_cli_output (vm, + "%lld l2fib entries with %d learned (or non-static) entries", + total_entries, l2learn_main.global_learn_count); if (raw) vlib_cli_output (vm, "Raw Hash Table:\n%U\n", @@ -347,7 +349,7 @@ l2fib_add_entry (u64 mac, BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ ); /* increment counter if dynamically learned mac */ - if (result.fields.static_mac) + if (result.fields.static_mac == 0) { l2learn_main.global_learn_count++; } @@ -635,7 +637,7 @@ l2fib_del_entry (u64 mac, u32 bd_index) result.raw = kv.value; /* decrement counter if dynamically learned mac */ - if (result.fields.static_mac) + if (result.fields.static_mac == 0) { if (l2learn_main.global_learn_count > 0) { -- cgit 1.2.3-korg From 9793477a28c45e4eb5bba3f2050fe415e57e8ad8 Mon Sep 17 00:00:00 2001 From: John Lo Date: Thu, 18 May 2017 22:26:47 -0400 Subject: Enforce Bridge Domain ID range to match 24-bit VNI range Enforce bridge domain ID range to allow a maximum value of 16M which matches the range of 24-bit VNI used for virtual overlay network ID. Fix "show bridge-domain" output to allow full 16M BD ID range to be displayed using 8-digit spaces. Change-Id: I80d9c76ea7c001bcccd3c19df1f3e55d2970f01c Signed-off-by: John Lo --- src/vlibapi/api_helper_macros.h | 14 ++++++++++++++ src/vnet/api_errno.h | 5 +++-- src/vnet/l2/l2_bd.c | 17 +++++++++++------ src/vnet/l2/l2_bd.h | 4 +++- src/vnet/l2/l2_input.c | 6 ++++++ src/vnet/lisp-gpe/interface.c | 6 ++++++ src/vpp/api/api.c | 2 ++ 7 files changed, 45 insertions(+), 9 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h index a492c3f4..2e29d4d7 100644 --- a/src/vlibapi/api_helper_macros.h +++ b/src/vlibapi/api_helper_macros.h @@ -155,6 +155,20 @@ bad_tx_sw_if_index: \ ; \ } while (0); +#define VALIDATE_BD_ID(mp) \ + do { u32 __rx_bd_id = ntohl(mp->bd_id); \ + if (__rx_bd_id > L2_BD_ID_MAX) { \ + rv = VNET_API_ERROR_BD_ID_EXCEED_MAX; \ + goto bad_bd_id; \ + } \ +} while(0); + +#define BAD_BD_ID_LABEL \ +do { \ +bad_bd_id: \ + ; \ +} while (0); + #define pub_sub_handler(lca,UCA) \ static void vl_api_want_##lca##_t_handler ( \ vl_api_want_##lca##_t *mp) \ diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index e694fbf1..b22bb3a8 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -110,8 +110,9 @@ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ _(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ -_(BD_NOT_MODIFIABLE, -121, "Default bridge domain 0 can be neither deleted nor modified") \ -_(UNSUPPORTED, -122, "Unsupported") +_(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \ +_(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \ +_(UNSUPPORTED, -123, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 351e6987..f68b6638 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -984,10 +984,10 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { printed = 1; vlib_cli_output (vm, - "%=5s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", - "ID", "Index", "BSN", "Age(min)", "Learning", - "U-Forwrd", "UU-Flood", "Flooding", "ARP-Term", - "BVI-Intf"); + "%=8s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", + "BD-ID", "Index", "BSN", "Age(min)", + "Learning", "U-Forwrd", "UU-Flood", "Flooding", + "ARP-Term", "BVI-Intf"); } if (bd_config->mac_age) @@ -995,7 +995,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) else as = format (as, "off"); vlib_cli_output (vm, - "%=5d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", + "%=8d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", bd_config->bd_id, bd_index, bd_config->seq_num, as, bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? "on" : "off", @@ -1123,6 +1123,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { if (bd_index != ~0) return VNET_API_ERROR_BD_ALREADY_EXISTS; + if (a->bd_id > L2_BD_ID_MAX) + return VNET_API_ERROR_BD_ID_EXCEED_MAX; bd_index = bd_add_bd_index (bdm, a->bd_id); u32 enable_flags = 0, disable_flags = 0; @@ -1262,11 +1264,14 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, error = clib_error_return (0, "bridge domain in use - remove members"); goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "bridge domain id does not exist"); + error = clib_error_return (0, "bridge domain ID does not exist"); goto done; case VNET_API_ERROR_BD_NOT_MODIFIABLE: error = clib_error_return (0, "bridge domain 0 can not be modified"); goto done; + case VNET_API_ERROR_BD_ID_EXCEED_MAX: + error = clib_error_return (0, "bridge domain ID exceed 16M limit"); + goto done; default: error = clib_error_return (0, "bd_add_del returned %d", rv); goto done; diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index e502d497..93ed1a85 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -49,7 +49,6 @@ typedef struct u16 spare; } l2_flood_member_t; - /* Per-bridge domain configuration */ typedef struct @@ -91,6 +90,9 @@ typedef struct } l2_bridge_domain_t; +/* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */ +#define L2_BD_ID_MAX ((1<<24)-1) + typedef struct { u32 bd_id; diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 41a93f56..aca23fe0 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -791,6 +791,12 @@ int_l2_bridge (vlib_main_t * vm, goto done; } + if (bd_id > L2_BD_ID_MAX) + { + error = clib_error_return (0, "bridge domain ID exceed 16M limit", + format_unformat_error, input); + goto done; + } bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); /* optional bvi */ diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index ff750563..94703abc 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -653,6 +653,12 @@ lisp_gpe_add_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) uword *hip, *si; u16 bd_index; + if (bd_id > L2_BD_ID_MAX) + { + clib_warning ("bridge domain ID %d exceed 16M limit", bd_id); + return ~0; + } + bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 16d51225..7e4c341e 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -419,6 +419,7 @@ static void if (mp->enable) { + VALIDATE_BD_ID (mp); u32 bd_id = ntohl (mp->bd_id); u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id); u32 bvi = mp->bvi; @@ -432,6 +433,7 @@ static void } BAD_RX_SW_IF_INDEX_LABEL; + BAD_BD_ID_LABEL; REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY); } -- cgit 1.2.3-korg From 0f360dc3aa40d0654198bd3f3850bd31a0d78f7e Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 14 Jun 2017 13:11:20 +0300 Subject: L2FWD:fix seq_num overwritten + validate l2fib entries when forwarding l2_classify memeber table_index was overlaid over l2.l2fib_seq_num which over written when table_index gets initialized in l2_input_classify solved by overlaying both table_index and opaque_index as only one is used seperated l2fib seq num from l2_input configs for better handling of theoretical ABA issue where an entry for a deleted interface is considered valid by the ager because a different interface with same sw_if_index and seq_num was created before the ager got a chance to delete Change-Id: I7b0eeded971627406f1c80834d7e02c0ebe62136 Signed-off-by: Eyal Bari --- src/vnet/buffer.h | 15 ++++++++--- src/vnet/l2/l2_bd.c | 5 ++-- src/vnet/l2/l2_fib.c | 19 +++---------- src/vnet/l2/l2_fib.h | 24 +++++++++++++++++ src/vnet/l2/l2_fwd.c | 72 +++++++++++++++++++++++++++++++++----------------- src/vnet/l2/l2_input.c | 4 +-- src/vnet/l2/l2_input.h | 3 --- src/vnet/l2/l2_learn.c | 13 +++++---- test/test_l2_fib.py | 3 --- 9 files changed, 99 insertions(+), 59 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index ec5e2f75..795bbd96 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -195,9 +195,13 @@ typedef struct /* L2 classify */ struct { - u64 pad; - u32 table_index; - u32 opaque_index; + u64 pad; /* paddind for l2 */ + u16 pad1; + union + { + u32 table_index; + u32 opaque_index; + }; u64 hash; } l2_classify; @@ -296,6 +300,11 @@ typedef struct STATIC_ASSERT (sizeof (vnet_buffer_opaque_t) <= STRUCT_SIZE_OF (vlib_buffer_t, opaque), "VNET buffer meta-data too large for vlib_buffer"); +STATIC_ASSERT (STRUCT_OFFSET_OF + (vnet_buffer_opaque_t, + l2_classify.table_index) >= + STRUCT_SIZE_OF (vnet_buffer_opaque_t, l2), + "l2_classify padding smaller than l2"); #define vnet_buffer(b) ((vnet_buffer_opaque_t *) (b)->opaque) diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index f68b6638..a87d02f2 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -1019,8 +1019,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { l2_flood_member_t *member = vec_elt_at_index (bd_config->members, i); - l2_input_config_t *int_config = - l2input_intf_config (member->sw_if_index); + u8 swif_seq_num = *l2fib_swif_seq_num (member->sw_if_index); u32 vtr_opr, dot1q, tag1, tag2; if (i == 0) { @@ -1033,7 +1032,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U", format_vnet_sw_if_index_name, vnm, member->sw_if_index, member->sw_if_index, - int_config->seq_num, member->shg, + swif_seq_num, member->shg, member->flags & L2_FLOOD_MEMBER_BVI ? "*" : "-", i < bd_config->flood_count ? "*" : "-", format_vtr, vtr_opr, dot1q, tag1, tag2); diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index f17eee2a..2bb6d105 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -41,17 +41,6 @@ * */ -typedef struct -{ - - /* hash table */ - BVT (clib_bihash) mac_table; - - /* convenience variables */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} l2fib_main_t; - l2fib_main_t l2fib_main; /** Format sw_if_index. If the value is ~0, use the text "N/A" */ @@ -65,7 +54,7 @@ format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args) vnet_sw_interface_t *swif = vnet_get_sw_interface_safe (vnm, sw_if_index); if (!swif) - return format (s, "Deleted"); + return format (s, "Stale"); return format (s, "%U", format_vnet_sw_interface_name, vnm, vnet_get_sw_interface_safe (vnm, sw_if_index)); @@ -305,11 +294,10 @@ VLIB_CLI_COMMAND (clear_l2fib_cli, static) = { static inline l2fib_seq_num_t l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index) { - l2_input_config_t *int_config = l2input_intf_config (sw_if_index); l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); /* *INDENT-OFF* */ return (l2fib_seq_num_t) { - .swif = int_config->seq_num, + .swif = *l2fib_swif_seq_num (sw_if_index), .bd = bd_config->seq_num, }; /* *INDENT-ON* */ @@ -748,8 +736,7 @@ l2fib_start_ager_scan (vlib_main_t * vm) void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index) { - l2_input_config_t *int_config = l2input_intf_config (sw_if_index); - int_config->seq_num += 1; + *l2fib_swif_seq_num (sw_if_index) += 1; l2fib_start_ager_scan (vm); } diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index e571a210..03184502 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -27,6 +27,22 @@ #define L2FIB_NUM_BUCKETS (64 * 1024) #define L2FIB_MEMORY_SIZE (256<<20) +typedef struct +{ + + /* hash table */ + BVT (clib_bihash) mac_table; + + /* per swif vector of sequence number for interface based flush of MACs */ + u8 *swif_seq_num; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2fib_main_t; + +extern l2fib_main_t l2fib_main; + /* * The L2fib key is the mac address and bridge domain ID */ @@ -350,6 +366,14 @@ l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); +static_always_inline u8 * +l2fib_swif_seq_num (u32 sw_if_index) +{ + l2fib_main_t *mp = &l2fib_main; + vec_validate (mp->swif_seq_num, sw_if_index); + return vec_elt_at_index (mp->swif_seq_num, sw_if_index); +} + BVT (clib_bihash) * get_mac_table (void); #endif diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c index f7e2ccb6..8140728b 100644 --- a/src/vnet/l2/l2_fwd.c +++ b/src/vnet/l2/l2_fwd.c @@ -89,7 +89,8 @@ _(HIT, "L2 forward hits") \ _(BVI_BAD_MAC, "BVI L3 MAC mismatch") \ _(BVI_ETHERTYPE, "BVI packet with unhandled ethertype") \ _(FILTER_DROP, "Filter Mac Drop") \ -_(REFLECT_DROP, "Reflection Drop") +_(REFLECT_DROP, "Reflection Drop") \ +_(STALE_DROP, "Stale entry Drop") typedef enum { @@ -123,28 +124,15 @@ l2fwd_process (vlib_main_t * vm, vlib_buffer_t * b0, u32 sw_if_index0, l2fib_entry_result_t * result0, u32 * next0) { - if (PREDICT_FALSE (result0->raw == ~0)) - { - /* - * lookup miss, so flood - * TODO:replicate packet to each intf in bridge-domain - * For now just drop - */ - if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD) - { - *next0 = L2FWD_NEXT_FLOOD; - } - else - { - /* Flooding is disabled */ - b0->error = node->errors[L2FWD_ERROR_FLOOD]; - *next0 = L2FWD_NEXT_DROP; - } + int try_flood = result0->raw == ~0; + int flood_error; + if (PREDICT_FALSE (try_flood)) + { + flood_error = L2FWD_ERROR_FLOOD; } else { - /* lookup hit, forward packet */ #ifdef COUNTERS em->counters[node_counter_base_index + L2FWD_ERROR_HIT] += 1; @@ -152,22 +140,37 @@ l2fwd_process (vlib_main_t * vm, vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index; *next0 = L2FWD_NEXT_L2_OUTPUT; + int l2fib_seq_num_valid = 1; + /* check l2fib seq num for stale entries */ + if (!result0->fields.static_mac) + { + l2fib_seq_num_t in_sn = {.as_u16 = vnet_buffer (b0)->l2.l2fib_sn }; + l2fib_seq_num_t expected_sn = { + .bd = in_sn.bd, + .swif = *l2fib_swif_seq_num (result0->fields.sw_if_index), + }; + l2fib_seq_num_valid = + expected_sn.as_u16 == result0->fields.sn.as_u16; + } + if (PREDICT_FALSE (!l2fib_seq_num_valid)) + { + flood_error = L2FWD_ERROR_STALE_DROP; + try_flood = 1; + } /* perform reflection check */ - if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index)) + else if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index)) { b0->error = node->errors[L2FWD_ERROR_REFLECT_DROP]; *next0 = L2FWD_NEXT_DROP; - - /* perform filter check */ } + /* perform filter check */ else if (PREDICT_FALSE (result0->fields.filter)) { b0->error = node->errors[L2FWD_ERROR_FILTER_DROP]; *next0 = L2FWD_NEXT_DROP; - - /* perform BVI check */ } + /* perform BVI check */ else if (PREDICT_FALSE (result0->fields.bvi)) { u32 rc; @@ -192,6 +195,27 @@ l2fwd_process (vlib_main_t * vm, } } } + + /* flood */ + if (PREDICT_FALSE (try_flood)) + { + /* + * lookup miss, so flood + * TODO:replicate packet to each intf in bridge-domain + * For now just drop + */ + if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD) + { + *next0 = L2FWD_NEXT_FLOOD; + } + else + { + /* Flooding is disabled */ + b0->error = node->errors[flood_error]; + *next0 = L2FWD_NEXT_DROP; + } + } + } diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index aca23fe0..22fc2a98 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -205,7 +205,7 @@ classify_and_dispatch (vlib_main_t * vm, /* Save bridge domain and interface seq_num */ /* *INDENT-OFF* */ l2fib_seq_num_t sn = { - .swif = config->seq_num, + .swif = *l2fib_swif_seq_num(sw_if_index0), .bd = bd_config->seq_num, }; /* *INDENT-ON* */ @@ -637,7 +637,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->xconnect = 0; config->bridge = 1; config->bd_index = bd_index; - config->seq_num += 1; + *l2fib_swif_seq_num (sw_if_index) += 1; /* * Enable forwarding, flooding, learning and ARP termination by default diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index cb67cb9d..c1b669b4 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -53,9 +53,6 @@ typedef struct /* split horizon group */ u8 shg; - /* sequence number for interface based flush of MACs */ - u8 seq_num; - } l2_input_config_t; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index adc5e70f..3ff2e704 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -138,11 +138,14 @@ l2learn_process (vlib_node_runtime_t * node, * The entry was in the table, and the sw_if_index matched, the normal case */ counter_base[L2LEARN_ERROR_HIT] += 1; - if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) - result0->fields.timestamp = timestamp; - if (PREDICT_FALSE - (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) - result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; + if (!result0->fields.static_mac) + { + if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) + result0->fields.timestamp = timestamp; + if (PREDICT_FALSE + (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; + } } else if (result0->raw == ~0) { diff --git a/test/test_l2_fib.py b/test/test_l2_fib.py index f9a78efc..9249a2ce 100644 --- a/test/test_l2_fib.py +++ b/test/test_l2_fib.py @@ -490,7 +490,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_int(self.pg_interfaces[0].sw_if_index) - self.sleep(1) self.run_verify_test(bd_id=1, dst_hosts=self.learned_hosts) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) @@ -504,7 +503,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_bd(bd_id=1) - self.sleep(1) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_test(bd_id=2, dst_hosts=self.learned_hosts) @@ -518,7 +516,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_all() - self.sleep(2) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_negat_test(bd_id=2, dst_hosts=flushed) -- cgit 1.2.3-korg From 8d00fff8dff4e449767601645422e03df92a83af Mon Sep 17 00:00:00 2001 From: John Lo Date: Thu, 3 Aug 2017 00:35:36 -0400 Subject: Add support for API client to receive L2 MAC events Added APIs want_l2_macs_events and l2_macs_event to allow an API client to receive notification events from VPP for MAC learned or aged in L2FIB. Only one API client is allowed for L2 MAC events. The want_l2_macs_events API allow caller to specify MAC learn limit, event scan delay and max number of MACs that can be included in a event message. These parameters should be choosen properly as to not have too many MAC events sent by VPP and overwhelm the API share memory. They can all be left as 0's so VPP will setup reasonable defaults which are: 1000 learn limit, 100 msec scan delay and 100 MACs per event message. If want_l2_macs_events is never called, VPP learning and aging should behave as before except that MAC entries provisioned by API or CLI will not be aged, even if it is not set as static_mac. These non static MACs, however, can be overwritten by MAC learning on a MAC move as a leared MAC. Only learned MACs are subject to aging. Change-Id: Ia3757a80cf8adb2811a089d2eafbd6439461285c Signed-off-by: John Lo --- src/vat/api_format.c | 86 +++++++++- src/vnet/api_errno.h | 5 +- src/vnet/l2/l2.api | 65 +++++++- src/vnet/l2/l2_api.c | 83 +++++++++- src/vnet/l2/l2_bd.c | 37 +---- src/vnet/l2/l2_fib.c | 394 ++++++++++++++++++++++++++++++++++------------ src/vnet/l2/l2_fib.h | 37 ++++- src/vnet/l2/l2_fwd.c | 3 +- src/vnet/l2/l2_learn.c | 30 ++-- src/vnet/l2/l2_learn.h | 5 + src/vpp/api/custom_dump.c | 33 +++- 11 files changed, 605 insertions(+), 173 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index bbd97ba1..27286686 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1283,6 +1283,30 @@ vl_api_ip6_nd_event_t_handler_json (vl_api_ip6_nd_event_t * mp) /* JSON output not supported */ } +static void +vl_api_l2_macs_event_t_handler (vl_api_l2_macs_event_t * mp) +{ + u32 n_macs = ntohl (mp->n_macs); + errmsg ("L2MAC event recived with pid %d cl-idx %d for %d macs: \n", + ntohl (mp->pid), mp->client_index, n_macs); + int i; + for (i = 0; i < n_macs; i++) + { + vl_api_mac_entry_t *mac = &mp->mac[i]; + errmsg (" [%d] sw_if_index %d mac_addr %U is_del %d \n", + i + 1, ntohl (mac->sw_if_index), + format_ethernet_address, mac->mac_addr, mac->is_del); + if (i == 1000) + break; + } +} + +static void +vl_api_l2_macs_event_t_handler_json (vl_api_l2_macs_event_t * mp) +{ + /* JSON output not supported */ +} + #define vl_api_bridge_domain_details_t_endian vl_noop_handler #define vl_api_bridge_domain_details_t_print vl_noop_handler @@ -4597,6 +4621,7 @@ _(modify_vhost_user_if_reply) \ _(delete_vhost_user_if_reply) \ _(want_ip4_arp_events_reply) \ _(want_ip6_nd_events_reply) \ +_(want_l2_macs_events_reply) \ _(input_acl_set_interface_reply) \ _(ipsec_spd_add_del_reply) \ _(ipsec_interface_add_del_spd_reply) \ @@ -4813,6 +4838,8 @@ _(WANT_IP4_ARP_EVENTS_REPLY, want_ip4_arp_events_reply) \ _(IP4_ARP_EVENT, ip4_arp_event) \ _(WANT_IP6_ND_EVENTS_REPLY, want_ip6_nd_events_reply) \ _(IP6_ND_EVENT, ip6_nd_event) \ +_(WANT_L2_MACS_EVENTS_REPLY, want_l2_macs_events_reply) \ +_(L2_MACS_EVENT, l2_macs_event) \ _(INPUT_ACL_SET_INTERFACE_REPLY, input_acl_set_interface_reply) \ _(IP_ADDRESS_DETAILS, ip_address_details) \ _(IP_DETAILS, ip_details) \ @@ -6607,8 +6634,9 @@ api_l2_flags (vat_main_t * vam) unformat_input_t *i = vam->input; vl_api_l2_flags_t *mp; u32 sw_if_index; - u32 feature_bitmap = 0; + u32 flags = 0; u8 sw_if_index_set = 0; + u8 is_set = 0; int ret; /* Parse args required to build the message */ @@ -6628,13 +6656,19 @@ api_l2_flags (vat_main_t * vam) break; } else if (unformat (i, "learn")) - feature_bitmap |= L2INPUT_FEAT_LEARN; + flags |= L2_LEARN; else if (unformat (i, "forward")) - feature_bitmap |= L2INPUT_FEAT_FWD; + flags |= L2_FWD; else if (unformat (i, "flood")) - feature_bitmap |= L2INPUT_FEAT_FLOOD; + flags |= L2_FLOOD; else if (unformat (i, "uu-flood")) - feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + flags |= L2_UU_FLOOD; + else if (unformat (i, "arp-term")) + flags |= L2_ARP_TERM; + else if (unformat (i, "off")) + is_set = 0; + else if (unformat (i, "disable")) + is_set = 0; else break; } @@ -6648,7 +6682,8 @@ api_l2_flags (vat_main_t * vam) M (L2_FLAGS, mp); mp->sw_if_index = ntohl (sw_if_index); - mp->feature_bitmap = ntohl (feature_bitmap); + mp->feature_bitmap = ntohl (flags); + mp->is_set = is_set; S (mp); W (ret); @@ -12534,6 +12569,42 @@ api_want_ip6_nd_events (vat_main_t * vam) return ret; } +static int +api_want_l2_macs_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_l2_macs_events_t *mp; + u8 enable_disable = 1; + u32 scan_delay = 0; + u32 max_macs_in_event = 0; + u32 learn_limit = 0; + int ret; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "learn-limit %d", &learn_limit)) + ; + else if (unformat (line_input, "scan-delay %d", &scan_delay)) + ; + else if (unformat (line_input, "max-entries %d", &max_macs_in_event)) + ; + else if (unformat (line_input, "disable")) + enable_disable = 0; + else + break; + } + + M (WANT_L2_MACS_EVENTS, mp); + mp->enable_disable = enable_disable; + mp->pid = htonl (getpid ()); + mp->learn_limit = htonl (learn_limit); + mp->scan_delay = (u8) scan_delay; + mp->max_macs_in_event = (u8) (max_macs_in_event / 10); + S (mp); + W (ret); + return ret; +} + static int api_input_acl_set_interface (vat_main_t * vam) { @@ -19831,7 +19902,7 @@ _(l2fib_add_del, \ _(l2fib_flush_bd, "bd_id ") \ _(l2fib_flush_int, " | sw_if_index ") \ _(l2_flags, \ - "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood]\n") \ + "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ _(bridge_flags, \ "bd_id [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ _(tap_connect, \ @@ -19974,6 +20045,7 @@ _(input_acl_set_interface, \ " [l2-table ] [del]") \ _(want_ip4_arp_events, "address [del]") \ _(want_ip6_nd_events, "address [del]") \ +_(want_l2_macs_events, "[disable] [learn-limit ] [scan-delay ] [max-entries ]") \ _(ip_address_dump, "(ipv4 | ipv6) ( | sw_if_index )") \ _(ip_dump, "ipv4 | ipv6") \ _(ipsec_spd_add_del, "spd_id [del]") \ diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 747c65e7..22522f34 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -112,8 +112,9 @@ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ _(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \ _(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \ -_(UNSUPPORTED, -123, "Unsupported") \ -_(SUBIF_DOESNT_EXIST, -124, "Subinterface doesn't exist") +_(SUBIF_DOESNT_EXIST, -123, "Subinterface doesn't exist") \ +_(L2_MACS_EVENT_CLINET_PRESENT, -124, "Client already exist for L2 MACs events") \ +_(UNSUPPORTED, -125, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index bb3990c6..e508bfb5 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -133,12 +133,64 @@ autoreply define l2fib_add_del u8 bvi_mac; }; -/** \brief Set L2 flags request !!! TODO - need more info, feature bits in l2_input.h +/** \brief Register to recive L2 MAC events for leanred and aged MAC + Will also change MAC learn limit to L2LEARN_INFORM_LIMIT + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param learn_limit - MAC learn limit, 0 => default to 1000 + @param scan_delay - event scan delay in 10 msec unit, 0 => default to 100 msec + @param max_macs_in_event - in units of 10 mac entries, 0 => default to 100 entries + @param enable_disable - 1 => register for MAC events, 0 => cancel registration + @param pid - sender's pid +*/ +autoreply define want_l2_macs_events +{ + u32 client_index; + u32 context; + u32 learn_limit; + u8 scan_delay; + u8 max_macs_in_event; + u8 enable_disable; + u32 pid; +}; + +/** \brief Entry for learned or aged MAC in L2 MAC Events + @param sw_if_index - sw_if_index in the domain + @param mac_addr - mac_address + @is_del - 0 => newly learned MAC, 1 => aged out MAC +*/ +typeonly define mac_entry +{ + u32 sw_if_index; + u8 mac_addr[6]; + u8 is_del; + u8 spare; +}; + +/** \brief L2 MAC event for a list of learned or aged MACs + @param client_index - opaque cookie to identify the sender + @param pid - client pid registered to receive notification + @param n_macs - number of learned/aged MAC enntries + @param mac - array of learned/aged MAC entries +*/ +define l2_macs_event +{ + u32 client_index; + u32 pid; + u32 n_macs; + vl_api_mac_entry_t mac[n_macs]; +}; + +/** \brief Set interface L2 flags (such as L2_LEARN, L2_FWD, + L2_FLOOD, L2_UU_FLOOD, or L2_ARP_TERM bits). This can be used + to disable one or more of the features represented by the + flag bits on an interface to override what is set as default + for all interfaces in the bridge domain @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - interface @param is_set - if non-zero, set the bits, else clear them - @param feature_bitmap - non-zero bits to set or clear + @param feature_bitmap - non-zero bits (as above) to set or clear */ define l2_flags { @@ -149,9 +201,10 @@ define l2_flags u32 feature_bitmap; }; -/** \brief Set L2 bits response +/** \brief Set interface L2 flags response @param context - sender context, to match reply w/ request @param retval - return code for the set l2 bits request + @param resulting_feature_bitmap - the internal l2 feature bitmap after the request is implemented */ define l2_flags_reply { @@ -250,12 +303,12 @@ manual_print manual_endian define bridge_domain_details }; /** \brief Set bridge flags (such as L2_LEARN, L2_FWD, L2_FLOOD, - L2_UU_FLOOD, or L2_ARP_TERM) request + L2_UU_FLOOD, or L2_ARP_TERM bits) request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bd_id - the bridge domain to set the flags for @param is_set - if non-zero, set the flags, else clear them - @param feature_bitmap - bits that are non-zero to set or clear + @param feature_bitmap - bits (as above) that are non-zero to set or clear */ define bridge_flags { @@ -269,7 +322,7 @@ define bridge_flags /** \brief Set bridge flags response @param context - sender context, to match reply w/ request @param retval - return code for the set bridge flags request - @param resulting_feature_bitmap - the feature bitmap value after the request is implemented + @param resulting_feature_bitmap - the internal L2 feature bitmap after the request is implemented */ define bridge_flags_reply { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a0b40d6d..c81cbad7 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -55,6 +56,7 @@ _(L2FIB_FLUSH_ALL, l2fib_flush_all) \ _(L2FIB_FLUSH_INT, l2fib_flush_int) \ _(L2FIB_FLUSH_BD, l2fib_flush_bd) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ +_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ @@ -221,8 +223,8 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) goto bad_sw_if_index; } } - u32 static_mac = mp->static_mac ? 1 : 0; - u32 bvi_mac = mp->bvi_mac ? 1 : 0; + u8 static_mac = mp->static_mac ? 1 : 0; + u8 bvi_mac = mp->bvi_mac ? 1 : 0; l2fib_add_fwd_entry (mac, bd_index, sw_if_index, static_mac, bvi_mac); } @@ -237,6 +239,58 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY); } +static void +vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t * mp) +{ + int rv = 0; + vl_api_want_l2_macs_events_reply_t *rmp; + l2learn_main_t *lm = &l2learn_main; + l2fib_main_t *fm = &l2fib_main; + u32 pid = ntohl (mp->pid); + u32 learn_limit = ntohl (mp->learn_limit); + + if (mp->enable_disable) + { + if (lm->client_pid == 0) + { + lm->client_pid = pid; + lm->client_index = mp->client_index; + + if (mp->max_macs_in_event) + fm->max_macs_in_event = mp->max_macs_in_event * 10; + else + fm->max_macs_in_event = L2FIB_EVENT_MAX_MACS_DEFAULT; + + if (mp->scan_delay) + fm->event_scan_delay = (f64) (mp->scan_delay) * 10e-3; + else + fm->event_scan_delay = L2FIB_EVENT_SCAN_DELAY_DEFAULT; + + /* change learn limit and flush all learned MACs */ + if (learn_limit && (learn_limit < L2LEARN_DEFAULT_LIMIT)) + lm->global_learn_limit = learn_limit; + else + lm->global_learn_limit = L2FIB_EVENT_LEARN_LIMIT_DEFAULT; + + l2fib_flush_all_mac (vlib_get_main ()); + } + else if (lm->client_pid != pid) + { + rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT; + goto exit; + } + } + else if (lm->client_pid) + { + lm->client_pid = 0; + lm->client_index = 0; + lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT; + } + +exit: + REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS_REPLY); +} + static void vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp) { @@ -293,8 +347,25 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) VALIDATE_SW_IF_INDEX (mp); u32 sw_if_index = ntohl (mp->sw_if_index); - u32 flags = ntohl (mp->feature_bitmap) & L2INPUT_VALID_MASK; - rbm = l2input_intf_bitmap_enable (sw_if_index, flags, mp->is_set); + u32 flags = ntohl (mp->feature_bitmap); + u32 bitmap = 0; + + if (flags & L2_LEARN) + bitmap |= L2INPUT_FEAT_LEARN; + + if (flags & L2_FWD) + bitmap |= L2INPUT_FEAT_FWD; + + if (flags & L2_FLOOD) + bitmap |= L2INPUT_FEAT_FLOOD; + + if (flags & L2_UU_FLOOD) + bitmap |= L2INPUT_FEAT_UU_FLOOD; + + if (flags & L2_ARP_TERM) + bitmap |= L2INPUT_FEAT_ARP_TERM; + + rbm = l2input_intf_bitmap_enable (sw_if_index, bitmap, mp->is_set); BAD_SW_IF_INDEX_LABEL; @@ -455,13 +526,13 @@ vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) goto out; } - bd_set_flags (vm, bd_index, flags, mp->is_set); + u32 bitmap = bd_set_flags (vm, bd_index, flags, mp->is_set); out: /* *INDENT-OFF* */ REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY, ({ - rmp->resulting_feature_bitmap = ntohl(flags); + rmp->resulting_feature_bitmap = ntohl(bitmap); })); /* *INDENT-ON* */ } diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index a87d02f2..6e0db058 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -263,7 +263,7 @@ bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) bd_config->feature_bitmap &= ~feature_bitmap; } - return 0; + return bd_config->feature_bitmap; } /** @@ -328,12 +328,7 @@ bd_learn (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_LEARN, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_LEARN, enable); done: return error; @@ -397,12 +392,7 @@ bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_FWD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_FWD, enable); done: return error; @@ -468,12 +458,7 @@ bd_flood (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_FLOOD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_FLOOD, enable); done: return error; @@ -538,12 +523,7 @@ bd_uu_flood (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable); done: return error; @@ -605,12 +585,7 @@ bd_arp_term (vlib_main_t * vm, enable = 0; /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_ARP_TERM, enable); done: return error; diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 7e59b098..8aa0ac29 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -31,6 +31,17 @@ #include +#include +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + /** * @file * @brief Ethernet MAC Address FIB Table Management. @@ -117,6 +128,7 @@ show_l2fib (vlib_main_t * vm, int i, j, k; u8 verbose = 0; u8 raw = 0; + u8 learn = 0; u32 bd_id, bd_index = ~0; u8 now = (u8) (vlib_time_now (vm) / 60); u8 *s = 0; @@ -127,12 +139,18 @@ show_l2fib (vlib_main_t * vm, verbose = 1; else if (unformat (input, "bd_index %d", &bd_index)) verbose = 1; + else if (unformat (input, "learn")) + { + learn = 1; + verbose = 0; + } else if (unformat (input, "bd_id %d", &bd_id)) { uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) { - verbose = 1; + if (learn == 0) + verbose = 1; bd_index = p[0]; } else @@ -155,7 +173,7 @@ show_l2fib (vlib_main_t * vm, if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) continue; - if (verbose && first_entry) + if ((verbose || learn) && first_entry) { first_entry = 0; vlib_cli_output (vm, @@ -168,13 +186,19 @@ show_l2fib (vlib_main_t * vm, key.raw = v->kvp[k].key; result.raw = v->kvp[k].value; - if (verbose + if ((verbose || learn) & ((bd_index >> 31) || (bd_index == key.fields.bd_index))) { + if (learn && result.fields.age_not) + { + total_entries++; + continue; /* skip provisioned macs */ + } + bd_config = vec_elt_at_index (l2input_main.bd_configs, key.fields.bd_index); - if (bd_config->mac_age && !result.fields.static_mac) + if (bd_config->mac_age && !result.fields.age_not) { i16 delta = now - result.fields.timestamp; delta += delta < 0 ? 256 : 0; @@ -206,9 +230,19 @@ show_l2fib (vlib_main_t * vm, if (total_entries == 0) vlib_cli_output (vm, "no l2fib entries"); else - vlib_cli_output (vm, - "%lld l2fib entries with %d learned (or non-static) entries", - total_entries, l2learn_main.global_learn_count); + { + l2learn_main_t *lm = &l2learn_main; + vlib_cli_output (vm, "L2FIB total/learned entries: %d/%d " + "Last scan time: %.4esec Learn limit: %d ", + total_entries, lm->global_learn_count, + msm->age_scan_duration, lm->global_learn_limit); + if (lm->client_pid) + vlib_cli_output (vm, "L2MAC events client PID: %d " + "Last e-scan time: %.4esec Delay: %.2esec " + "Max macs in event: %d", + lm->client_pid, msm->evt_scan_duration, + msm->event_scan_delay, msm->max_macs_in_event); + } if (raw) vlib_cli_output (vm, "Raw Hash Table:\n%U\n", @@ -242,7 +276,7 @@ show_l2fib (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_l2fib_cli, static) = { .path = "show l2fib", - .short_help = "show l2fib [verbose | bd_id | bd_index | raw]", + .short_help = "show l2fib [verbose | learn | bd_id | bd_index | raw", .function = show_l2fib, }; /* *INDENT-ON* */ @@ -309,36 +343,39 @@ l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index) */ void l2fib_add_entry (u64 mac, u32 bd_index, - u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac) + u32 sw_if_index, u8 static_mac, u8 filter_mac, u8 bvi_mac) { l2fib_entry_key_t key; l2fib_entry_result_t result; __attribute__ ((unused)) u32 bucket_contents; - l2fib_main_t *mp = &l2fib_main; + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; BVT (clib_bihash_kv) kv; /* set up key */ key.raw = l2fib_make_key ((u8 *) & mac, bd_index); + /* check if entry alread exist */ + if (BV (clib_bihash_search) (&fm->mac_table, &kv, &kv)) + { + /* decrement counter if overwriting a learned mac */ + result.raw = kv.value; + if ((result.fields.age_not == 0) && (lm->global_learn_count)) + lm->global_learn_count--; + } + /* set up result */ result.raw = 0; /* clear all fields */ result.fields.sw_if_index = sw_if_index; result.fields.static_mac = static_mac; result.fields.filter = filter_mac; result.fields.bvi = bvi_mac; - if (!static_mac) - result.fields.sn = l2fib_cur_seq_num (bd_index, sw_if_index); + result.fields.age_not = 1; /* no aging for provisioned entry */ kv.key = key.raw; kv.value = result.raw; - BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ ); - - /* increment counter if dynamically learned mac */ - if (result.fields.static_mac == 0) - { - l2learn_main.global_learn_count++; - } + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1 /* is_add */ ); } /** @@ -630,13 +667,8 @@ l2fib_del_entry_by_key (u64 raw_key) result.raw = kv.value; /* decrement counter if dynamically learned mac */ - if (result.fields.static_mac == 0) - { - if (l2learn_main.global_learn_count > 0) - { - l2learn_main.global_learn_count--; - } - } + if ((result.fields.age_not == 0) && (l2learn_main.global_learn_count)) + l2learn_main.global_learn_count--; /* Remove entry from hash table */ BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ ); @@ -910,111 +942,273 @@ BVT (clib_bihash) * get_mac_table (void) return &mp->mac_table; } +static_always_inline void * +allocate_mac_evt_buf (u32 client, u32 client_index) +{ + l2fib_main_t *fm = &l2fib_main; + vl_api_l2_macs_event_t *mp = vl_msg_api_alloc + (sizeof (*mp) + (fm->max_macs_in_event * sizeof (vl_api_mac_entry_t))); + mp->_vl_msg_id = htons (VL_API_L2_MACS_EVENT); + mp->pid = htonl (client); + mp->client_index = client_index; + return mp; +} + +static_always_inline f64 +l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only) +{ + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; + + BVT (clib_bihash) * h = &fm->mac_table; + int i, j, k; + f64 last_start = start_time; + f64 accum_t = 0; + f64 delta_t = 0; + u32 evt_idx = 0; + u32 learn_count = 0; + u32 client = lm->client_pid; + u32 cl_idx = lm->client_index; + vl_api_l2_macs_event_t *mp = 0; + unix_shared_memory_queue_t *q = 0; + + if (client) + { + mp = allocate_mac_evt_buf (client, cl_idx); + q = vl_api_client_index_to_input_queue (lm->client_index); + } + + for (i = 0; i < h->nbuckets; i++) + { + /* allow no more than 20us without a pause */ + delta_t = vlib_time_now (vm) - last_start; + if (delta_t > 20e-6) + { + vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */ + last_start = vlib_time_now (vm); + accum_t += delta_t; + } + + if (i < (h->nbuckets - 3)) + { + BVT (clib_bihash_bucket) * b = &h->buckets[i + 3]; + CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); + b = &h->buckets[i + 1]; + if (b->offset) + { + BVT (clib_bihash_value) * v = + BV (clib_bihash_get_value) (h, b->offset); + CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); + } + } + + BVT (clib_bihash_bucket) * b = &h->buckets[i]; + if (b->offset == 0) + continue; + BVT (clib_bihash_value) * v = BV (clib_bihash_get_value) (h, b->offset); + for (j = 0; j < (1 << b->log2_pages); j++) + { + for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) + { + if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) + continue; + + l2fib_entry_key_t key = {.raw = v->kvp[k].key }; + l2fib_entry_result_t result = {.raw = v->kvp[k].value }; + + if (result.fields.age_not == 0) + learn_count++; + + if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event)) + { + /* evet message full, sent it and start a new one */ + if (q && (q->cursize < q->maxsize)) + { + mp->n_macs = htonl (evt_idx); + vl_msg_api_send_shmem (q, (u8 *) & mp); + mp = allocate_mac_evt_buf (client, cl_idx); + } + else + { + clib_warning ("MAC event to pid %d queue stuffed!" + " %d MAC entries lost", client, evt_idx); + } + evt_idx = 0; + } + + if (client) + { + if (result.fields.lrn_evt) + { + /* copy mac entry to event msg */ + clib_memcpy (mp->mac[evt_idx].mac_addr, key.fields.mac, + 6); + mp->mac[evt_idx].is_del = 0; + mp->mac[evt_idx].sw_if_index = + htonl (result.fields.sw_if_index); + /* clear event bit and update mac entry */ + result.fields.lrn_evt = 0; + BVT (clib_bihash_kv) kv; + kv.key = key.raw; + kv.value = result.raw; + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1); + evt_idx++; + continue; /* skip aging */ + } + } + + if (event_only || result.fields.age_not) + continue; /* skip aging - static_mac alsways age_not */ + + /* start aging processing */ + u32 bd_index = key.fields.bd_index; + u32 sw_if_index = result.fields.sw_if_index; + u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index).as_u16; + if (result.fields.sn.as_u16 != sn) + goto age_out; /* stale mac */ + + l2_bridge_domain_t *bd_config = + vec_elt_at_index (l2input_main.bd_configs, bd_index); + + if (bd_config->mac_age == 0) + continue; /* skip aging */ + + i16 delta = (u8) (start_time / 60) - result.fields.timestamp; + delta += delta < 0 ? 256 : 0; + + if (delta < bd_config->mac_age) + continue; /* still valid */ + + age_out: + if (client) + { + /* copy mac entry to event msg */ + clib_memcpy (mp->mac[evt_idx].mac_addr, key.fields.mac, 6); + mp->mac[evt_idx].is_del = 1; + mp->mac[evt_idx].sw_if_index = + htonl (result.fields.sw_if_index); + evt_idx++; + } + /* delete mac entry */ + BVT (clib_bihash_kv) kv; + kv.key = key.raw; + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0); + learn_count--; + } + v++; + } + } + + /* keep learn count consistent */ + l2learn_main.global_learn_count = learn_count; + + if (mp) + { + /* send any outstanding mac event message else free message buffer */ + if (evt_idx) + { + if (q && (q->cursize < q->maxsize)) + { + mp->n_macs = htonl (evt_idx); + vl_msg_api_send_shmem (q, (u8 *) & mp); + } + else + { + clib_warning ("MAC event to pid %d queue stuffed!" + " %d MAC entries lost", client, evt_idx); + vl_msg_api_free (mp); + } + } + else + vl_msg_api_free (mp); + } + return delta_t + accum_t; +} + +/* Type of scan */ +#define SCAN_MAC_AGE 0 +#define SCAN_MAC_EVENT 1 + +/* Maximum f64 value */ +#define TIME_MAX (1.7976931348623157e+308) + static uword l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { uword event_type, *event_data = 0; - l2fib_main_t *msm = &l2fib_main; + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; bool enabled = 0; - f64 start_time, last_run_duration = 0, t; + bool scan = SCAN_MAC_AGE; /* SCAN_FOR_AGE or SCAN_FOR_EVENT */ + f64 start_time, next_age_scan_time = TIME_MAX; while (1) { if (enabled) - vlib_process_wait_for_event_or_clock (vm, 60 - last_run_duration); + { + if (lm->client_pid) /* mac event client waiting */ + vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay); + else /* agin only */ + { + f64 t = next_age_scan_time - vlib_time_now (vm); + if (t < fm->event_scan_delay) + t = fm->event_scan_delay; + vlib_process_wait_for_event_or_clock (vm, t); + } + } else vlib_process_wait_for_event (vm); event_type = vlib_process_get_events (vm, &event_data); vec_reset_length (event_data); + start_time = vlib_time_now (vm); + switch (event_type) { - case ~0: + case ~0: /* timer expired */ + if ((lm->client_pid == 0) || (start_time >= next_age_scan_time)) + { + scan = SCAN_MAC_AGE; + if (enabled) + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; + else + next_age_scan_time = TIME_MAX; + } + else + scan = SCAN_MAC_EVENT; break; + case L2_MAC_AGE_PROCESS_EVENT_START: + scan = SCAN_MAC_AGE; + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; enabled = 1; break; + case L2_MAC_AGE_PROCESS_EVENT_STOP: enabled = 0; + next_age_scan_time = TIME_MAX; + l2fib_main.age_scan_duration = 0; + l2fib_main.evt_scan_duration = 0; continue; + case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS: - enabled = 0; + scan = SCAN_MAC_AGE; + if (enabled) + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; + else + next_age_scan_time = TIME_MAX; break; + default: ASSERT (0); } - last_run_duration = start_time = vlib_time_now (vm); - BVT (clib_bihash) * h = &msm->mac_table; - int i, j, k; - for (i = 0; i < h->nbuckets; i++) - { - /* Allow no more than 10us without a pause */ - t = vlib_time_now (vm); - if (t > start_time + 10e-6) - { - vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */ - start_time = vlib_time_now (vm); - } - - if (i < (h->nbuckets - 3)) - { - BVT (clib_bihash_bucket) * b = &h->buckets[i + 3]; - CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); - b = &h->buckets[i + 1]; - if (b->offset) - { - BVT (clib_bihash_value) * v = - BV (clib_bihash_get_value) (h, b->offset); - CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); - } - } - - BVT (clib_bihash_bucket) * b = &h->buckets[i]; - if (b->offset == 0) - continue; - BVT (clib_bihash_value) * v = - BV (clib_bihash_get_value) (h, b->offset); - for (j = 0; j < (1 << b->log2_pages); j++) - { - for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) - { - if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) - continue; - - l2fib_entry_key_t key = {.raw = v->kvp[k].key }; - l2fib_entry_result_t result = {.raw = v->kvp[k].value }; - - if (result.fields.static_mac) - continue; - - u32 bd_index = key.fields.bd_index; - u32 sw_if_index = result.fields.sw_if_index; - u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index).as_u16; - if (result.fields.sn.as_u16 != sn) - { - l2fib_del_entry_by_key (key.raw); - continue; - } - l2_bridge_domain_t *bd_config = - vec_elt_at_index (l2input_main.bd_configs, bd_index); - - if (bd_config->mac_age == 0) - continue; - - i16 delta = - (u8) (start_time / 60) - result.fields.timestamp; - delta += delta < 0 ? 256 : 0; - - if (delta > bd_config->mac_age) - l2fib_del_entry_by_key (key.raw); - } - v++; - } - } - last_run_duration = vlib_time_now (vm) - last_run_duration; + if (scan == SCAN_MAC_EVENT) + l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1); + else + l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0); } return 0; } diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index ee6f0dc5..49a8b5b6 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -27,6 +27,18 @@ #define L2FIB_NUM_BUCKETS (64 * 1024) #define L2FIB_MEMORY_SIZE (256<<20) +/* Ager scan interval is 1 minute for aging */ +#define L2FIB_AGE_SCAN_INTERVAL (60.0) + +/* MAC event scan delay is 100 msec unless specified by MAC event client */ +#define L2FIB_EVENT_SCAN_DELAY_DEFAULT (0.1) + +/* Max MACs in a event message is 100 unless specified by MAC event client */ +#define L2FIB_EVENT_MAX_MACS_DEFAULT (100) + +/* MAC event learn limit is 1000 unless specified by MAC event client */ +#define L2FIB_EVENT_LEARN_LIMIT_DEFAULT (1000) + typedef struct { @@ -36,6 +48,16 @@ typedef struct /* per swif vector of sequence number for interface based flush of MACs */ u8 *swif_seq_num; + /* last event or ager scan duration */ + f64 evt_scan_duration; + f64 age_scan_duration; + + /* delay between event scans, default to 100 msec */ + f64 event_scan_delay; + + /* max macs in evet message, default to 100 entries */ + u32 max_macs_in_event; + /* convenience variables */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; @@ -89,12 +111,15 @@ typedef struct { struct { - u32 sw_if_index; /* output sw_if_index (L3 interface if bvi==1) */ + u32 sw_if_index; /* output sw_if_index (L3 intf if bvi==1) */ - u8 static_mac:1; /* static mac, no dataplane learning */ + u8 static_mac:1; /* static mac, no MAC move */ + u8 age_not:1; /* not subject to age */ u8 bvi:1; /* mac is for a bridged virtual interface */ u8 filter:1; /* drop packets to/from this mac */ - u8 unused1:5; + u8 lrn_evt:1; /* MAC learned to be sent in L2 MAC event */ + u8 unused:3; + u8 timestamp; /* timestamp for aging */ l2fib_seq_num_t sn; /* bd/int seq num */ } fields; @@ -348,11 +373,11 @@ void l2fib_clear_table (void); void l2fib_add_entry (u64 mac, u32 bd_index, - u32 sw_if_index, u32 static_mac, u32 drop_mac, u32 bvi_mac); + u32 sw_if_index, u8 static_mac, u8 drop_mac, u8 bvi_mac); static inline void -l2fib_add_fwd_entry (u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, - u32 bvi_mac) +l2fib_add_fwd_entry (u64 mac, u32 bd_index, u32 sw_if_index, u8 static_mac, + u8 bvi_mac) { l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, 0, bvi_mac); } diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c index 8140728b..2bb7307c 100644 --- a/src/vnet/l2/l2_fwd.c +++ b/src/vnet/l2/l2_fwd.c @@ -141,8 +141,9 @@ l2fwd_process (vlib_main_t * vm, vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index; *next0 = L2FWD_NEXT_L2_OUTPUT; int l2fib_seq_num_valid = 1; + /* check l2fib seq num for stale entries */ - if (!result0->fields.static_mac) + if (!result0->fields.age_not) { l2fib_seq_num_t in_sn = {.as_u16 = vnet_buffer (b0)->l2.l2fib_sn }; l2fib_seq_num_t expected_sn = { diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 65406292..47c036b0 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -123,11 +123,9 @@ l2learn_process (vlib_node_runtime_t * node, /* Check mac table lookup result */ if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) { - /* - * The entry was in the table, and the sw_if_index matched, the normal case - */ + /* Entry in L2FIB with matching sw_if_index matched - normal fast path */ counter_base[L2LEARN_ERROR_HIT] += 1; - int update = !result0->fields.static_mac && + int update = !result0->fields.age_not && /* static_mac always age_not */ (result0->fields.timestamp != timestamp || result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn); @@ -136,10 +134,10 @@ l2learn_process (vlib_node_runtime_t * node, } else if (result0->raw == ~0) { - /* The entry was not in table, so add it */ + /* Entry not in L2FIB - add it */ counter_base[L2LEARN_ERROR_MISS] += 1; - if (msm->global_learn_count == msm->global_learn_limit) + if (msm->global_learn_count >= msm->global_learn_limit) { /* * Global limit reached. Do not learn the mac but forward the packet. @@ -149,15 +147,22 @@ l2learn_process (vlib_node_runtime_t * node, return; } + /* Do not learn if mac is 0 */ + l2fib_entry_key_t key = *key0; + key.fields.bd_index = 0; + if (key.raw == 0) + return; + /* It is ok to learn */ msm->global_learn_count++; result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; + result0->fields.lrn_evt = (msm->client_pid != 0); cached_key->raw = ~0; /* invalidate the cache */ } else { - /* The entry was in the table, but with the wrong sw_if_index mapping (mac move) */ + /* Entry in L2FIB with different sw_if_index - mac move or filter */ if (result0->fields.filter) { ASSERT (result0->fields.sw_if_index == ~0); @@ -167,8 +172,6 @@ l2learn_process (vlib_node_runtime_t * node, return; } - counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; - if (result0->fields.static_mac) { /* @@ -185,6 +188,13 @@ l2learn_process (vlib_node_runtime_t * node, * TODO: check global/bridge domain/interface learn limits */ result0->fields.sw_if_index = sw_if_index0; + if (result0->fields.age_not) /* The mac was provisioned */ + { + msm->global_learn_count++; + result0->fields.age_not = 0; + } + result0->fields.lrn_evt = (msm->client_pid != 0); + counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; } /* Update the entry */ @@ -479,7 +489,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2learn_node, l2learn_node_fn) * Set the default number of dynamically learned macs to the number * of buckets. */ - mp->global_learn_limit = L2FIB_NUM_BUCKETS * 16; + mp->global_learn_limit = L2LEARN_DEFAULT_LIMIT; return 0; } diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index 0d95de04..000ab59e 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -34,6 +34,10 @@ typedef struct /* maximum number of dynamically learned mac entries */ u32 global_learn_limit; + /* client waiting for L2 MAC events for learned and aged MACs */ + u32 client_pid; + u32 client_index; + /* Next nodes for each feature */ u32 feat_next_node_index[32]; @@ -42,6 +46,7 @@ typedef struct vnet_main_t *vnet_main; } l2learn_main_t; +#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 16) l2learn_main_t l2learn_main; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 520361f6..a57799cb 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -373,10 +373,19 @@ vl_api_l2_flags_t_print (vl_api_l2_flags_t * mp, void *handle) s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); -#define _(a,b) \ - if (flags & L2INPUT_FEAT_ ## a) s = format (s, #a " "); - foreach_l2input_feat; -#undef _ + if (flags & L2_LEARN) + s = format (s, "learn "); + if (flags & L2_FWD) + s = format (s, "forward "); + if (flags & L2_FLOOD) + s = format (s, "flood "); + if (flags & L2_UU_FLOOD) + s = format (s, "uu-flood "); + if (flags & L2_ARP_TERM) + s = format (s, "arp-term "); + + if (mp->is_set == 0) + s = format (s, "clear "); FINISH; } @@ -1783,6 +1792,21 @@ static void *vl_api_want_ip6_nd_events_t_print FINISH; } +static void *vl_api_want_l2_macs_events_t_print + (vl_api_want_l2_macs_events_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: want_l2_macs_events "); + s = format (s, "learn-limit %d ", ntohl (mp->learn_limit)); + s = format (s, "scan-delay %d ", (u32) mp->scan_delay); + s = format (s, "max-entries %d ", (u32) mp->max_macs_in_event * 10); + if (mp->enable_disable == 0) + s = format (s, "disable"); + + FINISH; +} + static void *vl_api_input_acl_set_interface_t_print (vl_api_input_acl_set_interface_t * mp, void *handle) { @@ -3066,6 +3090,7 @@ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ _(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ +_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \ _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ -- cgit 1.2.3-korg From 483041413842e04f6958ae8cae4135dc2262d43b Mon Sep 17 00:00:00 2001 From: Jerome Tollet Date: Tue, 5 Sep 2017 12:13:22 +0100 Subject: Support for bridge domain free text tag Change-Id: I9a75fdafd0c1d87b6f071fda5b77ff5f6b79deb7 Signed-off-by: Jerome Tollet --- src/vnet/l2/l2.api | 2 ++ src/vnet/l2/l2_api.c | 8 ++++++++ src/vnet/l2/l2_bd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/vnet/l2/l2_bd.h | 5 +++++ 4 files changed, 66 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 9f97ebbe..baf830fa 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -249,6 +249,7 @@ autoreply define bridge_domain_add_del u8 learn; u8 arp_term; u8 mac_age; + u8 bd_tag[64]; u8 is_add; }; @@ -296,6 +297,7 @@ manual_print manual_endian define bridge_domain_details u8 learn; u8 arp_term; u8 mac_age; + u8 bd_tag[64]; u32 bvi_sw_if_index; u32 n_sw_ifs; vl_api_bridge_domain_sw_if_t sw_if_details[n_sw_ifs]; diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 989081fb..20d6ab32 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -420,6 +420,7 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) .arp_term = mp->arp_term, .mac_age = mp->mac_age, .bd_id = ntohl (mp->bd_id), + .bd_tag = mp->bd_tag }; int rv = bd_add_del (&a); @@ -451,6 +452,13 @@ send_bridge_domain_details (l2input_main_t * l2im, mp->arp_term = bd_feature_arp_term (bd_config); mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index); mp->mac_age = bd_config->mac_age; + if (bd_config->bd_tag) + { + strncpy ((char *) mp->bd_tag, (char *) bd_config->bd_tag, + ARRAY_LEN (mp->bd_tag) - 1); + mp->bd_tag[ARRAY_LEN (mp->bd_tag) - 1] = 0; + } + mp->context = context; sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details; diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 6e0db058..3670a4f0 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -108,6 +108,9 @@ bd_delete (bd_main_t * bdm, u32 bd_index) bd->bd_id = ~0; bd->feature_bitmap = 0; + /* free BD tag */ + vec_free (bd->bd_tag); + /* free memory used by BD */ vec_free (bd->members); hash_free (bd->mac_by_ip4); @@ -288,6 +291,29 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) L2_MAC_AGE_PROCESS_EVENT_STOP, 0); } + +void +bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag) +{ + u8 *old; + l2_bridge_domain_t *bd_config; + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + + old = bd_config->bd_tag; + + if (bd_tag[0]) + { + bd_config->bd_tag = format (0, "%s%c", bd_tag, 0); + } + else + { + bd_config->bd_tag = NULL; + } + + vec_free (old); +} + /** Set bridge-domain learn enable/disable. The CLI format is: @@ -906,6 +932,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 detail = 0; u32 intf = 0; u32 arp = 0; + u32 bd_tag = 0; u32 bd_id = ~0; uword *p; @@ -922,6 +949,8 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) intf = 1; if (unformat (input, "arp")) arp = 1; + if (unformat (input, "bd-tag")) + bd_tag = 1; if (bd_id == 0) return clib_error_return (0, @@ -1039,6 +1068,12 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) })); /* *INDENT-ON* */ } + + if ((detail || bd_tag) && (bd_config->bd_tag)) + { + vlib_cli_output (vm, "\n BD-Tag: %s", bd_config->bd_tag); + + } } } vec_free (as); @@ -1080,7 +1115,7 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bd_show_cli, static) = { .path = "show bridge-domain", - .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]", + .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp|bd-tag]]", .function = bd_show, }; /* *INDENT-ON* */ @@ -1134,6 +1169,10 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); bd_set_mac_age (vm, bd_index, a->mac_age); + + if (a->bd_tag) + bd_set_bd_tag (vm, bd_index, a->bd_tag); + } else { @@ -1166,6 +1205,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, u32 bd_id = ~0; u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; u32 mac_age = 0; + u8 *bd_tag = NULL; l2_bridge_domain_add_del_args_t _a, *a = &_a; int rv; @@ -1189,6 +1229,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, ; else if (unformat (line_input, "mac-age %d", &mac_age)) ; + else if (unformat (line_input, "bd-tag %s", &bd_tag)) + ; else if (unformat (line_input, "del")) { is_add = 0; @@ -1215,6 +1257,11 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, error = clib_error_return (0, "mac age must be less than 256"); goto done; } + if ((bd_tag) && (strlen ((char *) bd_tag) > 63)) + { + error = clib_error_return (0, "bd-tag cannot be longer than 63"); + goto done; + } memset (a, 0, sizeof (*a)); a->is_add = is_add; @@ -1225,6 +1272,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, a->learn = (u8) learn; a->arp_term = (u8) arp_term; a->mac_age = (u8) mac_age; + a->bd_tag = bd_tag; rv = bd_add_del (a); @@ -1252,6 +1300,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, } done: + vec_free (bd_tag); unformat_free (line_input); return error; @@ -1291,7 +1340,7 @@ VLIB_CLI_COMMAND (bd_create_cli, static) = { .path = "create bridge-domain", .short_help = "create bridge-domain " " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]" - " [mac-age ] [del]", + " [mac-age ] [bd-tag ] [del]", .function = bd_add_del_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 0e070651..e60f1ab3 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -88,6 +88,9 @@ typedef struct /* sequence number for bridge domain based flush of MACs */ u8 seq_num; + /* Bridge domain tag (C string NULL terminated) */ + u8 *bd_tag; + } l2_bridge_domain_t; /* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */ @@ -102,6 +105,7 @@ typedef struct u8 learn; u8 arp_term; u8 mac_age; + u8 *bd_tag; u8 is_add; } l2_bridge_domain_add_del_args_t; @@ -130,6 +134,7 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); +void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag); int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** -- cgit 1.2.3-korg From 50570ecef6d37b0c9d8c002f6dadb4ed0e138aa3 Mon Sep 17 00:00:00 2001 From: Jerome Tollet Date: Thu, 14 Sep 2017 12:53:56 +0100 Subject: Update of free text tag patch for BD Change-Id: Ia886ff2bfa2cf33ffbaa35ec89494d4300ec2769 Signed-off-by: Jerome Tollet --- src/vat/api_format.c | 23 ++++++++++++++++++++--- src/vnet/l2/l2.api | 1 + src/vnet/l2/l2_bd.c | 9 ++++++--- src/vnet/l2/l2_bd.h | 1 - src/vpp/api/custom_dump.c | 2 ++ 5 files changed, 29 insertions(+), 7 deletions(-) (limited to 'src/vnet/l2/l2_bd.c') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 43d1eb3d..ff3354c9 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -6356,6 +6356,7 @@ api_bridge_domain_add_del (vat_main_t * vam) u32 bd_id = ~0; u8 is_add = 1; u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; + u8 *bd_tag = NULL; u32 mac_age = 0; int ret; @@ -6376,6 +6377,8 @@ api_bridge_domain_add_del (vat_main_t * vam) ; else if (unformat (i, "mac-age %d", &mac_age)) ; + else if (unformat (i, "bd-tag %s", &bd_tag)) + ; else if (unformat (i, "del")) { is_add = 0; @@ -6388,13 +6391,22 @@ api_bridge_domain_add_del (vat_main_t * vam) if (bd_id == ~0) { errmsg ("missing bridge domain"); - return -99; + ret = -99; + goto done; } if (mac_age > 255) { errmsg ("mac age must be less than 256 "); - return -99; + ret = -99; + goto done; + } + + if ((bd_tag) && (strlen ((char *) bd_tag) > 63)) + { + errmsg ("bd-tag cannot be longer than 63"); + ret = -99; + goto done; } M (BRIDGE_DOMAIN_ADD_DEL, mp); @@ -6407,9 +6419,14 @@ api_bridge_domain_add_del (vat_main_t * vam) mp->arp_term = arp_term; mp->is_add = is_add; mp->mac_age = (u8) mac_age; + if (bd_tag) + strcpy ((char *) mp->bd_tag, (char *) bd_tag); S (mp); W (ret); + +done: + vec_free (bd_tag); return ret; } @@ -20152,7 +20169,7 @@ _(sw_interface_set_l2_bridge, \ "enable | disable") \ _(bridge_domain_set_mac_age, "bd_id mac-age 0-255") \ _(bridge_domain_add_del, \ - "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [del]\n") \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag ] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index baf830fa..ac923de4 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -285,6 +285,7 @@ typeonly manual_print manual_endian define bridge_domain_sw_if @param learn - learning state on all interfaces in the bd @param arp_term - arp termination state on all interfaces in the bd @param mac_age - mac aging time in min, 0 for disabled + @param bd_tag - optional textual tag for the bridge domain @param n_sw_ifs - number of sw_if_index's in the domain */ manual_print manual_endian define bridge_domain_details diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 3670a4f0..b1abb4c0 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -291,8 +291,11 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) L2_MAC_AGE_PROCESS_EVENT_STOP, 0); } +/** + Set the tag for the bridge domain. +*/ -void +static void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag) { u8 *old; @@ -1191,8 +1194,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) /** Create or delete bridge-domain. The CLI format: - create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] - [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] + create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] + [arp-term <0|1>] [mac-age ] [bd-tag ] [del] */ static clib_error_t * diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index e60f1ab3..fd34ae67 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -134,7 +134,6 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); -void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag); int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index be74b83a..2e1f980e 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -279,6 +279,8 @@ static void *vl_api_bridge_domain_add_del_t_print if (mp->is_add) { + if (mp->bd_tag[0]) + s = format (s, "bd_tag %s ", mp->bd_tag); s = format (s, "flood %d uu-flood %d ", mp->flood, mp->uu_flood); s = format (s, "forward %d learn %d ", mp->forward, mp->learn); s = format (s, "arp-term %d mac-age %d", mp->arp_term, mp->mac_age); -- cgit 1.2.3-korg