aboutsummaryrefslogtreecommitdiffstats
path: root/src/VppRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VppRenderer.cpp')
-rw-r--r--src/VppRenderer.cpp325
1 files changed, 325 insertions, 0 deletions
diff --git a/src/VppRenderer.cpp b/src/VppRenderer.cpp
new file mode 100644
index 0000000..b892595
--- /dev/null
+++ b/src/VppRenderer.cpp
@@ -0,0 +1,325 @@
+/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
+/*
+ * Implementation for VPPRenderer class
+ *
+ * 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 <boost/asio/placeholders.hpp>
+
+#include <opflexagent/logging.h>
+
+#include <vom/stat_reader.hpp>
+
+#include "VppLogHandler.hpp"
+#include "VppRenderer.hpp"
+
+namespace VPP
+{
+
+using boost::asio::placeholders::error;
+using boost::property_tree::ptree;
+using opflex::ofcore::OFFramework;
+using std::bind;
+
+VppRendererPlugin::VppRendererPlugin()
+{
+}
+
+std::unordered_set<std::string>
+VppRendererPlugin::getNames() const
+{
+ return {"vpp"};
+}
+
+opflexagent::Renderer *
+VppRendererPlugin::create(opflexagent::Agent &agent) const
+{
+ IdGenerator *idGen = new IdGenerator();
+ VOM::HW::cmd_q *vppQ = new VOM::HW::cmd_q();
+ VOM::stat_reader *vppSR = new stat_reader();
+ VppManager *vppManager = new VppManager(agent, *idGen, vppQ, vppSR);
+ return new VppRenderer(agent, *idGen, vppManager);
+}
+
+VPP::LogHandler vppLogHandler;
+
+static VOM::log_level_t
+agentLevelToVom(opflexagent::LogLevel level)
+{
+ switch (level)
+ {
+ case opflexagent::DEBUG:
+ return (VOM::log_level_t::DEBUG);
+ case opflexagent::INFO:
+ return (VOM::log_level_t::INFO);
+ case opflexagent::WARNING:
+ return (VOM::log_level_t::WARNING);
+ case opflexagent::ERROR:
+ return (VOM::log_level_t::ERROR);
+ case opflexagent::FATAL:
+ return (VOM::log_level_t::CRITICAL);
+ }
+ return (VOM::log_level_t::INFO);
+}
+
+VppRenderer::VppRenderer(opflexagent::Agent &agent,
+ IdGenerator &idGen,
+ VppManager *vppManager)
+ : Renderer(agent)
+ , idGen(idGen)
+ , vppManager(vppManager)
+ , tunnelEpManager(&agent)
+ , started(false)
+{
+ LOG(INFO) << "Vpp Renderer";
+
+ /*
+ * Register the call back handler for VOM logging and set the level
+ * according to the agent's settings
+ */
+ VOM::logger().set(agentLevelToVom(opflexagent::logLevel));
+ VOM::logger().set(&vppLogHandler);
+}
+
+VppRenderer::~VppRenderer()
+{
+ delete vppManager;
+}
+
+void
+VppRenderer::setProperties(const boost::property_tree::ptree &properties)
+{
+ // Set configuration from property tree. This configuration will
+ // be from a "renderers": { "vpp" { } } block from the agent
+ // configuration. Multiple calls are possible; later calls are
+ // merged with prior calls, overwriting any previously-set values.
+ LOG(opflexagent::INFO) << "Setting configuration for vpp renderer";
+ static const std::string ENCAP_VXLAN("encap.vxlan");
+ static const std::string ENCAP_IVXLAN("encap.ivxlan");
+ static const std::string ENCAP_VLAN("encap.vlan");
+ static const std::string UPLINK_IFACE("uplink-iface");
+ static const std::string UPLINK_SLAVES("uplink-slaves");
+ static const std::string UPLINK_VLAN("uplink-vlan");
+ static const std::string DHCP_OPTIONS("dhcp-opt");
+ static const std::string ENCAP_IFACE("encap-iface");
+ static const std::string REMOTE_IP("remote-ip");
+ static const std::string REMOTE_PORT("remote-port");
+ static const std::string VIRTUAL_ROUTER("forwarding"
+ ".virtual-router.enabled");
+ static const std::string VIRTUAL_ROUTER_MAC("forwarding"
+ ".virtual-router.mac");
+ static const std::string VIRTUAL_ROUTER_RA("forwarding.virtual-router"
+ ".ipv6.router-advertisement");
+ static const std::string CROSS_CONNECT("x-connect");
+ static const std::string EAST("east");
+ static const std::string WEST("west");
+ static const std::string EIFACE("iface");
+ static const std::string EVLAN("vlan");
+ static const std::string EIP("ip-address");
+ static const std::string ETAG_REWRITE("tag-rewrite");
+ static const std::string WIFACE("iface");
+ static const std::string WVLAN("vlan");
+ static const std::string WIP("ip-address");
+
+ auto vxlan = properties.get_child_optional(ENCAP_VXLAN);
+ auto ivxlan = properties.get_child_optional(ENCAP_IVXLAN);
+ auto vlan = properties.get_child_optional(ENCAP_VLAN);
+ auto vr = properties.get_child_optional(VIRTUAL_ROUTER);
+ auto x_connect = properties.get_child_optional(CROSS_CONNECT);
+
+ if (vlan)
+ {
+ uplinkIface = vlan.get().get<std::string>(UPLINK_IFACE, "");
+ uplinkVlan = vlan.get().get<uint16_t>(UPLINK_VLAN, 0);
+ vppManager->uplink().set(uplinkIface,
+ uplinkVlan,
+ vlan.get().get<std::string>(ENCAP_IFACE, ""));
+ auto slaves = vlan.get().get_child_optional(UPLINK_SLAVES);
+
+ if (slaves)
+ {
+ for (auto s : slaves.get())
+ {
+ vppManager->uplink().insert_slave_ifaces(s.second.data());
+ LOG(opflexagent::INFO) << s.second.data();
+ }
+ }
+ auto dhcp_options = vlan.get().get_child_optional(DHCP_OPTIONS);
+ if (dhcp_options)
+ {
+ for (auto d : dhcp_options.get())
+ {
+ vppManager->uplink().insert_dhcp_options(d.second.data());
+ LOG(opflexagent::INFO) << d.second.data();
+ }
+ }
+ encapType = encapTypeVlan;
+ }
+ else if (vxlan)
+ {
+ boost::asio::ip::address remote_ip;
+ boost::system::error_code ec;
+
+ remote_ip = boost::asio::ip::address::from_string(
+ vxlan.get().get<std::string>(REMOTE_IP, ""));
+
+ if (ec)
+ {
+ LOG(ERROR) << "Invalid tunnel destination IP: "
+ << vxlan.get().get<std::string>(REMOTE_IP, "") << ": "
+ << ec.message();
+ }
+ else
+ {
+ uplinkIface = vxlan.get().get<std::string>(UPLINK_IFACE, "");
+ uplinkVlan = vxlan.get().get<uint16_t>(UPLINK_VLAN, 0);
+ vppManager->uplink().set(
+ uplinkIface,
+ uplinkVlan,
+ vxlan.get().get<std::string>(ENCAP_IFACE, ""),
+ remote_ip,
+ vxlan.get().get<uint16_t>(REMOTE_PORT, 4789));
+ auto slaves = properties.get_child_optional(UPLINK_SLAVES);
+ }
+ encapType = encapTypeVxlan;
+ }
+ else if (ivxlan)
+ {
+ uplinkIface = ivxlan.get().get<std::string>(UPLINK_IFACE, "");
+ uplinkVlan = ivxlan.get().get<uint16_t>(UPLINK_VLAN, 0);
+ vppManager->uplink().set(
+ uplinkIface,
+ uplinkVlan,
+ ivxlan.get().get<std::string>(ENCAP_IFACE, ""));
+ auto slaves = ivxlan.get().get_child_optional(UPLINK_SLAVES);
+
+ if (slaves)
+ {
+ for (auto s : slaves.get())
+ {
+ vppManager->uplink().insert_slave_ifaces(s.second.data());
+ LOG(opflexagent::INFO) << s.second.data();
+ }
+ }
+ auto dhcp_options = ivxlan.get().get_child_optional(DHCP_OPTIONS);
+ if (dhcp_options)
+ {
+ for (auto d : dhcp_options.get())
+ {
+ vppManager->uplink().insert_dhcp_options(d.second.data());
+ LOG(opflexagent::INFO) << d.second.data();
+ }
+ }
+ encapType = encapTypeIvxlan;
+ }
+ if (vr)
+ {
+ vppManager->setVirtualRouter(
+ vr.get().get<bool>(VIRTUAL_ROUTER, true),
+ vr.get().get<bool>(VIRTUAL_ROUTER_RA, true),
+ vr.get().get<std::string>(VIRTUAL_ROUTER_MAC, "00:22:bd:f8:19:ff"));
+ }
+
+ if (x_connect)
+ {
+ for (auto x : x_connect.get())
+ {
+ auto east = x.second.get_child_optional(EAST);
+ auto west = x.second.get_child_optional(WEST);
+ if (east && west)
+ {
+ std::string ename = east.get().get<std::string>(EIFACE, "");
+ uint16_t evlan = east.get().get<uint16_t>(EVLAN, 0);
+ std::string eip = east.get().get<std::string>(EIP, "0.0.0.0");
+ std::string etag_rewrite =
+ east.get().get<std::string>(ETAG_REWRITE, "");
+ std::string wname = west.get().get<std::string>(WIFACE, "");
+ uint16_t wvlan = west.get().get<uint16_t>(WVLAN, 0);
+ std::string wip = west.get().get<std::string>(WIP, "0.0.0.0");
+ LOG(opflexagent::DEBUG) << "east:[" << ename << " , " << evlan
+ << " , " << eip << " , " << etag_rewrite
+ << "]";
+ LOG(opflexagent::DEBUG) << "west:[" << wname << " , " << wvlan
+ << " , " << wip << "]";
+ if (!ename.empty() && !wname.empty())
+ {
+ VPP::CrossConnect::xconnect_t xcon_east(
+ ename, evlan, eip, etag_rewrite);
+ VPP::CrossConnect::xconnect_t xcon_west(wname, wvlan, wip);
+ vppManager->crossConnect().insert_xconnect(
+ std::make_pair(xcon_east, xcon_west));
+ }
+ }
+ }
+ }
+
+ /*
+ * Are we opening an inspection socket?
+ */
+ auto inspect = properties.get<std::string>("inspect-socket", "");
+
+ if (inspect.length())
+ {
+ inspector.reset(new VppInspect(inspect));
+ }
+}
+
+void
+VppRenderer::start()
+{
+ // Called during agent startup
+ if (started) return;
+ started = true;
+ vppManager->start();
+ vppManager->registerModbListeners();
+ if ((encapType == encapTypeVxlan) || (encapType == encapTypeIvxlan))
+ {
+ tunnelEpManager.setUplinkIface(uplinkIface);
+ tunnelEpManager.setUplinkVlan(uplinkVlan);
+ tunnelEpManager.setParentRenderer(this);
+ tunnelEpManager.start();
+ }
+ LOG(opflexagent::INFO) << "Starting vpp renderer plugin";
+}
+
+void
+VppRenderer::stop()
+{
+ // Called during agent shutdown
+ if (!started) return;
+ started = false;
+ LOG(opflexagent::INFO) << "Stopping vpp renderer plugin";
+ if ((encapType == encapTypeVxlan) || (encapType == encapTypeIvxlan))
+ {
+ tunnelEpManager.stop();
+ }
+ vppManager->stop();
+}
+
+boost::asio::ip::address VppRenderer::getUplinkAddress()
+{
+ const boost::asio::ip::address addr =
+ vppManager->uplink().local_address();
+ return addr;
+}
+
+std::string
+VppRenderer::getUplinkMac()
+{
+ return vppManager->uplink().uplink_l2_address();
+}
+
+} // namespace VPP
+
+extern "C" const opflexagent::RendererPlugin *
+init_renderer_plugin()
+{
+ // Return a plugin implementation, which can ini
+ static const VPP::VppRendererPlugin vppPlugin;
+
+ return &vppPlugin;
+}