VOM: interface RD update reconfigures L3 bindings
Change-Id: I273e1ea28c3c146e4a88d031c790c1cc56dccf00 Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
This commit is contained in:
@ -149,7 +149,7 @@ interface::cend()
|
||||
void
|
||||
interface::sweep()
|
||||
{
|
||||
if (m_table_id) {
|
||||
if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
|
||||
m_table_id.data() = route::DEFAULT_TABLE;
|
||||
HW::enqueue(
|
||||
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
|
||||
@ -181,7 +181,7 @@ interface::replay()
|
||||
HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
|
||||
}
|
||||
|
||||
if (m_table_id) {
|
||||
if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
|
||||
HW::enqueue(
|
||||
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
|
||||
HW::enqueue(
|
||||
@ -267,32 +267,58 @@ void
|
||||
interface::update(const interface& desired)
|
||||
{
|
||||
/*
|
||||
* the desired state is always that the interface should be created
|
||||
*/
|
||||
* the desired state is always that the interface should be created
|
||||
*/
|
||||
if (rc_t::OK != m_hdl.rc()) {
|
||||
std::queue<cmd*> cmds;
|
||||
HW::enqueue(mk_create_cmd(cmds));
|
||||
}
|
||||
|
||||
/*
|
||||
* change the interface state to that which is deisred
|
||||
*/
|
||||
* change the interface state to that which is deisred
|
||||
*/
|
||||
if (m_state.update(desired.m_state)) {
|
||||
HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
|
||||
}
|
||||
|
||||
/*
|
||||
* change the interface state to that which is deisred
|
||||
*/
|
||||
* change the interface state to that which is deisred
|
||||
*/
|
||||
if (m_l2_address.update(desired.m_l2_address)) {
|
||||
HW::enqueue(new interface_cmds::set_mac_cmd(m_l2_address, m_hdl));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the interface is mapped into a route domain, set VPP's
|
||||
* table ID
|
||||
*/
|
||||
if (!m_table_id && m_rd) {
|
||||
* If the interface is mapped into a route domain, set VPP's
|
||||
* table ID
|
||||
*/
|
||||
if (m_rd != desired.m_rd) {
|
||||
/*
|
||||
* changing route domains. need to remove all L3 bindings, swap the table
|
||||
* then reapply the bindings.
|
||||
*/
|
||||
auto it = l3_binding::cbegin();
|
||||
|
||||
while (it != l3_binding::cend()) {
|
||||
if (it->second.lock()->itf().key() == key())
|
||||
it->second.lock()->sweep();
|
||||
++it;
|
||||
}
|
||||
m_rd = desired.m_rd;
|
||||
m_table_id.update(m_rd ? m_rd->table_id() : route::DEFAULT_TABLE);
|
||||
HW::enqueue(
|
||||
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
|
||||
HW::enqueue(
|
||||
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
|
||||
HW::write();
|
||||
|
||||
it = l3_binding::cbegin();
|
||||
while (it != l3_binding::cend()) {
|
||||
if (it->second.lock()->itf().key() == key())
|
||||
it->second.lock()->replay(); //(*it->second.lock());
|
||||
++it;
|
||||
}
|
||||
} else if (!m_table_id && m_rd) {
|
||||
HW::enqueue(
|
||||
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
|
||||
HW::enqueue(
|
||||
|
@ -540,9 +540,9 @@ private:
|
||||
|
||||
/**
|
||||
* shared pointer to the routeDoamin the interface is in.
|
||||
* NULL is not mapped - i.e. in eht default table
|
||||
* NULL is not mapped - i.e. in the default table
|
||||
*/
|
||||
const std::shared_ptr<route_domain> m_rd;
|
||||
std::shared_ptr<route_domain> m_rd;
|
||||
|
||||
/**
|
||||
* The state of the interface
|
||||
|
@ -71,6 +71,24 @@ l3_binding::prefix() const
|
||||
return (m_pfx);
|
||||
}
|
||||
|
||||
const interface&
|
||||
l3_binding::itf() const
|
||||
{
|
||||
return (*m_itf);
|
||||
}
|
||||
|
||||
l3_binding::const_iterator_t
|
||||
l3_binding::cbegin()
|
||||
{
|
||||
return m_db.cbegin();
|
||||
}
|
||||
|
||||
l3_binding::const_iterator_t
|
||||
l3_binding::cend()
|
||||
{
|
||||
return m_db.cend();
|
||||
}
|
||||
|
||||
std::string
|
||||
l3_binding::to_string() const
|
||||
{
|
||||
@ -85,8 +103,10 @@ void
|
||||
l3_binding::update(const l3_binding& desired)
|
||||
{
|
||||
/*
|
||||
* the desired state is always that the interface should be created
|
||||
*/
|
||||
* no updates for the binding. chaning the interface or the prefix is a change
|
||||
* to the
|
||||
* key, hence a new object
|
||||
*/
|
||||
if (!m_binding) {
|
||||
HW::enqueue(
|
||||
new l3_binding_cmds::bind_cmd(m_binding, m_itf->handle(), m_pfx));
|
||||
|
@ -45,6 +45,19 @@ public:
|
||||
*/
|
||||
~l3_binding();
|
||||
|
||||
/**
|
||||
* The key type for l3_bindings
|
||||
*/
|
||||
typedef std::pair<interface::key_type, route::prefix_t> key_type_t;
|
||||
|
||||
/**
|
||||
* The iterator type
|
||||
*/
|
||||
typedef singular_db<key_type_t, l3_binding>::const_iterator const_iterator_t;
|
||||
|
||||
static const_iterator_t cbegin();
|
||||
static const_iterator_t cend();
|
||||
|
||||
/**
|
||||
* Return the 'singular instance' of the L3-Config that matches this
|
||||
* object
|
||||
@ -57,20 +70,20 @@ public:
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* Return the prefix associated with this L3config
|
||||
* Return the prefix associated with this L3 binding
|
||||
*/
|
||||
const route::prefix_t& prefix() const;
|
||||
|
||||
/**
|
||||
* Return the interface associated with this L3 binding
|
||||
*/
|
||||
const interface& itf() const;
|
||||
|
||||
/**
|
||||
* Dump all l3_bindings into the stream provided
|
||||
*/
|
||||
static void dump(std::ostream& os);
|
||||
|
||||
/**
|
||||
* The key type for l3_bindings
|
||||
*/
|
||||
typedef std::pair<interface::key_type, route::prefix_t> key_type_t;
|
||||
|
||||
/**
|
||||
* Find an singular instance in the DB for the interface passed
|
||||
*/
|
||||
@ -142,6 +155,8 @@ private:
|
||||
*/
|
||||
void replay(void);
|
||||
|
||||
friend class interface;
|
||||
|
||||
/**
|
||||
* A reference counting pointer the interface that this L3 layer
|
||||
* represents. By holding the reference here, we can guarantee that
|
||||
|
@ -1467,4 +1467,91 @@ BOOST_AUTO_TEST_CASE(test_interface_events) {
|
||||
HW::dequeue(itf);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_interface_route_domain_change) {
|
||||
VppInit vi;
|
||||
const std::string rene = "ReneGoscinny";
|
||||
rc_t rc = rc_t::OK;
|
||||
|
||||
/*
|
||||
* Create an interface with two IP addresses
|
||||
*/
|
||||
std::string itf1_name = "host1";
|
||||
interface itf1(itf1_name,
|
||||
interface::type_t::AFPACKET,
|
||||
interface::admin_state_t::UP);
|
||||
HW::item<handle_t> hw_ifh1(2, rc_t::OK);
|
||||
HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
|
||||
HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
|
||||
ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh1, itf1_name));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh1));
|
||||
TRY_CHECK_RC(OM::write(rene, itf1));
|
||||
|
||||
route::prefix_t pfx_10("10.10.10.10", 24);
|
||||
l3_binding *l3_1 = new l3_binding(itf1, pfx_10);
|
||||
HW::item<bool> hw_l3_bind1(true, rc_t::OK);
|
||||
HW::item<bool> hw_l3_unbind1(false, rc_t::OK);
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
|
||||
TRY_CHECK_RC(OM::write(rene, *l3_1));
|
||||
|
||||
route::prefix_t pfx_11("10.10.11.11", 24);
|
||||
l3_binding *l3_2 = new l3_binding(itf1, pfx_11);
|
||||
HW::item<bool> hw_l3_bind2(true, rc_t::OK);
|
||||
HW::item<bool> hw_l3_unbind2(false, rc_t::OK);
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
|
||||
TRY_CHECK_RC(OM::write(rene, *l3_2));
|
||||
|
||||
route_domain rd(1);
|
||||
HW::item<bool> hw_rd_create(true, rc_t::OK);
|
||||
HW::item<bool> hw_rd_delete(false, rc_t::OK);
|
||||
HW::item<route::table_id_t> hw_rd_bind(1, rc_t::OK);
|
||||
HW::item<route::table_id_t> hw_rd_unbind(route::DEFAULT_TABLE, rc_t::OK);
|
||||
ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV4, 1));
|
||||
ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV6, 1));
|
||||
TRY_CHECK_RC(OM::write(rene, rd));
|
||||
|
||||
/*
|
||||
* update the interface to change to a new route-domain
|
||||
* expect that the l3-bindings are removed and readded.
|
||||
*/
|
||||
interface *itf2 = new interface(itf1_name,
|
||||
interface::type_t::AFPACKET,
|
||||
interface::admin_state_t::UP,
|
||||
rd);
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
|
||||
ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV4, hw_ifh1));
|
||||
ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV6, hw_ifh1));
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
|
||||
TRY_CHECK_RC(OM::write(rene, *itf2));
|
||||
|
||||
/*
|
||||
* mve the interface back to the default route-domain
|
||||
*/
|
||||
interface itf3(itf1_name,
|
||||
interface::type_t::AFPACKET,
|
||||
interface::admin_state_t::UP);
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
|
||||
ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV4, hw_ifh1));
|
||||
ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV6, hw_ifh1));
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
|
||||
ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
|
||||
TRY_CHECK_RC(OM::write(rene, itf3));
|
||||
|
||||
delete l3_1;
|
||||
delete l3_2;
|
||||
delete itf2;
|
||||
|
||||
STRICT_ORDER_OFF();
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
|
||||
ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh1));
|
||||
ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh1, itf1_name));
|
||||
ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV4, 1));
|
||||
ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV6, 1));
|
||||
|
||||
TRY_CHECK(OM::remove(rene));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Reference in New Issue
Block a user