Skip to content

Commit

Permalink
Changes for local network policies
Browse files Browse the repository at this point in the history
- Implemented on top of Genie changes from Tom
- Add the following classes
    class[gbpe/LocalL24Classifier]
    class[gbp/LocalSecGroup]
    class[gbp/LocalSecGroupSubject]
    class[gbp/LocalSecGroupRule]
    class[gbp/LocalAllowDenyAction]
    class[gbp/LocalSubnets]
    class[gbp/LocalSubnet]
- These are enabled via opflex.enable-local-netpol config variable
  and read from .netpol files in the netpol-sources.filesystem
  thats configured in the opflex config (Default localnetpol is disabled)
- Each security group will contain a .netpol json file containing
  corresponding netpol
- The implemenation will read these files and update the MODB
  via the read that then triggers callbacks. These will be the old
  callbacks in the policymanager that have been extended to also
  process the Local network policies.
- Add new classtype LOCAL_POLICY to differentiate between POLICY that
  is always assumed as remote and would trigger a resolveObj
- extend deserialize to support local ObjectInstances, currently it
  assumes its only called for remote ones.
- add LocalAllowDenyAction on startup since this is the only MO
  shared across netpols and should never be deleted. This is added
  in common tenant and one is created at startup.
- Implement delete by saving the notifs during add. File based
  delete will not work without some state because the file
  notification happens after the file is deleted.

Signed-off-by: Madhu Challa <challa@gmail.com>
  • Loading branch information
mchalla committed Jun 25, 2024
1 parent 5e6f2cb commit 2e7a124
Show file tree
Hide file tree
Showing 30 changed files with 775 additions and 101 deletions.
2 changes: 2 additions & 0 deletions agent-ovs/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ libopflex_agent_la_include_HEADERS = \
lib/include/opflexagent/Snat.h \
lib/include/opflexagent/SnatSource.h \
lib/include/opflexagent/SnatListener.h \
lib/include/opflexagent/FSNetpolSource.h \
lib/include/opflexagent/FSPacketDropLogConfigSource.h \
lib/include/opflexagent/PacketDropLogConfig.h \
lib/include/opflexagent/Faults.h \
Expand Down Expand Up @@ -228,6 +229,7 @@ libopflex_agent_la_SOURCES = \
lib/Snat.cpp \
lib/SnatManager.cpp \
lib/SnatSource.cpp \
lib/FSNetpolSource.cpp \
lib/FSPacketDropLogConfigSource.cpp \
lib/AgentPrometheusManager.cpp

Expand Down
30 changes: 29 additions & 1 deletion agent-ovs/lib/Agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <opflexagent/FSLearningBridgeSource.h>
#include <opflexagent/FSExternalEndpointSource.h>
#include <opflexagent/FSSnatSource.h>
#include <opflexagent/FSNetpolSource.h>
#include <opflexagent/FSPacketDropLogConfigSource.h>
#include <opflexagent/logging.h>

Expand Down Expand Up @@ -78,7 +79,8 @@ Agent::Agent(OFFramework& framework_, const LogParams& _logParams)
prometheusExposeEpSvcNan(false),
behaviorL34FlowsWithoutSubnet(true),
logParams(_logParams),
startupPolicyEnabled(false) {
startupPolicyEnabled(false),
localNetpolEnabled(false) {
std::random_device rng;
std::mt19937 urng(rng());
uuid = to_string(basic_random_generator<std::mt19937>(urng)());
Expand Down Expand Up @@ -149,6 +151,7 @@ void Agent::setProperties(const boost::property_tree::ptree& properties) {
static const std::string ENDPOINT_SOURCE_MODEL_LOCAL("endpoint-sources.model-local");
static const std::string SERVICE_SOURCE_PATH("service-sources.filesystem");
static const std::string SNAT_SOURCE_PATH("snat-sources.filesystem");
static const std::string NETPOL_SOURCE_PATH("netpol-sources.filesystem");
static const std::string DROP_LOG_CFG_SOURCE_FSPATH("drop-log-config-sources.filesystem");
static const std::string FAULT_SOURCE_FSPATH("host-agent-fault-sources.filesystem");
static const std::string PACKET_EVENT_NOTIF_SOCK("packet-event-notif.socket-name");
Expand Down Expand Up @@ -194,6 +197,7 @@ void Agent::setProperties(const boost::property_tree::ptree& properties) {
static const std::string OPFLEX_POLICY_FILE("opflex.startup.policy-file");
static const std::string OPFLEX_LOCAL_RESOLVE_AFTER_CONNECTION("opflex.startup.resolve-aft-conn");
static const std::string OPFLEX_STARTUP_POLICY_DURATION("opflex.startup.policy-duration");
static const std::string OPFLEX_ENABLE_LOCAL_NETPOL("opflex.enable-local-netpol");

// set feature flags to true
clearFeatureFlags();
Expand Down Expand Up @@ -327,6 +331,13 @@ void Agent::setProperties(const boost::property_tree::ptree& properties) {
snatSourcePaths.insert(v.second.data());
}

optional<const ptree&> netpolSource =
properties.get_child_optional(NETPOL_SOURCE_PATH);
if (netpolSource) {
for (const ptree::value_type &v : netpolSource.get())
netpolSourcePaths.insert(v.second.data());
}

optional<const ptree&> dropLogCfgSrc =
properties.get_child_optional(DROP_LOG_CFG_SOURCE_FSPATH);

Expand Down Expand Up @@ -556,6 +567,13 @@ void Agent::setProperties(const boost::property_tree::ptree& properties) {
localResolveAftConn = lResolveAftConn.get();
LOG(INFO) << "Startup policy resolve after connection set to " << localResolveAftConn;
}

optional<bool> enableLocalNetpol =
properties.get_optional<bool>(OPFLEX_ENABLE_LOCAL_NETPOL);
if (enableLocalNetpol && enableLocalNetpol.get()) {
localNetpolEnabled = true;
LOG(INFO) << "Local Network Policy is enabled";
}
}

void Agent::applyProperties() {
Expand All @@ -568,13 +586,16 @@ void Agent::applyProperties() {
policyManager.setOpflexDomain(opflexDomain.get());
}

policyManager.configLocalNetpol(localNetpolEnabled);
if (endpointSourceFSPaths.empty() &&
endpointSourceModelLocalNames.empty())
LOG(ERROR) << "No endpoint sources found in configuration.";
if (serviceSourcePaths.empty())
LOG(INFO) << "No service sources found in configuration.";
if (snatSourcePaths.empty())
LOG(INFO) << "No SNAT sources found in configuration.";
if (netpolSourcePaths.empty())
LOG(INFO) << "No Local Network Policy sources found in configuration.";
if (opflexPeers.empty())
LOG(ERROR) << "No Opflex peers found in configuration";
if (renderers.empty())
Expand Down Expand Up @@ -696,6 +717,13 @@ void Agent::start() {
new FSSnatSource(&snatManager, fsWatcher, path);
snatSources.emplace_back(source);
}
if (localNetpolEnabled) {
for (const std::string& path : netpolSourcePaths) {
FSNetpolSource* source =
new FSNetpolSource(framework, fsWatcher, path);
netpolSources.emplace_back(source);
}
}
if(!dropLogCfgSourcePath.empty()) {
opflex::modb::URI uri = (opflex::modb::URIBuilder()
.addElement("PolicyUniverse").addElement("ObserverDropLogConfig")
Expand Down
80 changes: 61 additions & 19 deletions agent-ovs/lib/EndpointManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,17 +883,32 @@ bool EndpointManager::updateEndpointLocal(const string& uuid,
}
newlocall2eps.insert(l2e->getURI());

vector<shared_ptr<EndPointToSecGroupRSrc> > oldSecGrps;
l2e->resolveEpdrEndPointToSecGroupRSrc(oldSecGrps);
const set<URI>& secGrps = es.endpoint->getSecurityGroups();
for (const shared_ptr<EndPointToSecGroupRSrc>& og :
oldSecGrps) {
optional<URI> targ = og->getTargetURI();
if (!targ || secGrps.find(targ.get()) == secGrps.end())
og->remove();
}
for (const URI& sg : secGrps) {
l2e->addEpdrEndPointToSecGroupRSrc(sg.toString());
if (policyManager.useLocalNetpol()) {
vector<shared_ptr<EndPointToLocalSecGroupRSrc> > oldSecGrps;
l2e->resolveEpdrEndPointToLocalSecGroupRSrc(oldSecGrps);
const set<URI>& secGrps = es.endpoint->getSecurityGroups();
for (const shared_ptr<EndPointToLocalSecGroupRSrc>& og :
oldSecGrps) {
optional<URI> targ = og->getTargetURI();
if (!targ || secGrps.find(targ.get()) == secGrps.end())
og->remove();
}
for (const URI& sg : secGrps) {
l2e->addEpdrEndPointToLocalSecGroupRSrc(sg.toString());
}
} else {
vector<shared_ptr<EndPointToSecGroupRSrc> > oldSecGrps;
l2e->resolveEpdrEndPointToSecGroupRSrc(oldSecGrps);
const set<URI>& secGrps = es.endpoint->getSecurityGroups();
for (const shared_ptr<EndPointToSecGroupRSrc>& og :
oldSecGrps) {
optional<URI> targ = og->getTargetURI();
if (!targ || secGrps.find(targ.get()) == secGrps.end())
og->remove();
}
for (const URI& sg : secGrps) {
l2e->addEpdrEndPointToSecGroupRSrc(sg.toString());
}
}

const optional<URI>& qosPol =
Expand Down Expand Up @@ -1007,13 +1022,33 @@ static URI formSecGroupURI (SecurityGroupContext& sgc) {
.build();
}

/* Form the URI of local secGroup from the given security group.
* This is needed since we want to generate URI without the EPR prefixes of the EP */
static URI formLocalSecGroupURI (SecurityGroupContext& sgc) {
optional<const string&> sgOpt = sgc.getSecGroup();
if (!sgOpt)
return URIBuilder().build();
const auto& sg = sgOpt.get();
size_t spaceStart = sg.find("PolicySpace") + 12;
size_t gsgStart = sg.rfind("GbpLocalSecGroup");
size_t nameStart = gsgStart + 17;
return URIBuilder()
.addElement("PolicyUniverse")
.addElement("PolicySpace")
.addElement(sg.substr(spaceStart, gsgStart-spaceStart-1))
.addElement("GbpLocalSecGroup")
.addElement(sg.substr(nameStart, sg.size()-nameStart-1))
.build();
}

static shared_ptr<modelgbp::epr::L2Ep>
populateL2E(shared_ptr<modelgbp::epr::L2Universe>& l2u,
shared_ptr<const Endpoint>& ep,
const string& uuid,
shared_ptr<modelgbp::gbp::BridgeDomain>& bd,
const URI& egURI,
const set<URI>& secGroups) {
const set<URI>& secGroups,
bool localNetpolEnabled) {
using namespace modelgbp::gbp;
using namespace modelgbp::gbpe;
using namespace modelgbp::epr;
Expand All @@ -1028,7 +1063,8 @@ populateL2E(shared_ptr<modelgbp::epr::L2Universe>& l2u,
vector<shared_ptr<SecurityGroupContext> > outSGC;
l2e->resolveEprSecurityGroupContext(outSGC);
for (auto &sgc : outSGC) {
auto sgURI = formSecGroupURI(*sgc);
auto sgURI = localNetpolEnabled ? formLocalSecGroupURI(*sgc)
: formSecGroupURI(*sgc);
if (secGroups.find(sgURI) == secGroups.end())
sgc->remove();
}
Expand Down Expand Up @@ -1073,7 +1109,8 @@ populateL3E(shared_ptr<modelgbp::epr::L3Universe>& l3u,
shared_ptr<modelgbp::gbp::RoutingDomain>& rd,
const string& ip,
const URI& egURI,
const set<URI>& secGroups) {
const set<URI>& secGroups,
bool localNetpolEnabled) {
using namespace modelgbp::gbp;
using namespace modelgbp::epr;

Expand All @@ -1087,7 +1124,8 @@ populateL3E(shared_ptr<modelgbp::epr::L3Universe>& l3u,
vector<shared_ptr<SecurityGroupContext> > outSGC;
l3e->resolveEprSecurityGroupContext(outSGC);
for (auto &sgc : outSGC) {
auto sgURI = formSecGroupURI(*sgc);
auto sgURI = localNetpolEnabled ? formLocalSecGroupURI(*sgc)
: formSecGroupURI(*sgc);
if (secGroups.find(sgURI) == secGroups.end())
sgc->remove();
}
Expand Down Expand Up @@ -1132,7 +1170,8 @@ bool EndpointManager::updateEndpointReg(const string& uuid) {
{
shared_ptr<L2Ep> l2e =
populateL2E(l2u.get(), es.endpoint, uuid,
bd.get(), egURI.get(), secGroups);
bd.get(), egURI.get(), secGroups,
policyManager.useLocalNetpol());

newl2eps.insert(l2e->getURI());
}
Expand All @@ -1152,7 +1191,8 @@ bool EndpointManager::updateEndpointReg(const string& uuid) {
shared_ptr<L2Ep> fl2e =
populateL2E(l2u.get(), es.endpoint, ipm.getUUID(), fbd.get(),
ipm.getEgURI().get(),
secGroups);
secGroups,
policyManager.useLocalNetpol());
newl2eps.insert(fl2e->getURI());
}
}
Expand All @@ -1171,7 +1211,8 @@ bool EndpointManager::updateEndpointReg(const string& uuid) {
shared_ptr<L3Ep> l3e =
populateL3E(l3u.get(), es.endpoint, uuid,
rd.get(), ip, egURI.get(),
secGroups);
secGroups,
policyManager.useLocalNetpol());
newl3eps.insert(l3e->getURI());
}

Expand All @@ -1192,7 +1233,8 @@ bool EndpointManager::updateEndpointReg(const string& uuid) {
populateL3E(l3u.get(), es.endpoint, ipm.getUUID(),
frd.get(), ipm.getFloatingIP().get(),
ipm.getEgURI().get(),
secGroups);
secGroups,
policyManager.useLocalNetpol());
newl3eps.insert(fl3e->getURI());
}
}
Expand Down
24 changes: 17 additions & 7 deletions agent-ovs/lib/FSEndpointSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,23 @@ void FSEndpointSource::updated(const fs::path& filePath) {
optional<string> secGrpName =
v.second.get_optional<string>(SEC_GROUP_NAME);
if (secGrpName && secGrpPS) {
newep.addSecurityGroup(opflex::modb::URIBuilder()
.addElement("PolicyUniverse")
.addElement("PolicySpace")
.addElement(secGrpPS.get())
.addElement("GbpSecGroup")
.addElement(secGrpName.get())
.build());
if (manager->getAgent().getPolicyManager().useLocalNetpol()) {
newep.addSecurityGroup(opflex::modb::URIBuilder()
.addElement("PolicyUniverse")
.addElement("PolicySpace")
.addElement(secGrpPS.get())
.addElement("GbpLocalSecGroup")
.addElement(secGrpName.get())
.build());
} else {
newep.addSecurityGroup(opflex::modb::URIBuilder()
.addElement("PolicyUniverse")
.addElement("PolicySpace")
.addElement(secGrpPS.get())
.addElement("GbpSecGroup")
.addElement(secGrpName.get())
.build());
}
}
}
}
Expand Down
98 changes: 98 additions & 0 deletions agent-ovs/lib/FSNetpolSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
* Implementation for FSNetpolSource class.
*
* Copyright (c) 2024 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
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(HAVE_SYS_INOTIFY_H) && defined(HAVE_SYS_EVENTFD_H)
#define USE_INOTIFY
#endif

#include <stdexcept>
#include <sstream>
#include <boost/algorithm/string/predicate.hpp>

#include <opflexagent/FSNetpolSource.h>
#include <opflexagent/logging.h>

namespace opflexagent {

using boost::optional;
namespace fs = boost::filesystem;
using std::string;
using std::runtime_error;

FSNetpolSource::FSNetpolSource(opflex::ofcore::OFFramework& framework_,
FSWatcher& listener,
const std::string& netpolDir)
: framework(framework_) {
LOG(INFO) << "Watching " << netpolDir << " for netpol data";
listener.addWatch(netpolDir, *this);
}

static bool isnetpol(fs::path filePath) {
string fstr = filePath.filename().string();
return (boost::algorithm::ends_with(fstr, ".netpol") &&
!boost::algorithm::starts_with(fstr, "."));
}

void FSNetpolSource::updated(const fs::path& filePath) {
if (!isnetpol(filePath)) return;

try {
string pathstr = filePath.string();
netpol_map_t::const_iterator it = knownNetpols.find(pathstr);
if (it != knownNetpols.end()) {
deleted(filePath);
}
opflex::modb::mointernal::StoreClient::notif_t notifs;
size_t n =
framework.updateMOs(pathstr, opflex::gbp::PolicyUpdateOp::REPLACE, &notifs);
knownNetpols[pathstr] = notifs;

LOG(INFO) << "Updated Netpol " << filePath.stem()
<< " from " << filePath
<< " ( " << n << " Objects )";
} catch (const std::exception& ex) {
LOG(ERROR) << "Could not load netpol from: "
<< filePath << ": "
<< ex.what();
} catch (...) {
LOG(ERROR) << "Unknown error while loading netpol "
<< "information from "
<< filePath;
}
}

void FSNetpolSource::deleted(const fs::path& filePath) {
try {
string pathstr = filePath.string();
netpol_map_t::iterator it = knownNetpols.find(pathstr);
if (it != knownNetpols.end()) {

framework.deleteMOs(it->second);
LOG(INFO) << "Removed netpol-uuid "
<< filePath.stem()
<< " at " << filePath
<< " ( " << it->second.size() << " Objects )";
knownNetpols.erase(it);
}
} catch (const std::exception& ex) {
LOG(ERROR) << "Could not delete netpol for "
<< filePath << ": "
<< ex.what();
} catch (...) {
LOG(ERROR) << "Unknown error while deleting netpol information for "
<< filePath;
}
}

} /* namespace opflexagent */
Loading

0 comments on commit 2e7a124

Please sign in to comment.