Implement group table 01/9501/4
authorRob Adams <readams@readams.net>
Wed, 30 Jul 2014 16:59:37 +0000 (09:59 -0700)
committerRob Adams <readams@readams.net>
Thu, 7 Aug 2014 22:19:37 +0000 (15:19 -0700)
* Still need to add actions to send to group table for L2 broadcast/multicast
* Still need unit test for group table

Change-Id: I062436fa22ebd5703424f96b22098c5801c0ae4b
Signed-off-by: Rob Adams <readams@readams.net>
16 files changed:
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/EndpointManager.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java
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/GroupTable.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTable.java [new file with mode: 0644]
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/resolver/EndpointProvider.java [deleted file]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapperTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTableTest.java [moved from groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java with 97% similarity]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java

index af3783af95f7774ffff5e3677cd62a54bdd45449..9483b9416f63cdf8afb3a702f4739fe5ea31e45f 100644 (file)
@@ -15,6 +15,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ScheduledExecutorService;
 
@@ -26,7 +27,6 @@ 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.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;
@@ -46,7 +46,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
+import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
 
 /**
  * Keep track of endpoints on the system.  Maintain an index of endpoints
@@ -61,7 +63,7 @@ import com.google.common.collect.Collections2;
  */
 public class EndpointManager 
         extends AbstractEndpointRegistry 
-        implements AutoCloseable, DataChangeListener, EndpointProvider
+        implements AutoCloseable, DataChangeListener
     {
     private static final Logger LOG = 
             LoggerFactory.getLogger(EndpointManager.class);
@@ -73,11 +75,12 @@ public class EndpointManager
 
     private final ConcurrentHashMap<EpKey, Endpoint> endpoints =
             new ConcurrentHashMap<>();
-    private final ConcurrentHashMap<NodeId, Set<EpKey>> endpointsByNode =
+    private final ConcurrentHashMap<NodeId, 
+                                    ConcurrentMap<EgKey, Set<EpKey>>> endpointsByNode =
             new ConcurrentHashMap<>();
     private final ConcurrentHashMap<EgKey, Set<EpKey>> endpointsByGroup = 
             new ConcurrentHashMap<>();
-    
+            
     private List<EndpointListener> listeners = new CopyOnWriteArrayList<>();
 
     public EndpointManager(DataBroker dataProvider,
@@ -115,10 +118,45 @@ public class EndpointManager
      * @param nodeId the nodeId of the switch to get endpoints for
      * @return a collection of {@link Endpoint} objects.
      */
-    public Collection<Endpoint> getEndpointsForNode(NodeId nodeId) {
-        Collection<EpKey> ebn = endpointsByNode.get(nodeId);
+    public Set<EgKey> getGroupsForNode(NodeId nodeId) {
+        Map<EgKey, Set<EpKey>> nodeEps = endpointsByNode.get(nodeId);
+        if (nodeEps == null) return Collections.emptySet();
+        return Collections.unmodifiableSet(nodeEps.keySet());
+    }
+    
+    /**
+     * Get the set of nodes
+     * @param nodeId the nodeId of the switch to get endpoints for
+     * @return a collection of {@link Endpoint} objects.
+     */
+    public Set<NodeId> getNodesForGroup(final EgKey egKey) {
+        return Collections.unmodifiableSet(Sets.filter(endpointsByNode.keySet(),
+                                                       new Predicate<NodeId>() {
+            @Override
+            public boolean apply(NodeId input) {
+                Map<EgKey, Set<EpKey>> nodeEps = 
+                        endpointsByNode.get(input);
+                return (nodeEps != null && 
+                        nodeEps.containsKey(egKey));
+            }
+
+        }));
+    }
+    
+    /**
+     * Get the endpoints in a particular group on a particular node
+     * @param nodeId the node ID to look up
+     * @param eg the group to look up
+     * @return the endpoints
+     */
+    public Collection<Endpoint> getEPsForNode(NodeId nodeId, EgKey eg) {
+        Map<EgKey, Set<EpKey>> nodeEps = endpointsByNode.get(nodeId);
+        if (nodeEps == null) return Collections.emptyList();
+        Collection<EpKey> ebn = nodeEps.get(eg); 
         if (ebn == null) return Collections.emptyList();
-        return Collections2.transform(ebn, indexTransform);
+        return Collections.unmodifiableCollection(Collections2
+                                                  .transform(ebn, 
+                                                             indexTransform));
     }
 
     /**
@@ -137,19 +175,25 @@ public class EndpointManager
     public void setLearningMode(LearningMode learningMode) {
         // No-op for now
     }
-
-    // ****************
-    // EndpointProvider
-    // ****************
-
-    @Override
+    
+    /**
+     * 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) {
         Collection<EpKey> ebg = endpointsByGroup.get(eg);
         if (ebg == null) return Collections.emptyList();
         return Collections2.transform(ebg, indexTransform);
     }
 
-    @Override
+    /**
+     * 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) {
         // XXX TODO consider group conditions as well.  Also need to notify
         // endpoint updated if the endpoint group conditions change
@@ -157,7 +201,7 @@ public class EndpointManager
             return endpoint.getCondition();
         else return Collections.emptyList();
     }
-
+    
     // ************************
     // AbstractEndpointRegistry
     // ************************
@@ -271,9 +315,20 @@ public class EndpointManager
         return new EgKey(endpoint.getTenant(), endpoint.getEndpointGroup());
     }
     
-    private Set<EpKey> getEpNSet(NodeId location) {
-        return SetUtils.getNestedSet(location, endpointsByNode);
+    private Set<EpKey> getEpNGSet(NodeId location, EgKey eg) {
+        ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByNode.get(location);
+        if (map == null) {
+            map = new ConcurrentHashMap<>();
+            ConcurrentMap<EgKey, Set<EpKey>> old = 
+                    endpointsByNode.putIfAbsent(location, map);
+            if (old != null)
+                map = old;
+        }
+        return SetUtils.getNestedSet(eg, map);
     }
+    
+    private static final ConcurrentMap<EgKey, Set<EpKey>> EMPTY_MAP =
+            new ConcurrentHashMap<>();
 
     private Set<EpKey> getEpGSet(EgKey eg) {
         return SetUtils.getNestedSet(eg, endpointsByGroup);
@@ -303,10 +358,15 @@ public class EndpointManager
         if (newEp != null)
             endpoints.put(epKey, newEp);
 
-        if (oldLoc != null && 
-            (newLoc == null || !oldLoc.equals(newLoc))) {
-            Set<EpKey> eps = getEpNSet(oldLoc);
+        if (oldLoc != null && oldKey != null &&
+            (newLoc == null || !oldLoc.equals(newLoc) ||
+            newKey == null || !oldKey.equals(newKey))) {
+            ConcurrentMap<EgKey, Set<EpKey>> map = 
+                    endpointsByNode.get(oldLoc);
+            Set<EpKey> eps = map.get(oldKey);
             eps.remove(epKey);
+            map.remove(oldKey, Collections.emptySet());
+            endpointsByNode.remove(oldLoc, EMPTY_MAP);
             notifyOldLoc = true;
         }
         if (oldKey != null &&
@@ -316,8 +376,8 @@ public class EndpointManager
             notifyOldEg = true;
         }
 
-        if (newLoc != null) {
-            Set<EpKey> eps = getEpNSet(newLoc);
+        if (newLoc != null && newKey != null) {
+            Set<EpKey> eps = getEpNGSet(newLoc, newKey);
             eps.add(epKey);
             LOG.debug("Endpoint {} added to node {}", epKey, newLoc);
             notifyNewLoc = true;
index b7aa73f70e7536259a2e6256d85cd17a265ae7e4..f7e06d0bbff8b46ddad71d1c4d6fb34e5fc2f80e 100644 (file)
@@ -27,9 +27,10 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.DestinationMapper;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.GroupTable;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable.OfTableCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
@@ -44,8 +45,6 @@ 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;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode;
@@ -56,9 +55,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -88,7 +85,7 @@ public class PolicyManager
     /**
      * The flow tables that make up the processing pipeline
      */
-    private final List<? extends FlowTable> flowPipeline;
+    private final List<? extends OfTable> flowPipeline;
 
     /**
      * The delay before triggering the flow update task in response to an
@@ -109,7 +106,7 @@ public class PolicyManager
     // 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 = 
+    private final ConcurrentMap<String, Integer> ordinals = 
             new ConcurrentHashMap<>();
     // XXX - need to garbage collect
     private final ConcurrentMap<ConditionGroup, Integer> cgOrdinals = 
@@ -137,13 +134,14 @@ public class PolicyManager
             t.submit();
         }
 
-        FlowTableCtx ctx = new FlowTableCtx(dataBroker, rpcRegistry, 
-                                            this, policyResolver, switchManager, 
-                                            endpointManager, executor);
+        OfTableCtx ctx = new OfTableCtx(dataBroker, rpcRegistry, 
+                                        this, policyResolver, switchManager, 
+                                        endpointManager, executor);
         flowPipeline = ImmutableList.of(new PortSecurity(ctx),
                                         new SourceMapper(ctx),
                                         new DestinationMapper(ctx),
-                                        new PolicyEnforcer(ctx));
+                                        new PolicyEnforcer(ctx),
+                                        new GroupTable(ctx));
 
         policyScope = policyResolver.registerListener(this);
         if (switchManager != null)
@@ -164,38 +162,30 @@ public class PolicyManager
 
     @Override
     public void switchReady(final NodeId nodeId) {
-        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
-        
-        NodeBuilder nb = new NodeBuilder()
-            .setId(nodeId)
-            .addAugmentation(FlowCapableNode.class, 
-                             new FlowCapableNodeBuilder()
-                                .setTable(Lists.transform(flowPipeline, 
-                                                          new Function<FlowTable, Table>() {
-                                    @Override
-                                    public Table apply(FlowTable input) {
-                                        return new TableBuilder()
-                                            .setId(Short.valueOf(input.getTableId()))
-                                            .build();
-                                    }
-                                })) .build());
-        t.put(LogicalDatastoreType.CONFIGURATION, 
-              FlowUtils.createNodePath(nodeId),
-              nb.build());
-        ListenableFuture<Void> result = t.submit();
-        Futures.addCallback(result, 
-                            new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void result) {
-                dirty.get().addNode(nodeId);
-                scheduleUpdate();
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error("Could not add switch {}", nodeId, t);
-            }
-        });
+//        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+//        
+//        NodeBuilder nb = new NodeBuilder()
+//            .setId(nodeId)
+//            .addAugmentation(FlowCapableNode.class, 
+//                             new FlowCapableNodeBuilder()
+//                                .build());
+//        t.merge(LogicalDatastoreType.CONFIGURATION, 
+//                FlowUtils.createNodePath(nodeId),
+//                nb.build(), true);
+//        ListenableFuture<Void> result = t.submit();
+//        Futures.addCallback(result, 
+//                            new FutureCallback<Void>() {
+//            @Override
+//            public void onSuccess(Void result) {
+//                dirty.get().addNode(nodeId);
+//                scheduleUpdate();
+//            }
+//
+//            @Override
+//            public void onFailure(Throwable t) {
+//                LOG.error("Could not add switch {}", nodeId, t);
+//            }
+//        });
         
     }
 
@@ -276,10 +266,10 @@ public class PolicyManager
         }
         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
+     * for the given policy item. 
      * @param tenantId the tenant ID of the element
      * @param id the unique ID for the element
      * @return the 32-bit ordinal value
@@ -287,57 +277,24 @@ public class PolicyManager
     public int getContextOrdinal(final TenantId tenantId, 
                                  final UniqueId id) throws Exception {
         if (tenantId == null || id == null) return 0;
-        ConcurrentMap<String, Integer> m = ordinals.get(tenantId);
-        if (m == null) {
-            m = new ConcurrentHashMap<>();
-            ConcurrentMap<String, Integer> old = 
-                    ordinals.putIfAbsent(tenantId, m);
-            if (old != null) m = old;
-        }
-        Integer ord = m.get(id.getValue());
+        return getContextOrdinal(tenantId.getValue() + "|" + id.getValue());
+    }
+
+    /**
+     * Get a 32-bit context ordinal suitable for use in the OF data plane
+     * for the given policy item.
+     * @param id the unique ID for the element
+     * @return the 32-bit ordinal value
+     */
+    public int getContextOrdinal(final String id) throws Exception {
+
+        Integer ord = ordinals.get(id);
         if (ord == null) {
             ord = policyOrdinal.getAndIncrement();
-            Integer old = m.putIfAbsent(id.getValue(), ord);
+            Integer old = ordinals.putIfAbsent(id, ord);
             if (old != null) ord = old;
         }
-
         return ord.intValue();
-//        while (true) {
-//            final ReadWriteTransaction t = dataBroker.newReadWriteTransaction();
-//            InstanceIdentifier<DataPlaneOrdinal> iid =
-//                    InstanceIdentifier.builder(OfOverlayOperational.class)
-//                    .child(DataPlaneOrdinal.class, 
-//                           new DataPlaneOrdinalKey(id, tenantId))
-//                    .build();
-//            ListenableFuture<Optional<DataObject>> r = 
-//                    t.read(LogicalDatastoreType.OPERATIONAL, iid);
-//            Optional<DataObject> res = r.get();
-//            if (res.isPresent()) {
-//                DataPlaneOrdinal o = (DataPlaneOrdinal)res.get();
-//                return o.getOrdinal().intValue();
-//            }
-//            final int ordinal = policyOrdinal.getAndIncrement();
-//            OfOverlayOperational oo = new OfOverlayOperationalBuilder()
-//                .setDataPlaneOrdinal(ImmutableList.of(new DataPlaneOrdinalBuilder()
-//                    .setId(id)
-//                    .setTenant(tenantId)
-//                    .setOrdinal(Long.valueOf(ordinal))
-//                    .build()))
-//                .build();
-//            t.merge(LogicalDatastoreType.OPERATIONAL, 
-//                    InstanceIdentifier.builder(OfOverlayOperational.class)
-//                    .build(), 
-//                    oo);
-//            ListenableFuture<RpcResult<TransactionStatus>> commitr = t.commit();
-//            try {
-//                commitr.get();
-//                return ordinal;
-//            } catch (ExecutionException e) {
-//                if (e.getCause() instanceof OptimisticLockFailedException)
-//                    continue;
-//                throw e;
-//            }
-//        }
     }
     
     // **************
@@ -369,7 +326,7 @@ public class PolicyManager
             if (!switchManager.isSwitchReady(nodeId)) return null;
             PolicyInfo info = policyResolver.getCurrentPolicy();
             if (info == null) return null;
-            for (FlowTable table : flowPipeline) {
+            for (OfTable table : flowPipeline) {
                 try {
                     table.update(nodeId, info, dirty);
                 } catch (Exception e) {
index 4e898fe17dd907ef944005c81f019939827985ba..0d7eab9752faeec900c8ed640e5d8bd2f8e3bac7 100644 (file)
@@ -66,7 +66,7 @@ public class DestinationMapper extends FlowTable {
     public static final MacAddress ROUTER_MAC = 
             new MacAddress("88:f0:31:b5:12:b5");
 
-    public DestinationMapper(FlowTableCtx ctx) {
+    public DestinationMapper(OfTable.OfTableCtx ctx) {
         super(ctx);
     }
 
@@ -84,15 +84,12 @@ public class DestinationMapper extends FlowTable {
         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
 
         HashSet<EgKey> visitedEgs = new HashSet<>();
-        for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
-            if (e.getTenant() == null || e.getEndpointGroup() == null)
-                continue;
-            EgKey key = new EgKey(e.getTenant(), e.getEndpointGroup());
-            
-            Set<EgKey> peers = Sets.union(Collections.singleton(key),
-                                          policyInfo.getPeers(key));
+        for (EgKey epg : ctx.epManager.getGroupsForNode(nodeId)) {
+            Set<EgKey> peers = Sets.union(Collections.singleton(epg),
+                                          policyInfo.getPeers(epg));
             for (EgKey peer : peers) {
-                syncEPG(t, tiid, flowMap, nodeId, policyInfo, peer, visitedEgs);
+                syncEPG(t, tiid, flowMap, nodeId, 
+                        policyInfo, peer, visitedEgs);
             }
         }
     }
index 0b3ef5fac5c4075142db41ea241f60d4cdae3588..a24aeceb89990e34dd3bc1650f59bb8b474360ac 100644 (file)
@@ -10,18 +10,11 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.ScheduledExecutorService;
 
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-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;
@@ -33,71 +26,26 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
- * Manage the state of a flow table by reacting to any events and updating
- * the table state.  This is an abstract class that must be extended for
- * each specific flow table being managed.
+ * Base class for managing flow tables
  * @author readams
  */
-public abstract class FlowTable {
+public abstract class FlowTable extends OfTable {
     protected static final Logger LOG =
             LoggerFactory.getLogger(FlowTable.class);
 
-    /**
-     * The context needed for flow tables
-     */
-    public static class FlowTableCtx {
-        protected final DataBroker dataBroker;
-        protected final RpcProviderRegistry rpcRegistry;
-
-        protected final PolicyManager policyManager;
-        protected final SwitchManager switchManager;
-        protected final EndpointManager epManager;
-
-        protected final PolicyResolver policyResolver;
-
-        protected final ScheduledExecutorService executor;
-
-        public FlowTableCtx(DataBroker dataBroker,
-                            RpcProviderRegistry rpcRegistry,
-                            PolicyManager policyManager,
-                            PolicyResolver policyResolver,
-                            SwitchManager switchManager,
-                            EndpointManager endpointManager,
-                            ScheduledExecutorService executor) {
-            super();
-            this.dataBroker = dataBroker;
-            this.rpcRegistry = rpcRegistry;
-            this.policyManager = policyManager;
-            this.switchManager = switchManager;
-            this.epManager = endpointManager;
-            this.policyResolver = policyResolver;
-            this.executor = executor;
-        }
-
-    }
-
-    protected final FlowTableCtx ctx;
-
-    public FlowTable(FlowTableCtx ctx) {
-        super();
-        this.ctx = ctx;
+    public FlowTable(OfTableCtx ctx) {
+        super(ctx);
     }
 
-    // *********
-    // FlowTable
-    // *********
+    // *******
+    // OfTable
+    // *******
 
-    /**
-     * Update the relevant flow table for the node
-     * @param nodeId the node to update
-     * @param dirty the dirty set
-     * @throws Exception
-     */
+    @Override
     public void update(NodeId nodeId, PolicyInfo policyInfo,
                        Dirty dirty) throws Exception {
         ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
@@ -134,6 +82,10 @@ public abstract class FlowTable {
         Futures.addCallback(result, updateCallback);
     }
 
+    // *********
+    // FlowTable
+    // *********
+
     /**
      * Sync flow state using the flow map
      * @throws Exception
@@ -164,25 +116,6 @@ public abstract class FlowTable {
             .setIdleTimeout(0);
     }
 
-    /**
-     * Generic callback for handling result of flow manipulation
-     * @author readams
-     *
-     * @param <T> the expected output type
-     */
-    protected static class FlowCallback<T> implements FutureCallback<T> {
-        @Override
-        public void onSuccess(T result) {
-        }
-
-        @Override
-        public void onFailure(Throwable t) {
-            LOG.error("Failed to add flow entry", t);
-        }
-    }
-    protected static final FlowCallback<Void> updateCallback =
-            new FlowCallback<>();
-
     /**
      * "Visit" a flow ID by checking if it already exists and if so marking
      * the {@link FlowCtx} visited bit.
@@ -209,7 +142,7 @@ public abstract class FlowTable {
         LOG.trace("{} {}", flow.getId(), flow);
         t.put(LogicalDatastoreType.CONFIGURATION,
               FlowUtils.createFlowPath(tiid, flow.getId()),
-              flow);
+              flow, true);
     }
 
     /**
index 88fc912668efcf5c0cf97ad010bb0deb26a4e9ce..4099b1c3bceb02f6e62189d9ac50c500710be799 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
 import java.util.ArrayList;
 
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 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.action.types.rev131112.action.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
@@ -37,6 +38,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.actions._case.WriteActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
@@ -85,9 +93,9 @@ public final class FlowUtils {
     /**
      * Creates a table path from a node ID and table ID
      *
-     * @param nodePath
-     * @param tableKey
-     * @return
+     * @param nodeId the ID of the node
+     * @param tableId the ID of the table
+     * @return the {@link InstanceIdentifier<Table>}
      */
     public static final InstanceIdentifier<Table> 
         createTablePath(final NodeId nodeId, 
@@ -97,7 +105,42 @@ public final class FlowUtils {
                 .child(Table.class, new TableKey(tableId))
                 .build();
     }
-
+    
+    /**
+     * Creates a group path from a node ID and group ID
+     *
+     * @param nodeId the Id of the node
+     * @param groupId the ID of the group table
+     * @return the {@link InstanceIdentifier<Group>}
+     */
+    public static final InstanceIdentifier<Group> 
+        createGroupPath(final NodeId nodeId, 
+                        final GroupId groupId) {
+        return createNodePath(nodeId).builder()
+                .augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(groupId))
+                .build();
+    }
+    /**
+     * Creates a group path from a node ID and group ID
+     *
+     * @param nodeId the Id of the node
+     * @param groupId the ID of the group table
+     * @param bucketId the ID of the bucket in the group table
+     * @return the {@link InstanceIdentifier<Bucket>}
+     */
+    public static final InstanceIdentifier<Bucket> 
+        createBucketPath(final NodeId nodeId, 
+                         final GroupId groupId,
+                         final BucketId bucketId) {
+        return createNodePath(nodeId).builder()
+                .augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(groupId))
+                .child(Buckets.class)
+                .child(Bucket.class, new BucketKey(bucketId))
+                .build();
+    }
+    
     /**
      * Creates a path for particular flow, by appending flow-specific information
      * to table path.
@@ -146,20 +189,24 @@ public final class FlowUtils {
     public static Instruction outputActionIns(NodeConnectorId id) {
         return writeActionIns(outputAction(id));
     }
-    
-    public static Instruction writeActionIns(Action... actions) {
+
+    public static ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> writeActionList(Action... actions) {
         ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> alist
             = new ArrayList<>();
         int count = 0;
         for (Action action : actions) {
             alist.add(new ActionBuilder()
-                .setOrder(Integer.valueOf(count++))
-                .setAction(action)
-                .build());
+            .setOrder(Integer.valueOf(count++))
+            .setAction(action)
+            .build());
         }
+        return alist;
+    }
+
+    public static Instruction writeActionIns(Action... actions) {
         return new WriteActionsCaseBuilder()
             .setWriteActions(new WriteActionsBuilder()
-                .setAction(alist)
+                .setAction(writeActionList(actions))
                 .build())
             .build();
     }
@@ -190,7 +237,7 @@ public final class FlowUtils {
     public static Action outputAction(NodeConnectorId id) {
         return new OutputActionCaseBuilder()
             .setOutputAction(new OutputActionBuilder()
-                .setOutputNodeConnector(id)
+                .setOutputNodeConnector(new Uri(id.getValue()))
                 .build())
             .build();
     }
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java
new file mode 100644 (file)
index 0000000..b219b9a
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+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.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+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;
+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.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+
+/**
+ * Manage the group tables for handling broadcast/multicast
+ * @author readams
+ */
+public class GroupTable extends OfTable {
+    private static final Logger LOG = 
+            LoggerFactory.getLogger(GroupTable.class);
+
+    public GroupTable(OfTableCtx ctx) {
+        super(ctx);
+        // TODO Auto-generated constructor stub
+    }
+    
+    @Override
+    public void update(NodeId nodeId, PolicyInfo policyInfo, Dirty dirty)
+            throws Exception {
+        // there appears to be no way of getting only the existing group
+        // tables unfortunately, so we have to get the whole goddamned node.
+        // Since this is happening concurrently with other things that are 
+        // working in subtrees of nodes, we have to do two transactions
+        ReadOnlyTransaction t = ctx.dataBroker.newReadOnlyTransaction();
+        InstanceIdentifier<Node> niid = 
+                FlowUtils.createNodePath(nodeId);
+        Optional<Node> r =
+                t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
+        if (!r.isPresent()) return;
+        FlowCapableNode fcn = r.get().getAugmentation(FlowCapableNode.class);
+        if (fcn == null) return;
+
+        HashMap<GroupId, GroupCtx> groupMap = new HashMap<>();
+
+        for (Group g : fcn.getGroup()) {
+            GroupCtx gctx = new GroupCtx(g.getGroupId());
+            groupMap.put(g.getGroupId(), gctx);
+
+            Buckets bs = g.getBuckets();
+            if (bs != null && bs.getBucket() != null)
+            for (Bucket b : bs.getBucket()) {
+                gctx.bucketMap.put(b.getBucketId(), new BucketCtx(b));
+            }
+        }
+        
+        sync(nodeId, policyInfo, dirty, groupMap);
+        
+        WriteTransaction wt = ctx.dataBroker.newWriteOnlyTransaction();
+        boolean wrote = false;
+        for (GroupCtx gctx : groupMap.values()) {
+            InstanceIdentifier<Group> giid = 
+                    FlowUtils.createGroupPath(nodeId, gctx.groupId);
+            if (!gctx.visited) {
+                // Remove group table
+                wrote = true;
+                wt.delete(LogicalDatastoreType.CONFIGURATION, giid);
+            } else {
+                ArrayList<Bucket> buckets = new ArrayList<>();
+                
+                // update group table
+                for (BucketCtx bctx : gctx.bucketMap.values()) {
+                    BucketId bid;
+                    if (bctx.b != null) bid = bctx.b.getBucketId();
+                    else bid = bctx.newb.getBucketId();
+                    InstanceIdentifier<Bucket> biid = 
+                            FlowUtils.createBucketPath(nodeId,
+                                                       gctx.groupId, 
+                                                       bid);
+                    if (!bctx.visited) {
+                        // remove bucket
+                        LOG.info("delete {} {}", gctx.groupId, bid);
+                        wrote = true;
+                        wt.delete(LogicalDatastoreType.CONFIGURATION, biid);
+                    } else if (bctx.b == null || 
+                               !Objects.equal(bctx.newb, 
+                                              bctx.b)) {
+                        // update bucket
+                        buckets.add(bctx.newb);
+                        LOG.info("{} {}", gctx.groupId, bctx.newb.getBucketId());
+                    }
+                    if (buckets.size() > 0) {
+                        GroupBuilder gb = new GroupBuilder()
+                            .setGroupId(gctx.groupId)
+                            .setGroupType(GroupTypes.GroupAll)
+                            .setBuckets(new BucketsBuilder()
+                            .setBucket(buckets)
+                            .build());
+                        wrote = true;
+                        wt.merge(LogicalDatastoreType.CONFIGURATION, 
+                                 giid, gb.build());
+                    }
+                }
+            }
+        }
+        if (wrote)
+            Futures.addCallback(wt.submit(), updateCallback);
+    }
+    
+    protected void sync(NodeId nodeId, PolicyInfo policyInfo, Dirty dirty,
+                        HashMap<GroupId, GroupCtx> groupMap) throws Exception {
+
+        for (EgKey epg : ctx.epManager.getGroupsForNode(nodeId)) {
+            IndexedTenant it = ctx.policyResolver.getTenant(epg.getTenantId());
+            if (it == null) continue;
+            EndpointGroup eg = it.getEndpointGroup(epg.getEgId());
+            if (eg == null || eg.getNetworkDomain() == null) continue;
+            L2FloodDomain fd = it.resolveL2FloodDomain(eg.getNetworkDomain());
+            if (fd == null) continue;
+
+            int fdId = ctx.policyManager.getContextOrdinal(epg.getTenantId(),
+                                                           fd.getId());
+            GroupId gid = new GroupId(Long.valueOf(fdId));
+            GroupCtx gctx = groupMap.get(gid);
+            if (gctx == null) {
+                groupMap.put(gid, gctx = new GroupCtx(gid)); 
+            }
+            gctx.visited = true;
+            
+            // we'll use the fdId with the high bit set for remote bucket
+            // and just the local port number for local bucket
+            for (NodeId destNode : ctx.epManager.getNodesForGroup(epg)) {
+                long bucketId = (long)ctx.policyManager
+                        .getContextOrdinal(destNode.getValue());
+                bucketId |= 1L << 31;
+
+                IpAddress tunDst = 
+                        ctx.switchManager.getTunnelIP(destNode);
+                NodeConnectorId tunPort =
+                        ctx.switchManager.getTunnelPort(nodeId);
+                if (tunDst == null || tunPort == null) continue;
+                if (tunDst.getIpv4Address() != null) {
+                    // XXX - TODO Add action: set tunnel dst to tunDst ipv4
+                } else if (tunDst.getIpv6Address() != null) {
+                    // XXX - TODO Add action: set tunnel dst to tunDst ipv6 
+                }
+
+                int epgId = ctx.policyManager
+                        .getContextOrdinal(epg.getTenantId(),
+                                           epg.getEgId());
+
+                // TODO add action: set tunnel ID to epgId
+                
+                Action output = FlowUtils.outputAction(tunPort);
+
+                BucketBuilder bb = new BucketBuilder()
+                    .setBucketId(new BucketId(Long.valueOf(bucketId)))
+                    .setAction(FlowUtils.writeActionList(output));
+                updateBucket(gctx, bb);
+            }
+            for (Endpoint localEp : ctx.epManager.getEPsForNode(nodeId, epg)) {
+                OfOverlayContext ofc = 
+                        localEp.getAugmentation(OfOverlayContext.class);
+                if (ofc == null || ofc.getNodeConnectorId() == null ||
+                    (LocationType.External.equals(ofc.getLocationType())))
+                    continue;
+                String cnid = ofc.getNodeConnectorId().getValue();
+                int ci = cnid.lastIndexOf(':');
+                if (ci < 0 || (ci+1 >= cnid.length()))
+                    continue;
+                long bucketId;
+                try {
+                    bucketId = Long.parseLong(cnid.substring(ci+1));                
+                } catch (NumberFormatException e) {
+                    LOG.warn("Could not parse port number {}", cnid);
+                    continue;
+                }
+
+                Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
+
+                BucketBuilder bb = new BucketBuilder()
+                    .setBucketId(new BucketId(Long.valueOf(bucketId)))
+                    .setAction(FlowUtils.writeActionList(output));
+                updateBucket(gctx, bb);
+            }
+        }
+    }
+
+    private static void updateBucket(GroupCtx gctx, BucketBuilder bb) {
+        BucketCtx bctx = gctx.bucketMap.get(bb.getBucketId());
+        if (bctx == null) {
+            gctx.bucketMap.put(bb.getBucketId(), 
+                               bctx = new BucketCtx(null));
+        }
+        bctx.visited = true;
+        bctx.newb = bb.build();        
+    }
+    
+    private static class BucketCtx {
+        Bucket b;
+        Bucket newb;
+        boolean visited = false;
+
+        public BucketCtx(Bucket b) {
+            super();
+            this.b = b;
+        }
+    }
+    
+    private static class GroupCtx {
+        GroupId groupId;
+        Map<BucketId, BucketCtx> bucketMap = new HashMap<>();
+        boolean visited = false;
+
+        public GroupCtx(GroupId groupId) {
+            super();
+            this.groupId = groupId;
+        }
+    }
+    
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTable.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTable.java
new file mode 100644 (file)
index 0000000..45b9379
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.concurrent.ScheduledExecutorService;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+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.inventory.rev130819.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+
+/**
+ * Manage the state of a openflow  table by reacting to any events and updating
+ * the table state.  This is an abstract class that must be extended for
+ * each specific table being managed.
+ * @author readams
+ */
+public abstract class OfTable {
+    protected static final Logger LOG =
+            LoggerFactory.getLogger(OfTable.class);
+
+    protected final OfTableCtx ctx;
+
+    public OfTable(OfTableCtx ctx) {
+        super();
+        this.ctx = ctx;
+    }
+
+    /**
+     * The context needed for flow tables
+     */
+    public static class OfTableCtx {
+        protected final DataBroker dataBroker;
+        protected final RpcProviderRegistry rpcRegistry;
+    
+        protected final PolicyManager policyManager;
+        protected final SwitchManager switchManager;
+        protected final EndpointManager epManager;
+    
+        protected final PolicyResolver policyResolver;
+    
+        protected final ScheduledExecutorService executor;
+    
+        public OfTableCtx(DataBroker dataBroker,
+                          RpcProviderRegistry rpcRegistry,
+                          PolicyManager policyManager,
+                          PolicyResolver policyResolver,
+                          SwitchManager switchManager,
+                          EndpointManager endpointManager,
+                          ScheduledExecutorService executor) {
+            super();
+            this.dataBroker = dataBroker;
+            this.rpcRegistry = rpcRegistry;
+            this.policyManager = policyManager;
+            this.switchManager = switchManager;
+            this.epManager = endpointManager;
+            this.policyResolver = policyResolver;
+            this.executor = executor;
+        }
+    
+    }
+
+    // *******
+    // OfTable
+    // *******
+
+    /**
+     * Update the relevant flow table for the node
+     * @param nodeId the node to update
+     * @param dirty the dirty set
+     * @throws Exception
+     */
+    public abstract void update(NodeId nodeId, 
+                                PolicyInfo policyInfo,
+                                Dirty dirty) throws Exception;
+    
+    // ***************
+    // Utility methods
+    // ***************
+
+
+    /**
+     * Generic callback for handling result of flow manipulation
+     * @author readams
+     *
+     * @param <T> the expected output type
+     */
+    protected static class OfCallback<T> implements FutureCallback<T> {
+        @Override
+        public void onSuccess(T result) {
+        }
+
+        @Override
+        public void onFailure(Throwable t) {
+            LOG.error("Failed to add flow entry", t);
+        }
+    }
+    protected static final OfCallback<Void> updateCallback =
+            new OfCallback<>();
+
+
+}
index 749baea817b15d465b2d285e54c218389c54d9ab..6194842f48e7206309f2bc7c990ebffcb6d7cf32 100644 (file)
@@ -58,7 +58,7 @@ public class PolicyEnforcer extends FlowTable {
 
     public static final short TABLE_ID = 3;
 
-    public PolicyEnforcer(FlowTableCtx ctx) {
+    public PolicyEnforcer(OfTable.OfTableCtx ctx) {
         super(ctx);
     }
 
@@ -75,63 +75,59 @@ public class PolicyEnforcer extends FlowTable {
         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);
+        for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
+            // Allow traffic within the same endpoint group if the policy
+            // specifies
+            IndexedTenant tenant = 
+                    ctx.policyResolver.getTenant(sepg.getTenantId());
+            EndpointGroup group = 
+                    tenant.getEndpointGroup(sepg.getEgId());
+            IntraGroupPolicy igp = group.getIntraGroupPolicy();
             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);
-                }
+                    ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
+                                                        sepg.getEgId());
+            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);
-                    
+            for (Endpoint src : ctx.epManager.getEPsForNode(nodeId, sepg)) {
+                if (src.getTenant() == null || src.getEndpointGroup() == null)
+                    continue;
+                
+                List<ConditionName> conds = 
+                        ctx.epManager.getCondsForEndpoint(src);
+                ConditionGroup scg = policyInfo.getEgCondGroup(sepg, conds);
+                int scgId = ctx.policyManager.getConfGroupOrdinal(scg);
+                
+                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);
+                        
+                    }
                 }
             }
         }
index c0fb19cc8f534cd8a06ce6011b1ef2e9255bc517..aac3a7cd5470dd00e0428a8bd5768f66f7760faf 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.EgKey;
 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;
@@ -45,7 +46,7 @@ public class PortSecurity extends FlowTable {
     
     public static final short TABLE_ID = 0;
     
-    public PortSecurity(FlowTableCtx ctx) {
+    public PortSecurity(OfTable.OfTableCtx ctx) {
         super(ctx);
     }
 
@@ -77,19 +78,21 @@ public class PortSecurity extends FlowTable {
         dropFlow(t, tiid, flowMap, 111, FlowUtils.IPv4);
         dropFlow(t, tiid, flowMap, 112, FlowUtils.IPv6);
 
-        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()))) {
-                // Allow layer 3 traffic (ARP and IP) with the correct source
-                // IP, MAC, and source port
-                l3flow(t, tiid, flowMap, e, ofc, 120, false);
-                l3flow(t, tiid, flowMap, e, ofc, 121, true);
-                
-                // Allow layer 2 traffic with the correct source MAC and 
-                // source port (note lower priority than drop IP rules) 
-                l2flow(t, tiid, flowMap, e, ofc, 100);
+        for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
+            for (Endpoint e : ctx.epManager.getEPsForNode(nodeId, sepg)) {
+                OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
+                if (ofc != null && ofc.getNodeConnectorId() != null &&
+                        (ofc.getLocationType() == null ||
+                        LocationType.Internal.equals(ofc.getLocationType()))) {
+                    // Allow layer 3 traffic (ARP and IP) with the correct 
+                    // source IP, MAC, and source port
+                    l3flow(t, tiid, flowMap, e, ofc, 120, false);
+                    l3flow(t, tiid, flowMap, e, ofc, 121, true);
+
+                    // Allow layer 2 traffic with the correct source MAC and 
+                    // source port (note lower priority than drop IP rules) 
+                    l2flow(t, tiid, flowMap, e, ofc, 100);
+                }
             }
         }
     }
index 9aad43ac35418f5b75a626552dbc6dbf1893f837..fb7f80453aede0e33678a43be71106743214df32 100644 (file)
@@ -45,7 +45,7 @@ public class SourceMapper extends FlowTable {
 
     public static final short TABLE_ID = 1;
 
-    public SourceMapper(FlowTableCtx ctx) {
+    public SourceMapper(OfTable.OfTableCtx ctx) {
         super(ctx);
     }
 
@@ -63,15 +63,17 @@ public class SourceMapper extends FlowTable {
         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
 
         // XXX TODO Set sEPG from tunnel ports using the tunnel ID
-        
-        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, policyInfo, nodeId, e, ofc);
-            } 
+
+        for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
+            for (Endpoint e : ctx.epManager.getEPsForNode(nodeId, sepg)) {
+                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, policyInfo, nodeId, e, ofc);
+                } 
+            }
         }
     }
     
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EndpointProvider.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/EndpointProvider.java
deleted file mode 100644 (file)
index c8037fc..0000000
+++ /dev/null
@@ -1,38 +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.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 2b626505c380130ee1fb69233694b372f448a0a1..551fe3fbb59c48d32620968f631e2df0949ef583 100644 (file)
@@ -49,7 +49,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class DestinationMapperTest extends FlowTableTest {
+public class DestinationMapperTest extends OfTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(DestinationMapperTest.class);
 
@@ -70,7 +70,7 @@ public class DestinationMapperTest extends FlowTableTest {
         ReadWriteTransaction t = dosync(null);
         verify(t, times(1)).put(any(LogicalDatastoreType.class), 
                                 Matchers.<InstanceIdentifier<Flow>>any(), 
-                                any(Flow.class));
+                                any(Flow.class), anyBoolean());
     }
 
     private void verifyDMap(Endpoint remoteEp, 
@@ -80,7 +80,7 @@ public class DestinationMapperTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
 
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -175,7 +175,7 @@ public class DestinationMapperTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
     
     @Override
similarity index 97%
rename from groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java
rename to groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTableTest.java
index 76ade5cffb9e51925f6d36f5d967a96ee66932f7..ac6e59e78ed7a46f7b4942b32fd87a1196044820 100644 (file)
@@ -16,7 +16,7 @@ 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.flow.FlowTable.FlowCtx;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable.OfTableCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.resolver.MockPolicyResolver;
@@ -67,8 +67,8 @@ import com.google.common.collect.ImmutableList;
 
 import static org.mockito.Mockito.*;
 
-public class FlowTableTest {
-    FlowTableCtx ctx;
+public class OfTableTest {
+    OfTableCtx ctx;
     FlowTable table;
     
     MockEndpointManager endpointManager;
@@ -98,13 +98,13 @@ public class FlowTableTest {
         policyManager = new MockPolicyManager(policyResolver, endpointManager);
         switchManager = new MockSwitchManager();
         
-        ctx = new FlowTableCtx(null, 
-                               null, 
-                               policyManager, 
-                               policyResolver, 
-                               switchManager, 
-                               endpointManager, 
-                               null);
+        ctx = new OfTableCtx(null, 
+                             null, 
+                             policyManager, 
+                             policyResolver, 
+                             switchManager, 
+                             endpointManager, 
+                             null);
     }
     
     protected void setup() throws Exception {
index f0d0183da39f54e027191a019ea165b08e08f902..33922fe87e18d82dfa74029e5e48fee503459c51 100644 (file)
@@ -22,11 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 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;
@@ -37,7 +33,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class PolicyEnforcerTest extends FlowTableTest {
+public class PolicyEnforcerTest extends OfTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(PolicyEnforcerTest.class);
 
@@ -54,7 +50,7 @@ public class PolicyEnforcerTest extends FlowTableTest {
         ReadWriteTransaction t = dosync(null);
         verify(t, times(1)).put(any(LogicalDatastoreType.class), 
                                 Matchers.<InstanceIdentifier<Flow>>any(), 
-                                any(Flow.class));
+                                any(Flow.class), anyBoolean());
     }
     
     @Test
@@ -71,7 +67,7 @@ public class PolicyEnforcerTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
         for (Flow f : ac.getAllValues()) {
@@ -85,7 +81,7 @@ public class PolicyEnforcerTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
 
     @Test
@@ -110,7 +106,7 @@ public class PolicyEnforcerTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
         for (Flow f : ac.getAllValues()) {
@@ -153,7 +149,7 @@ public class PolicyEnforcerTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
 
     @Test
index bd02feedaffefba3b132dfc20aaeaeb67cef50ad..5ab797f000b39c4000d7c07471cbf20528f52ca0 100644 (file)
@@ -47,7 +47,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class PortSecurityTest extends FlowTableTest {
+public class PortSecurityTest extends OfTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(PortSecurityTest.class);
     
@@ -64,7 +64,7 @@ public class PortSecurityTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, times(4)).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                 Matchers.<InstanceIdentifier<Flow>>any(), 
-                                ac.capture());
+                                ac.capture(), anyBoolean());
         int count = 0;
         
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -88,7 +88,7 @@ public class PortSecurityTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
 
     @Test
@@ -103,7 +103,7 @@ public class PortSecurityTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
         
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -122,7 +122,7 @@ public class PortSecurityTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
     
     @Test
@@ -138,7 +138,7 @@ public class PortSecurityTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
 
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -161,7 +161,7 @@ public class PortSecurityTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
     
     @Test
@@ -181,7 +181,7 @@ public class PortSecurityTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                      Matchers.<InstanceIdentifier<Flow>>any(),
-                                     ac.capture());
+                                     ac.capture(), anyBoolean());
         
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -211,6 +211,6 @@ public class PortSecurityTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
 }
index ef5c92dcc73176b749aa14394c7038c8ed70eca9..5bd8e3783e4740e7b0e6c08c164d00d3ea7c174a 100644 (file)
@@ -30,7 +30,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class SourceMapperTest extends FlowTableTest {
+public class SourceMapperTest extends OfTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(SourceMapperTest.class);
     @Before
@@ -46,7 +46,7 @@ public class SourceMapperTest extends FlowTableTest {
         ReadWriteTransaction t = dosync(null);
         verify(t, times(1)).put(any(LogicalDatastoreType.class), 
                                 Matchers.<InstanceIdentifier<Flow>>any(), 
-                                any(Flow.class));
+                                any(Flow.class), anyBoolean());
     }
     
     @Test
@@ -59,7 +59,7 @@ public class SourceMapperTest extends FlowTableTest {
         ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
         verify(t, times(2)).put(eq(LogicalDatastoreType.CONFIGURATION), 
                                 Matchers.<InstanceIdentifier<Flow>>any(),
-                                ac.capture());
+                                ac.capture(), anyBoolean());
 
         int count = 0;
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
@@ -82,7 +82,7 @@ public class SourceMapperTest extends FlowTableTest {
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
                                Matchers.<InstanceIdentifier<Flow>>any(), 
-                               any(Flow.class));
+                               any(Flow.class), anyBoolean());
     }
     
 }