Implement generation of policy enforcement table 16/9416/3
authorRob Adams <readams@readams.net>
Mon, 28 Jul 2014 22:18:55 +0000 (15:18 -0700)
committerRob Adams <readams@readams.net>
Mon, 28 Jul 2014 23:06:47 +0000 (16:06 -0700)
 * Refactor policy resolver semantics to provide the right APIs
 * Keep track of condition groups
 * Create rudimentary framework for generating rules from classifiers.

Change-Id: I044a3268bcd15aa0bc2ea072a73e7d74c72da5ad
Signed-off-by: Rob Adams <readams@readams.net>
36 files changed:
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/EndpointManager.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SubjectFeatures.java [deleted file]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTable.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurity.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Classifier.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/EtherTypeClassifier.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/IpProtoClassifier.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/L4Classifier.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionGroup.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionSet.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EgKey.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EndpointProvider.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenant.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/Policy.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyCache.java [deleted file]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyInfo.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyListener.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/RuleGroup.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/SetUtils.java [moved from groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SetUtils.java with 69% similarity]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/SingletonTask.java [moved from groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SingletonTask.java with 98% similarity]
groupbasedpolicy/src/main/yang/model/policy.yang
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapperTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/MockPolicyResolver.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/SingletonTaskTest.java [moved from groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SingletonTaskTest.java with 98% similarity]

index 843c8835eb5c9d8761e3230b601e4e703946cf11..af3783af95f7774ffff5e3677cd62a54bdd45449 100644 (file)
@@ -26,8 +26,9 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.endpoint.AbstractEndpointRegistry;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.groupbasedpolicy.resolver.EndpointProvider;
+import org.opendaylight.groupbasedpolicy.util.SetUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
@@ -47,7 +48,6 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 
-
 /**
  * Keep track of endpoints on the system.  Maintain an index of endpoints
  * and their locations for renderering.  The endpoint manager will maintain
@@ -61,7 +61,7 @@ import com.google.common.collect.Collections2;
  */
 public class EndpointManager 
         extends AbstractEndpointRegistry 
-        implements AutoCloseable, DataChangeListener
+        implements AutoCloseable, DataChangeListener, EndpointProvider
     {
     private static final Logger LOG = 
             LoggerFactory.getLogger(EndpointManager.class);
@@ -121,19 +121,6 @@ public class EndpointManager
         return Collections2.transform(ebn, indexTransform);
     }
 
-    /**
-     * Get a collection of endpoints in a particular endpoint group
-     * @param nodeId the nodeId of the switch to get endpoints for
-     * @return a collection of {@link Endpoint} objects.
-     */
-    public Collection<Endpoint> getEndpointsForGroup(TenantId tenantId, 
-                                                     EndpointGroupId egId) {
-        EgKey eg = new EgKey(tenantId, egId);
-        Collection<EpKey> ebg = endpointsByGroup.get(eg);
-        if (ebg == null) return Collections.emptyList();
-        return Collections2.transform(ebg, indexTransform);
-    }
-
     /**
      * Get the endpoint object for the given key
      * @param epKey the key
@@ -150,7 +137,27 @@ public class EndpointManager
     public void setLearningMode(LearningMode learningMode) {
         // No-op for now
     }
-    
+
+    // ****************
+    // EndpointProvider
+    // ****************
+
+    @Override
+    public Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
+        Collection<EpKey> ebg = endpointsByGroup.get(eg);
+        if (ebg == null) return Collections.emptyList();
+        return Collections2.transform(ebg, indexTransform);
+    }
+
+    @Override
+    public List<ConditionName> getCondsForEndpoint(Endpoint endpoint) {
+        // XXX TODO consider group conditions as well.  Also need to notify
+        // endpoint updated if the endpoint group conditions change
+        if (endpoint.getCondition() != null)
+            return endpoint.getCondition();
+        else return Collections.emptyList();
+    }
+
     // ************************
     // AbstractEndpointRegistry
     // ************************
@@ -312,13 +319,13 @@ public class EndpointManager
         if (newLoc != null) {
             Set<EpKey> eps = getEpNSet(newLoc);
             eps.add(epKey);
-            LOG.info("Endpoint {} added to node {}", epKey, newLoc);
+            LOG.debug("Endpoint {} added to node {}", epKey, newLoc);
             notifyNewLoc = true;
         }
         if (newKey != null) {
             Set<EpKey> gns = getEpGSet(newKey);
             gns.add(epKey);
-            LOG.info("Endpoint {} added to group {}", epKey, newKey);
+            LOG.debug("Endpoint {} added to group {}", epKey, newKey);
             notifyNewEg = true;
         }
 
index 821832563236872ad44b9bba8024cbb169588fc0..3fd17fbe8ad13c708b86e3a9a729aa0313f68a90 100644 (file)
@@ -61,10 +61,10 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
         int numCPU = Runtime.getRuntime().availableProcessors();
         executor = Executors.newScheduledThreadPool(numCPU * 2);
 
-        policyResolver = new PolicyResolver(dataProvider, executor);
         switchManager = new SwitchManager(dataProvider, executor);
         endpointManager = new EndpointManager(dataProvider, rpcRegistry,
                                               executor, switchManager);
+        policyResolver = new PolicyResolver(dataProvider, executor);
 
         policyManager = new PolicyManager(dataProvider,
                                           policyResolver,
index 0c65b55cd13877df7d1a8fa3186e2cc463b7cc4d..b7aa73f70e7536259a2e6256d85cd17a265ae7e4 100644 (file)
@@ -33,10 +33,15 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyListener;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyScope;
+import org.opendaylight.groupbasedpolicy.util.SetUtils;
+import org.opendaylight.groupbasedpolicy.util.SingletonTask;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
@@ -71,6 +76,7 @@ public class PolicyManager
 
     private final DataBroker dataBroker;
     private final SwitchManager switchManager;
+    private final PolicyResolver policyResolver;
     
     private final PolicyScope policyScope;
     
@@ -98,13 +104,17 @@ public class PolicyManager
     
     /**
      * Keep track of currently-allocated ordinals
-     * XXX should ultimately involve some sort of distributed agreement
-     * or a leader to allocate them.  For now we'll just use a counter and
-     * this local map
      */
+    // XXX For the endpoint groups, we need a globally unique ordinal, so
+    // should ultimately involve some sort of distributed agreement
+    // or a leader to allocate them.  For now we'll just use a counter and
+    // this local map.  Also theoretically need to garbage collect periodically
     private final ConcurrentMap<TenantId, ConcurrentMap<String, Integer>> ordinals = 
             new ConcurrentHashMap<>();
-    
+    // XXX - need to garbage collect
+    private final ConcurrentMap<ConditionGroup, Integer> cgOrdinals = 
+            new ConcurrentHashMap<>();
+            
     public PolicyManager(DataBroker dataBroker,
                          PolicyResolver policyResolver,
                          SwitchManager switchManager,
@@ -115,6 +125,7 @@ public class PolicyManager
         this.dataBroker = dataBroker;
         this.switchManager = switchManager;
         this.executor = executor;
+        this.policyResolver = policyResolver;
 
         if (dataBroker != null) {
             WriteTransaction t = dataBroker.newWriteOnlyTransaction();
@@ -247,7 +258,25 @@ public class PolicyManager
     public void setLearningMode(LearningMode learningMode) {
         // No-op for now
     }
-    
+
+    /**
+     * Get a unique ordinal for the given condition group, suitable for
+     * use in the data plane.  This is unique only for this node, and not 
+     * globally.
+     * @param cg the {@link ConditionGroup}
+     * @return the unique ID
+     */
+    public int getConfGroupOrdinal(final ConditionGroup cg) {
+        if (cg == null) return 0;
+        Integer ord = cgOrdinals.get(cg);
+        if (ord == null) {
+            ord = policyOrdinal.getAndIncrement();
+            Integer old = cgOrdinals.putIfAbsent(cg, ord);
+            if (old != null) ord = old; 
+        }
+        return ord.intValue();
+    }
+
     /**
      * Get a 32-bit context ordinal suitable for use in the OF data plane
      * for the given policy item.  Note that this function may block
@@ -337,10 +366,12 @@ public class PolicyManager
 
         @Override
         public Void call() throws Exception {
-            if (!switchManager.isSwitchReady(nodeId)) return null;            
+            if (!switchManager.isSwitchReady(nodeId)) return null;
+            PolicyInfo info = policyResolver.getCurrentPolicy();
+            if (info == null) return null;
             for (FlowTable table : flowPipeline) {
                 try {
-                    table.update(nodeId, dirty);
+                    table.update(nodeId, info, dirty);
                 } catch (Exception e) {
                     LOG.error("Failed to write flow table {}", 
                               table.getClass().getName(), e);
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SubjectFeatures.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SubjectFeatures.java
deleted file mode 100644 (file)
index 05c3acd..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2014 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
- */
-
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Defines the subject features that are supported by the OF overlay renderer
- */
-public class SubjectFeatures {
-    public static final ActionDefinition ALLOW = 
-            new ActionDefinitionBuilder()
-                .setId(new ActionDefinitionId("f942e8fd-e957-42b7-bd18-f73d11266d17"))
-                .setName(new ActionName("allow"))
-                .setDescription(new Description("Allow the specified traffic to pass"))
-                .build();
-
-    public static final ClassifierDefinition ETHER_TYPE = 
-            new ClassifierDefinitionBuilder()
-                .setId(new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335"))
-                .setName(new ClassifierName("ether_type"))
-                .setDescription(new Description("Match on the ether type of the traffic"))
-                .setParameter(ImmutableList.of(new ParameterBuilder()
-                    .setName(new ParameterName("type"))
-                    .setDescription(new Description("The ethertype to match against"))
-                    .setType(Type.Int)
-                    .build()))
-                .build();
-
-    public static final ClassifierDefinition IP_PROTO = 
-            new ClassifierDefinitionBuilder()
-                .setId(new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335"))
-                .setParent(ETHER_TYPE.getId())
-                .setName(new ClassifierName("ip_proto"))
-                .setDescription(new Description("Match on the IP protocol of IP traffic"))
-                .setParameter(ImmutableList.of(new ParameterBuilder()
-                    .setName(new ParameterName("proto"))
-                    .setDescription(new Description("The IP protocol to match against"))
-                    .setType(Type.Int)
-                    .build()))
-                .build();
-
-    public static final ClassifierDefinition UDP_PORT = 
-            new ClassifierDefinitionBuilder()
-                .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
-                .setParent(IP_PROTO.getId())
-                .setName(new ClassifierName("udp_port"))
-                .setDescription(new Description("Match on the port number of UDP traffic"))
-                .setParameter(ImmutableList.of(new ParameterBuilder()
-                    .setName(new ParameterName("port"))
-                    .setDescription(new Description("The port number to match against"))
-                    .setType(Type.Int)
-                    .build()))
-                .build();
-
-    public static final ClassifierDefinition TCP_PORT = 
-            new ClassifierDefinitionBuilder()
-                .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
-                .setParent(IP_PROTO.getId())
-                .setName(new ClassifierName("tcp_port"))
-                .setDescription(new Description("Match on the port number of TCP traffic"))
-                .setParameter(ImmutableList.of(new ParameterBuilder()
-                    .setName(new ParameterName("port"))
-                    .setDescription(new Description("The port number to match against"))
-                    .setType(Type.Int)
-                    .build()))
-                .build();
-
-    public static final SubjectFeatureDefinitions OF_OVERLAY_FEATURES =
-            new SubjectFeatureDefinitionsBuilder()
-                .setActionDefinition(ImmutableList.of(ALLOW))
-                .setClassifierDefinition(ImmutableList.of(ETHER_TYPE,
-                                                          IP_PROTO,
-                                                          UDP_PORT,
-                                                          TCP_PORT))
-                .build();
-}
index 8a32fbb906982bb2cd1c4d4b4cd584ec88912637..4e898fe17dd907ef944005c81f019939827985ba 100644 (file)
@@ -10,14 +10,18 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
@@ -30,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.I
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
@@ -40,6 +45,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
 
 /**
  * Manage the table that maps the destination address to the next hop
@@ -47,6 +56,9 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * @author readams
  */
 public class DestinationMapper extends FlowTable {
+    protected static final Logger LOG =
+            LoggerFactory.getLogger(DestinationMapper.class);
+
     public static final short TABLE_ID = 2;
     /**
      * This is the MAC address of the magical router in the sky
@@ -67,34 +79,21 @@ public class DestinationMapper extends FlowTable {
     public void sync(ReadWriteTransaction t, 
                      InstanceIdentifier<Table> tiid,
                      Map<String, FlowCtx> flowMap, 
-                     NodeId nodeId, Dirty dirty)
+                     NodeId nodeId, PolicyInfo policyInfo, Dirty dirty)
                              throws Exception {
+        dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
         HashSet<EgKey> visitedEgs = new HashSet<>();
-        for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+        for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
             if (e.getTenant() == null || e.getEndpointGroup() == null)
                 continue;
             EgKey key = new EgKey(e.getTenant(), e.getEndpointGroup());
-            syncEPG(t, tiid, flowMap, nodeId, key, visitedEgs);
             
-            Set<EgKey> peers = ctx.policyResolver
-                    .getProvidersForConsumer(e.getTenant(), 
-                                             e.getEndpointGroup());
-            syncEgKeys(t, tiid, flowMap, nodeId, peers, visitedEgs);
-            peers = ctx.policyResolver
-                    .getConsumersForProvider(e.getTenant(), 
-                                             e.getEndpointGroup());
-            syncEgKeys(t, tiid, flowMap, nodeId, peers, visitedEgs);
-        }
-    }
-    
-    private void syncEgKeys(ReadWriteTransaction t, 
-                            InstanceIdentifier<Table> tiid,
-                            Map<String, FlowCtx> flowMap, 
-                            NodeId nodeId,
-                            Set<EgKey> peers,
-                            HashSet<EgKey> visitedEgs) throws Exception {
-        for (EgKey key : peers) {
-            syncEPG(t, tiid, flowMap, nodeId, key, visitedEgs);
+            Set<EgKey> peers = Sets.union(Collections.singleton(key),
+                                          policyInfo.getPeers(key));
+            for (EgKey peer : peers) {
+                syncEPG(t, tiid, flowMap, nodeId, policyInfo, peer, visitedEgs);
+            }
         }
     }
 
@@ -103,28 +102,28 @@ public class DestinationMapper extends FlowTable {
     private void syncEPG(ReadWriteTransaction t, 
                          InstanceIdentifier<Table> tiid,
                          Map<String, FlowCtx> flowMap, 
-                         NodeId nodeId,
+                         NodeId nodeId, PolicyInfo policyInfo, 
                          EgKey key,
                          HashSet<EgKey> visitedEgs) throws Exception {
         if (visitedEgs.contains(key)) return;
         visitedEgs.add(key);
         
-        Collection<Endpoint> egEps = ctx.endpointManager
-                .getEndpointsForGroup(key.getTenantId(), key.getEgId());
+        Collection<Endpoint> egEps = ctx.epManager
+                .getEndpointsForGroup(key);
         for (Endpoint e : egEps) {
             if (e.getTenant() == null || e.getEndpointGroup() == null)
                 continue;
             OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
             if (ofc == null || ofc.getNodeId() == null) continue;
             
-            syncEP(t, tiid, flowMap, nodeId, e, ofc, key);
+            syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, key);
         }
     }
 
     private void syncEP(ReadWriteTransaction t,
                         InstanceIdentifier<Table> tiid,
                         Map<String, FlowCtx> flowMap, 
-                        NodeId nodeId, 
+                        NodeId nodeId, PolicyInfo policyInfo, 
                         Endpoint e, OfOverlayContext ofc,
                         EgKey key) 
                                  throws Exception {
@@ -148,6 +147,8 @@ public class DestinationMapper extends FlowTable {
                 // this is a local endpoint
                 nextHop = ofc.getNodeConnectorId().getValue();
 
+                // XXX - TODO - instead of outputting, write next hop
+                // to a register and output from the policy table
                 Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
 
                 instructions.add(new InstructionBuilder()
@@ -204,6 +205,17 @@ public class DestinationMapper extends FlowTable {
                 order +=1;
             }
         }
+        
+        int egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
+                                                       e.getEndpointGroup());
+        List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+        ConditionGroup cg = 
+                policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
+                                                    e.getEndpointGroup()), 
+                                          conds);
+        int cgId = ctx.policyManager.getConfGroupOrdinal(cg);
+        
+        // XXX TODO - add action set dEPG and dCG into registers
         Instruction gotoTable = new InstructionBuilder()
             .setOrder(order++)
             .setInstruction(FlowUtils.gotoTableIns((short)(getTableId()+1)))
@@ -219,6 +231,7 @@ public class DestinationMapper extends FlowTable {
             .append(nextHop)
             .toString());
         if (visit(flowMap, flowid.getValue())) {
+            LOG.info("{} deg:{} dcg:{}", e.getMacAddress(), egId, cgId);
             // XXX TODO add match against bridge domain register
             FlowBuilder flowb = base()
                 .setId(flowid)
index c24cc4817c119795381a3c711d30b42c516cbe7b..0b3ef5fac5c4075142db41ea241f60d4cdae3588 100644 (file)
@@ -20,10 +20,13 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SwitchManager;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -53,7 +56,7 @@ public abstract class FlowTable {
 
         protected final PolicyManager policyManager;
         protected final SwitchManager switchManager;
-        protected final EndpointManager endpointManager;
+        protected final EndpointManager epManager;
 
         protected final PolicyResolver policyResolver;
 
@@ -71,7 +74,7 @@ public abstract class FlowTable {
             this.rpcRegistry = rpcRegistry;
             this.policyManager = policyManager;
             this.switchManager = switchManager;
-            this.endpointManager = endpointManager;
+            this.epManager = endpointManager;
             this.policyResolver = policyResolver;
             this.executor = executor;
         }
@@ -95,13 +98,17 @@ public abstract class FlowTable {
      * @param dirty the dirty set
      * @throws Exception
      */
-    public void update(NodeId nodeId, Dirty dirty) throws Exception {
+    public void update(NodeId nodeId, PolicyInfo policyInfo,
+                       Dirty dirty) throws Exception {
         ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
         InstanceIdentifier<Table> tiid =
                 FlowUtils.createTablePath(nodeId, getTableId());
         Optional<Table> r =
                 t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
 
+        // Unfortunately, we need to construct a unique string ID for each
+        // flow which is redundant with all the information in the flow itself
+        // We'll build this map so at least we don't have to be O(n^2)
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
 
         if (r.isPresent()) {
@@ -114,7 +121,7 @@ public abstract class FlowTable {
             }
         }
 
-        sync(t, tiid, flowMap, nodeId, dirty);
+        sync(t, tiid, flowMap, nodeId, policyInfo, dirty);
 
         for (FlowCtx fx : flowMap.values()) {
             if (!fx.visited) {
@@ -134,7 +141,8 @@ public abstract class FlowTable {
     public abstract void sync(ReadWriteTransaction t,
                               InstanceIdentifier<Table> tiid,
                               Map<String, FlowCtx> flowMap,
-                              NodeId nodeId, Dirty dirty) throws Exception;
+                              NodeId nodeId, PolicyInfo policyInfo, 
+                              Dirty dirty) throws Exception;
 
     /**
      * Get the table ID being manipulated
@@ -204,6 +212,32 @@ public abstract class FlowTable {
               flow);
     }
 
+    /**
+     * Write a drop flow for the given ethertype at the given priority.
+     * If the ethertype is null, then drop all traffic
+     */
+    protected void dropFlow(ReadWriteTransaction t,
+                            InstanceIdentifier<Table> tiid,
+                            Map<String, FlowCtx> flowMap,
+                            Integer priority, Long etherType) {
+        FlowId flowid = new FlowId(new StringBuilder()
+            .append("drop|")
+            .append(etherType)
+            .toString());
+        if (visit(flowMap, flowid.getValue())) {
+            FlowBuilder flowb = base()
+                .setId(flowid)
+                .setPriority(priority)
+                .setInstructions(FlowUtils.dropInstructions());
+            if (etherType != null)
+                flowb.setMatch(new MatchBuilder()
+                    .setEthernetMatch(FlowUtils.ethernetMatch(null, null, 
+                                                              etherType))
+                        .build());
+            writeFlow(t, tiid, flowb.build());
+        }
+    }
+
     /**
      * Context object for keeping track of flow state
      */
index ad83cc756fed0a306c2f9442e5fc76e13cddc84f..88fc912668efcf5c0cf97ad010bb0deb26a4e9ce 100644 (file)
@@ -59,15 +59,15 @@ public final class FlowUtils {
     /**
      * ARP ethertype
      */
-    protected static final Long ARP = Long.valueOf(0x0806);
+    public static final Long ARP = Long.valueOf(0x0806);
     /**
      * IPv4 ethertype
      */
-    protected static final Long IPv4 = Long.valueOf(0x0800);
+    public static final Long IPv4 = Long.valueOf(0x0800);
     /**
      * IPv6 ethertype
      */
-    protected static final Long IPv6 = Long.valueOf(0x86DD);
+    public static final Long IPv6 = Long.valueOf(0x86DD);
     
     /**
      * Creates an Instance Identifier (path) for node with specified id
index 2f383de23a4ae49dad0649ac00a660aca79a252e..749baea817b15d465b2d285e54c218389c54d9ab 100644 (file)
@@ -8,13 +8,44 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.resolver.Policy;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
+import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Manage the table that enforces policy on the traffic.  Traffic is denied
@@ -22,22 +53,268 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * @author readams
  */
 public class PolicyEnforcer extends FlowTable {
+    protected static final Logger LOG =
+            LoggerFactory.getLogger(PolicyEnforcer.class);
+
     public static final short TABLE_ID = 3;
 
     public PolicyEnforcer(FlowTableCtx ctx) {
         super(ctx);
     }
 
+    @Override
+    public short getTableId() {
+        return TABLE_ID;
+    }
+
     @Override
     public void sync(ReadWriteTransaction t, InstanceIdentifier<Table> tiid,
-                     Map<String, FlowCtx> flowMap, NodeId nodeId, Dirty dirty)
+                     Map<String, FlowCtx> flowMap, NodeId nodeId, 
+                     PolicyInfo policyInfo, Dirty dirty)
+                             throws Exception {
+        dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
+        HashSet<CgPair> visitedPairs = new HashSet<>();
+        HashSet<EgKey> visitedEgs = new HashSet<>();
+        for (Endpoint src : ctx.epManager.getEndpointsForNode(nodeId)) {
+            if (src.getTenant() == null || src.getEndpointGroup() == null)
+                continue;
+
+            List<ConditionName> conds = 
+                    ctx.epManager.getCondsForEndpoint(src);
+            ConditionGroup scg = 
+                    policyInfo.getEgCondGroup(new EgKey(src.getTenant(), 
+                                                        src.getEndpointGroup()),
+                                              conds);
+            int sepgId = 
+                    ctx.policyManager.getContextOrdinal(src.getTenant(), 
+                                                        src.getEndpointGroup());
+            int scgId = ctx.policyManager.getConfGroupOrdinal(scg);
+            
+            EgKey sepg = new EgKey(src.getTenant(), src.getEndpointGroup());
+
+            if (!visitedEgs.contains(sepg)) {
+                visitedEgs.add(sepg);
+                IndexedTenant tenant = 
+                        ctx.policyResolver.getTenant(sepg.getTenantId());
+                EndpointGroup group = 
+                        tenant.getEndpointGroup(sepg.getEgId());
+                IntraGroupPolicy igp = group.getIntraGroupPolicy();
+                if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
+                    allowSameEpg(t, tiid, flowMap, nodeId, sepgId);
+                }
+            }
+            
+            Set<EgKey> peers = policyInfo.getPeers(sepg);
+            for (EgKey depg : peers) {
+                int depgId = 
+                        ctx.policyManager.getContextOrdinal(depg.getTenantId(), 
+                                                            depg.getEgId());
+
+                for (Endpoint dst : ctx.epManager.getEndpointsForGroup(depg)) {
+
+                    conds = ctx.epManager.getCondsForEndpoint(src);
+                    ConditionGroup dcg = 
+                            policyInfo.getEgCondGroup(new EgKey(dst.getTenant(), 
+                                                                dst.getEndpointGroup()),
+                                                      conds);
+                    int dcgId = ctx.policyManager.getConfGroupOrdinal(dcg);
+                    
+                    CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
+                    if (visitedPairs.contains(p)) continue;
+                    visitedPairs.add(p);
+                    syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
+                               p, depg, sepg, dcg, scg);
+
+                    p = new CgPair(sepgId, depgId, scgId, dcgId);
+                    if (visitedPairs.contains(p)) continue;
+                    visitedPairs.add(p);
+                    syncPolicy(t, tiid, flowMap, nodeId, policyInfo, 
+                               p, sepg, depg, scg, dcg);
+                    
+                }
+            }
+        }
+    }
+    
+    private void allowSameEpg(ReadWriteTransaction t, 
+                              InstanceIdentifier<Table> tiid,
+                              Map<String, FlowCtx> flowMap, NodeId nodeId,
+                              int sepgId) {
+        FlowId flowId = new FlowId(new StringBuilder()
+            .append("intraallow|")
+            .append(sepgId).toString());
+        if (visit(flowMap, flowId.getValue())) {
+            // XXX - TODO - add match against sepg, depg registers
+            // XXX - TOOD - add output action from destination register
+            FlowBuilder flow = base()
+                .setId(flowId)
+                .setPriority(65000);
+            writeFlow(t, tiid, flow.build());
+        }
+    }
+    
+    private void syncPolicy(ReadWriteTransaction t, 
+                            InstanceIdentifier<Table> tiid,
+                            Map<String, FlowCtx> flowMap, NodeId nodeId,
+                            PolicyInfo policyInfo, 
+                            CgPair p, EgKey sepg, EgKey depg,
+                            ConditionGroup scg, ConditionGroup dcg) 
                              throws Exception {
+        // XXX - TODO raise an exception for rules between the same
+        // endpoint group that are asymmetric
+        Policy policy = policyInfo.getPolicy(sepg, depg);
+        List<RuleGroup> rgs = policy.getRules(scg, dcg);
         
+        int priority = 65000;
+        for (RuleGroup rg : rgs) {
+            TenantId tenantId = rg.getContractTenant().getId();
+            IndexedTenant tenant = ctx.policyResolver.getTenant(tenantId); 
+            for (Rule r : rg.getRules()) {
+                syncDirection(t, tiid, flowMap, nodeId, tenant,
+                                    p, r, Direction.In, priority);
+                syncDirection(t, tiid, flowMap, nodeId, tenant,
+                                    p, r, Direction.Out, priority);
+                
+                priority -= 1;
+            }
+        }
     }
+    
+    private void syncDirection(ReadWriteTransaction t, 
+                               InstanceIdentifier<Table> tiid,
+                               Map<String, FlowCtx> flowMap, NodeId nodeId,
+                               IndexedTenant contractTenant,
+                               CgPair p, Rule r, Direction d, int priority) {
+        for (ClassifierRef cr : r.getClassifierRef()) {
+            if (cr.getDirection() != null && 
+                !cr.getDirection().equals(Direction.Bidirectional) && 
+                !cr.getDirection().equals(d))
+                continue;
+            
+            StringBuilder idb = new StringBuilder();
+            // XXX - TODO - implement connection tracking (requires openflow 
+            // extension and data plane support)
+
+            MatchBuilder baseMatch = new MatchBuilder();
+
+            if (d.equals(Direction.Out)) {
+                idb.append(p.sepg)
+                    .append("|")
+                    .append(p.scgId)
+                    .append("|")
+                    .append(p.depg)
+                    .append("|")
+                    .append(p.dcgId)
+                    .append("|")
+                    .append(priority);
+                // XXX - TODO - add match against sepg, depg, scg, and dcg
+                // registers
+            } else {
+                idb.append(p.depg)
+                    .append("|")
+                    .append(p.dcgId)
+                    .append("|")
+                    .append(p.sepg)
+                    .append("|")
+                    .append(p.scgId)
+                    .append("|")
+                    .append(priority);                
+                // XXX - TODO - add match against sepg, depg, scg, and dcg
+                // registers
+            }
+
+
+            ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
+            if (ci == null) {
+                // XXX TODO fail the match and raise an exception
+                LOG.warn("Classifier instance {} not found", 
+                         cr.getName().getValue());
+                return;
+            }
+            Classifier cfier = SubjectFeatures
+                    .getClassifier(ci.getClassifierDefinitionId());
+            if (cfier == null) {
+                // XXX TODO fail the match and raise an exception
+                LOG.warn("Classifier definition {} not found", 
+                         ci.getClassifierDefinitionId().getValue());
+                return;
+            }
+
+            List<MatchBuilder> matches = Collections.singletonList(baseMatch);
+            Map<String,Object> params = new HashMap<>();
+            for (ParameterValue v : ci.getParameterValue()) {
+                if (v.getName() == null) continue;
+                if (v.getIntValue() != null) {
+                    params.put(v.getName().getValue(), v.getIntValue());
+                } else if (v.getStringValue() != null) {
+                    params.put(v.getName().getValue(), v.getStringValue());
+                }
+            }
+            
+            matches = cfier.updateMatch(matches, params);
+            String baseId = idb.toString();
+            FlowBuilder flow = base()
+                    .setPriority(Integer.valueOf(priority));
+            for (MatchBuilder match : matches) {
+                Match m = match.build();
+                FlowId flowId = new FlowId(baseId + "|" + m.toString());
+                flow.setMatch(m)
+                    .setId(flowId)
+                    .setPriority(Integer.valueOf(priority));
+                if (visit(flowMap, flowId.getValue())) {
+                    LOG.info("{} {} {} {}", p.sepg, p.scgId, p.depg, p.dcgId);
+                    writeFlow(t, tiid, flow.build());
+                }
+            }
+        } 
 
-    @Override
-    public short getTableId() {
-        return TABLE_ID;
     }
 
+    @Immutable
+    private static class CgPair {
+        private final int sepg;
+        private final int depg;
+        private final int scgId;
+        private final int dcgId;
+        
+        public CgPair(int sepg, int depg, int scgId, int dcgId) {
+            super();
+            this.sepg = sepg;
+            this.depg = depg;
+            this.scgId = scgId;
+            this.dcgId = dcgId;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + dcgId;
+            result = prime * result + depg;
+            result = prime * result + scgId;
+            result = prime * result + sepg;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            CgPair other = (CgPair) obj;
+            if (dcgId != other.dcgId)
+                return false;
+            if (depg != other.depg)
+                return false;
+            if (scgId != other.scgId)
+                return false;
+            if (sepg != other.sepg)
+                return false;
+            return true;
+        }
+    }
 }
index d19480b21ae386a7b62003e65faa22b5050980e2..c0fb19cc8f534cd8a06ce6011b1ef2e9255bc517 100644 (file)
@@ -13,6 +13,7 @@ import java.util.Set;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -57,7 +58,7 @@ public class PortSecurity extends FlowTable {
     public void sync(ReadWriteTransaction t,
                      InstanceIdentifier<Table> tiid,
                      Map<String, FlowCtx> flowMap,
-                     NodeId nodeId, Dirty dirty) {
+                     NodeId nodeId, PolicyInfo policyInfo, Dirty dirty) {
         // Allow traffic from tunnel and external ports
         NodeConnectorId tunnelIf = ctx.switchManager.getTunnelPort(nodeId);
         if (tunnelIf != null)
@@ -76,7 +77,7 @@ public class PortSecurity extends FlowTable {
         dropFlow(t, tiid, flowMap, 111, FlowUtils.IPv4);
         dropFlow(t, tiid, flowMap, 112, FlowUtils.IPv6);
 
-        for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+        for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
             OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
             if (ofc != null && ofc.getNodeConnectorId() != null &&
                 (ofc.getLocationType() == null ||
@@ -112,29 +113,7 @@ public class PortSecurity extends FlowTable {
             writeFlow(t, tiid, flowb.build());
         }
     }
-    
-    private void dropFlow(ReadWriteTransaction t,
-                          InstanceIdentifier<Table> tiid,
-                          Map<String, FlowCtx> flowMap,
-                          Integer priority, Long etherType) {
-        FlowId flowid = new FlowId(new StringBuilder()
-            .append("drop|")
-            .append(etherType)
-            .toString());
-        if (visit(flowMap, flowid.getValue())) {
-            FlowBuilder flowb = base()
-                .setId(flowid)
-                .setPriority(priority)
-                .setInstructions(FlowUtils.dropInstructions());
-            if (etherType != null)
-                flowb.setMatch(new MatchBuilder()
-                    .setEthernetMatch(FlowUtils.ethernetMatch(null, null, 
-                                                              etherType))
-                        .build());
-            writeFlow(t, tiid, flowb.build());
-        }
-    }
-    
+        
     private void l2flow(ReadWriteTransaction t,
                         InstanceIdentifier<Table> tiid,
                         Map<String, FlowCtx> flowMap,
@@ -159,7 +138,6 @@ public class PortSecurity extends FlowTable {
             writeFlow(t, tiid, flowb.build());
         }
     }
-    
 
     private void l3flow(ReadWriteTransaction t,
                         InstanceIdentifier<Table> tiid,
index 97541e4db78fe08bf8d5fe509a65901d13630ea5..9aad43ac35418f5b75a626552dbc6dbf1893f837 100644 (file)
@@ -8,15 +8,20 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.util.List;
 import java.util.Map;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;
 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
@@ -26,6 +31,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Manage the table that assigns source endpoint group, bridge domain, and 
@@ -33,6 +40,9 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * @author readams
  */
 public class SourceMapper extends FlowTable {
+    protected static final Logger LOG =
+            LoggerFactory.getLogger(SourceMapper.class);
+
     public static final short TABLE_ID = 1;
 
     public SourceMapper(FlowTableCtx ctx) {
@@ -48,16 +58,19 @@ public class SourceMapper extends FlowTable {
     public void sync(ReadWriteTransaction t,
                      InstanceIdentifier<Table> tiid,
                      Map<String, FlowCtx> flowMap, 
-                     NodeId nodeId, Dirty dirty) throws Exception {
+                     NodeId nodeId, PolicyInfo policyInfo, 
+                     Dirty dirty) throws Exception {
+        dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
         // XXX TODO Set sEPG from tunnel ports using the tunnel ID
         
-        for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+        for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
             OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
             if (ofc != null && ofc.getNodeConnectorId() != null &&
                 (ofc.getLocationType() == null ||
                  LocationType.Internal.equals(ofc.getLocationType())) &&
                  e.getTenant() != null && e.getEndpointGroup() != null) {
-                syncEP(t, tiid, flowMap, nodeId, e, ofc);
+                syncEP(t, tiid, flowMap, policyInfo, nodeId, e, ofc);
             } 
         }
     }
@@ -65,6 +78,7 @@ public class SourceMapper extends FlowTable {
     private void syncEP(ReadWriteTransaction t,
                         InstanceIdentifier<Table> tiid,
                         Map<String, FlowCtx> flowMap, 
+                        PolicyInfo policyInfo,
                         NodeId nodeId, Endpoint e, OfOverlayContext ofc) 
                                  throws Exception {
         // Set sEPG, flood domain, bridge domain, and layer 3 context 
@@ -77,7 +91,7 @@ public class SourceMapper extends FlowTable {
         L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
         L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
 
-        int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
+        int egId = 0, bdId = 0, fdId = 0, l3Id = 0, cgId = 0;
         
         egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
                                                    e.getEndpointGroup());
@@ -90,7 +104,12 @@ public class SourceMapper extends FlowTable {
         if (l3c != null)
             l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
                                                        l3c.getId());
-        // TODO set source condition set ID as well
+        List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+        ConditionGroup cg = 
+                policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
+                                                    e.getEndpointGroup()), 
+                                          conds);
+        cgId = ctx.policyManager.getConfGroupOrdinal(cg);
         
         FlowId flowid = new FlowId(new StringBuilder()
             .append(ofc.getNodeConnectorId())
@@ -104,10 +123,12 @@ public class SourceMapper extends FlowTable {
             .append(fdId)
             .append("|")
             .append(l3Id)
+            .append("|")
+            .append(cgId)
             .toString());
         if (visit(flowMap, flowid.getValue())) {
-            LOG.info("{} eg:{} bd:{} fd:{} vrf:{}", 
-                     e.getMacAddress(), egId, bdId, fdId, l3Id);
+            LOG.info("{} seg:{} bd:{} fd:{} vrf:{} scg:{}", 
+                     e.getMacAddress(), egId, bdId, fdId, l3Id, cgId);
             FlowBuilder flowb = base()
                 .setPriority(Integer.valueOf(100))
                 .setId(flowid)
@@ -116,7 +137,7 @@ public class SourceMapper extends FlowTable {
                                                               null, null))
                     .setInPort(ofc.getNodeConnectorId())
                     .build())
-                // XXX TODO set sepg, bd, fd, vrf into registers
+                // XXX TODO set sepg, bd, fd, vrf, scg into registers
                 .setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)));
             writeFlow(t, tiid, flowb.build());
         }
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Classifier.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Classifier.java
new file mode 100644 (file)
index 0000000..a8d4d0d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+
+/**
+ * Represent a classifier definition, and provide tools for generating flow
+ * rules based on the classifier
+ * @author readams
+ */
+public abstract class Classifier {
+    /**
+     * Get the classifier definition for this classifier
+     * @return the {@link ClassifierDefinition} for this classifier
+     */
+    public abstract ClassifierDefinitionId getId();
+
+    /**
+     * Get the classifier definition for this classifier
+     * @return the {@link ClassifierDefinition} for this classifier
+     */
+    public abstract ClassifierDefinition getClassDef();
+    
+    /**
+     * Construct a set of matches that will apply to the traffic.  Augment
+     * the existing list of matches or add new matches.  It's important
+     * that the order of the returned list be consistent however
+     * @param matches The existing matches
+     * @param params the parameters for the classifier instance
+     * @return the updated list of matches (may be a different length)
+     */
+    public abstract List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+                                                   Map<String, Object> params);
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/EtherTypeClassifier.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/EtherTypeClassifier.java
new file mode 100644 (file)
index 0000000..79c73fa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Match on the ether type of the traffic
+ */
+public class EtherTypeClassifier extends Classifier {
+    public static final ClassifierDefinitionId ID = 
+            new ClassifierDefinitionId("6a48ab45-a462-429d-b18c-3a575b2c8bef");
+    protected static final String TYPE = "type";
+    protected static final ClassifierDefinition DEF = 
+            new ClassifierDefinitionBuilder()
+                .setId(ID)
+                .setName(new ClassifierName("ether_type"))
+                .setDescription(new Description("Match on the ether type of the traffic"))
+                .setParameter(ImmutableList.of(new ParameterBuilder()
+                    .setName(new ParameterName(TYPE))
+                    .setDescription(new Description("The ethertype to match against"))
+                    .setIsRequired(IsRequired.Required)
+                    .setType(Type.Int)
+                    .build()))
+                .build();
+
+    @Override
+    public ClassifierDefinitionId getId() {
+        return ID;
+    }
+
+    @Override
+    public ClassifierDefinition getClassDef() {
+        return DEF;
+    }
+
+    @Override
+    public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+                                          Map<String, Object> params) {
+        Object t = params.get(TYPE);
+        // XXX TODO generate exception and fail the match
+        if (t == null || !(t instanceof Long)) return matches;
+        Long type = (Long)t;
+        for (MatchBuilder match : matches) {
+            EthernetMatchBuilder em;
+            if (match.getEthernetMatch() != null)
+                em = new EthernetMatchBuilder(match.getEthernetMatch());
+            else
+                em = new EthernetMatchBuilder();
+            em.setEthernetType(new EthernetTypeBuilder()
+                .setType(new EtherType(type)).build());
+            match.setEthernetMatch(em.build());
+        }
+        return matches;
+    }
+
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/IpProtoClassifier.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/IpProtoClassifier.java
new file mode 100644 (file)
index 0000000..e105bc7
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Match on the IP protocol of IP traffic
+ */
+public class IpProtoClassifier extends EtherTypeClassifier {
+    public static final ClassifierDefinitionId ID = 
+            new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335");
+    protected static final String PROTO = "proto";
+    protected static final ClassifierDefinition DEF = 
+            new ClassifierDefinitionBuilder()
+                .setId(ID)
+                .setParent(EtherTypeClassifier.ID)
+                .setName(new ClassifierName("ip_proto"))
+                .setDescription(new Description("Match on the IP protocol of IP traffic"))
+                .setParameter(ImmutableList.of(new ParameterBuilder()
+                    .setName(new ParameterName(PROTO))
+                    .setDescription(new Description("The IP protocol to match against"))
+                    .setIsRequired(IsRequired.Required)
+                    .setType(Type.Int)
+                    .build()))
+                .build();
+
+    private static final Map<String, Object> ipv4 = 
+        ImmutableMap.<String,Object>of(TYPE, FlowUtils.IPv4);
+    private static final Map<String, Object> ipv6 = 
+            ImmutableMap.<String,Object>of(TYPE, FlowUtils.IPv6);
+
+    @Override
+    public ClassifierDefinitionId getId() {
+        return ID;
+    }
+
+    @Override
+    public ClassifierDefinition getClassDef() {
+        return DEF;
+    }
+
+    @Override
+    public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+                                          Map<String, Object> params) {
+        Object t = params.get(PROTO);
+        // XXX TODO generate exception and fail the match
+        if (t == null || !(t instanceof Long)) return matches;
+        Long proto = (Long)t;
+        
+        ArrayList<MatchBuilder> r = new ArrayList<>();
+        for (MatchBuilder b : matches) {
+            r.addAll(updateMatch(new MatchBuilder(b.build()), proto, ipv4));
+            r.addAll(updateMatch(new MatchBuilder(b.build()), proto, ipv6));
+        }
+        return r;
+    }
+
+    private List<MatchBuilder> updateMatch(MatchBuilder match,
+                                           Long proto,
+                                           Map<String, Object> parentParams) {
+        List<MatchBuilder> r = 
+                super.updateMatch(Collections.singletonList(match), 
+                                  parentParams);
+        for (MatchBuilder mb : r) {
+            IpMatchBuilder imb;
+            if (mb.getIpMatch() != null)
+                imb = new IpMatchBuilder(mb.getIpMatch());
+            else 
+                imb = new IpMatchBuilder();
+            imb.setIpProtocol(proto.shortValue());
+            mb.setIpMatch(imb.build());
+        }
+        return r;
+    }
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/L4Classifier.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/L4Classifier.java
new file mode 100644 (file)
index 0000000..229b472
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Match against TCP or UDP, and source and/or destination ports
+ * @author readams
+ */
+public class L4Classifier extends IpProtoClassifier {
+    public static final ClassifierDefinitionId ID = 
+            new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f");
+    private static final String SPORT = "sourceport";
+    private static final String DPORT = "destport";
+    private static final ClassifierDefinition DEF = 
+            new ClassifierDefinitionBuilder()
+                .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
+                .setParent(IpProtoClassifier.ID)
+                .setName(new ClassifierName("l4"))
+                .setDescription(new Description("Match on the port number of UDP or TCP traffic"))
+                .setParameter(ImmutableList.of(new ParameterBuilder()
+                        .setName(new ParameterName(SPORT))
+                        .setDescription(new Description("The source port number to match against"))
+                        .setType(Type.Int)
+                        .build(),
+                    new ParameterBuilder()
+                        .setName(new ParameterName(DPORT))
+                        .setDescription(new Description("The destination port number to match against"))
+                        .setType(Type.Int)
+                        .build(),
+                    new ParameterBuilder()
+                        .setName(new ParameterName(TYPE))
+                        .setDescription(new Description("TCP or UDP"))
+                        .setIsRequired(IsRequired.Required)
+                        .setType(Type.String)
+                        .build()))
+                .build();
+    
+    private static final Map<String, Object> tcp = 
+            ImmutableMap.<String,Object>of(PROTO, Long.valueOf(6));
+    private static final Map<String, Object> udp = 
+            ImmutableMap.<String,Object>of(PROTO, Long.valueOf(17));
+    
+    @Override
+    public ClassifierDefinitionId getId() {
+        return ID;
+    }
+
+    @Override
+    public ClassifierDefinition getClassDef() {
+        return DEF;
+    }
+
+    @Override
+    public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+                                          Map<String, Object> params) {
+        Object t = params.get(TYPE);
+        // XXX TODO generate exception and fail the match
+        if (t == null || !(t instanceof String)) return matches;
+        String type = (String)t;
+        
+        if ("UDP".equals(type))
+            matches = super.updateMatch(matches, udp);
+        else
+            matches = super.updateMatch(matches, tcp);            
+
+        Long sport = null;
+        Long dport = null;
+        t = params.get(SPORT);
+        if (t != null && (t instanceof Long))
+            sport = (Long)t;
+        t = params.get(DPORT);
+        if (t != null && (t instanceof Long))
+            dport = (Long)t;
+
+        for (MatchBuilder b : matches) {
+            if ("UDP".equals(type)) {
+                UdpMatchBuilder m = new UdpMatchBuilder();
+                if (sport != null)
+                    m.setUdpSourcePort(new PortNumber(sport.intValue()));
+                if (dport != null)
+                    m.setUdpDestinationPort(new PortNumber(dport.intValue()));
+                b.setLayer4Match(m.build());
+            } else {
+                TcpMatchBuilder m = new TcpMatchBuilder();
+                if (sport != null)
+                    m.setTcpSourcePort(new PortNumber(sport.intValue()));
+                if (dport != null)
+                    m.setTcpDestinationPort(new PortNumber(dport.intValue()));
+                b.setLayer4Match(m.build());
+            }
+        }
+        return matches;
+    }
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java
new file mode 100644 (file)
index 0000000..7d8377d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Defines the subject features that are supported by the OF overlay renderer
+ */
+public class SubjectFeatures {
+    private static final Map<ClassifierDefinitionId, Classifier> classifiers =
+            ImmutableMap.<ClassifierDefinitionId, Classifier>
+                of(EtherTypeClassifier.ID, new EtherTypeClassifier(),
+                   IpProtoClassifier.ID, new IpProtoClassifier(),
+                   L4Classifier.ID, new L4Classifier());
+
+    private static final List<ClassifierDefinition> classifierDefs =
+            ImmutableList.copyOf(Collections2.transform(classifiers.values(), 
+                new Function<Classifier, ClassifierDefinition>() {
+                    @Override
+                    public ClassifierDefinition apply(Classifier input) {
+                        return input.getClassDef();
+                    }
+                }
+            ));
+    
+    public static final ActionDefinition ALLOW = 
+            new ActionDefinitionBuilder()
+                .setId(new ActionDefinitionId("f942e8fd-e957-42b7-bd18-f73d11266d17"))
+                .setName(new ActionName("allow"))
+                .setDescription(new Description("Allow the specified traffic to pass"))
+                .build();
+
+    public static final SubjectFeatureDefinitions OF_OVERLAY_FEATURES =
+            new SubjectFeatureDefinitionsBuilder()
+                .setActionDefinition(ImmutableList.of(ALLOW))
+                .setClassifierDefinition(classifierDefs)
+                .build();
+
+    /**
+     * Get the {@link Classifier} associated with the given 
+     * {@link ClassifierDefinitionId}
+     * @param id the {@link ClassifierDefinitionId} to look up
+     * @return the {@link Classifier} if one exists, or <code>null</code> 
+     * otherwise
+     */
+    public static Classifier getClassifier(ClassifierDefinitionId id) {
+        return classifiers.get(id);
+    }
+                                           
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionGroup.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionGroup.java
new file mode 100644 (file)
index 0000000..5d0547b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * A condition group is a unique set of conditions that are active for a 
+ * particular endpoint group.  Because of the potential for combinatorial
+ * explosion with condition matchers, we only keep track of the combinations
+ * that are active for a particular endpoint group.
+ * @author readams
+ */
+@Immutable
+public class ConditionGroup {
+    public static final ConditionGroup EMPTY = 
+            new ConditionGroup(Collections.<ConditionSet>emptySet());
+    
+    private final Set<ConditionSet> conditionSets;
+    private final int hashCode;
+
+    public ConditionGroup(Set<ConditionSet> conditionSets) {
+        super();
+        this.conditionSets = Collections.unmodifiableSet(conditionSets);
+        hashCode = computeHashCode();
+    }
+
+    /**
+     * Check whether the given condition set is in this condition group
+     * @param cs the condition set to check
+     * @return <code>true</code> if the condition set is a member of this
+     * condition group
+     */
+    public boolean contains(ConditionSet cs) {
+        return conditionSets.contains(cs);
+    }
+    
+    private int computeHashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result +
+                 ((conditionSets == null) ? 0 : conditionSets.hashCode());
+        return result;
+    }
+    
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ConditionGroup other = (ConditionGroup) obj;
+        if (conditionSets == null) {
+            if (other.conditionSets != null)
+                return false;
+        } else if (!conditionSets.equals(other.conditionSets))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ConditionGroup [conditionSets=" + conditionSets + "]";
+    }
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionSet.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ConditionSet.java
new file mode 100644 (file)
index 0000000..1a33905
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+
+/**
+ * Represents a set of conditions for endpoint groups.  For an endpoint
+ * to match the condition set, all the conditions in "all" must match,
+ * and none of the conditions in "none" can match.  Additionally, in
+ * each set of "any" conditions, at least one condition must match.
+ * Note that if all sets are empty, then the condition set matches 
+ * automatically
+ * @author readams
+ */
+@Immutable
+public class ConditionSet {
+    private final Set<ConditionName> all;
+    private final Set<ConditionName> none;
+    private final Set<? extends Set<ConditionName>> any;
+    private final int hashCode;
+    
+    public static final ConditionSet EMPTY = 
+            new ConditionSet(Collections.<ConditionName>emptySet(),
+                             Collections.<ConditionName>emptySet(),
+                             Collections.<Set<ConditionName>>emptySet());
+    
+    public ConditionSet(Set<ConditionName> all,
+                        Set<ConditionName> none,
+                        Set<? extends Set<ConditionName>> any) {
+        super();
+        this.all = all;
+        this.none = none;
+        this.any = any;
+        this.hashCode = computeHashCode();
+    }
+    
+    /**
+     * Check if the condition set matches against the given list of conditions
+     * for a particular endpoint
+     * @param conditions the list of conditions
+     * @return <code>true</code> if the condition set matches the conditions
+     */
+    public boolean matches(List<ConditionName> conditions) {
+        Set<ConditionName> matching = new HashSet<>();
+        Set<Set<ConditionName>> anyMatch = new HashSet<>();
+        for (ConditionName name : conditions) {
+            if (none.contains(name)) return false;
+            if (all.contains(name)) matching.add(name);
+            for (Set<ConditionName> anyItem : any) {
+                if (anyItem.contains(name)) anyMatch.add(anyItem);
+            }
+        }
+        if (all.size() != matching.size()) return false;
+        if (any.size() != anyMatch.size()) return false;
+        return true;
+    }
+    
+    private int computeHashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((all == null) ? 0 : all.hashCode());
+        result = prime * result + ((any == null) ? 0 : any.hashCode());
+        result = prime * result + ((none == null) ? 0 : none.hashCode());
+        return result;
+    }
+    
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ConditionSet other = (ConditionSet) obj;
+        if (all == null) {
+            if (other.all != null)
+                return false;
+        } else if (!all.equals(other.all))
+            return false;
+        if (any == null) {
+            if (other.any != null)
+                return false;
+        } else if (!any.equals(other.any))
+            return false;
+        if (none == null) {
+            if (other.none != null)
+                return false;
+        } else if (!none.equals(other.none))
+            return false;
+        return true;
+    }
+    @Override
+    public String toString() {
+        return "ConditionSet [all=" + all + ", none=" + none + ", any=" +
+               any + "]";
+    }
+}
\ No newline at end of file
index d209ca0aceea1b36b209449d8a9a9c84bd2f3d02..9081d0a1fcc5de5809c36f373274010061e53751 100644 (file)
@@ -5,12 +5,15 @@ import javax.annotation.concurrent.Immutable;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+
 /**
  * A tuple referencing an endpoint group and its enclosing tenant
  * @author readams
  */
 @Immutable
-public class EgKey {
+public class EgKey implements Comparable<EgKey> {
     private final TenantId tenantId;
     private final EndpointGroupId egId;
     @Override
@@ -48,6 +51,25 @@ public class EgKey {
         this.tenantId = tenantId;
         this.egId = egId;
     }
+
+    @Override
+    public int compareTo(EgKey o) {
+        String tid = null;
+        if (tenantId != null) tid = tenantId.getValue();
+        String otid = null;
+        if (o.tenantId != null) otid = o.tenantId.getValue();
+        String egid = null;
+        if (egId != null) tid = egId.getValue();
+        String oegid = null;
+        if (o.egId != null) oegid = o.egId.getValue();
+        return ComparisonChain.start()
+            .compare(tid, otid, 
+                     Ordering.natural().nullsLast())
+            .compare(egid, oegid, 
+                     Ordering.natural().nullsLast())
+            .result();
+    }
+
     @Override
     public String toString() {
         return "EgKey [tenantId=" + tenantId + ", egId=" + egId + "]";
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EndpointProvider.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EndpointProvider.java
new file mode 100644 (file)
index 0000000..c8037fc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+
+/**
+ * When the policy changes, recompute the set of active condition groups
+ * based on the endpoints in a particular endpoint group
+ * @author readams
+ */
+public interface EndpointProvider {
+    /**
+     * Get a collection of endpoints in a particular endpoint group
+     * @param nodeId the nodeId of the switch to get endpoints for
+     * @return a collection of {@link Endpoint} objects.
+     */
+    public Collection<Endpoint> getEndpointsForGroup(EgKey eg);
+
+    /**
+     * Get the effective list of conditions that apply to a particular 
+     * endpoint.  This could include additional conditions over the condition
+     * labels directly represented in the endpoint object
+     * @param endpoint the {@link Endpoint} to resolve
+     * @return the list of {@link ConditionName}
+     */
+    public List<ConditionName> getCondsForEndpoint(Endpoint endpoint);
+}
index d15dbbb9daefb96358eccc762bb7b296e4312e7e..ffe055cd3e356eb4f1b2f5123a56aa33a699d364 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Map;
 
 import javax.annotation.concurrent.Immutable;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
@@ -24,7 +26,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
 
 /**
  * Wrap some convenient indexes around a {@link Tenant} object
@@ -41,6 +46,10 @@ public class IndexedTenant {
             new HashMap<>();
     private final Map<String, NetworkDomain> networkDomains =
             new HashMap<>();
+    private final Map<ClassifierName, ClassifierInstance> classifiers =
+            new HashMap<>();
+    private final Map<ActionName, ActionInstance> actions =
+            new HashMap<>();
     
     public IndexedTenant(Tenant tenant) {
         super();
@@ -77,6 +86,19 @@ public class IndexedTenant {
                 networkDomains.put(s.getId().getValue(), s);
             }
         }
+        if (tenant.getSubjectFeatureInstances() != null) {
+            SubjectFeatureInstances sfi = tenant.getSubjectFeatureInstances();
+            if (sfi.getClassifierInstance() != null) {
+                for (ClassifierInstance ci : sfi.getClassifierInstance()) {
+                    classifiers.put(ci.getName(), ci);
+                }
+            }
+            if (sfi.getActionInstance() != null) {
+                for (ActionInstance action : sfi.getActionInstance()) {
+                    actions.put(action.getName(), action);
+                }
+            }
+        }
     }
 
     /**
@@ -116,6 +138,26 @@ public class IndexedTenant {
     public Contract getContract(ContractId id) {
         return contracts.get(id);
     }
+    
+    /**
+     * Look up the classifier instance specified
+     * @param name the {@link ClassifierName}
+     * @return the {@link ClassifierInstance} if it exists, or <code>null</code> 
+     * otherwise
+     */
+    public ClassifierInstance getClassifier(ClassifierName name) {
+        return classifiers.get(name);
+    }
+
+    /**
+     * Look up the classifier instance specified
+     * @param name the {@link ActionName}
+     * @return the {@link ActionInstance} if it exists, or <code>null</code> 
+     * otherwise
+     */
+    public ActionInstance getAction(ActionName name) {
+        return actions.get(name);
+    }
 
     /**
      * Get the layer 3 context for the specified network domain by walking
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/Policy.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/Policy.java
new file mode 100644 (file)
index 0000000..e283a13
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
+
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
+
+/**
+ * Represent the policy that applies to a single pair of endpoint groups
+ * The policy is represented as a list of {@link RuleGroup} objects.  A 
+ * {@link RuleGroup} references ordered lists of rules from the policy,
+ * along with the associated {@link Tenant}, {@link Contract}, and 
+ * {@link SubjectName}.
+ * 
+ * A {@link RuleGroup} applies to a particular endpoint based on the set of
+ * conditions that are active for that endpoint.  All rule groups associated
+ * with matching {@link ConditionSet}s apply.
+ * @author readams
+ */
+@Immutable
+public class Policy {
+    public static final Policy EMPTY = 
+            new Policy(ImmutableTable.<ConditionSet, ConditionSet, 
+                                       List<RuleGroup>>of());
+    
+    final Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap;
+    final boolean reversed;
+    public Policy(Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap) {
+        super();
+        this.ruleMap = ruleMap;
+        this.reversed = false;
+    }
+    public Policy(Policy existing, boolean reversed) {
+        super();
+        this.ruleMap = existing.ruleMap;
+        this.reversed = existing.reversed != reversed;
+    }
+    
+    @Override
+    public String toString() {
+        return "Policy [ruleMap=" + ruleMap + "]";
+    }
+    
+    /**
+     * Get the rules that apply to a particular pair of condition groups
+     * @param fromCg the condition group that applies to the origin endpoint
+     * @param toCg the condition group that applies to the destination endpoint
+     * @return
+     */
+    public List<RuleGroup> getRules(ConditionGroup fromCg,
+                                    ConditionGroup toCg) {
+        ArrayList<RuleGroup> rules = new ArrayList<>();
+        for (Cell<ConditionSet, ConditionSet, List<RuleGroup>> cell : ruleMap.cellSet()) {
+            if (fromCg.contains(cell.getRowKey()) &&
+                    toCg.contains(cell.getColumnKey()))
+                rules.addAll(cell.getValue());
+        }
+        Collections.sort(rules);
+        return rules;
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyCache.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyCache.java
deleted file mode 100644 (file)
index 7c93ddf..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2014 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
- */
-
-package org.opendaylight.groupbasedpolicy.resolver;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.annotation.concurrent.Immutable;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
-
-import com.google.common.collect.Table;
-import com.google.common.collect.Table.Cell;
-
-/**
- * Represent the policy relationships between endpoint groups 
- * @author readams
- *
- */
-class PolicyCache {
-    
-    /**
-     * Store a policy object for each endpoint group pair.  The table
-     * is stored with the key as (consumer, provider).  Two endpoints could
-     * appear in both roles at the same time, in which case both policies would
-     * apply.
-     */
-    AtomicReference<Table<EgKey, EgKey, Policy>> policy = 
-            new AtomicReference<>();    
-            
-    // ***************
-    // PolicyCache API
-    // ***************
-            
-    /**
-     * Lookup a policy in the cache
-     */
-    protected List<RuleGroup> getPolicy(TenantId ep1Tenant,
-                                        EndpointGroupId ep1Group, 
-                                        ConditionSet ep1Conds,
-                                        TenantId ep2Tenant,
-                                        EndpointGroupId ep2Group, 
-                                        ConditionSet ep2Conds) {        
-        EgKey k1 = new EgKey(ep1Tenant, ep1Group);
-        EgKey k2 = new EgKey(ep2Tenant, ep2Group);
-        Policy p = policy.get().get(k1, k2);
-        if (p == null) return Collections.emptyList();
-        List<RuleGroup> result = p.ruleMap.get(ep1Conds, ep2Conds);
-        if (result == null) return Collections.emptyList();
-        return result;
-    }
-    
-    /**
-     * Get the set of providers that have contracts with the consumer
-     * @param tenant the tenant ID for the endpoint group
-     * @param eg the endpoint group ID
-     */
-    protected Set<EgKey> getProvidersForConsumer(TenantId tenant,
-                                                 EndpointGroupId eg) {
-        if (policy.get() == null) return Collections.emptySet();
-        EgKey k = new EgKey(tenant, eg);
-        return Collections.unmodifiableSet(policy.get().row(k).keySet());
-    }
-    
-    /**
-     * Get the set of providers that apply 
-     * @param tenant the tenant ID for the endpoint group
-     * @param eg the endpoint group ID
-     */
-    protected Set<EgKey> getConsumersForProvider(TenantId tenant,
-                                                 EndpointGroupId eg) {
-        if (policy.get() == null) return Collections.emptySet();
-        EgKey k = new EgKey(tenant, eg);
-        return Collections.unmodifiableSet(policy.get().column(k).keySet());
-    }
-    
-    /**
-     * Atomically update the active policy and notify policy listeners 
-     * of relevant changes
-     * @param newPolicy the new policy to set
-     * @return the set of consumers with updated policy
-     */
-    protected Set<EgKey> updatePolicy(Table<EgKey, EgKey, Policy> newPolicy,
-                                List<PolicyScope> policyListenerScopes) {
-        Table<EgKey, EgKey, Policy> oldPolicy = policy.getAndSet(newPolicy);
-        
-        HashSet<EgKey> notifySet = new HashSet<>(); 
-        
-        for (Cell<EgKey, EgKey, Policy> cell : newPolicy.cellSet()) {
-            Policy newp = cell.getValue();
-            Policy oldp = null;
-            if (oldPolicy != null)
-                oldp = oldPolicy.get(cell.getRowKey(), cell.getColumnKey());
-            if (oldp == null || !newp.equals(oldp)) {
-                notifySet.add(cell.getRowKey());
-            }
-        }
-        if (oldPolicy != null) {
-            for (Cell<EgKey, EgKey, Policy> cell : oldPolicy.cellSet()) {
-                if (!newPolicy.contains(cell.getRowKey(), cell.getColumnKey())) {
-                    notifySet.add(cell.getRowKey());
-                }
-            }
-        }
-        return notifySet;
-    }
-    
-    // **************
-    // Helper classes
-    // **************
-
-    @Immutable
-    protected static class Policy {
-        final Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap;
-        public Policy(Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap) {
-            super();
-            this.ruleMap = ruleMap;
-        }
-        @Override
-        public String toString() {
-            return "Policy [ruleMap=" + ruleMap + "]";
-        }
-    }
-
-    /**
-     * Represents a set of conditions for endpoint groups.  For an endpoint
-     * to match the condition set, all the conditions in "all" must match,
-     * and none of the conditions in "none" can match.  Additionally, in
-     * each set of "any" conditions, at least one condition must match.
-     * Note that if all sets are empty, then the condition set matches 
-     * automatically
-     * @author readams
-     */
-    @Immutable
-    public static class ConditionSet {
-        private final Set<ConditionName> all;
-        private final Set<ConditionName> none;
-        private final Set<? extends Set<ConditionName>> any;
-        private final int hashCode;
-        
-        public static final ConditionSet EMPTY = 
-                new ConditionSet(Collections.<ConditionName>emptySet(),
-                                 Collections.<ConditionName>emptySet(),
-                                 Collections.<Set<ConditionName>>emptySet());
-        
-        public ConditionSet(Set<ConditionName> all,
-                            Set<ConditionName> none,
-                            Set<? extends Set<ConditionName>> any) {
-            super();
-            this.all = all;
-            this.none = none;
-            this.any = any;
-            this.hashCode = computeHashCode();
-        }
-        
-        private int computeHashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((all == null) ? 0 : all.hashCode());
-            result = prime * result + ((any == null) ? 0 : any.hashCode());
-            result = prime * result + ((none == null) ? 0 : none.hashCode());
-            return result;
-        }
-        
-        @Override
-        public int hashCode() {
-            return hashCode;
-        }
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            ConditionSet other = (ConditionSet) obj;
-            if (all == null) {
-                if (other.all != null)
-                    return false;
-            } else if (!all.equals(other.all))
-                return false;
-            if (any == null) {
-                if (other.any != null)
-                    return false;
-            } else if (!any.equals(other.any))
-                return false;
-            if (none == null) {
-                if (other.none != null)
-                    return false;
-            } else if (!none.equals(other.none))
-                return false;
-            return true;
-        }
-        @Override
-        public String toString() {
-            return "ConditionSet [all=" + all + ", none=" + none + ", any=" +
-                   any + "]";
-        }
-    }
-}
\ No newline at end of file
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyInfo.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyInfo.java
new file mode 100644 (file)
index 0000000..aa6448f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+
+/**
+ * Represent the current policy snapshot for the set of tenants that are
+ * in scope
+ * @author readams
+ */
+@Immutable
+public class PolicyInfo {
+    final Table<EgKey, EgKey, Policy> policyMap;
+    final Map<EgKey, Set<ConditionSet>> egConditions;
+
+    public PolicyInfo(Table<EgKey, EgKey, Policy> policyMap,
+                      Map<EgKey, Set<ConditionSet>> egConditions) {
+        super();
+        this.policyMap = policyMap;
+        this.egConditions = egConditions;
+    }
+    public Table<EgKey, EgKey, Policy> getPolicyMap() {
+        return policyMap;
+    }
+    
+    /**
+     * Get the policy that currently applies to traffic flowing out of 
+     * the specified originating endpoint group into the specified destination
+     * endpoint group.  Note that there will be policy only for one of the two
+     * possible directions.
+     * 
+     * @param fromGroup the endpoint group for the originating endpoint
+     * @param toGroup the endpoint group for the destination endpoint
+     * @return the {@link Policy} that applies.  Cannot be null
+     */
+    public Policy getPolicy(EgKey fromGroup, EgKey toGroup) {
+        Policy p = policyMap.get(fromGroup, toGroup);
+        if (p == null) return Policy.EMPTY;
+        return p;
+    }
+
+    /**
+     * Get the condition sets for a particular endpoint group
+     * @param eg the endpoint group
+     * @return the set of condition sets that could apply to an endpoint
+     * in that endpoint group
+     */
+    public Set<ConditionSet> getEgConditions(EgKey eg) {
+        return Collections.unmodifiableSet(egConditions.get(eg));
+    }
+    
+    /**
+     * Get the condition group as it applies to the given list of conditions
+     * @param eg
+     * @param conditions
+     * @return
+     */
+    public ConditionGroup getEgCondGroup(EgKey eg, 
+                                         List<ConditionName> conditions) {
+        Set<ConditionSet> egconds = egConditions.get(eg);
+        if (egconds == null) return ConditionGroup.EMPTY;
+        Set<ConditionSet> matching = null;
+        for (ConditionSet cs : egconds) {
+            if (cs.matches(conditions)) {
+                if (matching == null) matching = new HashSet<>();
+                matching.add(cs);
+            }
+        }
+        if (matching == null) return ConditionGroup.EMPTY;
+        return new ConditionGroup(matching);
+    }
+
+    /**
+     * Get the set of endpoint groups that are peers for the given endpoint
+     * group
+     * @param eg the endpoint group
+     * @return the set of endpoint groups
+     */
+    public Set<EgKey> getPeers(EgKey eg) {
+        return Sets.union(policyMap.row(eg).keySet(), 
+                          policyMap.column(eg).keySet());
+    }
+}
\ No newline at end of file
index a42699481925ff2c49b48a1f7b4020dd49897605..5e8c71981a9258e2d086642b68219fbb721427d9 100644 (file)
@@ -18,11 +18,11 @@ import java.util.Set;
 public interface PolicyListener {
 
     /**
-     * Indicates that the policy related to the set of consumer endpoint groups
+     * Indicates that the policy related to the set of endpoint groups
      * has changed
-     * @param updatedConsumers the set of consumer endpoint groups involved
+     * @param updatedConsumers the set of endpoint groups involved
      * in a contract whose policy has changed
      */
-    public void policyUpdated(Set<EgKey> updatedConsumers);
+    public void policyUpdated(Set<EgKey> updatedGroups);
     
 }
index 996f6446ba589138b1f2e5f69ec16df60c1400d0..2426fcf7e054d0004d76697e2ef5d05abf8d7d50 100644 (file)
@@ -9,9 +9,12 @@
 package org.opendaylight.groupbasedpolicy.resolver;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -24,19 +27,20 @@ import javax.annotation.concurrent.Immutable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.ConditionSet;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ConsumerSelectionRelator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ProviderSelectionRelator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcher;
@@ -49,6 +53,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.RequirementMatcher;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.CapabilityMatcher;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
@@ -80,14 +85,6 @@ import com.google.common.util.concurrent.ListenableFuture;
  * list of rules that apply to a given pair of endpoints depends on the
  * conditions that are active on the endpoints.
  *
- * In a more formal sense: Let there be endpoint groups G_n, and for each G_n a
- * set of conditions C_n that can apply to endpoints in G_n.  Further, let S be
- * the set of lists of rules defined in the policy.  Our policy can be
- * represented as a function F: (G_n, 2^C_n, G_m, 2^C_m) -> S, where 2^C_n
- * represents the power set of C_n. In other words, we want to map all the
- * possible tuples of pairs of endpoints along with their active conditions
- * onto the right list of rules to apply.
- *
  * <p>We need to be able to query against this policy model, enumerate the
  * relevant classes of traffic and endpoints, and notify renderers when there
  * are changes to policy as it applies to active sets of endpoints and
@@ -112,7 +109,13 @@ public class PolicyResolver implements AutoCloseable {
 
     protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
 
-    protected PolicyCache policyCache = new PolicyCache();
+    /**
+     * Store a policy object for each endpoint group pair.  The table
+     * is stored with the key as (consumer, provider).  Two endpoints could
+     * appear in both roles at the same time, in which case both policies would
+     * apply.
+     */
+    AtomicReference<PolicyInfo> policy = new AtomicReference<>();
 
     public PolicyResolver(DataBroker dataProvider,
                           ScheduledExecutorService executor) {
@@ -141,50 +144,14 @@ public class PolicyResolver implements AutoCloseable {
     // *************************
 
     /**
-     * Get the policy that currently applies to a pair of endpoints.
-     * with the specified groups and conditions.  The first endpoint acts as
-     * the consumer and the second endpoint acts as the provider, so to get
-     * all policy related to this pair of endpoints you must call this
-     * function twice: once for each possible order of endpoints.
-     *
-     * @param ep1Tenant the tenant ID for the first endpoint
-     * @param ep1Group the endpoint group for the first endpoint
-     * @param ep1Conds The conditions that apply to the first endpoint
-     * @param ep2Tenant the tenant ID for the second endpoint
-     * @param ep2Group the endpoint group for the second endpoint
-     * @param ep2Conds The conditions that apply to the second endpoint.
-     * @return a list of {@link RuleGroup} that apply to the endpoints.
-     * Cannot be null, but may be an empty list of rulegroups
+     * Get a snapshot of the current policy
+     * @return the {@link PolicyInfo} object representing an immutable
+     * snapshot of the policy state
      */
-    public List<RuleGroup> getPolicy(TenantId ep1Tenant,
-                                     EndpointGroupId ep1Group,
-                                     ConditionSet ep1Conds,
-                                     TenantId ep2Tenant,
-                                     EndpointGroupId ep2Group,
-                                     ConditionSet ep2Conds) {
-        return policyCache.getPolicy(ep1Tenant, ep1Group, ep1Conds,
-                                     ep2Tenant, ep2Group, ep2Conds);
+    public PolicyInfo getCurrentPolicy() {
+        return policy.get();
     }
-    /**
-     * Get the set of providers that have contracts with the consumer
-     * @param tenant the tenant ID for the endpoint group
-     * @param eg the endpoint group ID
-     */
-    public Set<EgKey> getProvidersForConsumer(TenantId tenant,
-                                              EndpointGroupId eg) {
-        return policyCache.getProvidersForConsumer(tenant, eg);
-    }
-    
-    /**
-     * Get the set of providers that apply 
-     * @param tenant the tenant ID for the endpoint group
-     * @param eg the endpoint group ID
-     */
-    public Set<EgKey> getConsumersForProvider(TenantId tenant,
-                                              EndpointGroupId eg) {
-        return policyCache.getConsumersForProvider(tenant, eg);
-    }
-    
+
     /**
      * Get the normalized tenant for the given ID
      * @param tenant the tenant ID
@@ -222,12 +189,50 @@ public class PolicyResolver implements AutoCloseable {
     // **************
 
     /**
-     * Notify the policy listeners about a set of updated consumers
+     * Atomically update the active policy and notify policy listeners 
+     * of relevant changes
+     * @param policyMap the new policy to set
+     * @param egConditions the map of endpoint groups to relevant condition sets
+     * @return the set of groups with updated policy
      */
-    private void notifyListeners(Set<EgKey> updatedConsumers) {
+    protected Set<EgKey> updatePolicy(Table<EgKey, EgKey, Policy> policyMap,
+                                      Map<EgKey, Set<ConditionSet>> egConditions,
+                                      List<PolicyScope> policyListenerScopes) {
+        PolicyInfo newPolicy = new PolicyInfo(policyMap, egConditions);
+        PolicyInfo oldPolicy = policy.getAndSet(newPolicy);
+        
+        HashSet<EgKey> notifySet = new HashSet<>(); 
+        
+        for (Cell<EgKey, EgKey, Policy> cell : newPolicy.getPolicyMap().cellSet()) {
+            Policy newp = cell.getValue();
+            Policy oldp = null;
+            if (oldPolicy != null)
+                oldp = oldPolicy.getPolicyMap().get(cell.getRowKey(),
+                                                    cell.getColumnKey());
+            if (oldp == null || !newp.equals(oldp)) {
+                notifySet.add(cell.getRowKey());
+                notifySet.add(cell.getColumnKey());
+            }
+        }
+        if (oldPolicy != null) {
+            for (Cell<EgKey, EgKey, Policy> cell : oldPolicy.getPolicyMap().cellSet()) {
+                if (!newPolicy.getPolicyMap().contains(cell.getRowKey(),
+                                                       cell.getColumnKey())) {
+                    notifySet.add(cell.getRowKey());
+                    notifySet.add(cell.getColumnKey());
+                }
+            }
+        }
+        return notifySet;
+    }
+    
+    /**
+     * Notify the policy listeners about a set of updated groups
+     */
+    private void notifyListeners(Set<EgKey> updatedGroups) {
         for (final PolicyScope scope : policyListenerScopes) {
             Set<EgKey> filtered =
-                    Sets.filter(updatedConsumers, new Predicate<EgKey>() {
+                    Sets.filter(updatedGroups, new Predicate<EgKey>() {
                         @Override
                         public boolean apply(EgKey input) {
                             return scope.contains(input.getTenantId(),
@@ -283,6 +288,8 @@ public class PolicyResolver implements AutoCloseable {
                 // context
                 registration.close();
                 context = oldContext;
+            } else {
+                LOG.info("Added tenant {} to policy scope", tenantId);
             }
         }
 
@@ -291,7 +298,7 @@ public class PolicyResolver implements AutoCloseable {
         final IndexedTenant ot = tenantRef.get();
         ReadOnlyTransaction transaction =
                 dataProvider.newReadOnlyTransaction();
-        InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
+        final InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
         ListenableFuture<Optional<Tenant>> unresolved;
 
         unresolved = transaction.read(LogicalDatastoreType.CONFIGURATION, tiid);
@@ -299,7 +306,9 @@ public class PolicyResolver implements AutoCloseable {
         Futures.addCallback(unresolved, new FutureCallback<Optional<Tenant>>() {
             @Override
             public void onSuccess(Optional<Tenant> result) {
-                if (!result.isPresent()) return;
+                if (!result.isPresent()) {
+                    LOG.warn("Tenant {} not found", tenantId);
+                }
 
                 Tenant t = InheritanceUtils.resolveTenant((Tenant)result.get());
                 IndexedTenant it = new IndexedTenant(t);
@@ -308,11 +317,10 @@ public class PolicyResolver implements AutoCloseable {
                     updateTenant(tenantId);
                 } else {
                     // Update the policy cache and notify listeners
-                    Table<EgKey, EgKey, Policy> policy = resolvePolicy(t);
-                    Set<EgKey> updatedConsumers =
-                            policyCache.updatePolicy(policy, policyListenerScopes);
-
-                    notifyListeners(updatedConsumers);
+                    WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
+                    wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true);
+                    wt.submit();
+                    updatePolicy();
                 }
             }
 
@@ -323,7 +331,23 @@ public class PolicyResolver implements AutoCloseable {
         }, executor);
     }
 
-
+    protected void updatePolicy() {
+        try {
+            Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
+            Table<EgKey, EgKey, Policy> policyMap = 
+                    resolvePolicy(resolvedTenants.values(), 
+                                  egConditions);
+            Set<EgKey> updatedGroups =
+                    updatePolicy(policyMap,
+                                 egConditions, 
+                                 policyListenerScopes);
+
+            notifyListeners(updatedGroups);
+        } catch (Exception e) {
+            LOG.error("Failed to update policy", e);
+        }
+    }
+    
     /**
      * Resolve the policy in three phases:
      * (1) select contracts that in scope based on contract selectors.
@@ -333,14 +357,16 @@ public class PolicyResolver implements AutoCloseable {
      * apply for each pair of endpoint groups and the conditions that can
      * apply for for each endpoint in those groups.
      */
-    protected Table<EgKey, EgKey, Policy> resolvePolicy(Tenant t) {
+    protected Table<EgKey, EgKey, Policy> 
+            resolvePolicy(Collection<TenantContext> tenants,
+                          Map<EgKey, Set<ConditionSet>> egConditions) {
         // select contracts that apply for the given tenant
         Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                selectContracts(t);
+                selectContracts(tenants);
 
         // select subjects for the matching contracts and resolve the policy
         // for endpoint group pairs.  This does phase (2) and (3) as one step
-        return selectSubjects(contractMatches);
+        return selectSubjects(contractMatches, egConditions);
     }
 
     /**
@@ -348,12 +374,31 @@ public class PolicyResolver implements AutoCloseable {
      * groups, then perform subject selection for the pair
      */
     protected Table<EgKey, EgKey, List<ContractMatch>>
-        selectContracts(Tenant tenant) {
+        selectContracts(Collection<TenantContext> tenants) {
+        Table<TenantId, ContractId, 
+              List<ConsumerContractMatch>> consumerMatches =
+                HashBasedTable.create();
+        Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
+                HashBasedTable.create();
+
+        for (TenantContext tenant : tenants) {
+            IndexedTenant t = tenant.tenant.get();
+            if (t == null) continue;
+            selectContracts(consumerMatches, 
+                            contractMatches, 
+                            t.getTenant());
+        }
+        return contractMatches;
+    }
+    protected void selectContracts(Table<TenantId, 
+                                         ContractId, 
+                                         List<ConsumerContractMatch>> consumerMatches,
+                                   Table<EgKey, EgKey, 
+                                         List<ContractMatch>> contractMatches,
+                                   Tenant tenant) {
         // For each endpoint group, match consumer selectors
         // against contracts to get a set of matching consumer selectors
-        Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches =
-                HashBasedTable.create();
-        if (tenant.getEndpointGroup() == null) return HashBasedTable.create();
+        if (tenant.getEndpointGroup() == null) return;
         for (EndpointGroup group : tenant.getEndpointGroup()) {
             List<ConsumerContractMatch> r =
                     matchConsumerContracts(tenant, group);
@@ -372,8 +417,6 @@ public class PolicyResolver implements AutoCloseable {
 
         // Match provider selectors, and check each match for a corresponding
         // consumer selector match.
-        Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                HashBasedTable.create();
         for (EndpointGroup group : tenant.getEndpointGroup()) {
             List<ContractMatch> matches =
                     matchProviderContracts(tenant, group, consumerMatches);
@@ -393,7 +436,6 @@ public class PolicyResolver implements AutoCloseable {
                 egPairMatches.add(cm);
             }
         }
-        return contractMatches;
     }
 
     private boolean clauseMatches(Clause clause, ContractMatch match) {
@@ -482,8 +524,10 @@ public class PolicyResolver implements AutoCloseable {
 
     private Policy resolvePolicy(Tenant contractTenant,
                                  Contract contract,
+                                 boolean reverse,
                                  Policy merge,
-                                 Table<ConditionSet, ConditionSet, List<Subject>> subjectMap) {
+                                 Table<ConditionSet, ConditionSet,
+                                       List<Subject>> subjectMap) {
         Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap =
                 HashBasedTable.create();
         if (merge != null) {
@@ -492,35 +536,107 @@ public class PolicyResolver implements AutoCloseable {
         for (Cell<ConditionSet, ConditionSet, List<Subject>> entry :
                 subjectMap.cellSet()) {
             List<RuleGroup> rules = new ArrayList<>();
+            ConditionSet rowKey = entry.getRowKey();
+            ConditionSet columnKey = entry.getColumnKey();
+            if (reverse) {
+                rowKey = columnKey;
+                columnKey = entry.getRowKey();
+            }
             List<RuleGroup> oldrules =
-                    ruleMap.get(entry.getRowKey(), entry.getColumnKey());
+                    ruleMap.get(rowKey, columnKey);
             if (oldrules != null) {
                 rules.addAll(oldrules);
             }
             for (Subject s : entry.getValue()) {
                 if (s.getRule() == null) continue;
-                List<Rule> srules = Ordering
-                        .from(TenantUtils.RULE_COMPARATOR)
-                        .immutableSortedCopy(s.getRule());
+                List<Rule> srules;
+                if (reverse)
+                    srules = reverseRules(s.getRule());
+                else
+                    srules = Ordering
+                            .from(TenantUtils.RULE_COMPARATOR)
+                            .immutableSortedCopy(s.getRule());
+
                 RuleGroup rg = new RuleGroup(srules, s.getOrder(),
                                              contractTenant, contract,
                                              s.getName());
                 rules.add(rg);
             }
             Collections.sort(rules);
-            ruleMap.put(entry.getRowKey(), entry.getColumnKey(),
+            ruleMap.put(rowKey, columnKey,
                         Collections.unmodifiableList(rules));
         }
         return new Policy(ruleMap);
     }
+    
+    private List<Rule> reverseRules(List<Rule> rules) {
+        ArrayList<Rule> nrules = new ArrayList<>();
+        for (Rule input : rules) {
+            if (input.getClassifierRef() == null ||
+                input.getClassifierRef().size() == 0) {
+                nrules.add(input);
+                continue;
+            }
 
+            List<ClassifierRef> classifiers = new ArrayList<>();
+            for (ClassifierRef clr : input.getClassifierRef()) {
+                Direction nd = Direction.Bidirectional;
+                if (clr.getDirection() != null) {
+                    switch (clr.getDirection()) {
+                    case In:
+                        nd = Direction.Out;
+                        break;
+                    case Out:
+                        nd = Direction.In;
+                        break;
+                    case Bidirectional:
+                    default:
+                        nd = Direction.Bidirectional;
+                    }
+                }
+                classifiers.add(new ClassifierRefBuilder(clr)
+                    .setDirection(nd).build());
+            }
+            nrules.add(new RuleBuilder(input)
+                .setClassifierRef(Collections.unmodifiableList(classifiers))
+                .build());
+        }
+        Collections.sort(nrules, TenantUtils.RULE_COMPARATOR);
+        return Collections.unmodifiableList(nrules);
+    }
+
+    /**
+     * Get the "natural" direction for the policy for the given pair of 
+     * endpoint groups.
+     * @param one The first endpoint group
+     * @param two The second endpoint group
+     * @return true if the order should be reversed in the index
+     */
+    protected static boolean shouldReverse(EgKey one, EgKey two) {
+        if (one.compareTo(two) < 0) {
+            return true;
+        }
+        return false;
+    }
+    
+    private void addConditionSet(EgKey eg, ConditionSet cs, 
+                                 Map<EgKey, Set<ConditionSet>> egConditions) {
+        if (egConditions == null) return;
+        Set<ConditionSet> cset = egConditions.get(eg);
+        if (cset == null) {
+            egConditions.put(eg, cset = new HashSet<>());
+        }
+        cset.add(cs);
+    }
+    
     /**
      * Choose the set of subjects that in scope for each possible set of
      * endpoint conditions
      */
     protected Table<EgKey, EgKey, Policy>
             selectSubjects(Table<EgKey, EgKey,
-                                 List<ContractMatch>> contractMatches) {
+                                 List<ContractMatch>> contractMatches,
+                           Map<EgKey, Set<ConditionSet>> egConditions) {
         // Note that it's possible to further simplify the resulting policy
         // in the case of things like repeated rules, condition sets that
         // cover other condition sets, etc.  This would be a good thing to do
@@ -539,20 +655,14 @@ public class PolicyResolver implements AutoCloseable {
                                        match.consumer.getId());
                 EgKey pkey = new EgKey(match.providerTenant.getId(),
                                        match.provider.getId());
-                Policy existing = policy.get(ckey, pkey);
-                boolean alreadyMatched = false;
-                if (existing != null) {
-                    for (List<RuleGroup> rgl : existing.ruleMap.values()) {
-                        for (RuleGroup rg : rgl) {
-                            if (rg.relatedContract == match.contract) {
-                                alreadyMatched = true;
-                                break;
-                            }
-                        }
-                        if (alreadyMatched) break;
-                    }
-                    if (alreadyMatched) continue;
+                EgKey one = ckey;
+                EgKey two = pkey;
+                boolean reverse = shouldReverse(ckey, pkey);
+                if (reverse) {
+                    one = pkey;
+                    two = ckey;
                 }
+                Policy existing = policy.get(one, two);
 
                 HashMap<SubjectName, Subject> subjects = new HashMap<>();
                 for (Subject s : subjectList) {
@@ -566,7 +676,9 @@ public class PolicyResolver implements AutoCloseable {
                     if (clause.getSubjectRefs() != null &&
                         clauseMatches(clause, match)) {
                         ConditionSet consCSet = buildConsConditionSet(clause);
+                        addConditionSet(ckey, consCSet, egConditions);
                         ConditionSet provCSet = buildProvConditionSet(clause);
+                        addConditionSet(pkey, provCSet, egConditions);
                         List<Subject> clauseSubjects =
                                 subjectMap.get(consCSet, provCSet);
                         if (clauseSubjects == null) {
@@ -580,9 +692,10 @@ public class PolicyResolver implements AutoCloseable {
                     }
                 }
 
-                policy.put(ckey, pkey,
+                policy.put(one, two,
                            resolvePolicy(match.contractTenant,
                                          match.contract,
+                                         reverse,
                                          existing,
                                          subjectMap));
             }
@@ -807,5 +920,4 @@ public class PolicyResolver implements AutoCloseable {
         }
 
     }
-
 }
index 49f6012a36f15a8567a8bed7c96389f77c752b61..22292d3b6211460730327075aadd7aecd5cfd56e 100644 (file)
@@ -13,8 +13,9 @@ import com.google.common.collect.ComparisonChain;
 import com.google.common.collect.Ordering;
 
 /**
- * Represent a group of rules that apply to a given pair of endpoints.  Includes
- * references back to the normalized policy that resulted in the rule group.
+ * Represent a group of rules that could apply to a given pair of endpoints.  
+ * Includes references back to the normalized policy that resulted in the rule 
+ * group.
  * @author readams
  */
 @Immutable 
@@ -23,7 +24,7 @@ public class RuleGroup implements Comparable<RuleGroup> {
     final Integer order;
     final Tenant contractTenant;
     final Contract relatedContract;
-    final SubjectName relatedSubject; 
+    final SubjectName relatedSubject;
 
     public RuleGroup(List<Rule> rules, Integer order,
                      Tenant contractTenant, Contract contract,
@@ -99,6 +100,8 @@ public class RuleGroup implements Comparable<RuleGroup> {
         return ComparisonChain.start()
             .compare(order, o.order, 
                      Ordering.natural().nullsLast())
+            .compare(relatedSubject.getValue(), o.relatedSubject.getValue(),
+                     Ordering.natural().nullsLast())
             .result();
     }
 
similarity index 69%
rename from groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SetUtils.java
rename to groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/SetUtils.java
index 358a180cd3a891ac0ae34889c13441ec36214bfd..532d1bb6c4ba8526808d5510a6ac80233a113449 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
 
 import java.util.Collections;
 import java.util.Set;
@@ -14,12 +14,18 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 /**
- * Random utilities
+ * Utility methods related to managing sets and maps
  * @author readams
  */
 public class SetUtils {
-
-    protected static <K1, K2> Set<K2> 
+    /**
+     * Get and/or allocate as needed a nested concurrent set inside a concurrent
+     * map in a threadsafe way.
+     * @param key the key to the concurrent map
+     * @param set the concurrent map
+     * @return the nested concurrent set
+     */
+    public static <K1, K2> Set<K2> 
             getNestedSet(K1 key, ConcurrentMap<K1, Set<K2>> set) {
         Set<K2> inner = set.get(key);
         if (inner == null) {
similarity index 98%
rename from groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SingletonTask.java
rename to groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/SingletonTask.java
index 467ad87eff492e22fde9ea0f46e4413f1c3584b2..3669048b29085e433566b24ecf8f4de49c34c187 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
 
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
index 580a8ca8374a022831a35b69db19b8a39abd78d3..eda185a2c1dcb0405b76b2ca1e2cdc41efc6ec64 100644 (file)
@@ -458,12 +458,19 @@ module policy {
         description "Objects containing lists of classifier references";
 
         list classifier-ref {
+            key "name";
             description 
                 "A reference to classifier instance that is used to match 
                  traffic traveling between the endpoint groups that
                  form the contract.";
 
             leaf name {
+                description "A unique name for this classifier reference";
+                type gbp-common:classifier-name;
+                mandatory true;
+            }
+
+            leaf instance-name {
                 description "The name of the classifier instance";
                 type leafref {
                     path "/tenants/tenant/subject-feature-instances/classifier-instance/name";
@@ -514,7 +521,6 @@ module policy {
                 }
                 mandatory true;
             }
-            uses has-direction;
             uses has-order;
         }
     }
@@ -858,6 +864,26 @@ module policy {
                 uses has-requirements;
                 uses has-capabilities;
 
+                leaf intra-group-policy {
+                    description 
+                        "Governs how traffic within the endpoint group 
+                         should be handled.";
+                    default allow;
+                    type enumeration {
+                        enum allow {
+                            description 
+                                "Traffic between two endpoints in the group
+                                 is always allowed";
+                        }
+                        enum require-contract {
+                            description
+                                "Traffic between two endpoints in the group
+                                 is allowed only when a contract exists to 
+                                 allow it explicitly";
+                        }
+                    }
+                }
+
                 list consumer-named-selector {
                     description
                         "Consumer named selectors are named selectors 
index 148b05a63f14bdd0bf036e37a8262cf18eb387f2..2b626505c380130ee1fb69233694b372f448a0a1 100644 (file)
@@ -68,9 +68,9 @@ public class DestinationMapperTest extends FlowTableTest {
     @Test
     public void testNoEps() throws Exception {
         ReadWriteTransaction t = dosync(null);
-        verify(t, never()).put(any(LogicalDatastoreType.class), 
-                               Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+        verify(t, times(1)).put(any(LogicalDatastoreType.class), 
+                                Matchers.<InstanceIdentifier<Flow>>any(), 
+                                any(Flow.class));
     }
 
     private void verifyDMap(Endpoint remoteEp, 
@@ -86,7 +86,11 @@ public class DestinationMapperTest extends FlowTableTest {
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
         for (Flow f : ac.getAllValues()) {
             flowMap.put(f.getId().getValue(), new FlowCtx(f));
-            if (Objects.equals(localEp.getMacAddress(),
+            if (f.getMatch() == null) {
+                assertEquals(FlowUtils.dropInstructions(),
+                             f.getInstructions());
+                count += 1;
+            } else if (Objects.equals(localEp.getMacAddress(),
                                f.getMatch().getEthernetMatch()
                                    .getEthernetDestination().getAddress())) {
                 int icount = 0;
@@ -166,7 +170,7 @@ public class DestinationMapperTest extends FlowTableTest {
                 }
             }
         }
-        assertEquals(4, count);
+        assertEquals(5, count);
 
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
index c10e9de8d0ecca3f86bc6010e2238f3be0f815f1..76ade5cffb9e51925f6d36f5d967a96ee66932f7 100644 (file)
@@ -15,9 +15,10 @@ import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockEndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockSwitchManager;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.resolver.MockPolicyResolver;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
@@ -39,6 +40,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRefBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
@@ -111,6 +113,10 @@ public class FlowTableTest {
     }
 
     protected TenantBuilder baseTenant() {
+        return baseTenant(null);
+    }
+
+    protected TenantBuilder baseTenant(Direction direction) {
         return new TenantBuilder()
             .setId(tid)
             .setEndpointGroup(ImmutableList.of(new EndpointGroupBuilder()
@@ -153,11 +159,15 @@ public class FlowTableTest {
             .setSubjectFeatureInstances(new SubjectFeatureInstancesBuilder()
                 .setClassifierInstance(ImmutableList.of(new ClassifierInstanceBuilder()
                      .setName(new ClassifierName("tcp_80"))
-                     .setClassifierDefinitionId(SubjectFeatures.TCP_PORT.getId())
+                     .setClassifierDefinitionId(L4Classifier.ID)
                      .setParameterValue(ImmutableList.of(new ParameterValueBuilder()
-                          .setName(new ParameterName("port"))
-                          .setIntValue(Long.valueOf(80))
-                          .build()))
+                              .setName(new ParameterName("destport"))
+                              .setIntValue(Long.valueOf(80))
+                              .build(),
+                          new ParameterValueBuilder()
+                             .setName(new ParameterName("type"))
+                             .setStringValue("TCP")
+                             .build()))
                      .build()))
                 .setActionInstance(ImmutableList.of(new ActionInstanceBuilder()
                     .setName(new ActionName("allow"))
@@ -174,6 +184,7 @@ public class FlowTableTest {
                              .build()))
                          .setClassifierRef(ImmutableList.of(new ClassifierRefBuilder()
                              .setName(new ClassifierName("tcp_80"))
+                             .setDirection(direction)
                              .build()))
                          .build()))
                     .build()))
@@ -215,7 +226,8 @@ public class FlowTableTest {
         ReadWriteTransaction t = mock(ReadWriteTransaction.class);
         if (flowMap == null)
             flowMap = Collections.emptyMap();
-        table.sync(t, tiid, flowMap, nodeId, null);
+        table.sync(t, tiid, flowMap, nodeId, policyResolver.getCurrentPolicy(), 
+                   null);
         return t;
     }
 
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java
new file mode 100644 (file)
index 0000000..f0d0183
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014 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
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Matchers;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.*;
+
+import static org.mockito.Matchers.*;
+
+import static org.mockito.Mockito.*;
+
+public class PolicyEnforcerTest extends FlowTableTest {
+    protected static final Logger LOG = 
+            LoggerFactory.getLogger(PolicyEnforcerTest.class);
+
+    @Before
+    public void setup() throws Exception {
+        initCtx();
+        table = new PolicyEnforcer(ctx);
+        super.setup();
+    }
+    
+
+    @Test
+    public void testNoEps() throws Exception {
+        ReadWriteTransaction t = dosync(null);
+        verify(t, times(1)).put(any(LogicalDatastoreType.class), 
+                                Matchers.<InstanceIdentifier<Flow>>any(), 
+                                any(Flow.class));
+    }
+    
+    @Test
+    public void testSameEg() throws Exception {
+        Endpoint ep1 = localEP().build();
+        endpointManager.addEndpoint(ep1);
+        Endpoint ep2 = localEP()
+            .setMacAddress(new MacAddress("00:00:00:00:00:02"))
+            .build();
+        endpointManager.addEndpoint(ep2);
+        policyResolver.addTenant(baseTenant().build());
+        
+        ReadWriteTransaction t = dosync(null);
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                                     Matchers.<InstanceIdentifier<Flow>>any(),
+                                     ac.capture());
+        int count = 0;
+        HashMap<String, FlowCtx> flowMap = new HashMap<>();
+        for (Flow f : ac.getAllValues()) {
+            flowMap.put(f.getId().getValue(), new FlowCtx(f));
+            // XXX - TODO check actual match/action
+            if (f.getId().getValue().indexOf("intraallow") == 0)
+                count += 1;
+        }
+        assertEquals(1, count);
+
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               Matchers.<InstanceIdentifier<Flow>>any(), 
+                               any(Flow.class));
+    }
+
+    @Test
+    public void testDifferentEg() throws Exception {
+        doTestDifferentEg(null);
+        doTestDifferentEg(Direction.Bidirectional);
+        doTestDifferentEg(Direction.In);
+        doTestDifferentEg(Direction.Out);
+    }
+    
+    public void doTestDifferentEg(Direction direction) throws Exception {
+        Endpoint ep1 = localEP().build();
+        endpointManager.addEndpoint(ep1);
+        Endpoint ep2 = localEP()
+            .setMacAddress(new MacAddress("00:00:00:00:00:02"))
+            .setEndpointGroup(eg2)
+            .build();
+        endpointManager.addEndpoint(ep2);
+        policyResolver.addTenant(baseTenant(direction).build());
+        
+        ReadWriteTransaction t = dosync(null);
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                                     Matchers.<InstanceIdentifier<Flow>>any(),
+                                     ac.capture());
+        int count = 0;
+        HashMap<String, FlowCtx> flowMap = new HashMap<>();
+        for (Flow f : ac.getAllValues()) {
+            flowMap.put(f.getId().getValue(), new FlowCtx(f));
+            if (f.getId().getValue().indexOf("intraallow") == 0) {
+                count += 1;
+            } else if (f.getMatch() != null &&
+                       f.getMatch().getEthernetMatch() != null &&
+                       Objects.equals(FlowUtils.IPv4,
+                                      f.getMatch().getEthernetMatch()
+                                          .getEthernetType().getType().getValue()) &&
+                       f.getMatch().getIpMatch() != null &&
+                       Objects.equals(Short.valueOf((short)6),
+                                      f.getMatch().getIpMatch().getIpProtocol()) &&
+                       Objects.equals(Integer.valueOf(80),
+                                      ((TcpMatch)f.getMatch().getLayer4Match())
+                                          .getTcpDestinationPort().getValue())) {
+                // XXX - TODO - verify sepg/depg
+                count += 1;
+            } else if (f.getMatch() != null &&
+                       f.getMatch().getEthernetMatch() != null &&
+                       Objects.equals(FlowUtils.IPv6,
+                                      f.getMatch().getEthernetMatch()
+                                          .getEthernetType().getType().getValue()) &&
+                       f.getMatch().getIpMatch() != null &&
+                       Objects.equals(Short.valueOf((short)6),
+                                      f.getMatch().getIpMatch().getIpProtocol()) &&
+                       Objects.equals(Integer.valueOf(80),
+                                      ((TcpMatch)f.getMatch().getLayer4Match())
+                                          .getTcpDestinationPort().getValue())) {
+                // XXX - TODO - verify sepg/depg
+                count += 1;
+            }
+        }
+        if (direction == null || direction.equals(Direction.Bidirectional))
+            assertEquals(6, count);
+        else
+            assertEquals(4, count);
+
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               Matchers.<InstanceIdentifier<Flow>>any(), 
+                               any(Flow.class));
+    }
+
+    @Test
+    public void testConditions() throws Exception {
+        // XXX TODO
+    }
+}
index 8a8b226b17178f41f39aea2ec72ed6ecb26777b0..ef5c92dcc73176b749aa14394c7038c8ed70eca9 100644 (file)
@@ -44,9 +44,9 @@ public class SourceMapperTest extends FlowTableTest {
     public void testNoPolicy() throws Exception {
         endpointManager.addEndpoint(localEP().build());
         ReadWriteTransaction t = dosync(null);
-        verify(t, never()).put(any(LogicalDatastoreType.class), 
-                               Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+        verify(t, times(1)).put(any(LogicalDatastoreType.class), 
+                                Matchers.<InstanceIdentifier<Flow>>any(), 
+                                any(Flow.class));
     }
     
     @Test
@@ -57,7 +57,7 @@ public class SourceMapperTest extends FlowTableTest {
         
         ReadWriteTransaction t = dosync(null);
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
-        verify(t, times(1)).put(eq(LogicalDatastoreType.CONFIGURATION), 
+        verify(t, times(2)).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                 Matchers.<InstanceIdentifier<Flow>>any(),
                                 ac.capture());
 
@@ -65,7 +65,11 @@ public class SourceMapperTest extends FlowTableTest {
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
         for (Flow f : ac.getAllValues()) {
             flowMap.put(f.getId().getValue(), new FlowCtx(f));
-            if (Objects.equals(ep.getMacAddress(),
+            if (f.getMatch() == null) {
+                assertEquals(FlowUtils.dropInstructions(),
+                             f.getInstructions());
+                count += 1;
+            } else if (Objects.equals(ep.getMacAddress(),
                                f.getMatch().getEthernetMatch()
                                    .getEthernetSource().getAddress())) {
                 // XXX TODO verify register setting in the instructions
@@ -73,7 +77,7 @@ public class SourceMapperTest extends FlowTableTest {
                 count += 1;
             }
         }
-        assertEquals(1, count);
+        assertEquals(2, count);
 
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
index 705d30cd8f6eedf36b47e95b474c13b541264902..5aa46c07795e1f3f6bcf61ffcc17d036effadcc9 100644 (file)
@@ -8,11 +8,8 @@
 
 package org.opendaylight.groupbasedpolicy.resolver;
 
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
 
-import com.google.common.collect.Table;
-
 
 /**
  * Mock version of policy resolver useful for tests
@@ -30,7 +27,7 @@ public class MockPolicyResolver extends PolicyResolver {
         IndexedTenant it = new IndexedTenant(t);
         context.tenant.set(it);
         resolvedTenants.put(unresolvedTenant.getId(), context);
-        Table<EgKey, EgKey, Policy> policy = resolvePolicy(t);
-        policyCache.updatePolicy(policy, policyListenerScopes);
+        
+        updatePolicy();
     }
 }
index 1cb21997e25746aae18681c64e043298c8929d4d..eb9267ea0c802abab0aaa270d6c95247c18f7a25 100644 (file)
@@ -8,15 +8,20 @@
 
 package org.opendaylight.groupbasedpolicy.resolver;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.ConditionSet;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionSet;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.ContractMatch;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.TenantContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityMatcherName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
@@ -328,8 +333,12 @@ public class PolicyResolverTest {
     @Test
     public void testContractSelection() throws Exception {
         // named selectors
+        TenantContext tc = new TenantContext(null);
+        Collection<TenantContext> tCol = Collections.singleton(tc);
+        
+        tc.tenant.set(new IndexedTenant(tenant1));
         Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                resolver.selectContracts(tenant1);
+                resolver.selectContracts(tCol);
         assertEquals(1, contractMatches.size());
         List<ContractMatch> matches = 
                 contractMatches.get(new EgKey(tenant1.getId(), eg1.getId()),
@@ -338,7 +347,9 @@ public class PolicyResolverTest {
                       ImmutableList.of(tenant1.getId()),
                       matches);
 
-        contractMatches = resolver.selectContracts(tenant2);
+        
+        tc.tenant.set(new IndexedTenant(tenant2));
+        contractMatches = resolver.selectContracts(tCol);
         assertEquals(2, contractMatches.size());
         matches = contractMatches.get(new EgKey(tenant2.getId(), eg1.getId()),
                                       new EgKey(tenant2.getId(), eg2.getId()));
@@ -353,7 +364,8 @@ public class PolicyResolverTest {
                       matches);
         
         // target selectors
-        contractMatches = resolver.selectContracts(tenant3);
+        tc.tenant.set(new IndexedTenant(tenant3));
+        contractMatches = resolver.selectContracts(tCol);
         assertEquals(1, contractMatches.size());
         matches = contractMatches.get(new EgKey(tenant3.getId(), eg4.getId()),
                                       new EgKey(tenant3.getId(), eg5.getId()));
@@ -362,10 +374,12 @@ public class PolicyResolverTest {
                       matches);
         
         // empty matches
-        contractMatches = resolver.selectContracts(tenant0);
+        tc.tenant.set(new IndexedTenant(tenant0));
+        contractMatches = resolver.selectContracts(tCol);
         assertEquals(0, contractMatches.size());
 
-        contractMatches = resolver.selectContracts(tenant00);
+        tc.tenant.set(new IndexedTenant(tenant00));
+        contractMatches = resolver.selectContracts(tCol);
         assertEquals(0, contractMatches.size());
     }
 
@@ -376,15 +390,19 @@ public class PolicyResolverTest {
                                  ImmutableSet.of(cond3.getName()),
                                  ImmutableSet.of(ImmutableSet.of(cond1.getName(), 
                                                                  cond2.getName())));
-
+        TenantContext tc = new TenantContext(null);
+        Collection<TenantContext> tCol = Collections.singleton(tc);
+        
+        tc.tenant.set(new IndexedTenant(tenant1));
         Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
-                resolver.selectContracts(tenant1);
+                resolver.selectContracts(tCol);
+        Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
         Table<EgKey, EgKey, Policy> policy = 
-                resolver.selectSubjects(contractMatches);
+                resolver.selectSubjects(contractMatches, egConditions);
         assertEquals(1, policy.size());
-        Policy p = policy.get(new EgKey(tenant1.getId(), eg1.getId()),
-                              new EgKey(tenant1.getId(), eg2.getId()));
-        List<RuleGroup> rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+        Policy p = policy.get(new EgKey(tenant1.getId(), eg2.getId()),
+                              new EgKey(tenant1.getId(), eg1.getId()));
+        List<RuleGroup> rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
         assertNotNull(rules);
         assertEquals(1, rules.size());
         RuleGroup rg = rules.get(0);
@@ -394,13 +412,15 @@ public class PolicyResolverTest {
         assertEquals(1, rg.rules.size());
         assertEquals(rule1.getName(), rg.rules.get(0).getName());
 
-        contractMatches = resolver.selectContracts(tenant2);
-        policy = resolver.selectSubjects(contractMatches);
+        tc.tenant.set(new IndexedTenant(tenant2));
+        contractMatches = resolver.selectContracts(tCol);
+        egConditions = new HashMap<>();
+        policy = resolver.selectSubjects(contractMatches, egConditions);
 
         assertEquals(2, policy.size());
-        p = policy.get(new EgKey(tenant2.getId(), eg3.getId()),
-                       new EgKey(tenant2.getId(), eg2.getId()));
-        rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+        p = policy.get(new EgKey(tenant2.getId(), eg2.getId()),
+                       new EgKey(tenant2.getId(), eg3.getId()));
+        rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
         assertNotNull(rules);
         assertEquals(1, rules.size());
         rg = rules.get(0);
@@ -420,9 +440,9 @@ public class PolicyResolverTest {
         assertEquals(1, rg.rules.size());
         assertEquals(rule2.getName(), rg.rules.get(0).getName());
         
-        p = policy.get(new EgKey(tenant2.getId(), eg1.getId()),
-                       new EgKey(tenant2.getId(), eg2.getId()));
-        rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+        p = policy.get(new EgKey(tenant2.getId(), eg2.getId()),
+                       new EgKey(tenant2.getId(), eg1.getId()));
+        rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
         assertNotNull(rules);
         assertEquals(1, rules.size());
         rg = rules.get(0);
@@ -432,12 +452,14 @@ public class PolicyResolverTest {
         assertEquals(1, rg.rules.size());
         assertEquals(rule1.getName(), rg.rules.get(0).getName());
 
-        contractMatches = resolver.selectContracts(tenant3);
-        policy = resolver.selectSubjects(contractMatches);
+        tc.tenant.set(new IndexedTenant(tenant3));
+        contractMatches = resolver.selectContracts(tCol);
+        egConditions = new HashMap<>();
+        policy = resolver.selectSubjects(contractMatches, egConditions);
 
         assertEquals(1, policy.size());
-        p = policy.get(new EgKey(tenant3.getId(), eg4.getId()),
-                       new EgKey(tenant3.getId(), eg5.getId()));
+        p = policy.get(new EgKey(tenant3.getId(), eg5.getId()),
+                       new EgKey(tenant3.getId(), eg4.getId()));
         rules = p.ruleMap.get(ConditionSet.EMPTY, ConditionSet.EMPTY);
         assertNotNull(rules);
         assertEquals(1, rules.size());
similarity index 98%
rename from groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SingletonTaskTest.java
rename to groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/util/SingletonTaskTest.java
index 181883b149e6aa1d076719fcf1f25548f02938ec..a335247afb634086e0c0f1dadc9ea7ab4b728b5d 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
 
 import static org.junit.Assert.*;
 
@@ -16,7 +16,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SingletonTask;
+import org.opendaylight.groupbasedpolicy.util.SingletonTask;
 
 public class SingletonTaskTest {