From: Tali Date: Thu, 16 Mar 2017 12:53:03 +0000 (+0200) Subject: Policy classifier route group installation X-Git-Tag: release/carbon~184 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=4d5382208534ce435600b93abe057bfb3c4ad2c1;p=netvirt.git Policy classifier route group installation this patch depends on https://git.opendaylight.org/gerrit/#/c/53049/ Change-Id: Id7e8391722b3e3825b7e11ea04e126532f9b8e19 Signed-off-by: Tali --- diff --git a/vpnservice/policyservice/api/src/main/yang/policy-service.yang b/vpnservice/policyservice/api/src/main/yang/policy-service.yang index 7d0c8fdb6e..95daa4d0a2 100644 --- a/vpnservice/policyservice/api/src/main/yang/policy-service.yang +++ b/vpnservice/policyservice/api/src/main/yang/policy-service.yang @@ -100,6 +100,10 @@ module policy-service { leaf interface-name { type string; } + + leaf remote-dp-id { + type uint64; + } } } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyIdManager.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyIdManager.java index 4620c33a04..bde68d62f6 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyIdManager.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyIdManager.java @@ -8,6 +8,7 @@ package org.opendaylight.netvirt.policyservice; +import java.math.BigInteger; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -45,14 +46,41 @@ public class PolicyIdManager { @PostConstruct public void init() { LOG.info("init"); - createIdPool(); + createIdPools(); } - private void createIdPool() { - CreateIdPoolInput createPoolInput = new CreateIdPoolInputBuilder() - .setPoolName(PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME) - .setLow(PolicyServiceConstants.POLICY_CLASSIFIER_LOW_ID) - .setHigh(PolicyServiceConstants.POLICY_CLASSIFIER_HIGH_ID).build(); + public long getPolicyClassifierId(String policyClassifierName) { + return allocateId(policyClassifierName, PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME); + } + + public void releasePolicyClassifierId(String policyClassifierName) { + releaseId(policyClassifierName, PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME); + } + + public long getPolicyClassifierGroupId(String policyClassifierName, BigInteger remoteDpId) { + return allocateId(getPolicyClassifierGroupKey(policyClassifierName, remoteDpId), + PolicyServiceConstants.POLICY_GROUP_POOL_NAME); + } + + public void releasePolicyClassifierGroupId(String policyClassifierName, BigInteger remoteDpId) { + releaseId(getPolicyClassifierGroupKey(policyClassifierName, remoteDpId), + PolicyServiceConstants.POLICY_GROUP_POOL_NAME); + } + + public static String getPolicyClassifierGroupKey(String policyClassifier, BigInteger remoteDpId) { + return policyClassifier + '-' + remoteDpId; + } + + private void createIdPools() { + createIdPool(PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME, + PolicyServiceConstants.POLICY_CLASSIFIER_LOW_ID, PolicyServiceConstants.POLICY_CLASSIFIER_HIGH_ID); + createIdPool(PolicyServiceConstants.POLICY_GROUP_POOL_NAME, PolicyServiceConstants.POLICY_GROUP_LOW_ID, + PolicyServiceConstants.POLICY_GROUP_HIGH_ID); + } + + private void createIdPool(String poolName, long lowId, long highId) { + CreateIdPoolInput createPoolInput = new CreateIdPoolInputBuilder().setPoolName(poolName).setLow(lowId) + .setHigh(highId).build(); try { Future> result = idManager.createIdPool(createPoolInput); @@ -64,32 +92,29 @@ public class PolicyIdManager { } } - public long getPolicyClassifierId(String policyClassifierName) { - AllocateIdInput getIdInput = new AllocateIdInputBuilder() - .setPoolName(PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME).setIdKey(policyClassifierName).build(); + private long allocateId(String key, String poolName) { + AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(key).build(); try { Future> result = idManager.allocateId(getIdInput); RpcResult rpcResult = result.get(); return rpcResult.getResult().getIdValue(); } catch (InterruptedException | ExecutionException e) { - LOG.warn("Exception thrown while allocating id for key {}", policyClassifierName); + LOG.warn("Exception thrown while allocating id for key {}", key); } return PolicyServiceConstants.INVALID_ID; } - public void releasePolicyClassifierId(String policyClassifierName) { - ReleaseIdInput idInput = new ReleaseIdInputBuilder() - .setPoolName(PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME).setIdKey(policyClassifierName).build(); + private void releaseId(String key, String poolName) { + ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(key).build(); try { Future> result = idManager.releaseId(idInput); RpcResult rpcResult = result.get(); if (!rpcResult.isSuccessful()) { - LOG.warn("RPC Call to release {} returned with Errors {}", policyClassifierName, rpcResult.getErrors()); + LOG.warn("RPC Call to release {} returned with Errors {}", key, rpcResult.getErrors()); } } catch (InterruptedException | ExecutionException e) { - LOG.warn("Exception thrown while releasing id for key {}", policyClassifierName); + LOG.warn("Exception thrown while releasing id for key {}", key); } } - } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteGroupProgrammer.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteGroupProgrammer.java new file mode 100644 index 0000000000..b67c0a15b3 --- /dev/null +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteGroupProgrammer.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017 Hewlett Packard Enterprise, Co. 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 + */ + +package org.opendaylight.netvirt.policyservice; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator; +import org.opendaylight.netvirt.policyservice.util.PolicyServiceFlowUtil; +import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterface; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Program policy classifier fast-failover groups per remote DPN.
+ * Group id is allocated for combination of policy classifier and DPN id.
+ * The group buckets are built based on the underlay networks defined for the + * policy classifier.
+ * Each bucket in the group contains the tunnel egress actions for the actual + * tunnel interface associated with the underlay network. + * + */ +@Singleton +public class PolicyRouteGroupProgrammer { + private static final Logger LOG = LoggerFactory.getLogger(PolicyRouteGroupProgrammer.class); + + private final DataBroker dataBroker; + private final PolicyIdManager policyIdManager; + private final PolicyServiceUtil policyServiceUtil; + private final PolicyServiceFlowUtil policyServiceFlowUtil; + private final DataStoreJobCoordinator coordinator; + + @Inject + public PolicyRouteGroupProgrammer(final DataBroker dataBroker, final PolicyIdManager policyIdManager, + final PolicyServiceUtil policyServiceUtil, final PolicyServiceFlowUtil policyServiceFlowUtil) { + this.dataBroker = dataBroker; + this.policyIdManager = policyIdManager; + this.policyServiceUtil = policyServiceUtil; + this.policyServiceFlowUtil = policyServiceFlowUtil; + this.coordinator = DataStoreJobCoordinator.getInstance(); + } + + public void programPolicyClassifierGroups(String policyClassifier, List localDpIds, + List remoteDpIds, int addOrRemove) { + if (remoteDpIds == null || remoteDpIds.isEmpty()) { + LOG.debug("No remote DPNs found for policy classifier {}", policyClassifier); + return; + } + + coordinator.enqueueJob(policyClassifier, () -> { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + remoteDpIds.forEach(remoteDpId -> { + programPolicyClassifierGroups(policyClassifier, localDpIds, remoteDpId, tx, addOrRemove); + }); + return Collections.singletonList(tx.submit()); + }); + } + + public void programPolicyClassifierGroups(String policyClassifier, BigInteger dpId, + List tunnelInterfaces, int addOrRemove) { + if (tunnelInterfaces == null) { + LOG.debug("No tunnel interfaces found for policy classifier {} DPN {}", policyClassifier, dpId); + return; + + } + coordinator.enqueueJob(policyClassifier, () -> { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + tunnelInterfaces.forEach(tunnelInterface -> { + BigInteger remoteDpId = tunnelInterface.getRemoteDpId(); + programPolicyClassifierGroups(policyClassifier, Collections.singletonList(dpId), remoteDpId, tx, + addOrRemove); + }); + return Collections.singletonList(tx.submit()); + }); + } + + private void programPolicyClassifierGroups(String policyClassifier, List localDpIds, + BigInteger remoteDpId, WriteTransaction tx, int addOrRemove) { + long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifier, remoteDpId); + if (groupId == PolicyServiceConstants.INVALID_ID) { + LOG.error("Failed to get group id for policy classifier {}", policyClassifier); + return; + } + + if (localDpIds == null || localDpIds.isEmpty()) { + LOG.debug("No DPNs found for policy classifier {}", policyClassifier); + return; + } + + String groupName = PolicyIdManager.getPolicyClassifierGroupKey(policyClassifier, remoteDpId); + localDpIds.forEach(srcDpId -> { + if (!remoteDpId.equals(srcDpId)) { + policyServiceFlowUtil.updateGroupToTx(srcDpId, groupId, groupName, GroupTypes.GroupFf, addOrRemove, tx); + } + }); + } + + public void programPolicyClassifierGroupBuckets(String policyClassifier, List underlayNetworks, + int addOrRemove) { + if (underlayNetworks == null) { + return; + } + + coordinator.enqueueJob(policyClassifier, () -> { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + + for (int idx = 0; idx < underlayNetworks.size(); idx++) { + final int bucketId = idx; + String underlayNetwork = underlayNetworks.get(idx); + Optional.ofNullable(policyServiceUtil.getUnderlayNetworkDpnToInterfaces(underlayNetwork)) + .map(dpnToInterfaceList -> { + dpnToInterfaceList.forEach(dpnToInterfaces -> { + BigInteger dpId = dpnToInterfaces.getDpId(); + List tunnelInterfaces = dpnToInterfaces.getTunnelInterface(); + programPolicyClassifierGroupBuckets(policyClassifier, tunnelInterfaces, dpId, bucketId, + addOrRemove, tx); + }); + return dpnToInterfaceList; + }).orElseGet(() -> { + LOG.debug("No DpnToInterface found for underlay network {}", underlayNetwork); + return null; + }); + } + return Collections.singletonList(tx.submit()); + }); + } + + public void programPolicyClassifierGroupBuckets(String policyClassifier, List tunnelInterfaces, + BigInteger dpId, int bucketId, int addOrRemove) { + coordinator.enqueueJob(policyClassifier, () -> { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + programPolicyClassifierGroupBuckets(policyClassifier, tunnelInterfaces, dpId, bucketId, addOrRemove, tx); + return Collections.singletonList(tx.submit()); + }); + } + + private void programPolicyClassifierGroupBuckets(String policyClassifier, List tunnelInterfaces, + BigInteger dpId, int bucketId, int addOrRemove, WriteTransaction tx) { + if (tunnelInterfaces == null) { + LOG.debug("No tunnel interfaces found for policy classifier {} DPN {}", policyClassifier, dpId); + return; + } + + tunnelInterfaces.forEach(tunnelInterface -> { + String interfaceName = tunnelInterface.getInterfaceName(); + BigInteger remoteDpId = tunnelInterface.getRemoteDpId(); + long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifier, remoteDpId); + policyServiceFlowUtil.updateInterfaceBucketToTx(dpId, groupId, bucketId, interfaceName, addOrRemove, tx); + }); + } +} diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyServiceConstants.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyServiceConstants.java index cb00a9a9e4..859f82ad21 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyServiceConstants.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyServiceConstants.java @@ -13,6 +13,9 @@ public class PolicyServiceConstants { public static final String POLICY_CLASSIFIER_POOL_NAME = "policyClassifierPool"; public static final Long POLICY_CLASSIFIER_LOW_ID = 1L; public static final Long POLICY_CLASSIFIER_HIGH_ID = 30000L; + public static final String POLICY_GROUP_POOL_NAME = "policyGroupPool"; + public static final Long POLICY_GROUP_LOW_ID = 310000L; + public static final Long POLICY_GROUP_HIGH_ID = 320000L; public static final long INVALID_ID = 0; public static final int POLICY_FLOW_PRIOPITY = 42; } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/PolicyProfileChangeListener.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/PolicyProfileChangeListener.java index b637ebc73e..a4e907eb86 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/PolicyProfileChangeListener.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/PolicyProfileChangeListener.java @@ -23,6 +23,7 @@ import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.netvirt.policyservice.PolicyAceFlowProgrammer; import org.opendaylight.netvirt.policyservice.PolicyIdManager; +import org.opendaylight.netvirt.policyservice.PolicyRouteGroupProgrammer; import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.PolicyProfiles; @@ -53,14 +54,17 @@ public class PolicyProfileChangeListener private final PolicyIdManager policyIdManager; private final PolicyServiceUtil policyServiceUtil; private final PolicyAceFlowProgrammer aceFlowProgrammer; + private final PolicyRouteGroupProgrammer routeGroupProgramer; @Inject public PolicyProfileChangeListener(final DataBroker dataBroker, final PolicyIdManager policyIdManager, - final PolicyServiceUtil policyServiceUtil, final PolicyAceFlowProgrammer aceFlowProgrammer) { + final PolicyServiceUtil policyServiceUtil, final PolicyAceFlowProgrammer aceFlowProgrammer, + final PolicyRouteGroupProgrammer routeGroupProgramer) { this.dataBroker = dataBroker; this.policyIdManager = policyIdManager; this.policyServiceUtil = policyServiceUtil; this.aceFlowProgrammer = aceFlowProgrammer; + this.routeGroupProgramer = routeGroupProgramer; } @Override @@ -86,40 +90,60 @@ public class PolicyProfileChangeListener LOG.info("Policy profile {} removed", policyClassifier); List underlayNetworks = PolicyServiceUtil .getUnderlayNetworksFromPolicyRoutes(policyProfile.getPolicyRoute()); - handlePolicyProfileUpdate(policyClassifier, underlayNetworks, false); + policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(underlayNetworks, policyClassifier, false); + List dpnIds = policyServiceUtil.getUnderlayNetworksDpns(underlayNetworks); + List remoteDpIds = policyServiceUtil.getUnderlayNetworksRemoteDpns(underlayNetworks); + routeGroupProgramer.programPolicyClassifierGroups(policyClassifier, dpnIds, remoteDpIds, NwConstants.DEL_FLOW); + updatePolicyAclRules(policyClassifier, underlayNetworks, NwConstants.DEL_FLOW); policyIdManager.releasePolicyClassifierId(policyClassifier); - + releasePolicyClassifierGroupIds(policyClassifier, dpnIds); } @Override protected void update(InstanceIdentifier key, PolicyProfile origPolicyProfile, PolicyProfile updatedPolicyProfile) { - LOG.info("Policy profile {} updated", updatedPolicyProfile.getPolicyClassifier()); List origUnderlayNetworks = PolicyServiceUtil .getUnderlayNetworksFromPolicyRoutes(origPolicyProfile.getPolicyRoute()); List updatedUnderlayNetworks = PolicyServiceUtil .getUnderlayNetworksFromPolicyRoutes(updatedPolicyProfile.getPolicyRoute()); - List removedUnderlayNetworks = new ArrayList<>(origUnderlayNetworks); removedUnderlayNetworks.removeAll(updatedUnderlayNetworks); - policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(removedUnderlayNetworks, - origPolicyProfile.getPolicyClassifier(), false); + List addedUnderlayNetworks = new ArrayList<>(updatedUnderlayNetworks); + addedUnderlayNetworks.removeAll(origUnderlayNetworks); + + String policyClassifier = updatedPolicyProfile.getPolicyClassifier(); + LOG.info("Policy profile {} updated", policyClassifier); + policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(removedUnderlayNetworks, policyClassifier, false); + policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(addedUnderlayNetworks, policyClassifier, true); + + // rewrite all group buckets + routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, origUnderlayNetworks, + NwConstants.DEL_FLOW); + routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, updatedUnderlayNetworks, + NwConstants.ADD_FLOW); updatedUnderlayNetworks.removeAll(origUnderlayNetworks); policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(updatedUnderlayNetworks, updatedPolicyProfile.getPolicyClassifier(), true); + updatePolicyAclRules(policyClassifier, updatedUnderlayNetworks, NwConstants.ADD_FLOW); } @Override protected void add(InstanceIdentifier key, PolicyProfile policyProfile) { - LOG.info("Policy profile {} added", policyProfile.getPolicyClassifier()); + String policyClassifier = policyProfile.getPolicyClassifier(); + LOG.info("Policy profile {} added", policyClassifier); List underlayNetworks = PolicyServiceUtil .getUnderlayNetworksFromPolicyRoutes(policyProfile.getPolicyRoute()); - handlePolicyProfileUpdate(policyProfile.getPolicyClassifier(), underlayNetworks, true); + policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(underlayNetworks, policyClassifier, true); + List dpnIds = policyServiceUtil.getUnderlayNetworksDpns(underlayNetworks); + List remoteDpIds = policyServiceUtil.getUnderlayNetworksRemoteDpns(underlayNetworks); + routeGroupProgramer.programPolicyClassifierGroups(policyClassifier, dpnIds, remoteDpIds, NwConstants.ADD_FLOW); + routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, underlayNetworks, + NwConstants.ADD_FLOW); + updatePolicyAclRules(policyClassifier, underlayNetworks, NwConstants.ADD_FLOW); } - private void handlePolicyProfileUpdate(String policyClassifier, List underlayNetworks, boolean isAdded) { - policyServiceUtil.updatePolicyClassifierForUnderlayNetworks(underlayNetworks, policyClassifier, isAdded); + private void updatePolicyAclRules(String policyClassifier, List underlayNetworks, int addOrRemove) { List aclRules = policyServiceUtil.getPolicyClassifierAclRules(policyClassifier); if (aclRules == null || aclRules.isEmpty()) { LOG.debug("No policy ACE rules found for policy classifier {}", policyClassifier); @@ -139,7 +163,7 @@ public class PolicyProfileChangeListener .getPolicyAce(aclRule.getAclName(), aceRule.getRuleName()); if (policyAceOpt.isPresent()) { aceFlowProgrammer.programAceFlows(policyAceOpt.get(), policyClassifier, dpIds, - isAdded ? NwConstants.ADD_FLOW : NwConstants.DEL_FLOW); + addOrRemove); } }); return aceRules; @@ -150,4 +174,9 @@ public class PolicyProfileChangeListener }); } + private void releasePolicyClassifierGroupIds(String policyClassifier, List dpnIds) { + dpnIds.forEach(dpnId -> { + policyIdManager.releasePolicyClassifierGroupId(policyClassifier, dpnId); + }); + } } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/TunnelStateChangeListener.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/TunnelStateChangeListener.java index a98bdf0bd9..e0f3c7f71e 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/TunnelStateChangeListener.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/TunnelStateChangeListener.java @@ -20,6 +20,7 @@ import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepInfoAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface; @@ -85,28 +86,30 @@ public class TunnelStateChangeListener return; } - BigInteger dpnId = getTunnelDpnId(tunnelState); + BigInteger srcDpId = getTepDpnId(tunnelState.getSrcInfo()); + BigInteger dstDpId = getTepDpnId(tunnelState.getDstInfo()); String tunnelInterfaceName = tunnelState.getTunnelInterfaceName(); - if (BigInteger.ZERO.equals(dpnId)) { + if (BigInteger.ZERO.equals(srcDpId) || BigInteger.ZERO.equals(dstDpId)) { LOG.warn("No valid DPN found for tunnel {}", tunnelInterfaceName); return; } IpAddress tunnelIp = getTunnelIp(tunnelState); if (tunnelIp == null) { - LOG.warn("No tunnel ip found for tunnel {} DPN {}", tunnelInterfaceName, dpnId); + LOG.warn("No tunnel ip found for tunnel {} DPN {}", tunnelInterfaceName, srcDpId); return; } - String underlayNetwork = policyServiceUtil.getTunnelUnderlayNetwork(dpnId, tunnelIp); + String underlayNetwork = policyServiceUtil.getTunnelUnderlayNetwork(srcDpId, tunnelIp); if (underlayNetwork == null) { - LOG.debug("No underlay networks defined for tunnel {} DPN {}", tunnelInterfaceName, dpnId); + LOG.debug("No underlay networks defined for tunnel {} DPN {}", tunnelInterfaceName, srcDpId); return; } - LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network", tunnelInterfaceName, dpnId, + LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network", tunnelInterfaceName, srcDpId, underlayNetwork); - policyServiceUtil.updateTunnelInterfaceForUnderlayNetwork(underlayNetwork, dpnId, tunnelInterfaceName, isAdded); + policyServiceUtil.updateTunnelInterfaceForUnderlayNetwork(underlayNetwork, srcDpId, dstDpId, + tunnelInterfaceName, isAdded); } private static boolean isVxlanTunnel(StateTunnelList tunnelState) { @@ -114,9 +117,9 @@ public class TunnelStateChangeListener && tunnelState.getTransportType().isAssignableFrom(TunnelTypeVxlan.class); } - private static BigInteger getTunnelDpnId(StateTunnelList tunnelState) { - if (tunnelState.getSrcInfo() != null && tunnelState.getSrcInfo().getTepDeviceId() != null) { - return new BigInteger(tunnelState.getSrcInfo().getTepDeviceId()); + private static BigInteger getTepDpnId(TepInfoAttributes tepInfoAttributes) { + if (tepInfoAttributes != null && tepInfoAttributes.getTepDeviceId() != null) { + return new BigInteger(tepInfoAttributes.getTepDeviceId()); } return BigInteger.ZERO; diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/UnderlayNetworkDpnListener.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/UnderlayNetworkDpnListener.java index ffcb8adbc3..68bae31400 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/UnderlayNetworkDpnListener.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/UnderlayNetworkDpnListener.java @@ -8,7 +8,10 @@ package org.opendaylight.netvirt.policyservice.listeners; + import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -21,12 +24,14 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.netvirt.policyservice.PolicyAceFlowProgrammer; +import org.opendaylight.netvirt.policyservice.PolicyRouteGroupProgrammer; import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.UnderlayNetworks; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.UnderlayNetwork; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.PolicyProfile; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterface; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,13 +51,15 @@ public class UnderlayNetworkDpnListener private final DataBroker dataBroker; private final PolicyServiceUtil policyServiceUtil; private final PolicyAceFlowProgrammer aceFlowProgrammer; + private final PolicyRouteGroupProgrammer routeGroupProgramer; @Inject public UnderlayNetworkDpnListener(final DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil, - final PolicyAceFlowProgrammer aceFlowProgrammer) { + final PolicyAceFlowProgrammer aceFlowProgrammer, final PolicyRouteGroupProgrammer routeGroupProgramer) { this.dataBroker = dataBroker; this.policyServiceUtil = policyServiceUtil; this.aceFlowProgrammer = aceFlowProgrammer; + this.routeGroupProgramer = routeGroupProgramer; } @Override @@ -75,35 +82,102 @@ public class UnderlayNetworkDpnListener @Override protected void remove(InstanceIdentifier key, DpnToInterface dpnToInterface) { + String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); + BigInteger dpId = dpnToInterface.getDpId(); + List tunnelInterfaces = dpnToInterface.getTunnelInterface(); + LOG.info("DPN {} removed from underlay network {} with tunnels {}", dpId, underlayNetwork, tunnelInterfaces); + List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); + if (profiles == null || profiles.isEmpty()) { + LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); + return; + } + + populatePolicyGroupsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.DEL_FLOW); + populatePolicyAclRulesToDpn(underlayNetwork, dpId, profiles, NwConstants.DEL_FLOW); } @Override protected void update(InstanceIdentifier key, DpnToInterface origDpnToInterface, DpnToInterface updatedDpnToInterface) { + String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); + BigInteger dpId = updatedDpnToInterface.getDpId(); + LOG.info("DPN {} updated to underlay network {} with tunnels {}", dpId, underlayNetwork, + updatedDpnToInterface.getTunnelInterface()); + List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); + if (profiles == null || profiles.isEmpty()) { + LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); + return; + } + + List origTunnelInterfaces = Optional.ofNullable(origDpnToInterface.getTunnelInterface()) + .orElse(Collections.emptyList()); + List updatedTunnelInterfaces = Optional.ofNullable(updatedDpnToInterface.getTunnelInterface()) + .orElse(Collections.emptyList()); + List removedTunnelInterfaces = new ArrayList<>(origTunnelInterfaces); + removedTunnelInterfaces.removeAll(updatedTunnelInterfaces); + List addedTunnelInterfaces = new ArrayList<>(updatedTunnelInterfaces); + addedTunnelInterfaces.removeAll(origTunnelInterfaces); + + populatePolicyRoutesToDpn(underlayNetwork, profiles, removedTunnelInterfaces, dpId, NwConstants.DEL_FLOW); + populatePolicyRoutesToDpn(underlayNetwork, profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW); } @Override protected void add(InstanceIdentifier key, DpnToInterface dpnToInterface) { String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); BigInteger dpId = dpnToInterface.getDpId(); - LOG.info("DPN {} added to underlay network {}", dpId, underlayNetwork); - populatePolicyRulesToDpn(underlayNetwork, dpId); - - } - - private void populatePolicyRulesToDpn(String underlayNetwork, BigInteger dpId) { + List tunnelInterfaces = dpnToInterface.getTunnelInterface(); + LOG.info("DPN {} added to underlay network {} with tunnels {}", dpId, underlayNetwork, tunnelInterfaces); List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); if (profiles == null || profiles.isEmpty()) { LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); return; } + populatePolicyGroupsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW); + populatePolicyRoutesToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW); + populatePolicyAclRulesToDpn(underlayNetwork, dpId, profiles, NwConstants.ADD_FLOW); + } + + private void populatePolicyGroupsToDpn(String underlayNetwork, List profiles, + List tunnelInterfaces, BigInteger dpId, int addOrRemove) { + profiles.forEach(profile -> { + String policyClassifier = profile.getPolicyClassifier(); + routeGroupProgramer.programPolicyClassifierGroups(policyClassifier, dpId, tunnelInterfaces, addOrRemove); + }); + } + + private void populatePolicyRoutesToDpn(String underlayNetwork, List profiles, + List tunnelInterfaces, BigInteger dpId, int addOrRemove) { + profiles.forEach(profile -> { + String policyClassifier = profile.getPolicyClassifier(); + Optional.ofNullable(policyServiceUtil.getUnderlayNetworksForClassifier(policyClassifier)) + .map(underlayNetworks -> { + int bucketId = underlayNetworks.indexOf(underlayNetwork); + if (bucketId != -1) { + routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, tunnelInterfaces, + dpId, bucketId, addOrRemove); + } else { + LOG.warn("Policy classifier {} routes do not contain {}", policyClassifier, + underlayNetwork); + } + return underlayNetworks; + }).orElseGet(() -> { + LOG.warn("No underlay networks found for classifier {} while populating {} flows", + policyClassifier, underlayNetwork); + return null; + }); + }); + } + + private void populatePolicyAclRulesToDpn(String underlayNetwork, BigInteger dpId, List profiles, + int addOrRemove) { profiles.forEach(profile -> { String policyClassifier = profile.getPolicyClassifier(); Optional.ofNullable(policyServiceUtil.getPolicyClassifierAclRules(policyClassifier)).ifPresent(aclRules -> { aclRules.forEach(aclRule -> { - Optional.ofNullable(aclRule.getAceRule()).ifPresent(aceRules -> { + Optional.ofNullable(aclRule.getAceRule()).map(aceRules -> { aceRules.forEach(aceRule -> { com.google.common.base.Optional policyAceOpt = policyServiceUtil .getPolicyAce(aclRule.getAclName(), aceRule.getRuleName()); @@ -113,10 +187,13 @@ public class UnderlayNetworkDpnListener LOG.warn("Failed to get ACL {} rule {}", aclRule.getAclName(), aceRule.getRuleName()); } }); + return aceRules; + }).orElseGet(() -> { + LOG.debug("No ACE rule found for policy ACL {}", aclRule.getAclName()); + return null; }); }); }); }); } - } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceFlowUtil.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceFlowUtil.java index 1263e883cb..71ae152322 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceFlowUtil.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceFlowUtil.java @@ -10,13 +10,17 @@ package org.opendaylight.netvirt.policyservice.util; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; +import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.FlowEntity; +import org.opendaylight.genius.mdsalutil.GroupEntity; import org.opendaylight.genius.mdsalutil.InstructionInfo; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.genius.mdsalutil.MatchInfoBase; @@ -25,15 +29,23 @@ import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable; import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.netvirt.policyservice.PolicyServiceConstants; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Singleton public class PolicyServiceFlowUtil { + private static final Logger LOG = LoggerFactory.getLogger(PolicyServiceFlowUtil.class); private final IMdsalApiManager mdsalManager; + private final IInterfaceManager interfaceManager; @Inject - public PolicyServiceFlowUtil(final IMdsalApiManager mdsalManager) { + public PolicyServiceFlowUtil(final IMdsalApiManager mdsalManager, final IInterfaceManager interfaceManager) { this.mdsalManager = mdsalManager; + this.interfaceManager = interfaceManager; } public List getPolicyClassifierInstructions(long policyClassifierId) { @@ -55,4 +67,53 @@ public class PolicyServiceFlowUtil { mdsalManager.removeFlowToTx(flowEntity, tx); } } + + public void updateGroupToTx(BigInteger dpId, long groupId, String groupName, GroupTypes groupType, int addOrRemove, + WriteTransaction tx) { + if (addOrRemove == NwConstants.ADD_FLOW && mdsalManager.groupExists(dpId, groupId)) { + LOG.trace("Group {} id {} already exists", groupName, groupId); + return; + } + + GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpId, groupId, groupName, groupType, + Collections.emptyList()); + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Add group {} to DPN {}", groupId, dpId); + mdsalManager.addGroupToTx(groupEntity, tx); + } else { + LOG.debug("Remove group {} from DPN {}", groupId, dpId); + mdsalManager.removeGroupToTx(groupEntity, tx); + } + } + + public void updateInterfaceBucketToTx(BigInteger dpId, long groupId, int bucketId, String interfaceName, + int addOrRemove, WriteTransaction tx) { + if (groupId == PolicyServiceConstants.INVALID_ID) { + LOG.error("No valid group id found for interface {} DPN {}", interfaceName, dpId); + return; + } + + if (addOrRemove == NwConstants.DEL_FLOW) { + LOG.debug("Remove bucket for interface {} from group {} DPN {}", interfaceName, groupId, dpId); + mdsalManager.removeBucketToTx(dpId, groupId, bucketId, tx); + return; + } + + List egressActions = interfaceManager.getInterfaceEgressActions(interfaceName); + if (egressActions == null || egressActions.isEmpty()) { + LOG.error("Failed to get egress actions for interface {} DPN {}", interfaceName, dpId); + return; + } + + Long port = interfaceManager.getPortForInterface(interfaceName); + if (port == null) { + LOG.error("Failed to get port for interface {}", interfaceName); + return; + } + + Bucket bucket = MDSALUtil.buildBucket(MDSALUtil.buildActions(egressActions), MDSALUtil.GROUP_WEIGHT, bucketId, + port, MDSALUtil.WATCH_GROUP); + LOG.debug("Add bucket for interface {} to group {} DPN {}", interfaceName, groupId, dpId); + mdsalManager.addBucketToTx(dpId, groupId, bucket, tx); + } } diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceUtil.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceUtil.java index eb2a678193..845c3edcfd 100644 --- a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceUtil.java +++ b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceUtil.java @@ -148,19 +148,22 @@ public class PolicyServiceUtil { } } - public void updateTunnelInterfaceForUnderlayNetwork(String underlayNetwork, BigInteger dpId, String tunnelInterface, - boolean isAdded) { + public void updateTunnelInterfaceForUnderlayNetwork(String underlayNetwork, BigInteger srcDpId, BigInteger dstDpId, + String tunnelInterfaceName, boolean isAdded) { coordinator.enqueueJob(underlayNetwork, () -> { - InstanceIdentifier identifier = getUnderlyNetworkTunnelIdentifier(underlayNetwork, dpId, - tunnelInterface); + InstanceIdentifier identifier = getUnderlyNetworkTunnelIdentifier(underlayNetwork, srcDpId, + tunnelInterfaceName); WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); if (isAdded) { - tx.merge(LogicalDatastoreType.OPERATIONAL, identifier, - new TunnelInterfaceBuilder().setInterfaceName(tunnelInterface).build(), true); - LOG.info("Add tunnel {} on DPN {} to underlay network {}", tunnelInterface, dpId, underlayNetwork); + TunnelInterface tunnelInterface = new TunnelInterfaceBuilder().setInterfaceName(tunnelInterfaceName) + .setRemoteDpId(dstDpId).build(); + tx.merge(LogicalDatastoreType.OPERATIONAL, identifier, tunnelInterface, true); + LOG.info("Add tunnel {} on DPN {} to underlay network {}", tunnelInterfaceName, srcDpId, + underlayNetwork); } else { tx.delete(LogicalDatastoreType.OPERATIONAL, identifier); - LOG.info("Remove tunnel {} from DPN {} on underlay network {}", tunnelInterface, dpId, underlayNetwork); + LOG.info("Remove tunnel {} from DPN {} on underlay network {}", tunnelInterfaceName, srcDpId, + underlayNetwork); } return Collections.singletonList(tx.submit()); }); @@ -220,6 +223,15 @@ public class PolicyServiceUtil { .collect(Collectors.toList()); } + public List getUnderlayNetworksRemoteDpns(List underlayNetworks) { + if (underlayNetworks == null) { + return Collections.emptyList(); + } + + return underlayNetworks.stream().map(t -> getUnderlayNetworkRemoteDpns(t)).flatMap(t -> t.stream()).distinct() + .collect(Collectors.toList()); + } + public String getTunnelUnderlayNetwork(BigInteger dpId, IpAddress tunnelIp) { Node ovsdbNode = bridgeManager.getBridgeNode(dpId); if (ovsdbNode == null) { @@ -239,6 +251,25 @@ public class PolicyServiceUtil { return dpnToInterfaces.stream().map(t -> t.getDpId()).collect(Collectors.toList()); } + public static List getRemoteDpnsFromDpnToInterfaces(List dpnToInterfaces) { + if (dpnToInterfaces == null) { + return Collections.emptyList(); + } + + return dpnToInterfaces.stream().map(dpnToInterface -> getRemoteDpnsFromDpnToInterface(dpnToInterface)) + .flatMap(t -> t.stream()).distinct().collect(Collectors.toList()); + } + + public static List getRemoteDpnsFromDpnToInterface(DpnToInterface dpnToInterface) { + List tunnelInterfaces = dpnToInterface.getTunnelInterface(); + if (tunnelInterfaces == null) { + return Collections.emptyList(); + } + + return tunnelInterfaces.stream().map(tunnelInterface -> tunnelInterface.getRemoteDpId()) + .collect(Collectors.toList()); + } + public static List getUnderlayNetworksFromPolicyRoutes(List policyRoutes) { if (policyRoutes == null) { return Collections.emptyList(); @@ -253,13 +284,13 @@ public class PolicyServiceUtil { return aclType != null && aclType.isAssignableFrom(PolicyAcl.class); } - private List getUnderlayNetworkDpns(String underlayNetwork) { - InstanceIdentifier identifier = getUnderlyNetworkIdentifier(underlayNetwork); + public List getUnderlayNetworkDpnToInterfaces(String underlayNetwork) { + InstanceIdentifier identifier = InstanceIdentifier.create(UnderlayNetworks.class) + .child(UnderlayNetwork.class, new UnderlayNetworkKey(underlayNetwork)); try { Optional optUnderlayNetwork = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier); - return optUnderlayNetwork.isPresent() - ? getDpnsFromDpnToInterfaces(optUnderlayNetwork.get().getDpnToInterface()) + return optUnderlayNetwork.isPresent() ? optUnderlayNetwork.get().getDpnToInterface() : Collections.emptyList(); } catch (ReadFailedException e) { LOG.warn("Failed to get DPNs for underlay network {}", underlayNetwork); @@ -309,4 +340,12 @@ public class PolicyServiceUtil { .netvirt.policy.rev170207.underlay.networks.underlay.network .PolicyProfileKey(policyClassifier)); } + + public List getUnderlayNetworkDpns(String underlayNetwork) { + return getDpnsFromDpnToInterfaces(getUnderlayNetworkDpnToInterfaces(underlayNetwork)); + } + + public List getUnderlayNetworkRemoteDpns(String underlayNetwork) { + return getRemoteDpnsFromDpnToInterfaces(getUnderlayNetworkDpnToInterfaces(underlayNetwork)); + } } diff --git a/vpnservice/policyservice/impl/src/main/resources/org/opendaylight/blueprint/policyservice.xml b/vpnservice/policyservice/impl/src/main/resources/org/opendaylight/blueprint/policyservice.xml index e4b15665db..d6256a65d8 100644 --- a/vpnservice/policyservice/impl/src/main/resources/org/opendaylight/blueprint/policyservice.xml +++ b/vpnservice/policyservice/impl/src/main/resources/org/opendaylight/blueprint/policyservice.xml @@ -8,6 +8,8 @@ interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" /> +