aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohsin Kazmi <sykazmi@cisco.com>2018-03-02 12:31:37 +0100
committerNeale Ranns <nranns@cisco.com>2018-03-27 15:44:19 +0000
commited76ee24dfe76fb9400470a4efb3871acd37cad9 (patch)
tree2684523782279294dc609d03e4838d51bc54e4d4
parentde91006803f823a149b04738dd2bbfe18bfe9791 (diff)
VOM: bond: Add support for LACP
Change-Id: I0245263b212142858d3305b0f365d8342912dbb9 Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
-rw-r--r--src/vpp-api/vom/Makefile.am8
-rw-r--r--src/vpp-api/vom/bond_group_binding.cpp178
-rw-r--r--src/vpp-api/vom/bond_group_binding.hpp186
-rw-r--r--src/vpp-api/vom/bond_group_binding_cmds.cpp147
-rw-r--r--src/vpp-api/vom/bond_group_binding_cmds.hpp138
-rw-r--r--src/vpp-api/vom/bond_interface.cpp197
-rw-r--r--src/vpp-api/vom/bond_interface.hpp197
-rw-r--r--src/vpp-api/vom/bond_interface_cmds.cpp138
-rw-r--r--src/vpp-api/vom/bond_interface_cmds.hpp111
-rw-r--r--src/vpp-api/vom/bond_member.cpp130
-rw-r--r--src/vpp-api/vom/bond_member.hpp147
-rw-r--r--src/vpp-api/vom/interface.cpp65
-rw-r--r--src/vpp-api/vom/interface.hpp5
-rw-r--r--src/vpp-api/vom/interface_factory.cpp42
-rw-r--r--src/vpp-api/vom/interface_factory.hpp8
-rw-r--r--src/vpp-api/vom/interface_types.cpp4
-rw-r--r--src/vpp-api/vom/types.hpp6
-rw-r--r--test/ext/vom_test.cpp93
18 files changed, 1794 insertions, 6 deletions
diff --git a/src/vpp-api/vom/Makefile.am b/src/vpp-api/vom/Makefile.am
index 45c2c1ca7e2..00ab467fe0f 100644
--- a/src/vpp-api/vom/Makefile.am
+++ b/src/vpp-api/vom/Makefile.am
@@ -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 \
diff --git a/src/vpp-api/vom/bond_group_binding.cpp b/src/vpp-api/vom/bond_group_binding.cpp
new file mode 100644
index 00000000000..6958eb386ba
--- /dev/null
+++ b/src/vpp-api/vom/bond_group_binding.cpp
@@ -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:
+ */
diff --git a/src/vpp-api/vom/bond_group_binding.hpp b/src/vpp-api/vom/bond_group_binding.hpp
new file mode 100644
index 00000000000..bfac4881a44
--- /dev/null
+++ b/src/vpp-api/vom/bond_group_binding.hpp
@@ -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
diff --git a/src/vpp-api/vom/bond_group_binding_cmds.cpp b/src/vpp-api/vom/bond_group_binding_cmds.cpp
new file mode 100644
index 00000000000..3ffe9810173
--- /dev/null
+++ b/src/vpp-api/vom/bond_group_binding_cmds.cpp
@@ -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:
+ */
diff --git a/src/vpp-api/vom/bond_group_binding_cmds.hpp b/src/vpp-api/vom/bond_group_binding_cmds.hpp
new file mode 100644
index 00000000000..71c4f9fad64
--- /dev/null
+++ b/src/vpp-api/vom/bond_group_binding_cmds.hpp
@@ -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
diff --git a/src/vpp-api/vom/bond_interface.cpp b/src/vpp-api/vom/bond_interface.cpp
new file mode 100644
index 00000000000..32a00ad7f43
--- /dev/null
+++ b/src/vpp-api/vom/bond_interface.cpp
@@ -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:
+ */
diff --git a/src/vpp-api/vom/bond_interface.hpp b/src/vpp-api/vom/bond_interface.hpp
new file mode 100644
index 00000000000..4584bd14be2
--- /dev/null
+++ b/src/vpp-api/vom/bond_interface.hpp
@@ -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
diff --git a/src/vpp-api/vom/bond_interface_cmds.cpp b/src/vpp-api/vom/bond_interface_cmds.cpp
new file mode 100644
index 00000000000..d59560d4f5f
--- /dev/null
+++ b/src/vpp-api/vom/bond_interface_cmds.cpp
@@ -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:
+ */
diff --git a/src/vpp-api/vom/bond_interface_cmds.hpp b/src/vpp-api/vom/bond_interface_cmds.hpp
new file mode 100644
index 00000000000..06a8ac15009
--- /dev/null
+++ b/src/vpp-api/vom/bond_interface_cmds.hpp
@@ -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
diff --git a/src/vpp-api/vom/bond_member.cpp b/src/vpp-api/vom/bond_member.cpp
new file mode 100644
index 00000000000..f1a27b3d1c6
--- /dev/null
+++ b/src/vpp-api/vom/bond_member.cpp
@@ -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:
+ */
diff --git a/src/vpp-api/vom/bond_member.hpp b/src/vpp-api/vom/bond_member.hpp
new file mode 100644
index 00000000000..066933b74d7
--- /dev/null
+++ b/src/vpp-api/vom/bond_member.hpp
@@ -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
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp
index f943bf4a616..f323727b052 100644
--- a/src/vpp-api/vom/interface.cpp
+++ b/src/vpp-api/vom/interface.cpp
@@ -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()
diff --git a/src/vpp-api/vom/interface.hpp b/src/vpp-api/vom/interface.hpp
index b0aeb739fdb..0099bde42ba 100644
--- a/src/vpp-api/vom/interface.hpp
+++ b/src/vpp-api/vom/interface.hpp
@@ -96,6 +96,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
*/
static type_t from_string(const std::string& str);
diff --git a/src/vpp-api/vom/interface_factory.cpp b/src/vpp-api/vom/interface_factory.cpp
index ef26c3293d3..417f4775a7a 100644
--- a/src/vpp-api/vom/interface_factory.cpp
+++ b/src/vpp-api/vom/interface_factory.cpp
@@ -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
/*
diff --git a/src/vpp-api/vom/interface_factory.hpp b/src/vpp-api/vom/interface_factory.hpp
index a2c81993550..dda52752352 100644
--- a/src/vpp-api/vom/interface_factory.hpp
+++ b/src/vpp-api/vom/interface_factory.hpp
@@ -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);
};
};
diff --git a/src/vpp-api/vom/interface_types.cpp b/src/vpp-api/vom/interface_types.cpp
index 6d3dcae57f2..2e7eee3ce7c 100644
--- a/src/vpp-api/vom/interface_types.cpp
+++ b/src/vpp-api/vom/interface_types.cpp
@@ -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) {
diff --git a/src/vpp-api/vom/types.hpp b/src/vpp-api/vom/types.hpp
index 8543a6604bb..302e5ee47b1 100644
--- a/src/vpp-api/vom/types.hpp
+++ b/src/vpp-api/vom/types.hpp
@@ -53,6 +53,12 @@ enum class dependency_t
INTERFACE,
/**
+ * bond group binding is after interfaces but before
+ * anything else
+ */
+ BOND_BINDING,
+
+ /**
* Tunnel or virtual interfaces next
*/
TUNNEL,
diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp
index 435d8fdf9c4..29738e2437e 100644
--- a/test/ext/vom_test.cpp
+++ b/test/ext/vom_test.cpp
@@ -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";