VOM: bond: Add support for LACP
Change-Id: I0245263b212142858d3305b0f365d8342912dbb9 Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
This commit is contained in:
Mohsin Kazmi
committed by
Neale Ranns
parent
de91006803
commit
ed76ee24df
@ -78,6 +78,11 @@ libvom_la_SOURCES = \
|
||||
arp_proxy_binding.cpp \
|
||||
arp_proxy_config_cmds.cpp \
|
||||
arp_proxy_config.cpp \
|
||||
bond_group_binding_cmds.cpp \
|
||||
bond_group_binding.cpp \
|
||||
bond_interface_cmds.cpp \
|
||||
bond_interface.cpp \
|
||||
bond_member.cpp \
|
||||
bridge_domain_cmds.cpp \
|
||||
bridge_domain.cpp \
|
||||
bridge_domain_arp_entry.cpp \
|
||||
@ -169,6 +174,9 @@ endif
|
||||
vominclude_HEADERS = \
|
||||
arp_proxy_binding.hpp \
|
||||
arp_proxy_config.hpp \
|
||||
bond_group_binding.hpp \
|
||||
bond_interface.hpp \
|
||||
bond_member.hpp \
|
||||
bridge_domain.hpp \
|
||||
bridge_domain_arp_entry.hpp \
|
||||
bridge_domain_entry.hpp \
|
||||
|
178
src/vpp-api/vom/bond_group_binding.cpp
Normal file
178
src/vpp-api/vom/bond_group_binding.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vom/bond_group_binding.hpp"
|
||||
#include "vom/bond_group_binding_cmds.hpp"
|
||||
|
||||
namespace VOM {
|
||||
|
||||
/**
|
||||
* A DB of all bond interface binding
|
||||
*/
|
||||
singular_db<bond_group_binding::key_t, bond_group_binding>
|
||||
bond_group_binding::m_db;
|
||||
|
||||
bond_group_binding::event_handler bond_group_binding::m_evh;
|
||||
|
||||
bond_group_binding::bond_group_binding(const bond_interface& itf,
|
||||
const enslaved_itf_t& itfs)
|
||||
: m_itf(itf.singular())
|
||||
, m_mem_itfs(itfs)
|
||||
, m_binding(false)
|
||||
{
|
||||
}
|
||||
|
||||
bond_group_binding::bond_group_binding(const bond_group_binding& o)
|
||||
: m_itf(o.m_itf)
|
||||
, m_mem_itfs(o.m_mem_itfs)
|
||||
, m_binding(o.m_binding)
|
||||
{
|
||||
}
|
||||
|
||||
bond_group_binding::~bond_group_binding()
|
||||
{
|
||||
sweep();
|
||||
|
||||
// not in the DB anymore.
|
||||
m_db.release(key(), this);
|
||||
}
|
||||
|
||||
const bond_group_binding::key_t
|
||||
bond_group_binding::key() const
|
||||
{
|
||||
return (m_itf->key() + "-binding");
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::sweep()
|
||||
{
|
||||
|
||||
auto it = m_mem_itfs.cbegin();
|
||||
while (it != m_mem_itfs.cend()) {
|
||||
if (m_binding) {
|
||||
HW::enqueue(
|
||||
new bond_group_binding_cmds::unbind_cmd(m_binding, it->hdl()));
|
||||
}
|
||||
HW::write();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::dump(std::ostream& os)
|
||||
{
|
||||
m_db.dump(os);
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::replay()
|
||||
{
|
||||
auto it = m_mem_itfs.cbegin();
|
||||
while (it != m_mem_itfs.cend()) {
|
||||
if (m_binding) {
|
||||
HW::enqueue(
|
||||
new bond_group_binding_cmds::bind_cmd(m_binding, m_itf->handle(), *it));
|
||||
}
|
||||
HW::write();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
bond_group_binding::to_string() const
|
||||
{
|
||||
auto it = m_mem_itfs.cbegin();
|
||||
std::ostringstream s;
|
||||
s << "bond-interface-binding: " << m_itf->to_string() << " slave-itfs: [";
|
||||
while (it != m_mem_itfs.cend()) {
|
||||
s << " " << it->to_string();
|
||||
++it;
|
||||
}
|
||||
s << "]";
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::update(const bond_group_binding& desired)
|
||||
{
|
||||
/*
|
||||
* the desired state is always that the interface should be created
|
||||
*/
|
||||
auto it = m_mem_itfs.cbegin();
|
||||
while (it != m_mem_itfs.cend()) {
|
||||
if (!m_binding) {
|
||||
HW::enqueue(
|
||||
new bond_group_binding_cmds::bind_cmd(m_binding, m_itf->handle(), *it));
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_group_binding>
|
||||
bond_group_binding::find_or_add(const bond_group_binding& temp)
|
||||
{
|
||||
return (m_db.find_or_add(temp.key(), temp));
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_group_binding>
|
||||
bond_group_binding::singular() const
|
||||
{
|
||||
return find_or_add(*this);
|
||||
}
|
||||
|
||||
bond_group_binding::event_handler::event_handler()
|
||||
{
|
||||
OM::register_listener(this);
|
||||
inspect::register_handler({ "bond-intf-binding" }, "Bond interface binding",
|
||||
this);
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::event_handler::handle_replay()
|
||||
{
|
||||
m_db.replay();
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::event_handler::handle_populate(const client_db::key_t& key)
|
||||
{
|
||||
/*
|
||||
* handle it in interface class
|
||||
*/
|
||||
}
|
||||
|
||||
dependency_t
|
||||
bond_group_binding::event_handler::order() const
|
||||
{
|
||||
/*
|
||||
* We want enslaved interfaces bind to bond after interface
|
||||
* but before anything else.
|
||||
*/
|
||||
return (dependency_t::BOND_BINDING);
|
||||
}
|
||||
|
||||
void
|
||||
bond_group_binding::event_handler::show(std::ostream& os)
|
||||
{
|
||||
m_db.dump(os);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
186
src/vpp-api/vom/bond_group_binding.hpp
Normal file
186
src/vpp-api/vom/bond_group_binding.hpp
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __VOM_BOND_GROUP_BINDING_H__
|
||||
#define __VOM_BOND_GROUP_BINDING_H__
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "vom/bond_interface.hpp"
|
||||
#include "vom/bond_member.hpp"
|
||||
#include "vom/hw.hpp"
|
||||
#include "vom/inspect.hpp"
|
||||
#include "vom/interface.hpp"
|
||||
#include "vom/object_base.hpp"
|
||||
#include "vom/om.hpp"
|
||||
#include "vom/singular_db.hpp"
|
||||
|
||||
namespace VOM {
|
||||
/**
|
||||
* A representation of bond interface binding
|
||||
*/
|
||||
class bond_group_binding : public object_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The KEY can be used to uniquely identify the Bond Binding.
|
||||
* (other choices for keys, like the summation of the properties
|
||||
* of the rules, are rather too cumbersome to use
|
||||
*/
|
||||
typedef std::string key_t;
|
||||
|
||||
/**
|
||||
* The container type for enslaved itfs
|
||||
*/
|
||||
typedef std::set<bond_member> enslaved_itf_t;
|
||||
|
||||
/**
|
||||
* Construct a new object matching the desried state
|
||||
*/
|
||||
bond_group_binding(const bond_interface& itf, const enslaved_itf_t& mem);
|
||||
|
||||
/**
|
||||
* Copy Constructor
|
||||
*/
|
||||
bond_group_binding(const bond_group_binding& o);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~bond_group_binding();
|
||||
|
||||
/**
|
||||
* Return the 'singular' of the bond interface binding that matches this
|
||||
* object
|
||||
*/
|
||||
std::shared_ptr<bond_group_binding> singular() const;
|
||||
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* get the key to this object
|
||||
*/
|
||||
const key_t key() const;
|
||||
|
||||
/**
|
||||
* Dump all bond interface bindings into the stream provided
|
||||
*/
|
||||
static void dump(std::ostream& os);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Class definition for listeners to OM events
|
||||
*/
|
||||
class event_handler : public OM::listener, public inspect::command_handler
|
||||
{
|
||||
public:
|
||||
event_handler();
|
||||
virtual ~event_handler() = default;
|
||||
|
||||
/**
|
||||
* Handle a populate event
|
||||
*/
|
||||
void handle_populate(const client_db::key_t& key);
|
||||
|
||||
/**
|
||||
* Handle a replay event
|
||||
*/
|
||||
void handle_replay();
|
||||
|
||||
/**
|
||||
* Show the object in the Singular DB
|
||||
*/
|
||||
void show(std::ostream& os);
|
||||
|
||||
/**
|
||||
* Get the sortable Id of the listener
|
||||
*/
|
||||
dependency_t order() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* event_handler to register with OM
|
||||
*/
|
||||
static event_handler m_evh;
|
||||
|
||||
/**
|
||||
* Enqueue command to the VPP command Q for the update
|
||||
*/
|
||||
void update(const bond_group_binding& obj);
|
||||
|
||||
/**
|
||||
* Find or add bond interface binding to the OM
|
||||
*/
|
||||
static std::shared_ptr<bond_group_binding> find_or_add(
|
||||
const bond_group_binding& temp);
|
||||
|
||||
/*
|
||||
* It's the OM class that calls singular()
|
||||
*/
|
||||
friend class OM;
|
||||
|
||||
/**
|
||||
* It's the singular_db class that calls replay()
|
||||
*/
|
||||
friend class singular_db<key_t, bond_group_binding>;
|
||||
|
||||
/**
|
||||
* Sweep/reap the object if still stale
|
||||
*/
|
||||
void sweep(void);
|
||||
|
||||
/**
|
||||
* replay the object to create it in hardware
|
||||
*/
|
||||
void replay(void);
|
||||
|
||||
/**
|
||||
* A reference counting pointer to the bond interface.
|
||||
* By holding the reference here, we can guarantee that
|
||||
* this object will outlive the interface
|
||||
*/
|
||||
std::shared_ptr<bond_interface> m_itf;
|
||||
|
||||
/**
|
||||
* A list of member interfaces.
|
||||
*/
|
||||
const enslaved_itf_t m_mem_itfs;
|
||||
|
||||
/**
|
||||
* HW configuration for the binding. The bool representing the
|
||||
* do/don't bind.
|
||||
*/
|
||||
HW::item<bool> m_binding;
|
||||
|
||||
/**
|
||||
* A map of all bond interface bindings keyed against the interface +
|
||||
* "binding".
|
||||
*/
|
||||
static singular_db<key_t, bond_group_binding> m_db;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
||||
|
||||
#endif
|
147
src/vpp-api/vom/bond_group_binding_cmds.cpp
Normal file
147
src/vpp-api/vom/bond_group_binding_cmds.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vom/bond_group_binding_cmds.hpp"
|
||||
|
||||
namespace VOM {
|
||||
namespace bond_group_binding_cmds {
|
||||
|
||||
bind_cmd::bind_cmd(HW::item<bool>& item,
|
||||
const handle_t& bond_itf,
|
||||
const bond_member& itf)
|
||||
: rpc_cmd(item)
|
||||
, m_bond_itf(bond_itf)
|
||||
, m_itf(itf)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
bind_cmd::operator==(const bind_cmd& other) const
|
||||
{
|
||||
return ((m_bond_itf == other.m_bond_itf) && (m_itf == other.m_itf));
|
||||
}
|
||||
|
||||
rc_t
|
||||
bind_cmd::issue(connection& con)
|
||||
{
|
||||
msg_t req(con.ctx(), std::ref(*this));
|
||||
|
||||
auto& payload = req.get_request().get_payload();
|
||||
|
||||
m_itf.to_vpp(payload);
|
||||
payload.bond_sw_if_index = m_bond_itf.value();
|
||||
|
||||
VAPI_CALL(req.execute());
|
||||
|
||||
m_hw_item.set(wait());
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
bind_cmd::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "bond-itf-bind: " << m_hw_item.to_string()
|
||||
<< " bond-itf:" << m_bond_itf.to_string()
|
||||
<< " slave-itf:" << m_itf.hdl().to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
unbind_cmd::unbind_cmd(HW::item<bool>& item, const handle_t& itf)
|
||||
: rpc_cmd(item)
|
||||
, m_itf(itf)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
unbind_cmd::operator==(const unbind_cmd& other) const
|
||||
{
|
||||
return (m_itf == other.m_itf);
|
||||
}
|
||||
|
||||
rc_t
|
||||
unbind_cmd::issue(connection& con)
|
||||
{
|
||||
msg_t req(con.ctx(), std::ref(*this));
|
||||
|
||||
auto& payload = req.get_request().get_payload();
|
||||
payload.sw_if_index = m_itf.value();
|
||||
|
||||
VAPI_CALL(req.execute());
|
||||
|
||||
wait();
|
||||
m_hw_item.set(rc_t::NOOP);
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
unbind_cmd::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "bond-itf-unbind: " << m_hw_item.to_string()
|
||||
<< " slave-itf:" << m_itf.to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
dump_cmd::dump_cmd(const handle_t& hdl)
|
||||
: m_itf(hdl)
|
||||
{
|
||||
}
|
||||
|
||||
dump_cmd::dump_cmd(const dump_cmd& d)
|
||||
: m_itf(d.m_itf)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
dump_cmd::operator==(const dump_cmd& other) const
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
|
||||
rc_t
|
||||
dump_cmd::issue(connection& con)
|
||||
{
|
||||
m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
|
||||
auto& payload = m_dump->get_request().get_payload();
|
||||
payload.sw_if_index = m_itf.value();
|
||||
|
||||
VAPI_CALL(m_dump->execute());
|
||||
|
||||
wait();
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
dump_cmd::to_string() const
|
||||
{
|
||||
return ("bond-slave-itfs-dump");
|
||||
}
|
||||
|
||||
}; // namespace bond_group_binding_cmds
|
||||
}; // namespace VOM
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
138
src/vpp-api/vom/bond_group_binding_cmds.hpp
Normal file
138
src/vpp-api/vom/bond_group_binding_cmds.hpp
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __VOM_BOND_GROUP_BINDING_CMDS_H__
|
||||
#define __VOM_BOND_GROUP_BINDING_CMDS_H__
|
||||
|
||||
#include "vom/bond_group_binding.hpp"
|
||||
#include "vom/dump_cmd.hpp"
|
||||
|
||||
#include <vapi/bond.api.vapi.hpp>
|
||||
|
||||
namespace VOM {
|
||||
namespace bond_group_binding_cmds {
|
||||
/**
|
||||
* A command class that binds the slave interface to the bond interface
|
||||
*/
|
||||
class bind_cmd : public rpc_cmd<HW::item<bool>, rc_t, vapi::Bond_enslave>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
bind_cmd(HW::item<bool>& item,
|
||||
const handle_t& bond_itf,
|
||||
const bond_member& itf);
|
||||
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* Comparison operator - only used for UT
|
||||
*/
|
||||
bool operator==(const bind_cmd& i) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* sw_if_index of bond interface
|
||||
*/
|
||||
const handle_t m_bond_itf;
|
||||
|
||||
/**
|
||||
* member interface of bond group
|
||||
*/
|
||||
const bond_member m_itf;
|
||||
};
|
||||
|
||||
/**
|
||||
* A cmd class that detach slave from a bond interface
|
||||
*/
|
||||
class unbind_cmd : public rpc_cmd<HW::item<bool>, rc_t, vapi::Bond_detach_slave>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
unbind_cmd(HW::item<bool>& item, const handle_t& itf);
|
||||
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* Comparison operator - only used for UT
|
||||
*/
|
||||
bool operator==(const unbind_cmd& i) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* slave interface of bond group
|
||||
*/
|
||||
const handle_t m_itf;
|
||||
};
|
||||
|
||||
/**
|
||||
* A cmd class that Dumps slave itfs
|
||||
*/
|
||||
class dump_cmd : public VOM::dump_cmd<vapi::Sw_interface_slave_dump>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
dump_cmd(const handle_t& itf);
|
||||
dump_cmd(const dump_cmd& d);
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
/**
|
||||
* Comparison operator - only used for UT
|
||||
*/
|
||||
bool operator==(const dump_cmd& i) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The interface to get the addresses for
|
||||
*/
|
||||
const handle_t m_itf;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
||||
|
||||
#endif
|
197
src/vpp-api/vom/bond_interface.cpp
Normal file
197
src/vpp-api/vom/bond_interface.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vom/bond_interface.hpp"
|
||||
#include "vom/bond_group_binding.hpp"
|
||||
#include "vom/bond_group_binding_cmds.hpp"
|
||||
#include "vom/bond_interface_cmds.hpp"
|
||||
|
||||
namespace VOM {
|
||||
/**
|
||||
* Construct a new object matching the desried state
|
||||
*/
|
||||
bond_interface::bond_interface(const std::string& name,
|
||||
admin_state_t state,
|
||||
mode_t mode,
|
||||
lb_t lb)
|
||||
: interface(name, type_t::BOND, state)
|
||||
, m_l2_address(l2_address_t::ZERO)
|
||||
, m_mode(mode)
|
||||
, m_lb(lb)
|
||||
{
|
||||
}
|
||||
|
||||
bond_interface::bond_interface(const std::string& name,
|
||||
admin_state_t state,
|
||||
const l2_address_t& l2_address,
|
||||
mode_t mode,
|
||||
lb_t lb)
|
||||
: interface(name, type_t::BOND, state)
|
||||
, m_l2_address(l2_address)
|
||||
, m_mode(mode)
|
||||
, m_lb(lb)
|
||||
{
|
||||
}
|
||||
|
||||
bond_interface::~bond_interface()
|
||||
{
|
||||
sweep();
|
||||
release();
|
||||
}
|
||||
|
||||
bond_interface::bond_interface(const bond_interface& o)
|
||||
: interface(o)
|
||||
, m_l2_address(o.m_l2_address)
|
||||
, m_mode(o.m_mode)
|
||||
, m_lb(o.m_lb)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_interface>
|
||||
bond_interface::find(const handle_t& hdl)
|
||||
{
|
||||
return std::dynamic_pointer_cast<bond_interface>(interface::find(hdl));
|
||||
}
|
||||
|
||||
void
|
||||
bond_interface::set(bond_interface::mode_t mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
void
|
||||
bond_interface::set(bond_interface::lb_t lb)
|
||||
{
|
||||
m_lb = lb;
|
||||
}
|
||||
|
||||
std::string
|
||||
bond_interface::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
|
||||
s << this->interface::to_string() << " mode:" << m_mode.to_string()
|
||||
<< " lb:" << m_lb.to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
std::queue<cmd*>&
|
||||
bond_interface::mk_create_cmd(std::queue<cmd*>& q)
|
||||
{
|
||||
q.push(new bond_interface_cmds::create_cmd(m_hdl, name(), m_mode, m_lb,
|
||||
m_l2_address));
|
||||
|
||||
return (q);
|
||||
}
|
||||
|
||||
std::queue<cmd*>&
|
||||
bond_interface::mk_delete_cmd(std::queue<cmd*>& q)
|
||||
{
|
||||
q.push(new bond_interface_cmds::delete_cmd(m_hdl));
|
||||
|
||||
return (q);
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_interface>
|
||||
bond_interface::singular() const
|
||||
{
|
||||
return std::dynamic_pointer_cast<bond_interface>(singular_i());
|
||||
}
|
||||
|
||||
std::shared_ptr<interface>
|
||||
bond_interface::singular_i() const
|
||||
{
|
||||
return m_db.find_or_add(name(), *this);
|
||||
}
|
||||
|
||||
void
|
||||
bond_interface::set(handle_t& handle)
|
||||
{
|
||||
this->interface::set(handle);
|
||||
}
|
||||
|
||||
const bond_interface::mode_t bond_interface::mode_t::ROUND_ROBIN(1,
|
||||
"round-robin");
|
||||
const bond_interface::mode_t bond_interface::mode_t::ACTIVE_BACKUP(
|
||||
2,
|
||||
"active-backup");
|
||||
const bond_interface::mode_t bond_interface::mode_t::XOR(3, "xor");
|
||||
const bond_interface::mode_t bond_interface::mode_t::BROADCAST(4, "broadcast");
|
||||
const bond_interface::mode_t bond_interface::mode_t::LACP(5, "lacp");
|
||||
const bond_interface::mode_t bond_interface::mode_t::UNSPECIFIED(0,
|
||||
"unspecified");
|
||||
|
||||
const bond_interface::mode_t
|
||||
bond_interface::mode_t::from_numeric_val(uint8_t numeric)
|
||||
{
|
||||
if (1 == numeric) {
|
||||
return (bond_interface::mode_t::ROUND_ROBIN);
|
||||
}
|
||||
if (2 == numeric) {
|
||||
return (bond_interface::mode_t::ACTIVE_BACKUP);
|
||||
}
|
||||
if (3 == numeric) {
|
||||
return (bond_interface::mode_t::XOR);
|
||||
}
|
||||
if (4 == numeric) {
|
||||
return (bond_interface::mode_t::BROADCAST);
|
||||
}
|
||||
if (5 == numeric) {
|
||||
return (bond_interface::mode_t::LACP);
|
||||
}
|
||||
|
||||
return (bond_interface::mode_t::UNSPECIFIED);
|
||||
}
|
||||
|
||||
bond_interface::mode_t::mode_t(int v, const std::string& s)
|
||||
: enum_base<bond_interface::mode_t>(v, s)
|
||||
{
|
||||
}
|
||||
|
||||
const bond_interface::lb_t bond_interface::lb_t::L2(0, "l2");
|
||||
const bond_interface::lb_t bond_interface::lb_t::L34(1, "l34");
|
||||
const bond_interface::lb_t bond_interface::lb_t::L23(2, "l23");
|
||||
const bond_interface::lb_t bond_interface::lb_t::UNSPECIFIED(~0, "unspecified");
|
||||
|
||||
const bond_interface::lb_t
|
||||
bond_interface::lb_t::from_numeric_val(uint8_t numeric)
|
||||
{
|
||||
if (0 == numeric) {
|
||||
return (bond_interface::lb_t::L2);
|
||||
}
|
||||
if (1 == numeric) {
|
||||
return (bond_interface::lb_t::L34);
|
||||
}
|
||||
if (2 == numeric) {
|
||||
return (bond_interface::lb_t::L23);
|
||||
}
|
||||
|
||||
return (bond_interface::lb_t::UNSPECIFIED);
|
||||
}
|
||||
|
||||
bond_interface::lb_t::lb_t(int v, const std::string& s)
|
||||
: enum_base<bond_interface::lb_t>(v, s)
|
||||
{
|
||||
}
|
||||
}; // namespace VOM
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
197
src/vpp-api/vom/bond_interface.hpp
Normal file
197
src/vpp-api/vom/bond_interface.hpp
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __VOM_BOND_INTERFACE_H__
|
||||
#define __VOM_BOND_INTERFACE_H__
|
||||
|
||||
#include "vom/interface.hpp"
|
||||
|
||||
namespace VOM {
|
||||
/**
|
||||
* A bond-interface. e.g. a bond interface
|
||||
*/
|
||||
class bond_interface : public interface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* A bond interface mode
|
||||
*/
|
||||
struct mode_t : enum_base<mode_t>
|
||||
{
|
||||
/**
|
||||
* Round-Robin bond interface mode
|
||||
*/
|
||||
const static mode_t ROUND_ROBIN;
|
||||
/**
|
||||
* Active-backup bond interface mode
|
||||
*/
|
||||
const static mode_t ACTIVE_BACKUP;
|
||||
/**
|
||||
* XOR bond interface mode
|
||||
*/
|
||||
const static mode_t XOR;
|
||||
/**
|
||||
* Broadcast bond interface mode
|
||||
*/
|
||||
const static mode_t BROADCAST;
|
||||
/**
|
||||
* LACP bond interface mode
|
||||
*/
|
||||
const static mode_t LACP;
|
||||
/**
|
||||
* Unspecificed bond interface mode
|
||||
*/
|
||||
const static mode_t UNSPECIFIED;
|
||||
|
||||
/**
|
||||
* Convert VPP's value of the bond to a mode
|
||||
*/
|
||||
static const mode_t from_numeric_val(uint8_t v);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private constructor taking the value and the string name
|
||||
*/
|
||||
mode_t(int v, const std::string& s);
|
||||
};
|
||||
|
||||
/**
|
||||
* A bond interface load balance
|
||||
*/
|
||||
struct lb_t : enum_base<lb_t>
|
||||
{
|
||||
/**
|
||||
* L2 bond interface lb
|
||||
*/
|
||||
const static lb_t L2;
|
||||
/**
|
||||
* L34 bond interface lb
|
||||
*/
|
||||
const static lb_t L34;
|
||||
/**
|
||||
* L23 bond interface lb
|
||||
*/
|
||||
const static lb_t L23;
|
||||
/**
|
||||
* Unspecificed bond interface lb
|
||||
*/
|
||||
const static lb_t UNSPECIFIED;
|
||||
|
||||
/**
|
||||
* Convert VPP's value of the bond to a lb
|
||||
*/
|
||||
static const lb_t from_numeric_val(uint8_t v);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private constructor taking the value and the string name
|
||||
*/
|
||||
lb_t(int v, const std::string& s);
|
||||
};
|
||||
|
||||
bond_interface(const std::string& name,
|
||||
admin_state_t state,
|
||||
mode_t mode,
|
||||
lb_t lb = lb_t::UNSPECIFIED);
|
||||
|
||||
bond_interface(const std::string& name,
|
||||
admin_state_t state,
|
||||
const l2_address_t& l2_address,
|
||||
mode_t mode,
|
||||
lb_t lb = lb_t::UNSPECIFIED);
|
||||
|
||||
~bond_interface();
|
||||
bond_interface(const bond_interface& o);
|
||||
|
||||
/**
|
||||
* The the singular instance of the bond interface in the DB by handle
|
||||
*/
|
||||
static std::shared_ptr<bond_interface> find(const handle_t& hdl);
|
||||
|
||||
/**
|
||||
* Return the matching 'singular instance' of the BOND interface
|
||||
*/
|
||||
std::shared_ptr<bond_interface> singular() const;
|
||||
|
||||
/**
|
||||
* set the mode
|
||||
*/
|
||||
void set(mode_t mode);
|
||||
|
||||
/**
|
||||
* set the lb
|
||||
*/
|
||||
void set(lb_t lb);
|
||||
|
||||
/**
|
||||
* convert to string
|
||||
*/
|
||||
virtual std::string to_string() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* set the handle
|
||||
*/
|
||||
void set(handle_t& handle);
|
||||
friend class interface_factory;
|
||||
|
||||
private:
|
||||
/**
|
||||
* l2 address on bond interface
|
||||
*/
|
||||
l2_address_t m_l2_address;
|
||||
|
||||
/**
|
||||
* mode on bond interface
|
||||
*/
|
||||
mode_t m_mode;
|
||||
|
||||
/**
|
||||
* lb mode on bond interface
|
||||
*/
|
||||
lb_t m_lb;
|
||||
|
||||
/**
|
||||
* Return the matching 'instance' of the sub-interface
|
||||
* over-ride from the base class
|
||||
*/
|
||||
std::shared_ptr<interface> singular_i() const;
|
||||
|
||||
/**
|
||||
* Virtual functions to construct an interface create commands.
|
||||
*/
|
||||
virtual std::queue<cmd*>& mk_create_cmd(std::queue<cmd*>& cmds);
|
||||
|
||||
/**
|
||||
* Virtual functions to construct an interface delete commands.
|
||||
*/
|
||||
virtual std::queue<cmd*>& mk_delete_cmd(std::queue<cmd*>& cmds);
|
||||
|
||||
/*
|
||||
* It's the OM class that call singular()
|
||||
*/
|
||||
friend class OM;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
||||
|
||||
#endif
|
138
src/vpp-api/vom/bond_interface_cmds.cpp
Normal file
138
src/vpp-api/vom/bond_interface_cmds.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vom/bond_interface_cmds.hpp"
|
||||
|
||||
DEFINE_VAPI_MSG_IDS_BOND_API_JSON;
|
||||
|
||||
namespace VOM {
|
||||
namespace bond_interface_cmds {
|
||||
create_cmd::create_cmd(HW::item<handle_t>& item,
|
||||
const std::string& name,
|
||||
const bond_interface::mode_t& mode,
|
||||
const bond_interface::lb_t& lb,
|
||||
const l2_address_t& l2_address)
|
||||
: interface::create_cmd<vapi::Bond_create>(item, name)
|
||||
, m_mode(mode)
|
||||
, m_lb(lb)
|
||||
, m_l2_address(l2_address)
|
||||
{
|
||||
}
|
||||
|
||||
rc_t
|
||||
create_cmd::issue(connection& con)
|
||||
{
|
||||
msg_t req(con.ctx(), std::ref(*this));
|
||||
|
||||
auto& payload = req.get_request().get_payload();
|
||||
|
||||
if (m_l2_address != l2_address_t::ZERO) {
|
||||
m_l2_address.to_bytes(payload.mac_address, 6);
|
||||
payload.use_custom_mac = 1;
|
||||
}
|
||||
|
||||
payload.mode = m_mode.value();
|
||||
if ((m_mode == bond_interface::mode_t::XOR ||
|
||||
m_mode == bond_interface::mode_t::LACP) &&
|
||||
m_lb != bond_interface::lb_t::UNSPECIFIED)
|
||||
payload.lb = m_lb.value();
|
||||
|
||||
VAPI_CALL(req.execute());
|
||||
|
||||
m_hw_item = wait();
|
||||
if (m_hw_item.rc() == rc_t::OK) {
|
||||
insert_interface();
|
||||
}
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
create_cmd::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "bond-intf-create: " << m_hw_item.to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
delete_cmd::delete_cmd(HW::item<handle_t>& item)
|
||||
: interface::delete_cmd<vapi::Bond_delete>(item)
|
||||
{
|
||||
}
|
||||
|
||||
rc_t
|
||||
delete_cmd::issue(connection& con)
|
||||
{
|
||||
msg_t req(con.ctx(), std::ref(*this));
|
||||
|
||||
auto& payload = req.get_request().get_payload();
|
||||
payload.sw_if_index = m_hw_item.data().value();
|
||||
|
||||
VAPI_CALL(req.execute());
|
||||
|
||||
wait();
|
||||
m_hw_item.set(rc_t::NOOP);
|
||||
remove_interface();
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
delete_cmd::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "bond-itf-delete: " << m_hw_item.to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
dump_cmd::dump_cmd()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
dump_cmd::operator==(const dump_cmd& other) const
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
|
||||
rc_t
|
||||
dump_cmd::issue(connection& con)
|
||||
{
|
||||
m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
|
||||
|
||||
VAPI_CALL(m_dump->execute());
|
||||
|
||||
wait();
|
||||
|
||||
return rc_t::OK;
|
||||
}
|
||||
|
||||
std::string
|
||||
dump_cmd::to_string() const
|
||||
{
|
||||
return ("bond-itf-dump");
|
||||
}
|
||||
} // namespace bond_interface_cmds
|
||||
} // namespace VOM
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
111
src/vpp-api/vom/bond_interface_cmds.hpp
Normal file
111
src/vpp-api/vom/bond_interface_cmds.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __VOM_BOND_INTERFACE_CMDS_H__
|
||||
#define __VOM_BOND_INTERFACE_CMDS_H__
|
||||
|
||||
#include "vom/bond_interface.hpp"
|
||||
#include "vom/dump_cmd.hpp"
|
||||
#include "vom/interface.hpp"
|
||||
#include "vom/rpc_cmd.hpp"
|
||||
|
||||
#include <vapi/bond.api.vapi.hpp>
|
||||
#include <vapi/interface.api.vapi.hpp>
|
||||
|
||||
namespace VOM {
|
||||
namespace bond_interface_cmds {
|
||||
|
||||
/**
|
||||
* A functor class that creates an interface
|
||||
*/
|
||||
class create_cmd : public interface::create_cmd<vapi::Bond_create>
|
||||
{
|
||||
public:
|
||||
create_cmd(HW::item<handle_t>& item,
|
||||
const std::string& name,
|
||||
const bond_interface::mode_t& mode,
|
||||
const bond_interface::lb_t& lb,
|
||||
const l2_address_t& l2_address);
|
||||
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
|
||||
private:
|
||||
const bond_interface::mode_t m_mode;
|
||||
const bond_interface::lb_t m_lb;
|
||||
const l2_address_t m_l2_address;
|
||||
};
|
||||
|
||||
/**
|
||||
* A functor class that deletes a Tap interface
|
||||
*/
|
||||
class delete_cmd : public interface::delete_cmd<vapi::Bond_delete>
|
||||
{
|
||||
public:
|
||||
delete_cmd(HW::item<handle_t>& item);
|
||||
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A cmd class that Dumps all the Vpp Interfaces
|
||||
*/
|
||||
class dump_cmd : public VOM::dump_cmd<vapi::Sw_interface_bond_dump>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
dump_cmd();
|
||||
|
||||
/**
|
||||
* Issue the command to VPP/HW
|
||||
*/
|
||||
rc_t issue(connection& con);
|
||||
/**
|
||||
* convert to string format for debug purposes
|
||||
*/
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* Comparison operator - only used for UT
|
||||
*/
|
||||
bool operator==(const dump_cmd& i) const;
|
||||
};
|
||||
|
||||
}; // namespace bond_interface_cmds
|
||||
}; // namespace VOM
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
||||
#endif
|
130
src/vpp-api/vom/bond_member.cpp
Normal file
130
src/vpp-api/vom/bond_member.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "vom/bond_member.hpp"
|
||||
|
||||
namespace VOM {
|
||||
/**
|
||||
* Construct a new object matching the desried state
|
||||
*/
|
||||
bond_member::bond_member(const interface& itf, mode_t mode, rate_t rate)
|
||||
: m_itf(itf.singular())
|
||||
, m_mode(mode)
|
||||
, m_rate(rate)
|
||||
{
|
||||
}
|
||||
|
||||
bond_member::~bond_member()
|
||||
{
|
||||
}
|
||||
|
||||
bond_member::bond_member(const bond_member& o)
|
||||
: m_itf(o.m_itf)
|
||||
, m_mode(o.m_mode)
|
||||
, m_rate(o.m_rate)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
bond_member::to_vpp(vapi_payload_bond_enslave& bond_enslave) const
|
||||
{
|
||||
bond_enslave.sw_if_index = m_itf->handle().value();
|
||||
bond_enslave.is_passive = (m_mode == mode_t::PASSIVE) ? 1 : 0;
|
||||
bond_enslave.is_long_timeout = (m_rate == rate_t::SLOW) ? 1 : 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
bond_member::to_string() const
|
||||
{
|
||||
std::ostringstream s;
|
||||
|
||||
s << m_itf->to_string() << " mode:" << m_mode.to_string()
|
||||
<< " rate:" << m_rate.to_string();
|
||||
|
||||
return (s.str());
|
||||
}
|
||||
|
||||
bool
|
||||
bond_member::operator<(const bond_member& itf) const
|
||||
{
|
||||
return (m_itf->handle() < itf.m_itf->handle());
|
||||
}
|
||||
|
||||
void
|
||||
bond_member::set(mode_t mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
void
|
||||
bond_member::set(rate_t rate)
|
||||
{
|
||||
m_rate = rate;
|
||||
}
|
||||
|
||||
const handle_t
|
||||
bond_member::hdl(void) const
|
||||
{
|
||||
return m_itf->handle();
|
||||
}
|
||||
|
||||
bool
|
||||
bond_member::operator==(const bond_member& b) const
|
||||
{
|
||||
return ((m_itf == b.m_itf) && (m_mode == b.m_mode) && (m_rate == b.m_rate));
|
||||
}
|
||||
|
||||
const bond_member::mode_t bond_member::mode_t::ACTIVE(0, "active");
|
||||
const bond_member::mode_t bond_member::mode_t::PASSIVE(1, "passive");
|
||||
|
||||
const bond_member::mode_t
|
||||
bond_member::mode_t::from_numeric_val(uint8_t numeric)
|
||||
{
|
||||
if (0 == numeric)
|
||||
return (bond_member::mode_t::ACTIVE);
|
||||
|
||||
return (bond_member::mode_t::PASSIVE);
|
||||
}
|
||||
|
||||
bond_member::mode_t::mode_t(int v, const std::string& s)
|
||||
: enum_base<bond_member::mode_t>(v, s)
|
||||
{
|
||||
}
|
||||
|
||||
const bond_member::rate_t bond_member::rate_t::FAST(0, "fast");
|
||||
const bond_member::rate_t bond_member::rate_t::SLOW(1, "slow");
|
||||
|
||||
const bond_member::rate_t
|
||||
bond_member::rate_t::from_numeric_val(uint8_t numeric)
|
||||
{
|
||||
if (0 == numeric)
|
||||
return (bond_member::rate_t::FAST);
|
||||
|
||||
return (bond_member::rate_t::SLOW);
|
||||
}
|
||||
|
||||
bond_member::rate_t::rate_t(int v, const std::string& s)
|
||||
: enum_base<bond_member::rate_t>(v, s)
|
||||
{
|
||||
}
|
||||
}; // namespace VOM
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
147
src/vpp-api/vom/bond_member.hpp
Normal file
147
src/vpp-api/vom/bond_member.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __VOM_BOND_MEMBER_H__
|
||||
#define __VOM_BOND_MEMBER_H__
|
||||
|
||||
#include "vom/interface.hpp"
|
||||
#include <vapi/bond.api.vapi.hpp>
|
||||
|
||||
namespace VOM {
|
||||
/**
|
||||
* A bond-member. e.g. a bond_member interface
|
||||
*/
|
||||
class bond_member
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* A member interface mode
|
||||
*/
|
||||
struct mode_t : enum_base<mode_t>
|
||||
{
|
||||
/**
|
||||
* Active member interface mode
|
||||
*/
|
||||
const static mode_t ACTIVE;
|
||||
/**
|
||||
* Passive member interface mode
|
||||
*/
|
||||
const static mode_t PASSIVE;
|
||||
|
||||
/**
|
||||
* Convert VPP's value of the bond to a mode
|
||||
*/
|
||||
static const mode_t from_numeric_val(uint8_t v);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private constructor taking the value and the string name
|
||||
*/
|
||||
mode_t(int v, const std::string& s);
|
||||
};
|
||||
|
||||
/**
|
||||
* A member interface rate
|
||||
*/
|
||||
struct rate_t : enum_base<rate_t>
|
||||
{
|
||||
/**
|
||||
* Fast member interface rate
|
||||
*/
|
||||
const static rate_t FAST;
|
||||
/**
|
||||
* SLOW member interface rate
|
||||
*/
|
||||
const static rate_t SLOW;
|
||||
|
||||
/**
|
||||
* Convert VPP's value of the bond to a mode
|
||||
*/
|
||||
static const rate_t from_numeric_val(uint8_t v);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private constructor taking the value and the string name
|
||||
*/
|
||||
rate_t(int v, const std::string& s);
|
||||
};
|
||||
|
||||
bond_member(const interface& itf, mode_t mode, rate_t rate);
|
||||
|
||||
~bond_member();
|
||||
bond_member(const bond_member& o);
|
||||
|
||||
/**
|
||||
* convert to VPP
|
||||
*/
|
||||
void to_vpp(vapi_payload_bond_enslave& bond_enslave) const;
|
||||
|
||||
/**
|
||||
* set the mode
|
||||
*/
|
||||
void set(mode_t mode);
|
||||
|
||||
/**
|
||||
* set the rate
|
||||
*/
|
||||
void set(rate_t rate);
|
||||
|
||||
/**
|
||||
* convert to string
|
||||
*/
|
||||
std::string to_string(void) const;
|
||||
|
||||
/**
|
||||
* less-than operator
|
||||
*/
|
||||
bool operator<(const bond_member& mem_itf) const;
|
||||
|
||||
/**
|
||||
* Get the interface handle
|
||||
*/
|
||||
const handle_t hdl(void) const;
|
||||
|
||||
/**
|
||||
* equality operator
|
||||
*/
|
||||
bool operator==(const bond_member& i) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Refernece conter lock on the parent
|
||||
*/
|
||||
const std::shared_ptr<interface> m_itf;
|
||||
|
||||
/**
|
||||
* passive vs active member
|
||||
*/
|
||||
mode_t m_mode;
|
||||
|
||||
/**
|
||||
* slow 90sec. vs. fast 3sec timeout
|
||||
*/
|
||||
rate_t m_rate;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "mozilla")
|
||||
* End:
|
||||
*/
|
||||
|
||||
#endif
|
@ -14,6 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "vom/interface.hpp"
|
||||
#include "vom/bond_group_binding.hpp"
|
||||
#include "vom/bond_group_binding_cmds.hpp"
|
||||
#include "vom/bond_interface_cmds.hpp"
|
||||
#include "vom/interface_cmds.hpp"
|
||||
#include "vom/interface_factory.hpp"
|
||||
#include "vom/l3_binding_cmds.hpp"
|
||||
@ -464,6 +467,9 @@ interface::dump(std::ostream& os)
|
||||
void
|
||||
interface::event_handler::handle_populate(const client_db::key_t& key)
|
||||
{
|
||||
/*
|
||||
* dump VPP current states
|
||||
*/
|
||||
std::shared_ptr<interface_cmds::vhost_dump_cmd> vcmd =
|
||||
std::make_shared<interface_cmds::vhost_dump_cmd>();
|
||||
|
||||
@ -474,13 +480,10 @@ interface::event_handler::handle_populate(const client_db::key_t& key)
|
||||
std::shared_ptr<interface> vitf =
|
||||
interface_factory::new_vhost_user_interface(
|
||||
vhost_itf_record.get_payload());
|
||||
VOM_LOG(log_level_t::DEBUG) << "dump: " << vitf->to_string();
|
||||
VOM_LOG(log_level_t::DEBUG) << " vhost-dump: " << vitf->to_string();
|
||||
OM::commit(key, *vitf);
|
||||
}
|
||||
|
||||
/*
|
||||
* dump VPP current states
|
||||
*/
|
||||
std::shared_ptr<interface_cmds::dump_cmd> cmd =
|
||||
std::make_shared<interface_cmds::dump_cmd>();
|
||||
|
||||
@ -522,6 +525,60 @@ interface::event_handler::handle_populate(const client_db::key_t& key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_interface_cmds::dump_cmd> bcmd =
|
||||
std::make_shared<bond_interface_cmds::dump_cmd>();
|
||||
|
||||
HW::enqueue(bcmd);
|
||||
HW::write();
|
||||
|
||||
for (auto& bond_itf_record : *bcmd) {
|
||||
std::shared_ptr<bond_interface> bond_itf =
|
||||
interface_factory::new_bond_interface(bond_itf_record.get_payload());
|
||||
|
||||
VOM_LOG(log_level_t::DEBUG) << " bond-dump:" << bond_itf->to_string();
|
||||
|
||||
/*
|
||||
* Write each of the discovered interfaces into the OM,
|
||||
* but disable the HW Command q whilst we do, so that no
|
||||
* commands are sent to VPP
|
||||
*/
|
||||
OM::commit(key, *bond_itf);
|
||||
|
||||
std::shared_ptr<bond_group_binding_cmds::dump_cmd> scmd =
|
||||
std::make_shared<bond_group_binding_cmds::dump_cmd>(
|
||||
bond_group_binding_cmds::dump_cmd(bond_itf->handle()));
|
||||
|
||||
HW::enqueue(scmd);
|
||||
HW::write();
|
||||
|
||||
bond_group_binding::enslaved_itf_t enslaved_itfs;
|
||||
|
||||
for (auto& slave_itf_record : *scmd) {
|
||||
bond_member slave_itf = interface_factory::new_bond_member_interface(
|
||||
slave_itf_record.get_payload());
|
||||
|
||||
VOM_LOG(log_level_t::DEBUG) << " slave-dump:" << slave_itf.to_string();
|
||||
|
||||
/*
|
||||
* Write each of the discovered interfaces into the OM,
|
||||
* but disable the HW Command q whilst we do, so that no
|
||||
* commands are sent to VPP
|
||||
*/
|
||||
// OM::commit(slave_itf->key(), *slave_itf);
|
||||
enslaved_itfs.insert(slave_itf);
|
||||
}
|
||||
|
||||
if (!enslaved_itfs.empty()) {
|
||||
bond_group_binding bid(*bond_itf, enslaved_itfs);
|
||||
/*
|
||||
* Write each of the discovered interfaces into the OM,
|
||||
* but disable the HW Command q whilst we do, so that no
|
||||
* commands are sent to VPP
|
||||
*/
|
||||
OM::commit(key, bid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface::event_handler::event_handler()
|
||||
|
@ -95,6 +95,11 @@ public:
|
||||
*/
|
||||
const static type_t VHOST;
|
||||
|
||||
/**
|
||||
* bond interface type
|
||||
*/
|
||||
const static type_t BOND;
|
||||
|
||||
/**
|
||||
* Convert VPP's name of the interface to a type
|
||||
*/
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "vom/bond_interface.hpp"
|
||||
#include "vom/bond_member.hpp"
|
||||
#include "vom/interface_factory.hpp"
|
||||
#include "vom/sub_interface.hpp"
|
||||
#include "vom/tap_interface.hpp"
|
||||
@ -83,7 +85,7 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd)
|
||||
*/
|
||||
} else if (interface::type_t::VHOST == type) {
|
||||
/*
|
||||
* vhost interfaces already exist in db, look for it using
|
||||
* vhost interface already exist in db, look for it using
|
||||
* sw_if_index
|
||||
*/
|
||||
sp = interface::find(hdl);
|
||||
@ -93,6 +95,10 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd)
|
||||
if (!tag.empty())
|
||||
sp->set(tag);
|
||||
}
|
||||
} else if (interface::type_t::BOND == type) {
|
||||
sp = bond_interface(name, state, l2_address,
|
||||
bond_interface::mode_t::UNSPECIFIED)
|
||||
.singular();
|
||||
} else {
|
||||
sp = interface(name, type, state, tag).singular();
|
||||
sp->set(l2_address);
|
||||
@ -121,6 +127,40 @@ interface_factory::new_vhost_user_interface(
|
||||
sp->set(hdl);
|
||||
return (sp);
|
||||
}
|
||||
|
||||
std::shared_ptr<bond_interface>
|
||||
interface_factory::new_bond_interface(
|
||||
const vapi_payload_sw_interface_bond_details& vd)
|
||||
{
|
||||
std::shared_ptr<bond_interface> sp;
|
||||
std::string name = reinterpret_cast<const char*>(vd.interface_name);
|
||||
handle_t hdl(vd.sw_if_index);
|
||||
bond_interface::mode_t mode =
|
||||
bond_interface::mode_t::from_numeric_val(vd.mode);
|
||||
bond_interface::lb_t lb = bond_interface::lb_t::from_numeric_val(vd.lb);
|
||||
sp = bond_interface::find(hdl);
|
||||
if (sp) {
|
||||
sp->set(mode);
|
||||
sp->set(lb);
|
||||
}
|
||||
return (sp);
|
||||
}
|
||||
|
||||
bond_member
|
||||
interface_factory::new_bond_member_interface(
|
||||
const vapi_payload_sw_interface_slave_details& vd)
|
||||
{
|
||||
std::shared_ptr<bond_member> sp;
|
||||
std::string name = reinterpret_cast<const char*>(vd.interface_name);
|
||||
handle_t hdl(vd.sw_if_index);
|
||||
bond_member::mode_t mode =
|
||||
bond_member::mode_t::from_numeric_val(vd.is_passive);
|
||||
bond_member::rate_t rate =
|
||||
bond_member::rate_t::from_numeric_val(vd.is_long_timeout);
|
||||
std::shared_ptr<interface> itf = interface::find(hdl);
|
||||
bond_member bm(*itf, mode, rate);
|
||||
return (bm);
|
||||
}
|
||||
}; // namespace VOM
|
||||
|
||||
/*
|
||||
|
@ -18,8 +18,10 @@
|
||||
|
||||
#include <vapi/vapi.hpp>
|
||||
|
||||
#include "vom/bond_member.hpp"
|
||||
#include "vom/interface.hpp"
|
||||
|
||||
#include <vapi/bond.api.vapi.hpp>
|
||||
#include <vapi/interface.api.vapi.hpp>
|
||||
#include <vapi/vhost_user.api.vapi.hpp>
|
||||
|
||||
@ -36,6 +38,12 @@ public:
|
||||
|
||||
static std::shared_ptr<interface> new_vhost_user_interface(
|
||||
const vapi_payload_sw_interface_vhost_user_details& vd);
|
||||
|
||||
static std::shared_ptr<bond_interface> new_bond_interface(
|
||||
const vapi_payload_sw_interface_bond_details& vd);
|
||||
|
||||
static bond_member new_bond_member_interface(
|
||||
const vapi_payload_sw_interface_slave_details& vd);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include "vom/interface.hpp"
|
||||
|
||||
namespace VOM {
|
||||
/*
|
||||
* constants and enums
|
||||
@ -28,6 +27,7 @@ const interface::type_t interface::type_t::LOOPBACK(5, "LOOPBACK");
|
||||
const interface::type_t interface::type_t::LOCAL(6, "LOCAL");
|
||||
const interface::type_t interface::type_t::TAP(7, "TAP");
|
||||
const interface::type_t interface::type_t::VHOST(8, "VHOST");
|
||||
const interface::type_t interface::type_t::BOND(9, "Bond");
|
||||
|
||||
const interface::oper_state_t interface::oper_state_t::DOWN(0, "down");
|
||||
const interface::oper_state_t interface::oper_state_t::UP(1, "up");
|
||||
@ -41,6 +41,8 @@ interface::type_t::from_string(const std::string& str)
|
||||
if ((str.find("Virtual") != std::string::npos) ||
|
||||
(str.find("vhost") != std::string::npos)) {
|
||||
return interface::type_t::VHOST;
|
||||
} else if (str.find("Bond") != std::string::npos) {
|
||||
return interface::type_t::BOND;
|
||||
} else if (str.find("Ethernet") != std::string::npos) {
|
||||
return interface::type_t::ETHERNET;
|
||||
} else if (str.find("vxlan") != std::string::npos) {
|
||||
|
@ -52,6 +52,12 @@ enum class dependency_t
|
||||
*/
|
||||
INTERFACE,
|
||||
|
||||
/**
|
||||
* bond group binding is after interfaces but before
|
||||
* anything else
|
||||
*/
|
||||
BOND_BINDING,
|
||||
|
||||
/**
|
||||
* Tunnel or virtual interfaces next
|
||||
*/
|
||||
|
@ -20,6 +20,9 @@
|
||||
#include "vom/om.hpp"
|
||||
#include "vom/interface.hpp"
|
||||
#include "vom/interface_cmds.hpp"
|
||||
#include "vom/bond_interface_cmds.hpp"
|
||||
#include "vom/bond_group_binding.hpp"
|
||||
#include "vom/bond_group_binding_cmds.hpp"
|
||||
#include "vom/l2_binding.hpp"
|
||||
#include "vom/l2_binding_cmds.hpp"
|
||||
#include "vom/l3_binding.hpp"
|
||||
@ -178,6 +181,10 @@ public:
|
||||
{
|
||||
rc = handle_derived<interface_cmds::vhost_create_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(bond_interface_cmds::create_cmd))
|
||||
{
|
||||
rc = handle_derived<bond_interface_cmds::create_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(interface_cmds::loopback_delete_cmd))
|
||||
{
|
||||
rc = handle_derived<interface_cmds::loopback_delete_cmd>(f_exp, f_act);
|
||||
@ -190,6 +197,10 @@ public:
|
||||
{
|
||||
rc = handle_derived<interface_cmds::vhost_delete_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(bond_interface_cmds::delete_cmd))
|
||||
{
|
||||
rc = handle_derived<bond_interface_cmds::delete_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(interface_cmds::state_change_cmd))
|
||||
{
|
||||
rc = handle_derived<interface_cmds::state_change_cmd>(f_exp, f_act);
|
||||
@ -206,6 +217,14 @@ public:
|
||||
{
|
||||
rc = handle_derived<interface_cmds::set_tag>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(bond_group_binding_cmds::bind_cmd))
|
||||
{
|
||||
rc = handle_derived<bond_group_binding_cmds::bind_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(bond_group_binding_cmds::unbind_cmd))
|
||||
{
|
||||
rc = handle_derived<bond_group_binding_cmds::unbind_cmd>(f_exp, f_act);
|
||||
}
|
||||
else if (typeid(*f_exp) == typeid(route_domain_cmds::create_cmd))
|
||||
{
|
||||
rc = handle_derived<route_domain_cmds::create_cmd>(f_exp, f_act);
|
||||
@ -770,6 +789,80 @@ BOOST_AUTO_TEST_CASE(test_bvi) {
|
||||
TRY_CHECK(OM::remove(graham));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bond) {
|
||||
VppInit vi;
|
||||
const std::string cb = "CarolBerg";
|
||||
rc_t rc = rc_t::OK;
|
||||
|
||||
/*
|
||||
* creates the interfaces
|
||||
*/
|
||||
std::string itf1_name = "afpacket1";
|
||||
interface itf1(itf1_name,
|
||||
interface::type_t::AFPACKET,
|
||||
interface::admin_state_t::UP);
|
||||
|
||||
HW::item<handle_t> hw_ifh(2, rc_t::OK);
|
||||
ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
|
||||
|
||||
HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
|
||||
|
||||
TRY_CHECK_RC(OM::write(cb, itf1));
|
||||
|
||||
std::string itf2_name = "afpacket2";
|
||||
interface itf2(itf2_name,
|
||||
interface::type_t::AFPACKET,
|
||||
interface::admin_state_t::UP);
|
||||
|
||||
|
||||
HW::item<handle_t> hw_ifh2(4, rc_t::OK);
|
||||
ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
|
||||
|
||||
TRY_CHECK_RC(OM::write(cb, itf2));
|
||||
|
||||
std::string bond_name = "bond";
|
||||
bond_interface bond_itf(bond_name, interface::admin_state_t::UP,
|
||||
bond_interface::mode_t::LACP);
|
||||
|
||||
HW::item<handle_t> hw_ifh3(6, rc_t::OK);
|
||||
ADD_EXPECT(bond_interface_cmds::create_cmd(hw_ifh3, bond_name,
|
||||
bond_interface::mode_t::LACP, bond_interface::lb_t::L2, l2_address_t::ZERO));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh3));
|
||||
|
||||
TRY_CHECK_RC(OM::write(cb, bond_itf));
|
||||
|
||||
bond_member *bm1 = new bond_member(itf1, bond_member::mode_t::ACTIVE,
|
||||
bond_member::rate_t::SLOW);
|
||||
bond_member *bm2 = new bond_member(itf2, bond_member::mode_t::ACTIVE,
|
||||
bond_member::rate_t::SLOW);
|
||||
bond_group_binding *bgb = new bond_group_binding(bond_itf, {*bm1, *bm2});
|
||||
|
||||
HW::item<bool> bond_hw_bind(true, rc_t::OK);
|
||||
ADD_EXPECT(bond_group_binding_cmds::bind_cmd(bond_hw_bind, hw_ifh3.data(), *bm1));
|
||||
ADD_EXPECT(bond_group_binding_cmds::bind_cmd(bond_hw_bind, hw_ifh3.data(), *bm2));
|
||||
|
||||
TRY_CHECK_RC(OM::write(cb, *bgb));
|
||||
|
||||
delete bgb;
|
||||
delete bm2;
|
||||
delete bm1;
|
||||
|
||||
STRICT_ORDER_OFF();
|
||||
HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
|
||||
ADD_EXPECT(bond_group_binding_cmds::unbind_cmd(bond_hw_bind, hw_ifh.data()));
|
||||
ADD_EXPECT(bond_group_binding_cmds::unbind_cmd(bond_hw_bind, hw_ifh2.data()));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
|
||||
ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh3));
|
||||
ADD_EXPECT(bond_interface_cmds::delete_cmd(hw_ifh3));
|
||||
ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
|
||||
ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
|
||||
|
||||
TRY_CHECK(OM::remove(cb));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bridge) {
|
||||
VppInit vi;
|
||||
const std::string franz = "FranzKafka";
|
||||
|
Reference in New Issue
Block a user