/* Hey Emacs use -*- mode: C -*- */
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
* 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:
* limitations under the License.
*/
-option version = "3.1.0";
+option version = "3.2.0";
import "vnet/ip/ip_types.api";
import "vnet/ethernet/ethernet_types.api";
u32 learn_limit;
};
-/** \brief L2 bridge domain add or delete request
+/** \brief L2 bridge domain add or delete request - will be deprecated
@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
*/
autoreply define bridge_domain_add_del
{
+ option deprecated;
u32 client_index;
u32 context;
u32 bd_id;
bool is_add [default=true];
};
+/** \brief L2 bridge domain add delete request version 2
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param bd_id - if the id == ~0 creates a bridge domain with an unused id
+ if the id != ~0 the id of the bridge domain to create/delete
+ @param flood - enable/disable bcast/mcast flooding in the bd
+ @param uu_flood - enable/disable unknown unicast flood in the bd
+ @param forward - enable/disable forwarding on all interfaces in the bd
+ @param learn - enable/disable learning on all interfaces in the bd
+ @param arp_term - enable/disable arp termination in the bd
+ @param arp_ufwd - enable/disable arp unicast forwarding in the bd
+ @param mac_age - mac aging time in min, 0 for disabled
+ @param is_add - add or delete flag
+*/
+define bridge_domain_add_del_v2
+{
+ u32 client_index;
+ u32 context;
+ u32 bd_id;
+ bool flood;
+ bool uu_flood;
+ bool forward;
+ bool learn;
+ bool arp_term;
+ bool arp_ufwd;
+ u8 mac_age;
+ string bd_tag[64];
+ bool is_add [default=true];
+};
+
+/** \brief L2 bridge domain add delete version 2 response
+ @param context - sender context, to match reply w/ request
+ @param retval - return code for the set bridge flags request
+ @param resulting_id - the id for the new bridge domain
+*/
+define bridge_domain_add_del_v2_reply
+{
+ u32 context;
+ i32 retval;
+ u32 bd_id;
+};
+
+
/** \brief L2 bridge domain request operational state details
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
* l2_api.c - layer 2 forwarding api
*
* Copyright (c) 2016 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
* 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:
REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY);
}
+static void
+vl_api_bridge_domain_add_del_v2_t_handler (
+ vl_api_bridge_domain_add_del_v2_t *mp)
+{
+ vl_api_bridge_domain_add_del_v2_reply_t *rmp;
+ u32 bd_id = ntohl (mp->bd_id);
+ int rv = 0;
+
+ if ((~0 == bd_id) && (mp->is_add))
+ bd_id = bd_get_unused_id ();
+
+ if ((~0 == bd_id) && (mp->is_add))
+ rv = VNET_API_ERROR_EAGAIN;
+ else
+ {
+ 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,
+ .arp_ufwd = mp->arp_ufwd,
+ .mac_age = mp->mac_age,
+ .bd_id = bd_id,
+ .bd_tag = mp->bd_tag };
+ rv = bd_add_del (&a);
+ }
+ REPLY_MACRO2 (VL_API_BRIDGE_DOMAIN_ADD_DEL_V2_REPLY,
+ ({ rmp->bd_id = htonl (bd_id); }));
+}
+
static void
send_bridge_domain_details (l2input_main_t * l2im,
vl_api_registration_t * reg,
if (bd_id == ~0)
{
- error = clib_error_return (0, "bridge-domain-id not specified");
- goto done;
+ if (is_add)
+ {
+ bd_id = bd_get_unused_id ();
+ }
+ else
+ {
+ error = clib_error_return (0, "bridge-domain-id not specified");
+ goto done;
+ }
}
if (bd_id == 0)
};
/* *INDENT-ON* */
+/*
+ * Returns an unused bridge domain id, and ~0 if it can't find one.
+ */
+u32
+bd_get_unused_id ()
+{
+ bd_main_t *bdm = &bd_main;
+ int i, j;
+ int is_seed_low = 0;
+ static u32 seed = 0;
+ /* limit to 1M tries */
+ for (j = 0; j < 1 << 10; j++)
+ {
+ seed = random_u32 (&seed) & L2_BD_ID_MAX;
+ if (seed == 0)
+ continue;
+ if (seed < L2_BD_ID_MAX % 2)
+ is_seed_low = 1;
+ for (i = 0; i < L2_BD_ID_MAX % 2; i++)
+ {
+ /* look around randomly generated id */
+ if (is_seed_low)
+ seed += (2 * (i % 2) - 1) * i;
+ else
+ seed -= (2 * (i % 2) - 1) * i;
+ if (seed == ~0 || seed == 0)
+ continue;
+ if (bd_find_index (bdm, seed) == ~0)
+ return seed;
+ }
+ }
+ return ~0;
+}
/*
* fd.io coding-style-patch-verification: ON
* l2_bd.h : layer 2 bridge domain
*
* Copyright (c) 2013 Cisco and/or its affiliates.
+ * Copyright (c) 2022 Nordix Foundation.
* 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:
void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age);
void bd_set_learn_limit (vlib_main_t *vm, u32 bd_index, u32 learn_limit);
int bd_add_del (l2_bridge_domain_add_del_args_t * args);
-
+u32 bd_get_unused_id (void);
/**
* \brief Get a bridge domain.
*
/* SPDX-License-Identifier: Apache-2.0
* Copyright(c) 2021 Cisco Systems, Inc.
+ * Copyright(c) 2022 Nordix Foundation.
*/
#include <vat/vat.h>
return ret;
}
+static int
+api_bridge_domain_add_del_v2 (vat_main_t *vam)
+{
+ return -1;
+}
+
+static void
+vl_api_bridge_domain_add_del_v2_reply_t_handler (
+ vl_api_bridge_domain_add_del_v2_reply_t *mp)
+{
+}
+
#define foreach_pbb_vtr_op \
_ ("disable", L2_VTR_DISABLED) \
_ ("pop", L2_VTR_POP_2) \
# Create BD with MAC learning and unknown unicast flooding disabled
# and put interfaces to this BD
- cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=1, learn=1)
+ cls.vapi.bridge_domain_add_del_v2(
+ bd_id=cls.bd_id, uu_flood=1, learn=1, flood=1, forward=1, is_add=1
+ )
for pg_if in cls.pg_interfaces:
cls.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=pg_if.sw_if_index, bd_id=cls.bd_id
# Create BD with MAC learning and unknown unicast flooding disabled
# and put interfaces to this BD
- cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=1, learn=1)
+ cls.vapi.bridge_domain_add_del_v2(
+ bd_id=cls.bd_id, uu_flood=1, learn=1, flood=1, forward=1, is_add=1
+ )
for pg_if in cls.pg_interfaces:
cls.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=pg_if.sw_if_index, bd_id=cls.bd_id
# Create BD with MAC learning and unknown unicast flooding disabled
# and put interfaces to this BD
- cls.vapi.bridge_domain_add_del(bd_id=1, uu_flood=1, learn=1)
+ cls.vapi.bridge_domain_add_del_v2(
+ bd_id=1, uu_flood=1, learn=1, flood=1, forward=1, is_add=1
+ )
cls.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=cls.pg1._sw_if_index, bd_id=1
)
for bd_id in n_brs:
# Create BD with MAC learning and unknown unicast flooding
# disabled and put interfaces to this BD
- cls.vapi.bridge_domain_add_del(bd_id=bd_id, uu_flood=0, learn=0)
+ cls.vapi.bridge_domain_add_del_v2(
+ bd_id=bd_id, is_add=1, uu_flood=0, learn=0, flood=1, forward=1
+ )
ifs = [cls.pg_interfaces[i] for i in cls.bd_ifs(bd_id)]
for pg_if in ifs:
cls.vapi.sw_interface_set_l2_bridge(
#
# Create a single bridge Domain
#
- self.vapi.bridge_domain_add_del(bd_id=1)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
+ )
#
# add each interface to the BD. 3 interfaces per split horizon group
enable=0,
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
def test_flood_one(self):
"""L2 no-Flood Test"""
#
# Create a single bridge Domain
#
- self.vapi.bridge_domain_add_del(bd_id=1)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
+ )
#
# add 2 interfaces to the BD. this means a flood goes to only
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
def test_uu_fwd(self):
"""UU Flood"""
#
# Create a single bridge Domain
#
- self.vapi.bridge_domain_add_del(bd_id=1, uu_flood=1)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, uu_flood=1, flood=1, forward=1, learn=1
+ )
#
# add each interface to the BD. 3 interfaces per split horizon group
rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
if __name__ == "__main__":
def bd_add_del(self, bd_id=1, is_add=1):
if is_add:
- self.vapi.bridge_domain_add_del(bd_id=bd_id, is_add=is_add)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=bd_id, is_add=is_add, flood=1, uu_flood=1, forward=1, learn=1
+ )
for swif in self.bd_swifs(bd_id):
swif_idx = swif.sw_if_index
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=swif_idx, bd_id=bd_id, enable=is_add
)
if not is_add:
- self.vapi.bridge_domain_add_del(bd_id=bd_id, is_add=is_add)
+ self.vapi.bridge_domain_add_del_v2(bd_id=bd_id, is_add=is_add)
@classmethod
def arp_req(cls, src_host, host):
def setUp(self):
super(TestL2LearnLimit, self).setUp()
- self.vapi.bridge_domain_add_del(bd_id=1)
- self.vapi.bridge_domain_add_del(bd_id=2)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, flood=1, forward=1, learn=1, uu_flood=1
+ )
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=2, is_add=1, flood=1, forward=1, learn=1, uu_flood=1
+ )
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[0].sw_if_index, bd_id=1)
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[1].sw_if_index, bd_id=2)
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.pg_interfaces[1].sw_if_index, bd_id=2, enable=0
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
- self.vapi.bridge_domain_add_del(bd_id=2, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=2, is_add=0)
if __name__ == "__main__":
"""L2BD test with bridge domain limit"""
self.vapi.want_l2_macs_events(enable_disable=1, learn_limit=1000)
self.vapi.bridge_domain_set_default_learn_limit(4)
- self.vapi.bridge_domain_add_del(bd_id=3)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=3, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
+ )
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[2].sw_if_index, bd_id=3)
self.vapi.bridge_domain_set_learn_limit(2, 5)
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.pg_interfaces[2].sw_if_index, bd_id=3, enable=0
)
- self.vapi.bridge_domain_add_del(is_add=0, bd_id=3)
+ self.vapi.bridge_domain_add_del_v2(is_add=0, bd_id=3)
def setUp(self):
super(TestL2LearnLimitBdEnable, self).setUp()
- self.vapi.bridge_domain_add_del(bd_id=1)
- self.vapi.bridge_domain_add_del(bd_id=2)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
+ )
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=2, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
+ )
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[0].sw_if_index, bd_id=1)
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[1].sw_if_index, bd_id=2)
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.pg_interfaces[1].sw_if_index, bd_id=2, enable=0
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
- self.vapi.bridge_domain_add_del(bd_id=2, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=2, is_add=0)
if __name__ == "__main__":
def setUp(self):
super(TestL2LearnLimitEnable, self).setUp()
- self.vapi.bridge_domain_add_del(bd_id=1)
- self.vapi.bridge_domain_add_del(bd_id=2)
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=1, is_add=1, flood=1, forward=1, uu_flood=1, learn=1
+ )
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=2, is_add=1, flood=1, forward=1, uu_flood=1, learn=1
+ )
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[0].sw_if_index, bd_id=1)
self.vapi.sw_interface_set_l2_bridge(self.pg_interfaces[1].sw_if_index, bd_id=2)
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.pg_interfaces[1].sw_if_index, bd_id=2, enable=0
)
- self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
- self.vapi.bridge_domain_add_del(bd_id=2, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
+ self.vapi.bridge_domain_add_del_v2(bd_id=2, is_add=0)
if __name__ == "__main__":
# Create list of BDs
self.bd_list = []
+ # Create dict of BDs
+ self.bd_map = {}
+
# Create list of deleted BDs
self.bd_deleted_list = []
(Default value = 1)
"""
for b in range(start, start + count):
- self.vapi.bridge_domain_add_del(bd_id=b)
- self.logger.info("Bridge domain ID %d created" % b)
- if self.bd_list.count(b) == 0:
- self.bd_list.append(b)
- if self.bd_deleted_list.count(b) == 1:
- self.bd_deleted_list.remove(b)
+ if b == start:
+ self.vapi.bridge_domain_add_del_v2(
+ bd_id=b, flood=1, uu_flood=1, forward=1, learn=1, is_add=1
+ )
+ bd_id = b
+ else:
+ ret = self.vapi.bridge_domain_add_del_v2(
+ bd_id=0xFFFFFFFF, flood=1, uu_flood=1, forward=1, learn=1, is_add=1
+ )
+ bd_id = ret.bd_id
+ self.logger.info("Bridge domain ID %d created" % bd_id)
+ if self.bd_list.count(bd_id) == 0:
+ self.bd_map[b] = bd_id
+ self.bd_list.append(bd_id)
+ if self.bd_deleted_list.count(bd_id) == 1:
+ self.bd_deleted_list.remove(bd_id)
for j in self.bd_if_range(b):
pg_if = self.pg_interfaces[j]
self.vapi.sw_interface_set_l2_bridge(
- rx_sw_if_index=pg_if.sw_if_index, bd_id=b
+ rx_sw_if_index=pg_if.sw_if_index, bd_id=bd_id
)
self.logger.info(
- "pg-interface %s added to bridge domain ID %d" % (pg_if.name, b)
+ "pg-interface %s added to bridge domain ID %d" % (pg_if.name, bd_id)
)
self.pg_in_bd.append(pg_if)
hosts = self.hosts_by_pg_idx[pg_if.sw_if_index]
(Default value = 1)
"""
for b in range(start, start + count):
+ bd_id = self.bd_map[b]
for j in self.bd_if_range(b):
pg_if = self.pg_interfaces[j]
self.vapi.sw_interface_set_l2_bridge(
- rx_sw_if_index=pg_if.sw_if_index, bd_id=b, enable=0
+ rx_sw_if_index=pg_if.sw_if_index, bd_id=bd_id, enable=0
)
self.pg_in_bd.remove(pg_if)
- self.vapi.bridge_domain_add_del(bd_id=b, is_add=0)
- self.bd_list.remove(b)
- self.bd_deleted_list.append(b)
- self.logger.info("Bridge domain ID %d deleted" % b)
+ self.logger.info(
+ "pg-interface %s removed from bridge domain ID %d"
+ % (pg_if.name, bd_id)
+ )
+ self.vapi.bridge_domain_add_del_v2(bd_id=bd_id, is_add=0)
+ self.bd_map.pop(b)
+ self.bd_list.remove(bd_id)
+ self.bd_deleted_list.append(bd_id)
+ self.logger.info("Bridge domain ID %d deleted" % bd_id)
def create_stream(self, src_if):
"""
self.arp_ufwd = arp_ufwd
def add_vpp_config(self):
- self._test.vapi.bridge_domain_add_del(
+ self._test.vapi.bridge_domain_add_del_v2(
bd_id=self.bd_id,
flood=self.flood,
uu_flood=self.uu_flood,
return self
def remove_vpp_config(self):
- self._test.vapi.bridge_domain_add_del(bd_id=self.bd_id, is_add=0)
+ self._test.vapi.bridge_domain_add_del_v2(bd_id=self.bd_id, is_add=0)
def query_vpp_config(self):
return find_bridge_domain(self._test, self.bd_id)
"bier_table_add_del": {
"is_add": 1,
},
- "bridge_domain_add_del": {
- "flood": 1,
- "uu_flood": 1,
- "forward": 1,
- "learn": 1,
- "is_add": 1,
- },
"bvi_delete": {},
"geneve_add_del_tunnel": {
"mcast_sw_if_index": 4294967295,