Policy routing table flow installation 72/53572/13
authorTali <tali.ben-meir@hpe.com>
Mon, 20 Mar 2017 16:38:57 +0000 (18:38 +0200)
committerTali <tali.ben-meir@hpe.com>
Wed, 29 Mar 2017 23:07:54 +0000 (02:07 +0300)
Route each combination of policy classifier and logical interface
to the corresponding policy classifier group

Change-Id: I74d30a2b0a7da1c0023c47bcd8b81c533ee67b81
Signed-off-by: Tali <tali.ben-meir@hpe.com>
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyIdManager.java
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteFlowProgrammer.java [new file with mode: 0644]
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/PolicyProfileChangeListener.java
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/TunnelStateChangeListener.java
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/listeners/UnderlayNetworkDpnListener.java
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceFlowUtil.java
vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/util/PolicyServiceUtil.java
vpnservice/policyservice/impl/src/main/resources/org/opendaylight/blueprint/policyservice.xml

index bde68d62f6c0d0834637317085ab878bc4799b8c..006c145279c63e640069128050cb5a2509118fb3 100644 (file)
@@ -8,7 +8,11 @@
 
 package org.opendaylight.netvirt.policyservice;
 
+import com.google.common.collect.ImmutableMap;
+
 import java.math.BigInteger;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
@@ -37,6 +41,10 @@ public class PolicyIdManager {
     private static final Logger LOG = LoggerFactory.getLogger(PolicyIdManager.class);
 
     private final IdManagerService idManager;
+    private final Map<String,
+            Map<String, Long>> idCache = ImmutableMap.of(//
+                    PolicyServiceConstants.POLICY_CLASSIFIER_POOL_NAME, new ConcurrentHashMap<String, Long>(),
+                    PolicyServiceConstants.POLICY_GROUP_POOL_NAME, new ConcurrentHashMap<String, Long>());
 
     @Inject
     public PolicyIdManager(final IdManagerService idManager) {
@@ -93,11 +101,20 @@ public class PolicyIdManager {
     }
 
     private long allocateId(String key, String poolName) {
+        Long id = idCache.get(poolName).get(key);
+        if (id != null) {
+            return id;
+        }
+
         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(key).build();
         try {
             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
             RpcResult<AllocateIdOutput> rpcResult = result.get();
-            return rpcResult.getResult().getIdValue();
+            Long idValue = rpcResult.getResult().getIdValue();
+            if (idValue != null) {
+                idCache.get(poolName).put(key, idValue);
+                return idValue;
+            }
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception thrown while allocating id for key {}", key);
         }
@@ -106,6 +123,7 @@ public class PolicyIdManager {
     }
 
     private void releaseId(String key, String poolName) {
+        idCache.get(poolName).remove(key);
         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(key).build();
         try {
             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
diff --git a/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteFlowProgrammer.java b/vpnservice/policyservice/impl/src/main/java/org/opendaylight/netvirt/policyservice/PolicyRouteFlowProgrammer.java
new file mode 100644 (file)
index 0000000..f931314
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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 com.google.common.base.Optional;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+
+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.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Program POLICY_ROUTING_TABLE flows. Each flow is composed from<br>
+ * * OF matches - logical tunnel lport tag and policy classifier metadata
+ * bits<br>
+ * * OF actions - set policy classifier group id based on the remote DPN
+ * associated with the logical tunnel.
+ *
+ */
+@Singleton
+public class PolicyRouteFlowProgrammer {
+    private static final Logger LOG = LoggerFactory.getLogger(PolicyRouteFlowProgrammer.class);
+
+    private final DataBroker dataBroker;
+    private final PolicyIdManager policyIdManager;
+    private final PolicyServiceUtil policyServiceUtil;
+    private final PolicyServiceFlowUtil policyFlowUtil;
+    private final DataStoreJobCoordinator coordinator;
+
+    @Inject
+    public PolicyRouteFlowProgrammer(final DataBroker dataBroker, final PolicyIdManager policyIdManager,
+            final PolicyServiceUtil policyServiceUtil, final PolicyServiceFlowUtil policyFlowUtil) {
+        this.dataBroker = dataBroker;
+        this.policyIdManager = policyIdManager;
+        this.policyServiceUtil = policyServiceUtil;
+        this.policyFlowUtil = policyFlowUtil;
+        this.coordinator = DataStoreJobCoordinator.getInstance();
+    }
+
+    public void programPolicyClassifierFlows(String policyClassifierName, List<BigInteger> localDpIds,
+            List<BigInteger> remoteDpIds, int addOrRemove) {
+        long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
+        if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
+            LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
+            return;
+        }
+
+        coordinator.enqueueJob(policyClassifierName, () -> {
+            WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+            remoteDpIds.forEach(remoteDpId -> {
+                long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifierName, remoteDpId);
+                if (groupId != PolicyServiceConstants.INVALID_ID) {
+                    List<InstructionInfo> instructions = policyFlowUtil.getPolicyRouteInstructions(groupId);
+                    localDpIds.forEach(localDpId -> {
+                        if (!remoteDpId.equals(localDpId)) {
+                            programPolicyClassifierFlow(policyClassifierName, policyClassifierId, instructions,
+                                    localDpId, remoteDpId, tx, addOrRemove);
+                        }
+                    });
+                } else {
+                    LOG.error("Failed to get group id for policy classifier {} DPN {}", policyClassifierName,
+                            remoteDpId);
+                }
+            });
+            return Collections.singletonList(tx.submit());
+        });
+
+    }
+
+    public void programPolicyClassifierFlow(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
+            int addOrRemove) {
+        programPolicyClassifierFlow(policyClassifierName, localDpId, remoteDpId, addOrRemove, false);
+    }
+
+    public void programPolicyClassifierFlow(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
+            int addOrRemove, boolean createIfMissing) {
+        long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
+        if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
+            LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
+            return;
+        }
+
+        long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifierName, remoteDpId);
+        if (groupId == PolicyServiceConstants.INVALID_ID) {
+            LOG.error("Failed to get group id for policy classifier {} DPN {}", policyClassifierName, remoteDpId);
+            return;
+        }
+
+        if (addOrRemove == NwConstants.ADD_FLOW && createIfMissing) {
+            addPolicyClassifierGroup(policyClassifierName, localDpId, remoteDpId, addOrRemove, groupId);
+        }
+
+        List<InstructionInfo> instructions = policyFlowUtil.getPolicyRouteInstructions(groupId);
+        coordinator.enqueueJob(policyClassifierName, () -> {
+            WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+            programPolicyClassifierFlow(policyClassifierName, policyClassifierId, instructions, localDpId, remoteDpId,
+                    tx, addOrRemove);
+            return Collections.singletonList(tx.submit());
+        });
+
+    }
+
+    private void programPolicyClassifierFlow(String policyClassifierName, long policyClassifierId,
+            List<InstructionInfo> instructions, BigInteger localDpId, BigInteger remoteDpId, WriteTransaction tx,
+            int addOrRemove) {
+        Optional<Integer> lportTagOpt = policyServiceUtil.getLogicalTunnelLportTag(localDpId, remoteDpId);
+        if (!lportTagOpt.isPresent()) {
+            LOG.debug("Missing lport-tag for policy classifier {} logical tunnel for source DPN {} dst DPN {}",
+                    policyClassifierName, localDpId, remoteDpId);
+            return;
+        }
+
+        List<MatchInfoBase> matches = policyFlowUtil.getPolicyRouteMatches(policyClassifierId, lportTagOpt.get());
+        LOG.debug("{} policy classifier {} route on source DPN {} dest DPN {}",
+                addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", policyClassifierName, localDpId,
+                remoteDpId);
+        policyFlowUtil.updateFlowToTx(localDpId, NwConstants.EGRESS_POLICY_ROUTING_TABLE,
+                PolicyIdManager.getPolicyClassifierGroupKey(policyClassifierName, remoteDpId),
+                PolicyServiceConstants.POLICY_FLOW_PRIOPITY, NwConstants.EGRESS_POLICY_ROUTING_COOKIE, matches,
+                instructions, addOrRemove, tx);
+    }
+
+    private void addPolicyClassifierGroup(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
+            int addOrRemove, long groupId) {
+        coordinator.enqueueJob(policyClassifierName, () -> {
+            WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+            policyFlowUtil.updateGroupToTx(localDpId, groupId,
+                    PolicyIdManager.getPolicyClassifierGroupKey(policyClassifierName, remoteDpId), GroupTypes.GroupFf,
+                    addOrRemove, tx);
+            return Collections.singletonList(tx.submit());
+        });
+    }
+
+}
index a4e907eb8641b8f623223ba3df2a0b072edc2d34..7a870e8d4dfc72313dbf9a4f89ddb76f84b2c4fa 100644 (file)
@@ -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.PolicyRouteFlowProgrammer;
 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;
@@ -54,16 +55,18 @@ public class PolicyProfileChangeListener
     private final PolicyIdManager policyIdManager;
     private final PolicyServiceUtil policyServiceUtil;
     private final PolicyAceFlowProgrammer aceFlowProgrammer;
+    private final PolicyRouteFlowProgrammer routeFlowProgrammer;
     private final PolicyRouteGroupProgrammer routeGroupProgramer;
 
     @Inject
     public PolicyProfileChangeListener(final DataBroker dataBroker, final PolicyIdManager policyIdManager,
             final PolicyServiceUtil policyServiceUtil, final PolicyAceFlowProgrammer aceFlowProgrammer,
-            final PolicyRouteGroupProgrammer routeGroupProgramer) {
+            final PolicyRouteFlowProgrammer routeFlowProgrammer, final PolicyRouteGroupProgrammer routeGroupProgramer) {
         this.dataBroker = dataBroker;
         this.policyIdManager = policyIdManager;
         this.policyServiceUtil = policyServiceUtil;
         this.aceFlowProgrammer = aceFlowProgrammer;
+        this.routeFlowProgrammer = routeFlowProgrammer;
         this.routeGroupProgramer = routeGroupProgramer;
     }
 
@@ -95,6 +98,7 @@ public class PolicyProfileChangeListener
         List<BigInteger> remoteDpIds = policyServiceUtil.getUnderlayNetworksRemoteDpns(underlayNetworks);
         routeGroupProgramer.programPolicyClassifierGroups(policyClassifier, dpnIds, remoteDpIds, NwConstants.DEL_FLOW);
         updatePolicyAclRules(policyClassifier, underlayNetworks, NwConstants.DEL_FLOW);
+        routeFlowProgrammer.programPolicyClassifierFlows(policyClassifier, dpnIds, remoteDpIds, NwConstants.DEL_FLOW);
         policyIdManager.releasePolicyClassifierId(policyClassifier);
         releasePolicyClassifierGroupIds(policyClassifier, dpnIds);
     }
@@ -141,6 +145,7 @@ public class PolicyProfileChangeListener
         routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, underlayNetworks,
                 NwConstants.ADD_FLOW);
         updatePolicyAclRules(policyClassifier, underlayNetworks, NwConstants.ADD_FLOW);
+        routeFlowProgrammer.programPolicyClassifierFlows(policyClassifier, dpnIds, remoteDpIds, NwConstants.ADD_FLOW);
     }
 
     private void updatePolicyAclRules(String policyClassifier, List<String> underlayNetworks, int addOrRemove) {
index e0f3c7f71eeb7c859e17d9afd485315328eac530..1709f4a493b657dc3959e17c5deae695a860df67 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.netvirt.policyservice.listeners;
 
 import java.math.BigInteger;
+import java.util.List;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
@@ -17,12 +18,16 @@ import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 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.PolicyRouteFlowProgrammer;
 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.TunnelTypeLogicalGroup;
 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.policy.profiles.PolicyProfile;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -30,7 +35,9 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Listen on operational {@link StateTunnelList} changes and update
- * {@link DpnToInterface} accordingly for tunnel interfaces of type VxLAN.
+ * {@link DpnToInterface} accordingly for tunnel interfaces of type VxLAN.<br>
+ * When logical tunnel interface state is added or removed, the corresponding
+ * POLICY_ROUTING_TABLE entries will be updated.
  *
  */
 @Singleton
@@ -40,11 +47,14 @@ public class TunnelStateChangeListener
 
     private final DataBroker dataBroker;
     private final PolicyServiceUtil policyServiceUtil;
+    private final PolicyRouteFlowProgrammer routeFlowProgrammer;
 
     @Inject
-    public TunnelStateChangeListener(DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil) {
+    public TunnelStateChangeListener(DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil,
+            final PolicyRouteFlowProgrammer routeFlowProgrammer) {
         this.dataBroker = dataBroker;
         this.policyServiceUtil = policyServiceUtil;
+        this.routeFlowProgrammer = routeFlowProgrammer;
     }
 
     @Override
@@ -66,8 +76,12 @@ public class TunnelStateChangeListener
 
     @Override
     protected void remove(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
-        LOG.debug("Tunnel state {} removed", tunnelState);
-        handleTunnelUpdate(tunnelState, false);
+        LOG.trace("Tunnel state {} removed", tunnelState);
+        if (isLogicalGroupTunnel(tunnelState)) {
+            populatePolicyRoutesToDpn(tunnelState, NwConstants.DEL_FLOW);
+        } else if (isVxlanTunnel(tunnelState)) {
+            updateTunnelToUnderlayNetworkOperDs(tunnelState, false);
+        }
     }
 
     @Override
@@ -77,15 +91,47 @@ public class TunnelStateChangeListener
 
     @Override
     protected void add(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
-        LOG.debug("Tunnel state {} added", tunnelState);
-        handleTunnelUpdate(tunnelState, true);
+        LOG.trace("Tunnel state {} added", tunnelState);
+        if (isVxlanTunnel(tunnelState)) {
+            updateTunnelToUnderlayNetworkOperDs(tunnelState, true);
+        } else if (isLogicalGroupTunnel(tunnelState)) {
+            populatePolicyRoutesToDpn(tunnelState, NwConstants.ADD_FLOW);
+        }
     }
 
-    private void handleTunnelUpdate(StateTunnelList tunnelState, boolean isAdded) {
-        if (!isVxlanTunnel(tunnelState)) {
+    private void populatePolicyRoutesToDpn(StateTunnelList tunnelState, int addOrRemove) {
+        BigInteger srcDpId = getTepDpnId(tunnelState.getSrcInfo());
+        BigInteger dstDpId = getTepDpnId(tunnelState.getDstInfo());
+        String tunnelInterfaceName = tunnelState.getTunnelInterfaceName();
+        if (BigInteger.ZERO.equals(srcDpId) || BigInteger.ZERO.equals(dstDpId)) {
+            LOG.warn("No valid DPN found for logical tunnel {}", tunnelInterfaceName);
+            return;
+        }
+
+        List<PolicyProfile> policyProfiles = policyServiceUtil.getAllPolicyProfiles();
+        if (policyProfiles == null || policyProfiles.isEmpty()) {
+            LOG.debug("No policy profiles found on addition of {}", tunnelInterfaceName);
             return;
         }
 
+        policyProfiles.forEach(policyProfile -> {
+            String policyClassifier = policyProfile.getPolicyClassifier();
+            List<String> underlayNetworks = PolicyServiceUtil
+                    .getUnderlayNetworksFromPolicyRoutes(policyProfile.getPolicyRoute());
+            underlayNetworks.forEach(underlayNetwork -> {
+                if (policyServiceUtil.underlayNetworkContainsDpn(underlayNetwork, srcDpId)
+                        && policyServiceUtil.underlayNetworkContainsRemoteDpn(underlayNetwork, dstDpId)) {
+                    routeFlowProgrammer.programPolicyClassifierFlow(policyClassifier, srcDpId, dstDpId, addOrRemove,
+                            true);
+                } else {
+                    LOG.trace("logical tunnel {} source DPN {} dest DPN {} not associated to policy classifier {}",
+                            tunnelInterfaceName, srcDpId, dstDpId, policyClassifier);
+                }
+            });
+        });
+    }
+
+    private void updateTunnelToUnderlayNetworkOperDs(StateTunnelList tunnelState, boolean isAdded) {
         BigInteger srcDpId = getTepDpnId(tunnelState.getSrcInfo());
         BigInteger dstDpId = getTepDpnId(tunnelState.getDstInfo());
         String tunnelInterfaceName = tunnelState.getTunnelInterfaceName();
@@ -106,8 +152,8 @@ public class TunnelStateChangeListener
             return;
         }
 
-        LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network", tunnelInterfaceName, srcDpId,
-                underlayNetwork);
+        LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network {}", tunnelInterfaceName,
+                srcDpId, underlayNetwork);
         policyServiceUtil.updateTunnelInterfaceForUnderlayNetwork(underlayNetwork, srcDpId, dstDpId,
                 tunnelInterfaceName, isAdded);
     }
@@ -117,6 +163,11 @@ public class TunnelStateChangeListener
                 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeVxlan.class);
     }
 
+    private static boolean isLogicalGroupTunnel(StateTunnelList tunnelState) {
+        return tunnelState.getTransportType() != null
+                && tunnelState.getTransportType().isAssignableFrom(TunnelTypeLogicalGroup.class);
+    }
+
     private static BigInteger getTepDpnId(TepInfoAttributes tepInfoAttributes) {
         if (tepInfoAttributes != null && tepInfoAttributes.getTepDeviceId() != null) {
             return new BigInteger(tepInfoAttributes.getTepDeviceId());
index 68bae3140082051c4fa943dc1cdbae628095c39b..53e683c55da43d1128cdaefb020fd6b7261fe7f8 100644 (file)
@@ -24,6 +24,7 @@ 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.PolicyRouteFlowProgrammer;
 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;
@@ -51,14 +52,17 @@ public class UnderlayNetworkDpnListener
     private final DataBroker dataBroker;
     private final PolicyServiceUtil policyServiceUtil;
     private final PolicyAceFlowProgrammer aceFlowProgrammer;
+    private final PolicyRouteFlowProgrammer routeFlowProgrammer;
     private final PolicyRouteGroupProgrammer routeGroupProgramer;
 
     @Inject
     public UnderlayNetworkDpnListener(final DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil,
-            final PolicyAceFlowProgrammer aceFlowProgrammer, final PolicyRouteGroupProgrammer routeGroupProgramer) {
+            final PolicyAceFlowProgrammer aceFlowProgrammer, final PolicyRouteFlowProgrammer routeFlowProgrammer,
+            final PolicyRouteGroupProgrammer routeGroupProgramer) {
         this.dataBroker = dataBroker;
         this.policyServiceUtil = policyServiceUtil;
         this.aceFlowProgrammer = aceFlowProgrammer;
+        this.routeFlowProgrammer = routeFlowProgrammer;
         this.routeGroupProgramer = routeGroupProgramer;
     }
 
@@ -92,8 +96,7 @@ public class UnderlayNetworkDpnListener
             return;
         }
 
-        populatePolicyGroupsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.DEL_FLOW);
-        populatePolicyAclRulesToDpn(underlayNetwork, dpId, profiles, NwConstants.DEL_FLOW);
+        populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.DEL_FLOW);
     }
 
     @Override
@@ -118,8 +121,9 @@ public class UnderlayNetworkDpnListener
         List<TunnelInterface> addedTunnelInterfaces = new ArrayList<>(updatedTunnelInterfaces);
         addedTunnelInterfaces.removeAll(origTunnelInterfaces);
 
-        populatePolicyRoutesToDpn(underlayNetwork, profiles, removedTunnelInterfaces, dpId, NwConstants.DEL_FLOW);
-        populatePolicyRoutesToDpn(underlayNetwork, profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW);
+        populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, removedTunnelInterfaces, dpId, NwConstants.DEL_FLOW);
+        populatePolicyGroupsToDpn(underlayNetwork, profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW);
+        populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW);
     }
 
     @Override
@@ -135,8 +139,9 @@ public class UnderlayNetworkDpnListener
         }
 
         populatePolicyGroupsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW);
-        populatePolicyRoutesToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW);
+        populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW);
         populatePolicyAclRulesToDpn(underlayNetwork, dpId, profiles, NwConstants.ADD_FLOW);
+        populatePolicyRoutesToDpn(profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW);
     }
 
     private void populatePolicyGroupsToDpn(String underlayNetwork, List<PolicyProfile> profiles,
@@ -147,7 +152,7 @@ public class UnderlayNetworkDpnListener
         });
     }
 
-    private void populatePolicyRoutesToDpn(String underlayNetwork, List<PolicyProfile> profiles,
+    private void populatePolicyGroupBucketsToDpn(String underlayNetwork, List<PolicyProfile> profiles,
             List<TunnelInterface> tunnelInterfaces, BigInteger dpId, int addOrRemove) {
         profiles.forEach(profile -> {
             String policyClassifier = profile.getPolicyClassifier();
@@ -182,7 +187,7 @@ public class UnderlayNetworkDpnListener
                             com.google.common.base.Optional<Ace> policyAceOpt = policyServiceUtil
                                     .getPolicyAce(aclRule.getAclName(), aceRule.getRuleName());
                             if (policyAceOpt.isPresent()) {
-                                aceFlowProgrammer.programAceFlows(policyAceOpt.get(), dpId, NwConstants.ADD_FLOW);
+                                aceFlowProgrammer.programAceFlows(policyAceOpt.get(), dpId, addOrRemove);
                             } else {
                                 LOG.warn("Failed to get ACL {} rule {}", aclRule.getAclName(), aceRule.getRuleName());
                             }
@@ -196,4 +201,20 @@ public class UnderlayNetworkDpnListener
             });
         });
     }
+
+    private void populatePolicyRoutesToDpn(List<PolicyProfile> profiles, List<TunnelInterface> tunnelInterfaces,
+            BigInteger dpId, int addOrRemove) {
+        if (tunnelInterfaces == null) {
+            LOG.debug("No tunnel interfaces found for DPN {}", dpId);
+            return;
+        }
+
+        profiles.forEach(policyProfile -> {
+            String policyClassifier = policyProfile.getPolicyClassifier();
+            tunnelInterfaces.forEach(tunnelInterface -> {
+                BigInteger remoteDpId = tunnelInterface.getRemoteDpId();
+                routeFlowProgrammer.programPolicyClassifierFlow(policyClassifier, dpId, remoteDpId, addOrRemove);
+            });
+        });
+    }
 }
index 71ae152322334dbbf13cb2aac244687e2d60eadb..30d210e2b1c3058428b0480424a2e96a8258041f 100644 (file)
@@ -26,12 +26,17 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
 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.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,6 +61,22 @@ public class PolicyServiceFlowUtil {
         return instructions;
     }
 
+    public List<MatchInfoBase> getPolicyRouteMatches(long policyClassifierId, int lportTag) {
+        List<MatchInfoBase> matches = new ArrayList<>();
+        // FIXME reg6 masking support will allow matching only based on the lport-tag bits
+        matches.add(new NxMatchRegister(NxmNxReg6.class,
+                MetaDataUtil.getReg6ValueForLPortDispatcher(lportTag, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)));
+        matches.add(new MatchMetadata(MetaDataUtil.getPolicyClassifierMetaData(policyClassifierId),
+                MetaDataUtil.METADATA_MASK_POLICY_CLASSIFER_ID));
+        return matches;
+    }
+
+    public List<InstructionInfo> getPolicyRouteInstructions(long groupId) {
+        List<InstructionInfo> instructions = new ArrayList<>();
+        instructions.add(new InstructionApplyActions(Collections.singletonList(new ActionGroup(groupId))));
+        return instructions;
+    }
+
     public void updateFlowToTx(BigInteger dpId, short tableId, String flowName, int priority, BigInteger cookie,
             List<? extends MatchInfoBase> matches, List<InstructionInfo> instructions, int addOrRemove,
             WriteTransaction tx) {
@@ -113,7 +134,7 @@ public class PolicyServiceFlowUtil {
 
         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);
+        LOG.debug("Add bucket id {} for interface {} to group {} DPN {}", bucketId, interfaceName, groupId, dpId);
         mdsalManager.addBucketToTx(dpId, groupId, bucket, tx);
     }
 }
index 845c3edcfddf8be8e56cc49a982c1ecd588849c1..c8177d7745eaec773808da1e167a6f4d39c83f27 100644 (file)
@@ -14,6 +14,8 @@ import java.math.BigInteger;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
@@ -25,6 +27,8 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.netvirt.elanmanager.api.IElanBridgeManager;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AclBase;
@@ -35,6 +39,12 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Actions;
 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.TunnelTypeLogicalGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.PolicyAcl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.PolicyProfiles;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.SetPolicyClassifier;
@@ -56,10 +66,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.un
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,12 +81,17 @@ public class PolicyServiceUtil {
 
     private final DataBroker dataBroker;
     private final IElanBridgeManager bridgeManager;
+    private final ItmRpcService itmRpcService;
+    private final IInterfaceManager interfaceManager;
     private final DataStoreJobCoordinator coordinator;
 
     @Inject
-    public PolicyServiceUtil(final DataBroker dataBroker, final IElanBridgeManager bridgeManager) {
+    public PolicyServiceUtil(final DataBroker dataBroker, final IElanBridgeManager bridgeManager,
+            final ItmRpcService itmRpcService, final IInterfaceManager interfaceManager) {
         this.dataBroker = dataBroker;
         this.bridgeManager = bridgeManager;
+        this.itmRpcService = itmRpcService;
+        this.interfaceManager = interfaceManager;
         this.coordinator = DataStoreJobCoordinator.getInstance();
     }
 
@@ -88,14 +103,20 @@ public class PolicyServiceUtil {
             return Optional.absent();
         }
 
-        if (setPolicyClassifier.getDirection() == null
-                || !setPolicyClassifier.getDirection().isAssignableFrom(DirectionEgress.class)) {
+        Class<? extends DirectionBase> direction;
+        try {
+            direction = setPolicyClassifier.getDirection();
+        } catch (IllegalArgumentException e) {
+            LOG.warn("Failed to parse policy classifier direction");
+            return null;
+        }
+
+        if (direction == null || !direction.isAssignableFrom(DirectionEgress.class)) {
             LOG.trace("Ignoring non egress policy ACE rule {}", ace.getRuleName());
             return Optional.absent();
         }
 
         return Optional.of(setPolicyClassifier.getPolicyClassifier());
-
     }
 
     public Optional<Ace> getPolicyAce(String aclName, String ruleName) {
@@ -109,6 +130,18 @@ public class PolicyServiceUtil {
         }
     }
 
+    public List<PolicyProfile> getAllPolicyProfiles() {
+        InstanceIdentifier<PolicyProfiles> identifier = InstanceIdentifier.create(PolicyProfiles.class);
+        try {
+            Optional<PolicyProfiles> optProfiles = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, identifier);
+            return optProfiles.isPresent() ? optProfiles.get().getPolicyProfile() : Collections.emptyList();
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to get policy profiles");
+            return Collections.emptyList();
+        }
+    }
+
     public List<String> getUnderlayNetworksForClassifier(String policyClassifier) {
         InstanceIdentifier<PolicyProfile> identifier = getPolicyClassifierIdentifier(policyClassifier);
         try {
@@ -182,14 +215,14 @@ public class PolicyServiceUtil {
                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks
                         .underlay.network.PolicyProfile> identifier = getUnderlayNetworkPolicyClassifierIdentifier(
                                 policyClassifier, underlayNetwork);
+
                 if (isAdded) {
                     tx.merge(LogicalDatastoreType.OPERATIONAL, identifier,
                             new PolicyProfileBuilder().setPolicyClassifier(policyClassifier).build(), true);
                     LOG.info("Add policy classifier {} to underlay network {}", policyClassifier, underlayNetwork);
                 } else {
                     tx.delete(LogicalDatastoreType.OPERATIONAL, identifier);
-                    LOG.info("Remove policy classifier {} from underlay network {}", policyClassifier,
-                            underlayNetwork);
+                    LOG.info("Remove policy classifier {} from underlay network {}", policyClassifier, underlayNetwork);
                 }
                 return Collections.singletonList(tx.submit());
             });
@@ -232,6 +265,42 @@ public class PolicyServiceUtil {
                 .collect(Collectors.toList());
     }
 
+    public boolean underlayNetworkContainsDpn(String underlayNetwork, BigInteger dpId) {
+        return dpnToInterfacesContainsDpn(getUnderlayNetworkDpnToInterfaces(underlayNetwork), dpId);
+    }
+
+    public boolean underlayNetworkContainsRemoteDpn(String underlayNetwork, BigInteger dpId) {
+        return dpnToInterfacesContainsRemoteDpn(getUnderlayNetworkDpnToInterfaces(underlayNetwork), dpId);
+    }
+
+    public static boolean dpnToInterfacesContainsDpn(List<DpnToInterface> dpnToInterfaces, BigInteger dpId) {
+        if (dpnToInterfaces == null) {
+            return false;
+        }
+
+        return dpnToInterfaces.stream().filter(dpnToInterface -> dpnToInterface.getDpId().equals(dpId)).findFirst()
+                .isPresent();
+    }
+
+    public static boolean dpnToInterfacesContainsRemoteDpn(List<DpnToInterface> dpnToInterfaces, BigInteger dpId) {
+        if (dpnToInterfaces == null) {
+            return false;
+        }
+
+        return dpnToInterfaces.stream().filter(dpnToInterface -> dpnToInterfaceContainsRemoteDpn(dpnToInterface, dpId))
+                .findFirst().isPresent();
+    }
+
+    public static boolean dpnToInterfaceContainsRemoteDpn(DpnToInterface dpnToInterface, BigInteger dpId) {
+        List<TunnelInterface> tunnelInterfaces = dpnToInterface.getTunnelInterface();
+        if (tunnelInterfaces == null) {
+            return false;
+        }
+
+        return tunnelInterfaces.stream().filter(tunnelInterface -> tunnelInterface.getRemoteDpId().equals(dpId))
+                .findFirst().isPresent();
+    }
+
     public String getTunnelUnderlayNetwork(BigInteger dpId, IpAddress tunnelIp) {
         Node ovsdbNode = bridgeManager.getBridgeNode(dpId);
         if (ovsdbNode == null) {
@@ -348,4 +417,37 @@ public class PolicyServiceUtil {
     public List<BigInteger> getUnderlayNetworkRemoteDpns(String underlayNetwork) {
         return getRemoteDpnsFromDpnToInterfaces(getUnderlayNetworkDpnToInterfaces(underlayNetwork));
     }
+
+
+    public Optional<Integer> getLogicalTunnelLportTag(BigInteger srcDpId, BigInteger dstDpId) {
+        Optional<String> logicalTunnelNameOpt = getLogicalTunnelName(srcDpId, dstDpId);
+        if (!logicalTunnelNameOpt.isPresent()) {
+            LOG.debug("Failed to get logical tunnel for source DPN {} dst DPN {}", srcDpId, dstDpId);
+            return Optional.absent();
+        }
+
+        String logicalTunnelName = logicalTunnelNameOpt.get();
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(logicalTunnelName);
+        if (interfaceInfo == null) {
+            LOG.debug("Failed to get interface info for logical tunnel {}", logicalTunnelName);
+            return Optional.absent();
+        }
+
+        return Optional.of(interfaceInfo.getInterfaceTag());
+    }
+
+    public Optional<String> getLogicalTunnelName(BigInteger srcDpId, BigInteger dstDpId) {
+        Future<RpcResult<GetTunnelInterfaceNameOutput>> tunnelInterfaceOutput = itmRpcService
+                .getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder().setSourceDpid(srcDpId)
+                        .setDestinationDpid(dstDpId).setTunnelType(TunnelTypeLogicalGroup.class).build());
+        try {
+            if (tunnelInterfaceOutput.get().isSuccessful()) {
+                return Optional.of(tunnelInterfaceOutput.get().getResult().getInterfaceName());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error in RPC call getTunnelInterfaceName {} for source DPN {} dst DPN {}", srcDpId, dstDpId);
+        }
+
+        return Optional.absent();
+    }
 }
index d6256a65d898209335cd8ff2e0f1c406589d98de..070e96b3b752df5c626c626883e21096cf8ee63d 100644 (file)
@@ -15,6 +15,8 @@
   <reference id="iElanBridgeManager"
     interface="org.opendaylight.netvirt.elanmanager.api.IElanBridgeManager" />
 
+  <odl:rpc-service id="itmRpcService"
+    interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService" />
   <odl:rpc-service id="idManagerService"
     interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService" />