/* -*- 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 #include #include "VppContractManager.hpp" #include "VppEndPointGroupManager.hpp" #include "VppLog.hpp" #include "VppRuntime.hpp" using namespace VOM; namespace VPP { ContractManager::ContractManager(Runtime &r) : m_runtime(r) { } static void get_group_sclass(Runtime &runtime, const std::unordered_set &uris, std::vector &ids) { opflexagent::PolicyManager &pm = runtime.policy_manager(); for (auto &u : uris) { boost::optional sclass = pm.getSclassForGroup(u); if (!sclass) { sclass = pm.getSclassForExternalNet(u); } if (sclass) { ids.push_back(sclass.get()); } else { VLOGW << "No Sclass for: " << u; } } } static void get_group_scope_sclass(Runtime &runtime, const std::unordered_set &uris, std::vector> &ids) { opflexagent::PolicyManager &pm = runtime.policy_manager(); for (auto &u : uris) { try { EndPointGroupManager::ForwardInfo fwd = EndPointGroupManager::get_fwd_info(runtime, u); ids.push_back(std::make_pair(fwd.rdId, fwd.sclass)); } catch (EndPointGroupManager::NoFowardInfoException &e) { VLOGW << "No RD for: " << u; } } } static uint32_t getRdId(IdGen &id_gen, const std::shared_ptr epgRd) { uint32_t rdId = 0; if (epgRd) { boost::optional rdURI = epgRd.get()->getURI(); if (rdURI) rdId = id_gen.get(modelgbp::gbp::RoutingDomain::CLASS_ID, rdURI.get()); } return rdId; } static uint32_t getBdId(IdGen &id_gen, const std::shared_ptr epgBd) { uint32_t bdId = 0; if (epgBd) { boost::optional bdURI = epgBd.get()->getURI(); bdId = id_gen.get(modelgbp::gbp::BridgeDomain::CLASS_ID, bdURI.get()); } return bdId; } void ContractManager::handle_update(const opflex::modb::URI &uri) { VLOGD << "Updating contract " << uri; const std::string &uuid = uri.toString(); OM::mark_n_sweep ms(uuid); opflexagent::PolicyManager &polMgr = m_runtime.policy_manager(); if (!polMgr.contractExists(uri)) { // Contract removed return; } opflexagent::PolicyManager::uri_set_t provURIs; opflexagent::PolicyManager::uri_set_t consURIs; opflexagent::PolicyManager::uri_set_t intraURIs; polMgr.getContractProviders(uri, provURIs); polMgr.getContractConsumers(uri, consURIs); polMgr.getContractIntra(uri, intraURIs); std::vector> provIds; std::vector consIds; get_group_scope_sclass(m_runtime, provURIs, provIds); get_group_sclass(m_runtime, consURIs, consIds); opflexagent::PolicyManager::rule_list_t rules; polMgr.getContractRules(uri, rules); gbp_contract::gbp_rules_t gbp_rules; ACL::l3_list::rules_t in_rules, out_rules; gbp_contract::ethertype_set_t in_ethertypes, out_ethertypes; for (auto rule : rules) { uint8_t dir = rule->getDirection(); const std::shared_ptr &cls = rule->getL24Classifier(); uint32_t priority = rule->getPriority(); const ethertype_t ðerType = ethertype_t::from_numeric_val( cls->getEtherT(modelgbp::l2::EtherTypeEnumT::CONST_UNSPECIFIED)); ACL::action_t act = ACL::action_t::from_bool( (rule->getAllow() || rule->getRedirect()), cls->getConnectionTracking( modelgbp::gbp::ConnTrackEnumT::CONST_NORMAL)); if (dir == modelgbp::gbp::DirectionEnumT::CONST_BIDIRECTIONAL || dir == modelgbp::gbp::DirectionEnumT::CONST_IN) { auto it = out_ethertypes.find(etherType); if (it == out_ethertypes.end()) out_ethertypes.insert(etherType); } if (dir == modelgbp::gbp::DirectionEnumT::CONST_BIDIRECTIONAL || dir == modelgbp::gbp::DirectionEnumT::CONST_OUT) { auto it = in_ethertypes.find(etherType); if (it == in_ethertypes.end()) in_ethertypes.insert(etherType); } if (etherType != modelgbp::l2::EtherTypeEnumT::CONST_IPV4 && etherType != modelgbp::l2::EtherTypeEnumT::CONST_IPV6) { VLOGD << "Contract for Protocol " << etherType.to_string() << " ,(IPv4/IPv6)" << " are allowed"; continue; } route::prefix_t srcIp(route::prefix_t::ZERO); route::prefix_t dstIp(route::prefix_t::ZERO); if (etherType == modelgbp::l2::EtherTypeEnumT::CONST_IPV6) { srcIp = route::prefix_t::ZEROv6; dstIp = route::prefix_t::ZEROv6; } ACL::l3_rule l3_rule(priority, act, srcIp, dstIp); setParamUpdate(*cls, l3_rule); if (dir == modelgbp::gbp::DirectionEnumT::CONST_BIDIRECTIONAL || dir == modelgbp::gbp::DirectionEnumT::CONST_IN) { out_rules.insert(l3_rule); } if (dir == modelgbp::gbp::DirectionEnumT::CONST_BIDIRECTIONAL || dir == modelgbp::gbp::DirectionEnumT::CONST_OUT) { in_rules.insert(l3_rule); } if (rule->getRedirect() && rule->getRedirectDestGrpURI()) { opflexagent::PolicyManager::redir_dest_list_t redirList; gbp_rule::next_hops_t nhs; uint8_t hashAlgo = 0, resilientHashEnabled = 0; boost::optional destGrpUri = rule->getRedirectDestGrpURI(); polMgr.getPolicyDestGroup( destGrpUri.get(), redirList, hashAlgo, resilientHashEnabled); for (auto dst : redirList) { uint8_t macAddr[6] = {0}; dst->getMac().toUIntArray(macAddr); mac_address_t mac(macAddr); gbp_rule::next_hop_t nh( dst->getIp(), mac, getBdId(m_runtime.id_gen, dst->getBD()), getRdId(m_runtime.id_gen, dst->getRD())); nhs.insert(nh); } if (nhs.size() == 0) { VLOGI << "Redirect Contract with no NHs: " << uri; continue; } if (hashAlgo == modelgbp::gbp::HashingAlgorithmEnumT::CONST_SYMMETRIC) { gbp_rule::next_hop_set_t next_hop_set( gbp_rule::hash_mode_t::SYMMETRIC, nhs); gbp_rule gr(rule->getPriority(), next_hop_set, gbp_rule::action_t::REDIRECT); gbp_rules.insert(gr); } else if (hashAlgo == modelgbp::gbp::HashingAlgorithmEnumT::CONST_DSTIP) { gbp_rule::next_hop_set_t next_hop_set( gbp_rule::hash_mode_t::DST_IP, nhs); gbp_rule gr(rule->getPriority(), next_hop_set, gbp_rule::action_t::REDIRECT); gbp_rules.insert(gr); } else if (hashAlgo == modelgbp::gbp::HashingAlgorithmEnumT::CONST_SRCIP) { gbp_rule::next_hop_set_t next_hop_set( gbp_rule::hash_mode_t::SRC_IP, nhs); gbp_rule gr(rule->getPriority(), next_hop_set, gbp_rule::action_t::REDIRECT); gbp_rules.insert(gr); } } else if (rule->getAllow()) { gbp_rule gr(rule->getPriority(), gbp_rule::action_t::PERMIT); gbp_rules.insert(gr); } else { gbp_rule gr(rule->getPriority(), gbp_rule::action_t::DENY); gbp_rules.insert(gr); } } for (const auto pvnid : provIds) { for (const uint32_t &cvnid : consIds) { if (pvnid.second == cvnid) /* intra group is allowed by default */ continue; /* * Derive the contract scope from the provider's RD */ VLOGD << "Contract prov:[" << pvnid.first << ", " << pvnid.second << "]" << " cons:" << cvnid; if (!in_rules.empty()) { ACL::l3_list inAcl(uuid + "in", in_rules); OM::write(uuid, inAcl); gbp_contract gbpc_in(pvnid.first, pvnid.second, cvnid, inAcl, gbp_rules, in_ethertypes); OM::write(uuid, gbpc_in); } if (!out_rules.empty()) { ACL::l3_list outAcl(uuid + "out", out_rules); OM::write(uuid, outAcl); gbp_contract gbpc_out(pvnid.first, cvnid, pvnid.second, outAcl, gbp_rules, out_ethertypes); OM::write(uuid, gbpc_out); } } } } }; // namespace VPP /* * Local Variables: * eval: (c-set-style "llvm.org") * End: */