From a83d9d67113dc75d21a68dba14891ed5e1bea7ec Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 19 Jun 2019 08:30:46 -0700 Subject: Initial Commit of VPP OPflex Renderer Change-Id: I6264537538ad2646cddfa404de38a6bbf3abaa35 Signed-off-by: Neale Ranns --- src/VppManager.cpp | 566 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 566 insertions(+) create mode 100644 src/VppManager.cpp (limited to 'src/VppManager.cpp') 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 +#include +#include + +#include +#include +#include +#include + +#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 + +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(m_runtime); + m_epgm = std::make_shared(m_runtime); + m_sgm = std::make_shared(m_runtime.agent); + m_cm = std::make_shared(m_runtime.agent, m_runtime.id_gen); + m_rdm = std::make_shared(m_runtime); + m_eim = std::make_shared(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(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 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 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> 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: + */ -- cgit 1.2.3-korg