Add source mapping table and refactor/simplify flow table 60/8960/3
authorRob Adams <readams@readams.net>
Sat, 12 Jul 2014 00:14:41 +0000 (17:14 -0700)
committerRob Adams <readams@readams.net>
Tue, 15 Jul 2014 16:29:46 +0000 (09:29 -0700)
Add simple scheme for allocating ordinals for use in the forwarding
plane to map to egs, bds, fds, etc.
Add tests for source mapper and port security tables

Change-Id: If4054a128cb0de921a492524bbf02aa1245ce158
Signed-off-by: Rob Adams <readams@readams.net>
21 files changed:
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/endpoint/AbstractEndpointRegistry.java
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/SwitchManager.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/PortSecurity.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceEPGTable.java [deleted file]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenant.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
groupbasedpolicy/src/main/yang/model/endpoint.yang
groupbasedpolicy/src/main/yang/renderer/ofoverlay/ofoverlay.yang
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockEndpointManager.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockPolicyManager.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenantTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/MockPolicyResolver.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolverTest.java

index 8677954b48c6747e286f27e5097f25c3faeab10d..8ec98f956554b8b182f0b3d241c5c2eefb45be09 100644 (file)
@@ -70,30 +70,35 @@ public abstract class AbstractEndpointRegistry
         this.dataProvider = dataProvider;
         this.executor = executor;
 
-        rpcRegistration =
-                rpcRegistry.addRpcImplementation(EndpointService.class, this);
+        if (rpcRegistry != null) {
+            rpcRegistration =
+                    rpcRegistry.addRpcImplementation(EndpointService.class, this);
+        } else
+            rpcRegistration = null;
         
-        // XXX - This is a hack to avoid a bug in the data broker
-        // API where you have to write all the parents before you can write
-        // a child
-        InstanceIdentifier<Endpoints> iid = 
-                InstanceIdentifier.builder(Endpoints.class).build();
-        WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
-        t.put(LogicalDatastoreType.OPERATIONAL, 
-              iid, new EndpointsBuilder().build());
-        ListenableFuture<RpcResult<TransactionStatus>> f = t.commit();
-        Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
-
-            @Override
-            public void onSuccess(RpcResult<TransactionStatus> result) {
-                
-            }
+        if (dataProvider != null) {
+            // XXX - This is a hack to avoid a bug in the data broker
+            // API where you have to write all the parents before you can write
+            // a child
+            InstanceIdentifier<Endpoints> iid = 
+                    InstanceIdentifier.builder(Endpoints.class).build();
+            WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
+            t.put(LogicalDatastoreType.OPERATIONAL, 
+                  iid, new EndpointsBuilder().build());
+            ListenableFuture<RpcResult<TransactionStatus>> f = t.commit();
+            Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
 
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error("Could not write endpoint base container", t);
-            }
-        });
+                @Override
+                public void onSuccess(RpcResult<TransactionStatus> result) {
+
+                }
+
+                @Override
+                public void onFailure(Throwable t) {
+                    LOG.error("Could not write endpoint base container", t);
+                }
+            });
+        }
 
         // XXX TODO - age out endpoint data and remove 
         // endpoint group/condition mappings with no conditions
index 9a96e6d4f7540a7a9b3ae54b9af82badf41f983c..843c8835eb5c9d8761e3230b601e4e703946cf11 100644 (file)
@@ -86,11 +86,14 @@ public class EndpointManager
                            SwitchManager switchManager) {
         super(dataProvider, rpcRegistry, executor);
         
-        listenerReg = 
-                dataProvider.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, 
-                                                        endpointsIid, 
-                                                        this, 
-                                                        DataChangeScope.ONE);
+        if (dataProvider != null) {
+            listenerReg = dataProvider
+                    .registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, 
+                                                endpointsIid, 
+                                                this, 
+                                                DataChangeScope.ONE);
+        } else
+            listenerReg = null;
 
         LOG.debug("Initialized OFOverlay endpoint manager");
     }
@@ -272,7 +275,7 @@ public class EndpointManager
     /**
      * Update the endpoint indexes.  Set newEp to null to remove.
      */
-    private void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
+    protected void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
         // XXX TODO only keep track of endpoints that are attached 
         // to switches that are actually connected to us
         NodeId oldLoc = getLocation(oldEp);
index 1a5a36da4fb0b75d4e711aa23baa9566c1bab556..5dbf66b2fa46a2b0dc33fe30e3caaab7865b725d 100644 (file)
@@ -19,6 +19,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorCompletionService;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
@@ -30,7 +31,7 @@ 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.PortSecurity;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceEPGTable;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyListener;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
@@ -38,6 +39,9 @@ import org.opendaylight.groupbasedpolicy.resolver.PolicyScope;
 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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
@@ -83,6 +87,21 @@ public class PolicyManager
      * event in milliseconds.
      */
     private final static int FLOW_UPDATE_DELAY = 250;
+
+    /**
+     * Counter used to allocate ordinal values for forwarding contexts
+     * and VNIDs
+     */
+    private final AtomicInteger policyOrdinal = new AtomicInteger(1);
+    
+    /**
+     * 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
+     */
+    private final ConcurrentMap<TenantId, ConcurrentMap<String, Integer>> ordinals = 
+            new ConcurrentHashMap<>();
     
     public PolicyManager(DataBroker dataBroker,
                          PolicyResolver policyResolver,
@@ -96,13 +115,14 @@ public class PolicyManager
         this.executor = executor;
 
         FlowTableCtx ctx = new FlowTableCtx(dataBroker, rpcRegistry, 
-                                            policyResolver, switchManager, 
+                                            this, policyResolver, switchManager, 
                                             endpointManager, executor);
         flowPipeline = ImmutableList.of(new PortSecurity(ctx),
-                                        new SourceEPGTable(ctx));
+                                        new SourceMapper(ctx));
         
         policyScope = policyResolver.registerListener(this);
-        switchManager.registerListener(this);
+        if (switchManager != null)
+            switchManager.registerListener(this);
         endpointManager.registerListener(this);
         
         dirty = new AtomicReference<>(new Dirty());
@@ -129,7 +149,9 @@ public class PolicyManager
                                                           new Function<FlowTable, Table>() {
                                     @Override
                                     public Table apply(FlowTable input) {
-                                        return input.getEmptyTable();
+                                        return new TableBuilder()
+                                            .setId(Short.valueOf(input.getTableId()))
+                                            .build();
                                     }
                                 })) .build());
         t.put(LogicalDatastoreType.CONFIGURATION, 
@@ -207,13 +229,78 @@ public class PolicyManager
         // No-op for now
     }
     
+    /**
+     * 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
+     * @param tenantId the tenant ID of the element
+     * @param id the unique ID for the element
+     * @return the 32-bit ordinal value
+     */
+    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());
+        if (ord == null) {
+            ord = policyOrdinal.getAndIncrement();
+            Integer old = m.putIfAbsent(id.getValue(), 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;
+//            }
+//        }
+    }
+    
     // **************
     // Implementation
     // **************
-    
+
     private void scheduleUpdate() {
-        LOG.info("Scheduling flow update task");
-        flowUpdateTask.reschedule(FLOW_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+        if (switchManager != null) {
+            LOG.trace("Scheduling flow update task");
+            flowUpdateTask.reschedule(FLOW_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+        }
     }
     
     /**
@@ -252,7 +339,7 @@ public class PolicyManager
     private class FlowUpdateTask implements Runnable {
         @Override
         public void run() {
-            LOG.info("Beginning flow update task");
+            LOG.debug("Beginning flow update task");
 
             Dirty d = dirty.getAndSet(new Dirty());
             CompletionService<Void> ecs
@@ -270,7 +357,7 @@ public class PolicyManager
                     LOG.error("Failed to update flow tables", e);
                 }
             }
-            LOG.info("Flow update completed");
+            LOG.debug("Flow update completed");
         }
     }
     
index d0a6130d012323c0dd13711bd7752d73faf0ad2d..9bd035f2c3739e597a2a2ffabfc26a13c25aa22c 100644 (file)
@@ -171,7 +171,7 @@ public class SwitchManager implements AutoCloseable, DataChangeListener {
         FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class);
         if (fcn == null) return;
 
-        LOG.info("{} update", node.getId());
+        LOG.debug("{} update", node.getId());
         
         SwitchState state = switches.get(node.getId()); 
         if (state == null) {
index f854cf789374ed689b8159a65b1c7948bed6aebc..cf77368ebc613ee0e69bdd152cc38ce2e603277f 100644 (file)
@@ -8,24 +8,34 @@
 
 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.TransactionStatus;
+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.PolicyResolver;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+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.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 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
@@ -44,6 +54,7 @@ public abstract class FlowTable {
         protected final DataBroker dataBroker;
         protected final RpcProviderRegistry rpcRegistry;
         
+        protected final PolicyManager policyManager;
         protected final SwitchManager switchManager;
         protected final EndpointManager endpointManager;
         
@@ -53,6 +64,7 @@ public abstract class FlowTable {
 
         public FlowTableCtx(DataBroker dataBroker,
                             RpcProviderRegistry rpcRegistry,
+                            PolicyManager policyManager,
                             PolicyResolver policyResolver,
                             SwitchManager switchManager,
                             EndpointManager endpointManager,
@@ -60,6 +72,7 @@ public abstract class FlowTable {
             super();
             this.dataBroker = dataBroker;
             this.rpcRegistry = rpcRegistry;
+            this.policyManager = policyManager;
             this.switchManager = switchManager;
             this.endpointManager = endpointManager;
             this.policyResolver = policyResolver;
@@ -69,15 +82,10 @@ public abstract class FlowTable {
     }
     
     protected final FlowTableCtx ctx;
-    protected final SalFlowService flowService;
-    protected final OpendaylightFlowStatisticsService statsService;
 
     public FlowTable(FlowTableCtx ctx) {
         super();
         this.ctx = ctx;
-        this.flowService = ctx.rpcRegistry.getRpcService(SalFlowService.class);
-        this.statsService = 
-                ctx.rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class);
     }
 
     // *********
@@ -90,17 +98,66 @@ public abstract class FlowTable {
      * @param dirty the dirty set
      * @throws Exception 
      */
-    public abstract void update(NodeId nodeId, Dirty dirty) throws Exception;
+    public void update(NodeId nodeId, Dirty dirty) throws Exception {
+        ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
+        InstanceIdentifier<Table> tiid = 
+                FlowUtils.createTablePath(nodeId, getTableId());
+        Optional<DataObject> r = 
+                t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
+
+        HashMap<String, FlowCtx> flowMap = new HashMap<>();
+
+        if (r.isPresent()) {
+            Table curTable = (Table)r.get();
+
+            if (curTable.getFlow() != null) {
+                for (Flow f : curTable.getFlow()) {
+                    flowMap.put(f.getId().getValue(), new FlowCtx(f));
+                }
+            }
+        }
+
+        sync(t, tiid, flowMap, nodeId, dirty);
+
+        for (FlowCtx fx : flowMap.values()) {
+            if (!fx.visited) {
+                t.delete(LogicalDatastoreType.CONFIGURATION,
+                         FlowUtils.createFlowPath(tiid, fx.f.getKey()));
+            }
+        }
+        
+        ListenableFuture<RpcResult<TransactionStatus>> result = t.commit();
+        Futures.addCallback(result, updateCallback);
+    }
 
     /**
-     * Construct an empty flow table 
-     * @return the {@link Table}
+     * Sync flow state using the flow map
+     * @throws Exception 
      */
-    public abstract Table getEmptyTable();
+    public abstract void sync(ReadWriteTransaction t,
+                              InstanceIdentifier<Table> tiid,
+                              Map<String, FlowCtx> flowMap,
+                              NodeId nodeId, Dirty dirty) throws Exception;
+    
+    /**
+     * Get the table ID being manipulated
+     */
+    public abstract short getTableId();
     
     // ***************
     // Utility methods
     // ***************
+
+    /**
+     * Get a base flow builder with some common features already set
+     */
+    protected FlowBuilder base() {
+        return new FlowBuilder()
+            .setTableId(getTableId())
+            .setBarrier(false)
+            .setHardTimeout(0)
+            .setIdleTimeout(0);
+    }    
     
     /**
      * Generic callback for handling result of flow manipulation
@@ -122,7 +179,48 @@ public abstract class FlowTable {
             LOG.error("Failed to add flow entry", t);            
         }
     }
-
     protected static final FlowCallback<TransactionStatus> updateCallback =
             new FlowCallback<>();
+
+    /**
+     * "Visit" a flow ID by checking if it already exists and if so marking
+     * the {@link FlowCtx} visited bit.
+     * @param flowMap the map containing the existing flows for this table
+     * @param flowId the ID for the flow
+     * @return <code>true</code> if the flow needs to be added
+     */
+    protected static boolean visit(Map<String, FlowCtx> flowMap, 
+                                   String flowId) {
+        FlowCtx c = flowMap.get(flowId);
+        if (c != null) {
+            c.visited = true;
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Write the given flow to the transaction
+     */
+    protected static void writeFlow(ReadWriteTransaction t,
+                                    InstanceIdentifier<Table> tiid,
+                                    Flow flow) {
+        LOG.trace("{} {}", flow.getId(), flow);
+        t.put(LogicalDatastoreType.CONFIGURATION, 
+              FlowUtils.createFlowPath(tiid, flow.getId()), 
+              flow);
+    }
+    
+    /**
+     * Context object for keeping track of flow state
+     */
+    protected static class FlowCtx {
+        Flow f;
+        boolean visited = false;
+
+        public FlowCtx(Flow f) {
+            super();
+            this.f = f;
+        }
+    }
 }
index 6ea36022e12ae989329f29048cde15de5d8bfe4a..5277fb96546d7ac565b50d8ac33aa9ba16b789da 100644 (file)
@@ -8,8 +8,6 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
-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.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
@@ -20,21 +18,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 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.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCaseBuilder;
 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.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
@@ -43,8 +35,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 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.EthernetMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.collect.ImmutableList;
@@ -66,16 +56,6 @@ public final class FlowUtils {
                 .child(Node.class, new NodeKey(nodeId))
                 .build();
     }
-    
-    /**
-     * Create a NodeRef from a node ID
-     *
-     * @param nodeId the {@link NodeId}
-     * @return the {@link NodeRef}
-     */
-    public static final NodeRef createNodeRef(final NodeId nodeId) {
-        return new NodeRef(createNodePath(nodeId));
-    }
 
     /**
      * Shorten's node child path to node path.
@@ -120,12 +100,6 @@ public final class FlowUtils {
                 .child(Table.class, new TableKey(tableId))
                 .build();
     }
-    
-    public static final FlowTableRef createTableRef(final NodeId nodeId, 
-                                                    final short tableId) {
-        return new FlowTableRef(createTablePath(nodeId, tableId));
-    }
-
 
     /**
      * Creates a path for particular flow, by appending flow-specific information
@@ -141,20 +115,6 @@ public final class FlowUtils {
         return table.child(Flow.class, flowKey);
     }
     
-    /**
-     * Creates a path for particular flow, by appending flow-specific information
-     * to table path.
-     *
-     * @param table
-     * @param flowId
-     * @return
-     */
-    public static InstanceIdentifier<Flow> 
-            createFlowPath(final InstanceIdentifier<Table> table, 
-                           final String flowId) {
-        return createFlowPath(table, new FlowKey(new FlowId(flowId)));
-    }
-    
     /**
      * Creates a path for particular flow, by appending flow-specific information
      * to table path.
@@ -168,80 +128,6 @@ public final class FlowUtils {
                            final FlowId flowId) {
         return createFlowPath(table, new FlowKey(flowId));
     }
-    
-    /**
-     * Extract table id from table path.
-     *
-     * @param tablePath
-     * @return
-     */
-    public static Short getTableId(final InstanceIdentifier<Table> tablePath) {
-        return tablePath.firstKeyOf(Table.class, TableKey.class).getId();
-    }
-
-    /**
-     * Extracts NodeConnectorKey from node connector path.
-     */
-    public static NodeConnectorKey 
-        getNodeConnectorKey(final InstanceIdentifier<?> nodeConnectorPath) {
-        return nodeConnectorPath.firstKeyOf(NodeConnector.class, 
-                                            NodeConnectorKey.class);
-    }
-
-    /**
-     * Extracts NodeKey from node path.
-     */
-    public static NodeKey getNodeKey(final InstanceIdentifier<?> nodePath) {
-        return nodePath.firstKeyOf(Node.class, NodeKey.class);
-    }
-
-
-    //
-    public static final InstanceIdentifier<NodeConnector> 
-        createNodeConnectorIdentifier(final String nodeIdValue,
-                                      final String nodeConnectorIdValue) {
-        return createNodePath(new NodeId(nodeIdValue))
-                .child(NodeConnector.class, 
-                       new NodeConnectorKey(new NodeConnectorId(nodeConnectorIdValue)));
-    }
-    
-    /**
-     * @param nodeConnectorRef
-     * @return
-     */
-    public static InstanceIdentifier<Node> 
-        generateNodeInstanceIdentifier(final NodeConnectorRef nodeConnectorRef) {
-        return nodeConnectorRef.getValue().firstIdentifierOf(Node.class);
-    }
-
-    /**
-     * @param nodeConnectorRef
-     * @param flowTableKey
-     * @return
-     */
-    public static InstanceIdentifier<Table> 
-        generateFlowTableInstanceIdentifier(final NodeConnectorRef nodeConnectorRef, 
-                                            final TableKey flowTableKey) {
-        return generateNodeInstanceIdentifier(nodeConnectorRef).builder()
-                .augmentation(FlowCapableNode.class)
-                .child(Table.class, flowTableKey)
-                .build();
-    }
-
-    /**
-     * @param nodeConnectorRef
-     * @param flowTableKey
-     * @param flowKey
-     * @return
-     */
-    public static InstanceIdentifier<Flow> 
-        generateFlowInstanceIdentifier(final NodeConnectorRef nodeConnectorRef,
-                                       final TableKey flowTableKey,
-                                       final FlowKey flowKey) {
-        return generateFlowTableInstanceIdentifier(nodeConnectorRef, 
-                                                   flowTableKey)
-                .child(Flow.class, flowKey);
-    }
 
     public static Instructions gotoTable(short tableId) {
         return new InstructionsBuilder()
@@ -260,8 +146,8 @@ public final class FlowUtils {
         return new InstructionsBuilder()
             .setInstruction(ImmutableList.of(new InstructionBuilder()
                 .setOrder(Integer.valueOf(0))
-                .setInstruction(new ApplyActionsCaseBuilder()
-                    .setApplyActions(new ApplyActionsBuilder()
+                .setInstruction(new WriteActionsCaseBuilder()
+                    .setWriteActions(new WriteActionsBuilder()
                         .setAction(ImmutableList.of(new ActionBuilder()
                             .setOrder(Integer.valueOf(0))
                             .setAction(new DropActionCaseBuilder()
index 3e90e3846a9a3fb97990a40422f3c6c9492e50e8..cc2a02be230636c9a5533e247b59523906acb7f8 100644 (file)
@@ -1,37 +1,37 @@
+/*
+ * 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.Map;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
 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;
 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.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.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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 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.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
  * Manage the table that enforces port security
  * @author readams
@@ -41,130 +41,102 @@ public class PortSecurity extends FlowTable {
             LoggerFactory.getLogger(PortSecurity.class);
     
     public static final short TABLE_ID = 0;
-    private static final Long ARP = Long.valueOf(0x0806);
-    private static final Long IPv4 = Long.valueOf(0x0800);
-    private static final Long IPv6 = Long.valueOf(0x86DD);
+    protected static final Long ARP = Long.valueOf(0x0806);
+    protected static final Long IPv4 = Long.valueOf(0x0800);
+    protected static final Long IPv6 = Long.valueOf(0x86DD);
     
     public PortSecurity(FlowTableCtx ctx) {
         super(ctx);
     }
-    
+
     @Override
-    public Table getEmptyTable() {
-        return new TableBuilder()
-            .setId(Short.valueOf((short)TABLE_ID))
-            .build();
+    public short getTableId() {
+        return TABLE_ID;
     }
-    
-    @Override
-    public void update(NodeId nodeId, Dirty dirty) throws Exception {
-        ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
-        InstanceIdentifier<Table> tiid = 
-                FlowUtils.createTablePath(nodeId, TABLE_ID);
-        Optional<DataObject> r = 
-                t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
-
-        HashMap<String, FlowCtx> flowMap = new HashMap<>();
-
-        if (r.isPresent()) {
-            Table curTable = (Table)r.get();
 
-            if (curTable.getFlow() != null) {
-                for (Flow f : curTable.getFlow()) {
-                    flowMap.put(f.getId().getValue(), new FlowCtx(f));
-                }
-            }
-        }
-        
+    @Override
+    public void sync(ReadWriteTransaction t,
+                     InstanceIdentifier<Table> tiid,
+                     Map<String, FlowCtx> flowMap,
+                     NodeId nodeId, Dirty dirty) {
+        // Default drop all
         dropFlow(t, tiid, flowMap, 1, null);
+        
+        // Drop IP traffic that doesn't match a source IP rule
         dropFlow(t, tiid, flowMap, 110, ARP);
         dropFlow(t, tiid, flowMap, 111, IPv4);
-        dropFlow(t, tiid, flowMap, 113, IPv6);
+        dropFlow(t, tiid, flowMap, 112, IPv6);
+        
+        // XXX - TODO Allow traffic from tunnel ports and external ports
 
         for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
             OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
-            if (ofc != null && ofc.getNodeConnectorId() != null) {
+            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 (FlowCtx fx : flowMap.values()) {
-            if (!fx.visited) {
-                t.delete(LogicalDatastoreType.CONFIGURATION,
-                         FlowUtils.createFlowPath(tiid, fx.f.getKey()));
-            }
-        }
-        
-        ListenableFuture<RpcResult<TransactionStatus>> result = t.commit();
-        Futures.addCallback(result, updateCallback);
-    }
-    
-    private static FlowBuilder base() {
-        return new FlowBuilder()
-            .setTableId(TABLE_ID)
-            .setBarrier(false)
-            .setHardTimeout(0)
-            .setIdleTimeout(0)
-            .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)));
     }
     
     private void dropFlow(ReadWriteTransaction t,
                           InstanceIdentifier<Table> tiid,
-                          HashMap<String, FlowCtx> flowMap,
+                          Map<String, FlowCtx> flowMap,
                           Integer priority, Long etherType) {
         FlowId flowid = new FlowId(new StringBuilder()
             .append("drop|")
             .append(etherType)
             .toString());
         if (visit(flowMap, flowid.getValue())) {
-            Flow flow = base()
+            FlowBuilder flowb = base()
                 .setId(flowid)
                 .setPriority(priority)
-                .setMatch(new MatchBuilder()
-                        .setEthernetMatch(FlowUtils.ethernetMatch(null, null, 
-                                                                  etherType))
-                        .build())
-                 .setInstructions(FlowUtils.dropInstructions())
-                .build();
-            LOG.trace("{} {}", flow.getId(), flow);
-            t.put(LogicalDatastoreType.CONFIGURATION, 
-                  FlowUtils.createFlowPath(tiid, flowid), 
-                  flow);
+                .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,
-                        HashMap<String, FlowCtx> flowMap,
+                        Map<String, FlowCtx> flowMap,
                         Endpoint e, OfOverlayContext ofc,
                         Integer priority) {
         FlowId flowid = new FlowId(new StringBuilder()
+            .append(ofc.getNodeConnectorId())
+            .append("|")
             .append(e.getMacAddress().getValue())
             .toString());
         if (visit(flowMap, flowid.getValue())) {
             FlowBuilder flowb = base()
                 .setPriority(priority)
-                    .setId(flowid)
-                    .setMatch(new MatchBuilder()
-                        .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(), 
-                                                                  null, null))
-                        .setInPort(ofc.getNodeConnectorId())
-                        .build());
+                .setId(flowid)
+                .setMatch(new MatchBuilder()
+                    .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(), 
+                                                              null, null))
+                    .setInPort(ofc.getNodeConnectorId())
+                    .build())
+                .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)));
 
-            Flow flow = flowb.build();
-            LOG.trace("{} {}", flow.getId(), flow);
-            t.put(LogicalDatastoreType.CONFIGURATION, 
-                  FlowUtils.createFlowPath(tiid, flowid), 
-                  flow);
+            writeFlow(t, tiid, flowb.build());
         }
     }
     
 
     private void l3flow(ReadWriteTransaction t,
                         InstanceIdentifier<Table> tiid,
-                        HashMap<String, FlowCtx> flowMap,
+                        Map<String, FlowCtx> flowMap,
                         Endpoint e, OfOverlayContext ofc,
                         Integer priority,
                         boolean arp) {
@@ -198,6 +170,8 @@ public class PortSecurity extends FlowTable {
                 continue;
             }
             FlowId flowid = new FlowId(new StringBuilder()
+                .append(ofc.getNodeConnectorId())
+                .append("|")
                 .append(e.getMacAddress().getValue())
                 .append("|")
                 .append(ikey)
@@ -215,33 +189,11 @@ public class PortSecurity extends FlowTable {
                         .setLayer3Match(m)
                         .setInPort(ofc.getNodeConnectorId())
                         .build())
+                    .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)))
                     .build();
-                LOG.trace("{} {}", flow.getId(), flow);
 
-                t.put(LogicalDatastoreType.CONFIGURATION, 
-                      FlowUtils.createFlowPath(tiid, flowid), 
-                      flow);
+                writeFlow(t, tiid, flow);
             }
         }
     }
-    
-    private static boolean visit(HashMap<String, FlowCtx> flowMap, 
-                                 String flowId) {
-        FlowCtx c = flowMap.get(flowId);
-        if (c != null) {
-            c.visited = true;
-            return false;
-        }
-        return true;
-    }
-    
-    private static class FlowCtx {
-        Flow f;
-        boolean visited = false;
-
-        public FlowCtx(Flow f) {
-            super();
-            this.f = f;
-        }
-    }
 }
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceEPGTable.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceEPGTable.java
deleted file mode 100644 (file)
index e49338e..0000000
+++ /dev/null
@@ -1,42 +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.flow;
-
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
-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.inventory.rev130819.NodeId;
-
-
-/**
- * Manage the table that assigns source endpoint group, bridge domain, and 
- * router domain to registers to be used by other tables.
- * @author readams
- */
-public class SourceEPGTable extends FlowTable {
-    public static final short TABLE_ID = 1;
-
-    public SourceEPGTable(FlowTableCtx ctx) {
-        super(ctx);
-    }
-
-    @Override
-    public void update(NodeId nodeId, Dirty dirty) {
-        // TODO Auto-generated method stub
-        
-    }
-
-    @Override
-    public Table getEmptyTable() {
-        return new TableBuilder()
-            .setId(Short.valueOf((short)TABLE_ID))
-            .build();
-    }
-
-}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java
new file mode 100644 (file)
index 0000000..50c7576
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
+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.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.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.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Manage the table that assigns source endpoint group, bridge domain, and 
+ * router domain to registers to be used by other tables.
+ * @author readams
+ */
+public class SourceMapper extends FlowTable {
+    public static final short TABLE_ID = 1;
+
+    public SourceMapper(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) throws Exception {
+        // XXX TODO Set sEPG from tunnel ports using the tunnel ID
+        
+        for (Endpoint e : ctx.endpointManager.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);
+            } 
+        }
+    }
+    
+    private void syncEP(ReadWriteTransaction t,
+                        InstanceIdentifier<Table> tiid,
+                        Map<String, FlowCtx> flowMap, 
+                        NodeId nodeId, Endpoint e, OfOverlayContext ofc) 
+                                 throws Exception {
+        // Set sEPG, flood domain, bridge domain, and layer 3 context 
+        // for internal endpoints by directly matching each endpoint
+        IndexedTenant tenant = ctx.policyResolver.getTenant(e.getTenant());
+        if (tenant == null) return;
+
+        EndpointGroup eg = tenant.getEndpointGroup(e.getEndpointGroup());
+        L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+        L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
+        L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
+
+        int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
+        
+        egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
+                                                   e.getEndpointGroup());
+        if (bd != null)
+            bdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+                                                       bd.getId());
+        if (fd != null)
+            fdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+                                                       fd.getId());
+        if (l3c != null)
+            l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
+                                                       l3c.getId());
+        // TODO set source condition set ID as well
+        
+        FlowId flowid = new FlowId(new StringBuilder()
+            .append(ofc.getNodeConnectorId())
+            .append("|")
+            .append(e.getMacAddress().getValue())
+            .append("|")
+            .append(egId)
+            .append("|")
+            .append(bdId)
+            .append("|")
+            .append(fdId)
+            .append("|")
+            .append(l3Id)
+            .toString());
+        if (visit(flowMap, flowid.getValue())) {
+            LOG.info("{} eg:{} bd:{} fd:{} vrf:{}", 
+                     e.getMacAddress(), egId, bdId, fdId, l3Id);
+            FlowBuilder flowb = base()
+                .setPriority(Integer.valueOf(100))
+                .setId(flowid)
+                .setMatch(new MatchBuilder()
+                    .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(), 
+                                                              null, null))
+                    .setInPort(ofc.getNodeConnectorId())
+                    .build())
+                // XXX TODO set sepg, bd, fd, vrf into registers
+                .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)));
+            writeFlow(t, tiid, flowb.build());
+        }
+    }
+}
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenant.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenant.java
new file mode 100644 (file)
index 0000000..d15dbbb
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.annotation.concurrent.Immutable;
+
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.NetworkDomain;
+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 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.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.Subnet;
+
+/**
+ * Wrap some convenient indexes around a {@link Tenant} object
+ * @author readams
+ */
+@Immutable
+public class IndexedTenant {
+    private final Tenant tenant;
+    private final int hashCode;
+
+    private final Map<EndpointGroupId, EndpointGroup> endpointGroups =
+            new HashMap<>();
+    private final Map<ContractId, Contract> contracts =
+            new HashMap<>();
+    private final Map<String, NetworkDomain> networkDomains =
+            new HashMap<>();
+    
+    public IndexedTenant(Tenant tenant) {
+        super();
+        this.tenant = tenant;
+        this.hashCode = tenant.hashCode();
+        
+        if (tenant.getEndpointGroup() != null) {
+            for (EndpointGroup eg : tenant.getEndpointGroup()) {
+                endpointGroups.put(eg.getId(), eg);
+            }
+        }
+        if (tenant.getContract() != null) {
+            for (Contract c : tenant.getContract()) {
+                contracts.put(c.getId(), c);
+            }
+        }
+        if (tenant.getL3Context() != null) {
+            for (L3Context c : tenant.getL3Context()) {
+                networkDomains.put(c.getId().getValue(), c);
+            }
+        }
+        if (tenant.getL2BridgeDomain() != null) {
+            for (L2BridgeDomain c : tenant.getL2BridgeDomain()) {
+                networkDomains.put(c.getId().getValue(), c);
+            }
+        }
+        if (tenant.getL2FloodDomain() != null) {
+            for (L2FloodDomain c : tenant.getL2FloodDomain()) {
+                networkDomains.put(c.getId().getValue(), c);
+            }
+        }
+        if (tenant.getSubnet() != null) {
+            for (Subnet s : tenant.getSubnet()) {
+                networkDomains.put(s.getId().getValue(), s);
+            }
+        }
+    }
+
+    /**
+     * Get the underlying tenant object
+     * @return the {@link Tenant}
+     */
+    public Tenant getTenant() {
+        return tenant;
+    }
+    
+    /**
+     * Look up the network domain specified
+     * @param id the {@link NetworkDomainId}
+     * @return the {@link NetworkDomain} if it exists, or <code>null</code> 
+     * otherwise
+     */
+    public NetworkDomain getNetworkDomain(NetworkDomainId id) {
+        return networkDomains.get(id.getValue());
+    }
+
+    /**
+     * Look up the endpoint group specified
+     * @param id the {@link EndpointGroupId}
+     * @return the {@link EndpointGroup} if it exists, or <code>null</code> 
+     * otherwise
+     */
+    public EndpointGroup getEndpointGroup(EndpointGroupId id) {
+        return endpointGroups.get(id);
+    }
+    
+    /**
+     * Look up the contract specified
+     * @param id the {@link ContractId}
+     * @return the {@link Contract} if it exists, or <code>null</code> 
+     * otherwise
+     */
+    public Contract getContract(ContractId id) {
+        return contracts.get(id);
+    }
+
+    /**
+     * Get the layer 3 context for the specified network domain by walking
+     * up the hierarchy
+     * @param id the {@link NetworkDomainId} for the network domain
+     * @return the {@link L3Context} or <code>null</code> if it does not exist
+     */
+    public L3Context resolveL3Context(NetworkDomainId id) {
+        return resolveDomain(L3Context.class, id);
+    }
+
+    /**
+     * Get the layer 2 bridge domain for the specified network domain by walking
+     * up the hierarchy
+     * @param id the {@link NetworkDomainId} for the network domain
+     * @return the {@link L2BridgeDomain} or <code>null</code> if it does
+     * not exist
+     */
+    public L2BridgeDomain resolveL2BridgeDomain(NetworkDomainId id) {
+        return resolveDomain(L2BridgeDomain.class, id);
+    }
+
+    /**
+     * Get the layer 2 flood domain for the specified network domain by walking
+     * up the hierarchy
+     * @param id the {@link NetworkDomainId} for the network domain
+     * @return the {@link L2FloodDomain} or <code>null</code> if it does
+     * not exist
+     */
+    public L2FloodDomain resolveL2FloodDomain(NetworkDomainId id) {
+        return resolveDomain(L2FloodDomain.class, id);
+    }
+
+    /**
+     * If the specified network domain represents a subnet, return it.
+     * @param id the {@link NetworkDomainId}
+     * @return the {@link Subnet} if it exists, or <code>null</code> otherwise
+     */
+    public Subnet resolveSubnet(NetworkDomainId id) {
+        NetworkDomain d = networkDomains.get(id.getValue());
+        if (d == null) return null;
+        if (d instanceof Subnet) return (Subnet)d;
+        return null;
+    }
+
+    // ******
+    // Object
+    // ******
+    
+    @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;
+        IndexedTenant other = (IndexedTenant) obj;
+        if (tenant == null) {
+            if (other.tenant != null)
+                return false;
+        } else if (!tenant.equals(other.tenant))
+            return false;
+        return true;
+    }
+
+    // **************
+    // Implementation
+    // **************
+
+    private <C extends NetworkDomain> C resolveDomain(Class<C> domainClass,
+                                                      NetworkDomainId id) {
+        HashSet<NetworkDomainId> visited = new HashSet<>();        
+        while (id != null) {
+            if (visited.contains(id)) return null;
+            visited.add(id);
+            NetworkDomain d = networkDomains.get(id.getValue());
+            if (d == null) return null;
+            if (domainClass.isInstance(d)) return domainClass.cast(d);
+            if (d instanceof Subnet)
+                id = ((Subnet)d).getParent();
+            if (d instanceof L2BridgeDomain)
+                id = ((L2BridgeDomain)d).getParent();
+            if (d instanceof L2FloodDomain)
+                id = ((L2FloodDomain)d).getParent();
+        }
+        return null;
+    }
+}
index 3a5745d0f63a50da7fb9915693516bd99cf39d5a..39d98b09749d7e905bc5b6ef62a97212a4e2c796 100644 (file)
@@ -110,7 +110,7 @@ public class PolicyResolver implements AutoCloseable {
      */
     private CopyOnWriteArrayList<PolicyScope> policyListenerScopes;
     
-    private ConcurrentMap<TenantId, TenantContext> resolvedTenants;
+    protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
     
     private PolicyCache policyCache = new PolicyCache();
     
@@ -121,7 +121,6 @@ public class PolicyResolver implements AutoCloseable {
         this.executor = executor;
         policyListenerScopes = new CopyOnWriteArrayList<>();
         resolvedTenants = new ConcurrentHashMap<>();
-        
         LOG.debug("Initialized renderer common policy resolver");
     }
 
@@ -167,6 +166,17 @@ public class PolicyResolver implements AutoCloseable {
                                      ep2Tenant, ep2Group, ep2Conds);
     }
 
+    /**
+     * Get the normalized tenant for the given ID
+     * @param tenant the tenant ID
+     * @return the {@link Tenant}
+     */
+    public IndexedTenant getTenant(TenantId tenant) {
+        TenantContext tc = resolvedTenants.get(tenant);
+        if (tc == null) return null;
+        return tc.tenant.get();
+    }
+    
     /**
      * Register a listener to receive update events.
      * @param listener the {@link PolicyListener} object to receive the update
@@ -235,15 +245,20 @@ public class PolicyResolver implements AutoCloseable {
     }
 
     private void updateTenant(final TenantId tenantId) {
+        if (dataProvider == null) return;
+
         TenantContext context = resolvedTenants.get(tenantId);
         if (context == null) {
-            ListenerRegistration<DataChangeListener> registration = 
-                    dataProvider.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                                                            TenantUtils.tenantIid(tenantId), 
-                                                            new PolicyChangeListener(tenantId),
-                                                            DataChangeScope.SUBTREE);
+            ListenerRegistration<DataChangeListener> registration = null;
+            if (dataProvider != null) {
+                 registration = dataProvider
+                         .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                                                     TenantUtils.tenantIid(tenantId), 
+                                                     new PolicyChangeListener(tenantId),
+                                                     DataChangeScope.SUBTREE);
+            }
 
-            context = new TenantContext(tenantId, registration);
+            context = new TenantContext(registration);
             TenantContext oldContext = 
                     resolvedTenants.putIfAbsent(tenantId, context);
             if (oldContext != null) {
@@ -255,8 +270,8 @@ public class PolicyResolver implements AutoCloseable {
         }
 
         // Resolve the new tenant and update atomically
-        final AtomicReference<Tenant> tenantRef = context.tenant;
-        final Tenant ot = tenantRef.get();
+        final AtomicReference<IndexedTenant> tenantRef = context.tenant;
+        final IndexedTenant ot = tenantRef.get();
         ReadOnlyTransaction transaction = 
                 dataProvider.newReadOnlyTransaction();
         InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
@@ -270,7 +285,8 @@ public class PolicyResolver implements AutoCloseable {
                 if (!result.isPresent()) return;
 
                 Tenant t = InheritanceUtils.resolveTenant((Tenant)result.get());
-                if (!tenantRef.compareAndSet(ot, t)) {
+                IndexedTenant it = new IndexedTenant(t);
+                if (!tenantRef.compareAndSet(ot, it)) {
                     // concurrent update of tenant policy.  Retry
                     updateTenant(tenantId);
                 } else {
@@ -668,16 +684,13 @@ public class PolicyResolver implements AutoCloseable {
         return matches;
     }
 
-    private static class TenantContext {
-        //TenantId tenantId;
+    protected static class TenantContext {
         ListenerRegistration<DataChangeListener> registration;
 
-        AtomicReference<Tenant> tenant = new AtomicReference<Tenant>();
+        AtomicReference<IndexedTenant> tenant = new AtomicReference<>();
         
-        public TenantContext(TenantId tenantId,
-                             ListenerRegistration<DataChangeListener> registration) {
+        public TenantContext(ListenerRegistration<DataChangeListener> registration) {
             super();
-            //this.tenantId = tenantId;
             this.registration = registration;
         }
     }
index bfb5a609d1e2eb8636520dbf217963e7619379c3..a7e7545f9abd57f68087c42cb53df908b7747aec 100644 (file)
@@ -28,9 +28,9 @@ module endpoint {
         description 
             "The fields that identify an endpoint by a layer 2 address";
         leaf l2-context {
-            type gbp-common:l2-context-id;
+            type gbp-common:l2-bridge-domain-id;
             description 
-                "The context for the layer 2 address for this endpoint";
+                "The bridge domain for the layer 2 address for this endpoint";
         }
         leaf mac-address {
             type yang:mac-address;
index 8c739f2de26269e3bb5d00bfa9f74e68f0d4d345..620fec4fbe114e798ee388b1292464f992ccc39b 100644 (file)
@@ -59,7 +59,32 @@ module ofoverlay {
             }
         }
     }
+    /*
+    container of-overlay-operational {
+        description 
+            "Operational parameters for the OpenFlow overlay renderer";
+
+        config false;
 
+        list data-plane-ordinal {
+            description 
+                "Map elements of the policy to the id used on the network";
+            key "tenant id";
+            leaf tenant {
+                description "The tenant for the policy element";
+                type gbp-common:tenant-id;
+            }
+            leaf id {
+                description "The ID of the item";
+                type gbp-common:unique-id;
+            }
+            leaf ordinal {
+                description "The 32-bit ordinal for the item";
+                type uint32;
+            }
+        }
+    }
+    */
     grouping endpoint-location {
         description 
             "The location for this endpoint in the overlay network";
@@ -71,8 +96,8 @@ module ofoverlay {
                 enum internal {
                     description 
                     "The endpoint is located on a port that is part of 
-                             the overlay network.  You must include the node ID
-                             and port number for this endpoint.";
+                     the overlay network.  You must include the node
+                     ID and port number for this endpoint.";
                 }
                 enum external {
                     description "This endpoint is not inside the overlay.";
@@ -83,13 +108,19 @@ module ofoverlay {
         leaf node-id {
             description 
                 "The OpenFlow switch for the endpoint. Must be included 
-                     for all internal endpoints.";
+                 for all internal endpoints.  The format is
+                 openflow:[dpid] where the dpid is the value of the
+                 switch DPID cast to a long.";
             type inv:node-id;
         }
 
         leaf node-connector-id {
             description 
-                "The node connector for the endpoint's OpenFlow port";
+                "The node connector for the endpoint's OpenFlow port. The 
+                 format is openflow:[dpid]:[port] where the dpid is
+                 the value of the switch DPID cast to a long, and port
+                 is the openflow port number of the interface where
+                 the endpoint is connected.";
             type inv:node-connector-id;
         }
     }
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockEndpointManager.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockEndpointManager.java
new file mode 100644 (file)
index 0000000..9f7848e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.endpoint.rev140421.endpoints.Endpoint;
+
+/**
+ * Class for mocking up endpoints for unit tests
+ * @author readams
+ */
+public class MockEndpointManager extends EndpointManager {
+
+    public MockEndpointManager() {
+        super(null, null, null, null);
+    }
+
+    public void addEndpoint(Endpoint ep) {
+        updateEndpoint(null, ep);
+    }
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockPolicyManager.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/MockPolicyManager.java
new file mode 100644 (file)
index 0000000..1644587
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.groupbasedpolicy.resolver.PolicyResolver;
+
+public class MockPolicyManager extends PolicyManager {
+
+    public MockPolicyManager(PolicyResolver policyResolver,
+                             EndpointManager endpointManager) {
+        super(null, policyResolver, null, endpointManager, null, null);
+    }
+
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java
new file mode 100644 (file)
index 0000000..8d38e69
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.Collections;
+import java.util.Map;
+
+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.flow.FlowTable.FlowCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
+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;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+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.tenants.TenantBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
+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.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.mockito.Mockito.*;
+
+public class FlowTableTest {
+    FlowTableCtx ctx;
+    FlowTable table;
+    MockEndpointManager endpointManager;
+    MockPolicyResolver policyResolver;
+    MockPolicyManager policyManager;
+    
+    NodeId nodeId = new NodeId("openflow:1");
+    InstanceIdentifier<Table> tiid;
+    
+    L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");
+    L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");
+    L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");
+    SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");
+    TenantId tid = new TenantId("1118c691-8520-47ad-80b8-4cf5e3fe3302");
+    EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");
+    
+    public void initCtx() {
+        endpointManager = new MockEndpointManager();
+        policyResolver = new MockPolicyResolver();
+        policyManager = new MockPolicyManager(policyResolver, endpointManager);
+        ctx = new FlowTableCtx(null, 
+                               null, 
+                               policyManager, 
+                               policyResolver, 
+                               null, 
+                               endpointManager, 
+                               null);
+    }
+    
+    public void setup() throws Exception {
+        tiid = FlowUtils.createTablePath(nodeId, 
+                                         table.getTableId());
+    }
+
+    public TenantBuilder baseTenant() {
+        return new TenantBuilder()
+            .setId(tid)
+            .setEndpointGroup(ImmutableList.of(new EndpointGroupBuilder()
+                .setId(eg)
+                .setNetworkDomain(sub)
+                .build()))
+            .setL3Context(ImmutableList.of(new L3ContextBuilder()
+                .setId(l3c)
+                .build()))
+            .setL2BridgeDomain(ImmutableList.of(new L2BridgeDomainBuilder()
+                .setId(bd)
+                .setParent(l3c)
+                .build()))
+            .setL2FloodDomain(ImmutableList.of(new L2FloodDomainBuilder()
+                .setId(fd)
+                .setParent(bd)
+                .build()))
+            .setSubnet(ImmutableList.of(new SubnetBuilder()
+                .setId(sub)
+                .setParent(fd)
+                .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.0.1/24")))
+                .build()));
+    }
+
+    public EndpointBuilder baseEP() {
+        OfOverlayContext ofc = new OfOverlayContextBuilder()
+            .setNodeId(nodeId)
+            .setNodeConnectorId(new NodeConnectorId(nodeId.getValue() + ":1"))
+            .build();
+        return new EndpointBuilder()
+            .addAugmentation(OfOverlayContext.class, ofc)
+            .setL2Context(bd)
+            .setTenant(tid)
+            .setEndpointGroup(eg)
+            .setMacAddress(new MacAddress("00:00:00:00:00:01"));
+    }
+    
+    public ReadWriteTransaction dosync(Map<String, FlowCtx> flowMap) 
+              throws Exception {
+        ReadWriteTransaction t = mock(ReadWriteTransaction.class);
+        if (flowMap == null)
+            flowMap = Collections.emptyMap();
+        table.sync(t, tiid, flowMap, nodeId, null);
+        return t;
+    }
+
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java
new file mode 100644 (file)
index 0000000..9ffe278
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+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.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+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.endpoint.fields.L3Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.*;
+
+import static org.mockito.Matchers.*;
+
+import static org.mockito.Mockito.*;
+
+public class PortSecurityTest extends FlowTableTest {
+    protected static final Logger LOG = 
+            LoggerFactory.getLogger(PortSecurityTest.class);
+    
+    @Before
+    public void setup() throws Exception {
+        initCtx();
+        table = new PortSecurity(ctx);
+        super.setup();
+    }
+
+    @Test
+    public void testDefaultDeny() throws Exception {
+        ReadWriteTransaction t = dosync(null);
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, times(4)).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                      any(InstanceIdentifier.class), ac.capture());
+        int count = 0;
+        
+        HashMap<String, FlowCtx> flowMap = new HashMap<>();
+        for (Flow f : ac.getAllValues()) {
+            flowMap.put(f.getId().getValue(), new FlowCtx(f));
+            Long etherType = null;
+            if (f.getMatch() != null) {
+                etherType = f.getMatch().getEthernetMatch()
+                        .getEthernetType().getType().getValue().longValue();
+            }
+            if (f.getMatch() == null ||
+                PortSecurity.ARP.equals(etherType) ||
+                PortSecurity.IPv4.equals(etherType) ||
+                PortSecurity.IPv6.equals(etherType)) {
+                count += 1;
+                assertEquals(FlowUtils.dropInstructions(),
+                             f.getInstructions());
+            } 
+        }
+        assertEquals(4, count);
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               any(InstanceIdentifier.class), 
+                               any(Flow.class));
+    }
+    
+    @Test
+    public void testL2() throws Exception {
+        List<L3Address> l3 = Collections.emptyList();
+        Endpoint ep = baseEP()
+            .setL3Address(l3)
+            .build();
+       
+        endpointManager.addEndpoint(ep);
+        ReadWriteTransaction t = dosync(null);
+        
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                      any(InstanceIdentifier.class), 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.getMatch() != null &&
+                f.getMatch().getEthernetMatch() != null &&
+                f.getMatch().getEthernetMatch().getEthernetSource() != null &&
+                Objects.equals(ep.getMacAddress(), 
+                               f.getMatch().getEthernetMatch()
+                                   .getEthernetSource().getAddress()) &&
+                Objects.equals(ep.getAugmentation(OfOverlayContext.class).getNodeConnectorId(), 
+                               f.getMatch().getInPort())) {
+                count += 1;
+                assertEquals(FlowUtils.gotoTable((short)(table.getTableId()+1)),
+                             f.getInstructions());
+            }
+        }
+        assertEquals(1, count);
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               any(InstanceIdentifier.class), 
+                               any(Flow.class));
+    }
+    
+    @Test
+    public void testL3() throws Exception {
+        Endpoint ep = baseEP()
+            .setL3Address(ImmutableList.of(new L3AddressBuilder()
+                .setIpAddress(new IpAddress(new Ipv4Address("10.10.10.10")))
+                .build(),
+                new L3AddressBuilder()
+                .setIpAddress(new IpAddress(new Ipv6Address("2001:db8:85a3::8a2e:370:7334")))
+                .build()))
+            .build();
+        
+        endpointManager.addEndpoint(ep);
+        ReadWriteTransaction t = dosync(null);
+        
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                      any(InstanceIdentifier.class), 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.getMatch() != null &&
+                Objects.equals(ep.getAugmentation(OfOverlayContext.class).getNodeConnectorId(), 
+                               f.getMatch().getInPort()) &&
+                ((f.getMatch().getLayer3Match() != null &&
+                  f.getMatch().getLayer3Match() instanceof Ipv4Match &&
+                  Objects.equals(ep.getL3Address().get(0).getIpAddress().getIpv4Address().getValue(),
+                                 ((Ipv4Match)f.getMatch().getLayer3Match()).getIpv4Source().getValue())) ||
+                 (f.getMatch().getLayer3Match() != null &&
+                  f.getMatch().getLayer3Match() instanceof ArpMatch &&
+                  Objects.equals(ep.getL3Address().get(0).getIpAddress().getIpv4Address().getValue(),
+                                 ((ArpMatch)f.getMatch().getLayer3Match()).getArpSourceTransportAddress().getValue())) ||
+                 (f.getMatch().getLayer3Match() != null &&
+                  f.getMatch().getLayer3Match() instanceof Ipv6Match &&
+                  Objects.equals(ep.getL3Address().get(1).getIpAddress().getIpv6Address().getValue(),
+                                 ((Ipv6Match)f.getMatch().getLayer3Match()).getIpv6Source().getValue())))) {
+                count += 1;
+                assertEquals(FlowUtils.gotoTable((short)(table.getTableId()+1)),
+                             f.getInstructions());
+            }
+        }
+        assertEquals(3, count);
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               any(InstanceIdentifier.class), 
+                               any(Flow.class));
+    }
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java
new file mode 100644 (file)
index 0000000..65fad8f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.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.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+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 SourceMapperTest extends FlowTableTest {
+    protected static final Logger LOG = 
+            LoggerFactory.getLogger(SourceMapperTest.class);
+    @Before
+    public void setup() throws Exception {
+        initCtx();
+        table = new SourceMapper(ctx);
+        super.setup();
+    }
+    
+    @Test
+    public void testNoPolicy() throws Exception {
+        endpointManager.addEndpoint(baseEP().build());
+        ReadWriteTransaction t = dosync(null);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               any(InstanceIdentifier.class), 
+                               any(Flow.class));
+    }
+    
+    @Test
+    public void testMap() throws Exception {
+        Endpoint ep = baseEP().build();
+        endpointManager.addEndpoint(ep);
+        policyResolver.addTenant(baseTenant().build());
+        
+        ReadWriteTransaction t = dosync(null);
+        ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+        verify(t, times(1)).put(eq(LogicalDatastoreType.CONFIGURATION), 
+                      any(InstanceIdentifier.class), 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 (Objects.equals(ep.getMacAddress(),
+                               f.getMatch().getEthernetMatch().getEthernetSource().getAddress())) {
+                // XXX TODO verify register setting in the instructions
+                LOG.info("{}", f);
+                count += 1;
+            }
+            
+        }
+        assertEquals(1, count);
+
+        t = dosync(flowMap);
+        verify(t, never()).put(any(LogicalDatastoreType.class), 
+                               any(InstanceIdentifier.class), 
+                               any(Flow.class));
+    }
+    
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenantTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/IndexedTenantTest.java
new file mode 100644 (file)
index 0000000..7582f5c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+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.TenantBuilder;
+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.L2BridgeDomainBuilder;
+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.L2FloodDomainBuilder;
+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.L3ContextBuilder;
+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.SubnetBuilder;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.*;
+
+public class IndexedTenantTest {
+
+    @Test
+    public void testResolveND() throws Exception {
+        SubnetId sid = new SubnetId("dd25397d-d829-4c8d-8c01-31f129b8de8f");
+        L3ContextId l3id = new L3ContextId("f2311f52-890f-4095-8b85-485ec8b92b3c");
+        L2BridgeDomainId bdid= new L2BridgeDomainId("70aeb9ea-4ca1-4fb9-9780-22b04b84a0d6");
+        L2FloodDomainId fdid = new L2FloodDomainId("252fbac6-bb6e-4d16-808d-6f56d20e5cca");
+
+        L3Context l3c = new L3ContextBuilder().setId(l3id).build();
+        L2BridgeDomain bd = new L2BridgeDomainBuilder()
+            .setParent(l3id)
+            .setId(bdid).build();
+        L2FloodDomain fd = new L2FloodDomainBuilder()
+            .setParent(bdid)
+            .setId(fdid).build();
+        Subnet s = new SubnetBuilder()
+            .setParent(fdid)
+            .setId(sid).build();
+        Tenant t = new TenantBuilder()
+            .setSubnet(ImmutableList.of(s))
+            .setL2BridgeDomain(ImmutableList.of(bd))
+            .setL3Context(ImmutableList.of(l3c))
+            .setL2FloodDomain(ImmutableList.of(fd))
+            .build();
+        IndexedTenant it = new IndexedTenant(t);
+
+        assertNotNull(it.getNetworkDomain(sid));
+        assertEquals(sid, it.resolveSubnet(sid).getId());
+        assertEquals(l3id, it.resolveL3Context(sid).getId());
+        assertEquals(bdid, it.resolveL2BridgeDomain(sid).getId());
+        assertEquals(fdid, it.resolveL2FloodDomain(sid).getId());
+    }
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/MockPolicyResolver.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/resolver/MockPolicyResolver.java
new file mode 100644 (file)
index 0000000..108555a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+
+
+/**
+ * Mock version of policy resolver useful for tests
+ * @author readams
+ */
+public class MockPolicyResolver extends PolicyResolver {
+
+    public MockPolicyResolver() {
+        super(null, null);
+    }
+
+    public void addTenant(Tenant unresolvedTenant) {
+        TenantContext context = new TenantContext(null);
+        Tenant t = InheritanceUtils.resolveTenant(unresolvedTenant);
+        IndexedTenant it = new IndexedTenant(t);
+        context.tenant.set(it);
+        resolvedTenants.put(unresolvedTenant.getId(), context);
+    }
+}
index f6fc8cf777d2904a025408be396ac173e380ec45..1cb21997e25746aae18681c64e043298c8929d4d 100644 (file)
@@ -448,11 +448,6 @@ public class PolicyResolverTest {
         assertEquals(1, rg.rules.size());
         assertEquals(rule2.getName(), rg.rules.get(0).getName());
     }
-    
-    @Test
-    public void testUpdates() throws Exception {
-        // test subscriptions and update notifications
-    }
 
     private static class ContractMatchKey {
         TenantId tenant;