aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorMohsin Kazmi <sykazmi@cisco.com>2018-06-29 17:04:23 +0200
committerNeale Ranns <nranns@cisco.com>2018-07-03 11:26:04 +0000
commit6b1cdd3a2050ed9eb79817a01ca311915edf5d9e (patch)
tree1d85c7a53da071c1db06389e0734699437e2d403 /extras
parent208daa1adb8069083b67a36e9f16ac27373fa5bf (diff)
vom: Add cross connect support
Change-Id: Ia316730d8f9fe9836200aa96e0b5fd827dc71c98 Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Diffstat (limited to 'extras')
-rw-r--r--extras/vom/vom/Makefile.am3
-rw-r--r--extras/vom/vom/l2_xconnect.cpp210
-rw-r--r--extras/vom/vom/l2_xconnect.hpp194
-rw-r--r--extras/vom/vom/l2_xconnect_cmds.cpp144
-rw-r--r--extras/vom/vom/l2_xconnect_cmds.hpp147
5 files changed, 698 insertions, 0 deletions
diff --git a/extras/vom/vom/Makefile.am b/extras/vom/vom/Makefile.am
index 2abf3463c8f..6c24d01ce7c 100644
--- a/extras/vom/vom/Makefile.am
+++ b/extras/vom/vom/Makefile.am
@@ -114,6 +114,8 @@ libvom_la_SOURCES = \
ip_unnumbered.cpp \
l2_binding_cmds.cpp \
l2_binding.cpp \
+ l2_xconnect_cmds.cpp \
+ l2_xconnect.cpp \
l3_binding_cmds.cpp \
l3_binding.cpp \
lldp_binding_cmds.cpp \
@@ -204,6 +206,7 @@ vominclude_HEADERS = \
interface_span.hpp \
ip_unnumbered.hpp \
l2_binding.hpp \
+ l2_xconnect.hpp \
l3_binding.hpp \
lldp_binding.hpp \
lldp_global.hpp \
diff --git a/extras/vom/vom/l2_xconnect.cpp b/extras/vom/vom/l2_xconnect.cpp
new file mode 100644
index 00000000000..83d6541fad4
--- /dev/null
+++ b/extras/vom/vom/l2_xconnect.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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/l2_xconnect.hpp"
+#include "vom/l2_xconnect_cmds.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+/**
+ * A DB of all the L2 x-connect Configs
+ */
+singular_db<l2_xconnect::key_t, l2_xconnect> l2_xconnect::m_db;
+
+l2_xconnect::event_handler l2_xconnect::m_evh;
+
+/**
+ * Construct a new object matching the desried state
+ */
+l2_xconnect::l2_xconnect(const interface& east_itf, const interface& west_itf)
+ : m_east_itf(east_itf.singular())
+ , m_west_itf(west_itf.singular())
+ , m_xconnect_east(0)
+ , m_xconnect_west(0)
+{
+}
+
+l2_xconnect::l2_xconnect(const l2_xconnect& o)
+ : m_east_itf(o.m_east_itf)
+ , m_west_itf(o.m_west_itf)
+ , m_xconnect_east(o.m_xconnect_east)
+ , m_xconnect_west(o.m_xconnect_west)
+{
+}
+
+const l2_xconnect::key_t
+l2_xconnect::key() const
+{
+ if (m_east_itf->name() < m_west_itf->name())
+ return (std::make_pair(m_east_itf->key(), m_west_itf->key()));
+ return (std::make_pair(m_west_itf->key(), m_east_itf->key()));
+}
+
+bool
+l2_xconnect::operator==(const l2_xconnect& l) const
+{
+ return ((*m_east_itf == *l.m_east_itf) && (*m_west_itf == *l.m_west_itf));
+}
+
+std::shared_ptr<l2_xconnect>
+l2_xconnect::find(const key_t& key)
+{
+ return (m_db.find(key));
+}
+
+void
+l2_xconnect::sweep()
+{
+ if (m_xconnect_east && m_xconnect_west &&
+ handle_t::INVALID != m_east_itf->handle() &&
+ handle_t::INVALID != m_west_itf->handle()) {
+ HW::enqueue(new l2_xconnect_cmds::unbind_cmd(
+ m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
+ HW::enqueue(new l2_xconnect_cmds::unbind_cmd(
+ m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
+ }
+
+ HW::write();
+}
+
+void
+l2_xconnect::replay()
+{
+ if (m_xconnect_east && m_xconnect_west &&
+ handle_t::INVALID != m_east_itf->handle() &&
+ handle_t::INVALID != m_west_itf->handle()) {
+ HW::enqueue(new l2_xconnect_cmds::bind_cmd(
+ m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
+ HW::enqueue(new l2_xconnect_cmds::bind_cmd(
+ m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
+ }
+}
+
+l2_xconnect::~l2_xconnect()
+{
+ sweep();
+
+ // not in the DB anymore.
+ m_db.release(key(), this);
+}
+
+std::string
+l2_xconnect::to_string() const
+{
+ std::ostringstream s;
+ s << "L2-xconnect:[" << m_east_itf->to_string() << " "
+ << m_west_itf->to_string() << " " << m_xconnect_east.to_string() << " "
+ << m_xconnect_west.to_string() << "]";
+
+ return (s.str());
+}
+
+void
+l2_xconnect::update(const l2_xconnect& desired)
+{
+ /*
+ * the desired state is always that the interface should be created
+ */
+ if (rc_t::OK != m_xconnect_east.rc() && rc_t::OK != m_xconnect_west.rc()) {
+ HW::enqueue(new l2_xconnect_cmds::bind_cmd(
+ m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
+ HW::enqueue(new l2_xconnect_cmds::bind_cmd(
+ m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
+ }
+}
+
+std::shared_ptr<l2_xconnect>
+l2_xconnect::find_or_add(const l2_xconnect& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<l2_xconnect>
+l2_xconnect::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+l2_xconnect::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+l2_xconnect::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "l2-xconnect" }, "L2 xconnects", this);
+}
+
+void
+l2_xconnect::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+l2_xconnect::event_handler::handle_populate(const client_db::key_t& key)
+{
+ /**
+ * This needs to be done here
+ */
+ std::shared_ptr<l2_xconnect_cmds::dump_cmd> cmd =
+ std::make_shared<l2_xconnect_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& x_record : *cmd) {
+ auto& payload = x_record.get_payload();
+
+ VOM_LOG(log_level_t::DEBUG) << "l2-xconnect dump: "
+ << " east-itf: " << payload.rx_sw_if_index
+ << " west-itf: " << payload.tx_sw_if_index;
+
+ std::shared_ptr<interface> east_itf =
+ interface::find(payload.rx_sw_if_index);
+ std::shared_ptr<interface> west_itf =
+ interface::find(payload.tx_sw_if_index);
+
+ if (east_itf && west_itf) {
+ if (east_itf->name() > west_itf->name())
+ continue;
+ l2_xconnect l2_xc(*east_itf, *west_itf);
+ OM::commit(key, l2_xc);
+ }
+ }
+}
+
+dependency_t
+l2_xconnect::event_handler::order() const
+{
+ return (dependency_t::BINDING);
+}
+
+void
+l2_xconnect::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/l2_xconnect.hpp b/extras/vom/vom/l2_xconnect.hpp
new file mode 100644
index 00000000000..0699869bcdb
--- /dev/null
+++ b/extras/vom/vom/l2_xconnect.hpp
@@ -0,0 +1,194 @@
+/*
+ * 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_L2_XCONNECT_H__
+#define __VOM_L2_XCONNECT_H__
+
+#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 Class representing the cross connnect of an L2 interface with another
+ * l2 interface
+ */
+class l2_xconnect : public object_base
+{
+public:
+ /**
+ * Key type for an L2 xconnect in the singular DB
+ */
+ typedef std::pair<interface::key_t, interface::key_t> key_t;
+
+ /**
+ * Construct a new object matching the desried state
+ */
+ l2_xconnect(const interface& east_itf, const interface& west_itf);
+
+ /**
+ * Copy Constructor
+ */
+ l2_xconnect(const l2_xconnect& o);
+
+ /**
+ * Destructor
+ */
+ ~l2_xconnect();
+
+ /**
+ * Return the xconnect's key
+ */
+ const key_t key() const;
+
+ /**
+ * Comparison operator - for UT
+ */
+ bool operator==(const l2_xconnect& l) const;
+
+ /**
+ * Return the 'singular instance' of the L2 config that matches this
+ * object
+ */
+ std::shared_ptr<l2_xconnect> singular() const;
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Dump all l2_xconnects into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * Static function to find the bridge_domain in the model
+ */
+ static std::shared_ptr<l2_xconnect> find(const key_t& key);
+
+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;
+
+ /**
+ * Enque commands to the VPP command Q for the update
+ */
+ void update(const l2_xconnect& obj);
+
+ /**
+ * Find or Add the singular instance in the DB
+ */
+ static std::shared_ptr<l2_xconnect> find_or_add(const l2_xconnect& 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, l2_xconnect>;
+
+ /**
+ * 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 the interface that this L2 layer
+ * represents. By holding the reference here, we can guarantee that
+ * this object will outlive the interface
+ */
+ const std::shared_ptr<interface> m_east_itf;
+
+ /**
+ * A reference counting pointer the Bridge-Domain that this L2
+ * interface is bound to. By holding the reference here, we can
+ * guarantee that this object will outlive the BD.
+ */
+ const std::shared_ptr<interface> m_west_itf;
+
+ /**
+ * HW configuration for the xconnect. The bool representing the
+ * do/don't bind.
+ */
+ HW::item<bool> m_xconnect_east;
+
+ /**
+ * HW configuration for the xconnect. The bool representing the
+ * do/don't bind.
+ */
+ HW::item<bool> m_xconnect_west;
+
+ /**
+ * A map of all L2 interfaces key against the interface's handle_t
+ */
+ static singular_db<key_t, l2_xconnect> m_db;
+};
+
+std::ostream& operator<<(std::ostream& os, const l2_xconnect::key_t& key);
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/l2_xconnect_cmds.cpp b/extras/vom/vom/l2_xconnect_cmds.cpp
new file mode 100644
index 00000000000..dc2c40c3b46
--- /dev/null
+++ b/extras/vom/vom/l2_xconnect_cmds.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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/l2_xconnect_cmds.hpp"
+
+namespace VOM {
+namespace l2_xconnect_cmds {
+bind_cmd::bind_cmd(HW::item<bool>& item,
+ const handle_t& east_itf,
+ const handle_t& west_itf)
+ : rpc_cmd(item)
+ , m_east_itf(east_itf)
+ , m_west_itf(west_itf)
+{
+}
+
+bool
+bind_cmd::operator==(const bind_cmd& other) const
+{
+ return ((m_east_itf == other.m_east_itf) && (m_west_itf == other.m_west_itf));
+}
+
+rc_t
+bind_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.rx_sw_if_index = m_east_itf.value();
+ payload.tx_sw_if_index = m_west_itf.value();
+ payload.enable = 1;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return (rc_t::OK);
+}
+
+std::string
+bind_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "L2-bind: " << m_hw_item.to_string()
+ << " east-itf:" << m_east_itf.to_string()
+ << " west-itf:" << m_west_itf.to_string();
+
+ return (s.str());
+}
+
+unbind_cmd::unbind_cmd(HW::item<bool>& item,
+ const handle_t& east_itf,
+ const handle_t& west_itf)
+ : rpc_cmd(item)
+ , m_east_itf(east_itf)
+ , m_west_itf(west_itf)
+{
+}
+
+bool
+unbind_cmd::operator==(const unbind_cmd& other) const
+{
+ return ((m_east_itf == other.m_east_itf) && (m_west_itf == other.m_west_itf));
+}
+
+rc_t
+unbind_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.rx_sw_if_index = m_east_itf.value();
+ payload.tx_sw_if_index = m_west_itf.value();
+ payload.enable = 0;
+
+ 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 << "L2-unbind: " << m_hw_item.to_string()
+ << " east-itf:" << m_east_itf.to_string()
+ << " west-itf:" << m_west_itf.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 ("l2-xconnect-dump");
+}
+
+}; // namespace l2_xconnect_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/l2_xconnect_cmds.hpp b/extras/vom/vom/l2_xconnect_cmds.hpp
new file mode 100644
index 00000000000..fbb869f025b
--- /dev/null
+++ b/extras/vom/vom/l2_xconnect_cmds.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_L2_XCONNECT_CMDS_H__
+#define __VOM_L2_XCONNECT_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/l2_xconnect.hpp"
+#include "vom/rpc_cmd.hpp"
+
+#include <vapi/l2.api.vapi.hpp>
+#include <vapi/vpe.api.vapi.hpp>
+
+namespace VOM {
+namespace l2_xconnect_cmds {
+
+/**
+ * A functor class that binds L2 configuration to an interface
+ */
+class bind_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Sw_interface_set_l2_xconnect>
+{
+public:
+ /**
+ * Constructor
+ */
+ bind_cmd(HW::item<bool>& item,
+ const handle_t& east_itf,
+ const handle_t& west_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:
+ /**
+ * The east interface for cross_connect
+ */
+ const handle_t m_east_itf;
+
+ /**
+ * The west interface for x-connect
+ */
+ const handle_t m_west_itf;
+};
+
+/**
+ * A cmd class that Unbinds L2 configuration from an interface
+ */
+class unbind_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Sw_interface_set_l2_xconnect>
+{
+public:
+ /**
+ * Constructor
+ */
+ unbind_cmd(HW::item<bool>& item,
+ const handle_t& east_itf,
+ const handle_t& west_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:
+ /**
+ * The east interface for x-connect
+ */
+ const handle_t m_east_itf;
+
+ /**
+ * The west interface for x-connect
+ */
+ const handle_t m_west_itf;
+};
+
+/**
+ * A cmd class that Dumps all the bridge domains
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::L2_xconnect_dump>
+{
+public:
+ /**
+ * 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 l2_xconnect_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif