aboutsummaryrefslogtreecommitdiffstats
path: root/src/VppManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VppManager.cpp')
-rw-r--r--src/VppManager.cpp566
1 files changed, 566 insertions, 0 deletions
diff --git a/src/VppManager.cpp b/src/VppManager.cpp
new file mode 100644
index 0000000..2040db4
--- /dev/null
+++ b/src/VppManager.cpp
@@ -0,0 +1,566 @@
+/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
+/*
+ * Copyright (c) 2018 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <boost/asio/ip/host_name.hpp>
+#include <boost/asio/placeholders.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "VppContractManager.hpp"
+#include "VppEndPointGroupManager.hpp"
+#include "VppEndPointManager.hpp"
+#include "VppExtItfManager.hpp"
+#include "VppIdGen.hpp"
+#include "VppLog.hpp"
+#include "VppManager.hpp"
+#include "VppRouteManager.hpp"
+#include "VppSecurityGroupManager.hpp"
+
+#include <opflexagent/EndpointManager.h>
+
+using std::bind;
+using boost::asio::placeholders::error;
+
+namespace VPP
+{
+/**
+ * An owner of the objects VPP learns during boot-up
+ */
+static const std::string BOOT_KEY = "__boot__";
+
+VppManager::VppManager(opflexagent::Agent &agent_,
+ opflexagent::IdGenerator &idGen_,
+ VOM::HW::cmd_q *q,
+ VOM::stat_reader *sr)
+ : m_runtime(agent_, idGen_)
+ , m_task_queue(agent_.getAgentIOService())
+ , stopping(false)
+{
+ VOM::HW::init(q, sr);
+ VOM::OM::init();
+
+ m_runtime.system_name = boost::asio::ip::host_name();
+ m_runtime.agent.getFramework().registerPeerStatusListener(this);
+}
+
+VppManager::~VppManager()
+{
+ VLOGE << "VppManager exiting";
+}
+
+void
+VppManager::start()
+{
+ VLOGI << "start vpp manager; mode:"
+ << (int)m_runtime.agent.getRendererForwardingMode();
+
+ /*
+ * create the update delegators
+ */
+ m_runtime.is_transport_mode =
+ (opflex::ofcore::OFConstants::TRANSPORT_MODE ==
+ m_runtime.agent.getRendererForwardingMode());
+ m_epm = std::make_shared<EndPointManager>(m_runtime);
+ m_epgm = std::make_shared<EndPointGroupManager>(m_runtime);
+ m_sgm = std::make_shared<SecurityGroupManager>(m_runtime.agent);
+ m_cm = std::make_shared<ContractManager>(m_runtime.agent, m_runtime.id_gen);
+ m_rdm = std::make_shared<RouteManager>(m_runtime);
+ m_eim = std::make_shared<ExtItfManager>(m_runtime);
+
+ initPlatformConfig();
+
+ /*
+ * make sure the first event in the task Q is the blocking
+ * connection initiation to VPP ...
+ */
+ m_task_queue.dispatch("init-connection",
+ bind(&VppManager::handleInitConnection, this));
+
+ /**
+ * DO BOOT
+ */
+
+ /**
+ * ... followed by vpp boot dump
+ */
+ m_task_queue.dispatch("boot-dump", bind(&VppManager::handleBoot, this));
+
+ /**
+ * ... followed by uplink configuration
+ */
+ m_task_queue.dispatch("uplink-configure",
+ bind(&VppManager::handleUplinkConfigure, this));
+
+ /**
+ * ... followed by cross connect configuration
+ */
+ m_task_queue.dispatch("xconnect-configure",
+ bind(&VppManager::handleXConnectConfigure, this));
+}
+
+void
+VppManager::handleCloseConnection()
+{
+ if (!hw_connected) return;
+
+ VOM::interface::disable_events();
+ VOM::HW::disconnect();
+
+ VLOGD << "Close VPP connection";
+}
+
+void
+VppManager::handleInitConnection()
+{
+ if (stopping) return;
+
+ VLOGD << "Open VPP connection";
+
+ while (VOM::HW::connect() != true)
+ ;
+
+ hw_connected = true;
+
+ /**
+ * We are insterested in getting interface events from VPP
+ */
+ VOM::interface::enable_events(*this);
+
+ /**
+ * Scehdule a timer to Poll for HW livensss
+ */
+ m_poll_timer.reset(
+ new boost::asio::deadline_timer(m_runtime.agent.getAgentIOService()));
+ m_poll_timer->expires_from_now(boost::posix_time::seconds(3));
+ m_poll_timer->async_wait(bind(&VppManager::handleHWPollTimer, this, error));
+
+ /**
+ * Scehdule a timer for HW stats
+ */
+ m_stats_timer.reset(
+ new boost::asio::deadline_timer(m_runtime.agent.getAgentIOService()));
+ m_stats_timer->expires_from_now(boost::posix_time::seconds(5));
+ m_stats_timer->async_wait(
+ bind(&VppManager::handleHWStatsTimer, this, error));
+}
+
+void
+VppManager::handleUplinkConfigure()
+{
+ if (stopping) return;
+
+ m_runtime.uplink.configure(m_runtime.system_name);
+}
+
+void
+VppManager::handleXConnectConfigure()
+{
+ if (stopping) return;
+
+ m_xconnect.configure_xconnect();
+}
+
+void
+VppManager::handleSweepTimer(const boost::system::error_code &ec)
+{
+ if (stopping || ec) return;
+
+ VLOGI << "sweep boot data";
+
+ /*
+ * the sweep timer was not cancelled, continue with purging old state.
+ */
+ if (hw_connected)
+ VOM::OM::sweep(BOOT_KEY);
+ else if (!stopping)
+ {
+ m_sweep_timer.reset(new boost::asio::deadline_timer(
+ m_runtime.agent.getAgentIOService()));
+ m_sweep_timer->expires_from_now(boost::posix_time::seconds(30));
+ m_sweep_timer->async_wait(
+ bind(&VppManager::handleSweepTimer, this, error));
+ }
+}
+
+void
+VppManager::handleHWPollTimer(const boost::system::error_code &ec)
+{
+ if (stopping || ec) return;
+
+ if (hw_connected && VOM::HW::poll())
+ {
+ /*
+ * re-scehdule a timer to Poll for HW liveness
+ */
+ m_poll_timer.reset(new boost::asio::deadline_timer(
+ m_runtime.agent.getAgentIOService()));
+ m_poll_timer->expires_from_now(boost::posix_time::seconds(3));
+ m_poll_timer->async_wait(
+ bind(&VppManager::handleHWPollTimer, this, error));
+ return;
+ }
+
+ hw_connected = false;
+ VOM::HW::disconnect();
+ VLOGD << "Reconnecting ....";
+ if (VOM::HW::connect())
+ {
+ VLOGD << "Replay the state after reconnecting ...";
+ VOM::OM::replay();
+ hw_connected = true;
+ }
+
+ if (!stopping)
+ {
+ m_poll_timer.reset(new boost::asio::deadline_timer(
+ m_runtime.agent.getAgentIOService()));
+ m_poll_timer->expires_from_now(boost::posix_time::seconds(1));
+ m_poll_timer->async_wait(
+ bind(&VppManager::handleHWPollTimer, this, error));
+ }
+ else
+ {
+ VOM::HW::disconnect();
+ }
+}
+
+void
+VppManager::handleHWStatsTimer(const boost::system::error_code &ec)
+{
+ if (stopping || ec) return;
+
+ VLOGD << "stats reading";
+
+ VOM::HW::read_stats();
+
+ m_stats_timer.reset(
+ new boost::asio::deadline_timer(m_runtime.agent.getAgentIOService()));
+ m_stats_timer->expires_from_now(boost::posix_time::seconds(5));
+ m_stats_timer->async_wait(
+ bind(&VppManager::handleHWStatsTimer, this, error));
+}
+
+void
+VppManager::handleBoot()
+{
+ if (stopping) return;
+
+ /**
+ * Read the state from VPP
+ */
+ VOM::OM::populate(BOOT_KEY);
+}
+
+void
+VppManager::registerModbListeners()
+{
+ // Initialize policy listeners
+ m_runtime.agent.getEndpointManager().registerListener(this);
+ m_runtime.agent.getServiceManager().registerListener(this);
+ m_runtime.agent.getExtraConfigManager().registerListener(this);
+ m_runtime.agent.getPolicyManager().registerListener(this);
+}
+
+void
+VppManager::stop()
+{
+ stopping = true;
+
+ m_runtime.agent.getEndpointManager().unregisterListener(this);
+ m_runtime.agent.getServiceManager().unregisterListener(this);
+ m_runtime.agent.getExtraConfigManager().unregisterListener(this);
+ m_runtime.agent.getPolicyManager().unregisterListener(this);
+
+ if (m_stats_timer)
+ {
+ m_stats_timer->cancel();
+ }
+
+ if (m_sweep_timer)
+ {
+ m_sweep_timer->cancel();
+ }
+
+ if (m_poll_timer)
+ {
+ m_poll_timer->cancel();
+ }
+
+ m_task_queue.dispatch("close-connection",
+ bind(&VppManager::handleCloseConnection, this));
+
+ VLOGD << "stop VppManager";
+}
+
+void
+VppManager::setVirtualRouter(bool virtualRouterEnabled,
+ bool routerAdv,
+ const std::string &virtualRouterMac)
+{
+ if (virtualRouterEnabled)
+ {
+ m_runtime.vr = std::make_shared<VirtualRouter>(virtualRouterMac);
+ }
+}
+
+void
+VppManager::endpointUpdated(const std::string &uuid)
+{
+ if (stopping) return;
+
+ m_task_queue.dispatch(uuid,
+ bind(&EndPointManager::handle_update, m_epm, uuid));
+}
+
+void
+VppManager::externalEndpointUpdated(const std::string &uuid)
+{
+ if (stopping) return;
+
+ m_task_queue.dispatch(
+ uuid, bind(&EndPointManager::handle_external_update, m_epm, uuid));
+}
+
+void
+VppManager::remoteEndpointUpdated(const std::string &uuid)
+{
+ if (stopping) return;
+
+ m_task_queue.dispatch(
+ uuid, bind(&EndPointManager::handle_remote_update, m_epm, uuid));
+}
+
+void
+VppManager::serviceUpdated(const std::string &uuid)
+{
+ if (stopping) return;
+
+ VLOGI << "Service Update Not supported ";
+}
+
+void
+VppManager::rdConfigUpdated(const opflex::modb::URI &rdURI)
+{
+ m_task_queue.dispatch(
+ rdURI.toString(),
+ bind(&RouteManager::handle_domain_update, m_rdm, rdURI));
+}
+
+void
+VppManager::egDomainUpdated(const opflex::modb::URI &egURI)
+{
+ if (stopping) return;
+
+ m_task_queue.dispatch(
+ egURI.toString(),
+ bind(&EndPointGroupManager::handle_update, m_epgm, egURI));
+}
+
+void
+VppManager::domainUpdated(opflex::modb::class_id_t cid,
+ const opflex::modb::URI &domURI)
+{
+ if (stopping) return;
+
+ m_task_queue.dispatch(
+ domURI.toString(),
+ bind(&VppManager::handleDomainUpdate, this, cid, domURI));
+}
+
+void
+VppManager::secGroupSetUpdated(const EndpointListener::uri_set_t &secGrps)
+{
+ if (stopping) return;
+ m_task_queue.dispatch(
+ "setSecGrp:",
+ std::bind(&SecurityGroupManager::handle_set_update, m_sgm, secGrps));
+}
+
+void
+VppManager::secGroupUpdated(const opflex::modb::URI &uri)
+{
+ if (stopping) return;
+ m_task_queue.dispatch(
+ "secGrp:", std::bind(&SecurityGroupManager::handle_update, m_sgm, uri));
+}
+
+void
+VppManager::contractUpdated(const opflex::modb::URI &contractURI)
+{
+ if (stopping) return;
+ m_task_queue.dispatch(
+ contractURI.toString(),
+ bind(&ContractManager::handle_update, m_cm, contractURI));
+}
+
+void
+VppManager::externalInterfaceUpdated(const opflex::modb::URI &uri)
+{
+ if (stopping) return;
+ m_task_queue.dispatch(uri.toString(),
+ bind(&ExtItfManager::handle_update, m_eim, uri));
+}
+
+void
+VppManager::localRouteUpdated(const opflex::modb::URI &uri)
+{
+ if (stopping) return;
+ m_task_queue.dispatch(uri.toString(),
+ bind(&RouteManager::handle_route_update, m_rdm, uri));
+}
+
+void
+VppManager::handle_interface_event(std::vector<VOM::interface::event> e)
+{
+ if (stopping) return;
+ m_task_queue.dispatch("InterfaceEvent",
+ bind(&VppManager::handleInterfaceEvent, this, e));
+}
+
+void
+VppManager::configUpdated(const opflex::modb::URI &configURI)
+{
+ VLOGI << "Config Updated ";
+ if (stopping) return;
+ m_runtime.agent.getAgentIOService().dispatch(
+ bind(&VppManager::handleConfigUpdate, this, configURI));
+}
+
+void
+VppManager::portStatusUpdate(const std::string &portName,
+ uint32_t portNo,
+ bool fromDesc)
+{
+ if (stopping) return;
+ m_runtime.agent.getAgentIOService().dispatch(
+ bind(&VppManager::handlePortStatusUpdate, this, portName, portNo));
+}
+
+void
+VppManager::peerStatusUpdated(const std::string &, int, PeerStatus peerStatus)
+{
+ if (stopping) return;
+}
+
+void
+VppManager::handleDomainUpdate(opflex::modb::class_id_t cid,
+ const opflex::modb::URI &domURI)
+{
+ if (stopping) return;
+
+ VLOGD << "Updating domain: " << domURI;
+
+ switch (cid)
+ {
+ case modelgbp::gbp::RoutingDomain::CLASS_ID:
+ m_rdm->handle_domain_update(domURI);
+ break;
+ case modelgbp::gbp::Subnet::CLASS_ID:
+ if (!modelgbp::gbp::Subnet::resolve(m_runtime.agent.getFramework(),
+ domURI))
+ {
+ VLOGD << "Cleaning up for Subnet: " << domURI;
+ }
+ break;
+ case modelgbp::gbp::BridgeDomain::CLASS_ID:
+ if (!modelgbp::gbp::BridgeDomain::resolve(
+ m_runtime.agent.getFramework(), domURI))
+ {
+ VLOGD << "Cleaning up for BD: " << domURI;
+ m_runtime.id_gen.erase(cid, domURI);
+ }
+ break;
+ case modelgbp::gbp::FloodDomain::CLASS_ID:
+ if (!modelgbp::gbp::FloodDomain::resolve(m_runtime.agent.getFramework(),
+ domURI))
+ {
+ VLOGD << "Cleaning up for FD: " << domURI;
+ m_runtime.id_gen.erase(cid, domURI);
+ }
+ break;
+ case modelgbp::gbp::L3ExternalNetwork::CLASS_ID:
+ if (!modelgbp::gbp::L3ExternalNetwork::resolve(
+ m_runtime.agent.getFramework(), domURI))
+ {
+ VLOGD << "Cleaning up for L3ExtNet: " << domURI;
+ m_runtime.id_gen.erase(cid, domURI);
+ }
+ break;
+ }
+}
+
+void
+VppManager::handleInterfaceEvent(std::vector<VOM::interface::event> events)
+{
+ if (stopping) return;
+
+ for (auto &e : events)
+ {
+ VLOGD << "Interface Event: " << e.itf.to_string()
+ << " state: " << e.state.to_string();
+ }
+}
+
+void
+VppManager::initPlatformConfig()
+{
+ boost::optional<std::shared_ptr<modelgbp::platform::Config>> config =
+ modelgbp::platform::Config::resolve(
+ m_runtime.agent.getFramework(),
+ m_runtime.agent.getPolicyManager().getOpflexDomain());
+}
+
+void
+VppManager::handleConfigUpdate(const opflex::modb::URI &configURI)
+{
+ VLOGD << "Updating platform config " << configURI;
+ if (stopping) return;
+
+ initPlatformConfig();
+
+ /**
+ * Now that we are known to be opflex connected,
+ * Scehdule a timer to sweep the state we read when we first connected
+ * to VPP.
+ */
+ m_sweep_timer.reset(
+ new boost::asio::deadline_timer(m_runtime.agent.getAgentIOService()));
+ m_sweep_timer->expires_from_now(boost::posix_time::seconds(30));
+ m_sweep_timer->async_wait(bind(&VppManager::handleSweepTimer, this, error));
+}
+
+void
+VppManager::handlePortStatusUpdate(const std::string &portName, uint32_t)
+{
+ VLOGD << "Port-status update for " << portName;
+ if (stopping) return;
+}
+
+Uplink &
+VppManager::uplink()
+{
+ return m_runtime.uplink;
+}
+CrossConnect &
+VppManager::crossConnect()
+{
+ return m_xconnect;
+}
+
+}; // namespace opflexagent
+
+/*
+ * Local Variables:
+ * eval: (c-set-style "llvm.org")
+ * End:
+ */