Implement SFC integration 93/19993/5
authorThomas Bachman <tbachman@yahoo.com>
Sat, 11 Apr 2015 22:37:28 +0000 (18:37 -0400)
committerKeith Burns (alagalah) <alagalah@gmail.com>
Thu, 14 May 2015 17:56:19 +0000 (10:56 -0700)
- Query based on Chainname
- Validate Chain before moving from CONF to OPER
- Added ChainAction
- Added things in SwitchManager/EndpointManager to modify READY state so we don't write flows to switches
  with no endpoints

Change-Id: I84d2549a444f10ddabed146f857af38d0e6369c0
Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
24 files changed:
commons/parent/pom.xml
distribution-karaf/pom.xml
features/pom.xml
features/src/main/resources/features.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
renderers/ofoverlay/pom.xml
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java [new file with mode: 0644]
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/MockSwitchManager.java

index fdfb3de03d5d00a0f6b9a9cabc81f7bcf9a7c2af..79a878b85b908da7152c27770941d66e887c0c4b 100644 (file)
@@ -30,6 +30,7 @@
     <generated.yang.docs>${project.build.directory}/site/models</generated.yang.docs>
     <config.version>0.3.0-SNAPSHOT</config.version>
     <mdsal.version>1.2.0-SNAPSHOT</mdsal.version>
+    <sfc.version>0.1.0-SNAPSHOT</sfc.version>
     <restconf.version>1.2.0-SNAPSHOT</restconf.version>
     <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
     <openflowplugin.version>0.1.0-SNAPSHOT</openflowplugin.version>
index 47fd9c27b9481c5a44dae7e4eadc82316217c871..744e6972358f19ff1b0a9bc2444a067f2df2bb4a 100644 (file)
@@ -25,6 +25,7 @@
 
   <properties>
     <groupbasedpolicy.project.version>0.2.0-SNAPSHOT</groupbasedpolicy.project.version>
+    <sfc.version>0.1.0-SNAPSHOT</sfc.version>
   </properties>
 
   <dependencies>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-sb-rest</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-ovs</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfcofl2</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-netconf</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
   <scm>
     <connection>scm:git:ssh://git.opendaylight.org:29418/groupbasedpolicy.git</connection>
index b203d0d6b036285a2ad9a17ce4c1c502c021c976..9bf94657e3a5e06ead841692622a27812450d637 100644 (file)
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-sb-rest</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-ovs</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfcofl2</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>features-sfc-netconf</artifactId>
+      <version>${sfc.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.openflowplugin</groupId>
       <artifactId>features-openflowplugin</artifactId>
index e16767b8ef2330578917bd520ab09eaeff421872..22d1beab7aebd11f116ddf3a096434bcdb60df2b 100644 (file)
     <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/${openflowplugin.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.ovsdb/southbound-features/${ovsdb.southbound.version}/xml/features</repository>
 
+
     <!-- Repos needed by the Neutron Mapper -->
     <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
-
+   <!-- Repos needed by ofoverlay for SFC -->
+    <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.sfc/features-sfc-sb-rest/${sfc.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.sfc/features-sfc-netconf/${sfc.version}/xml/features</repository>
     <!-- Repos needed by the UI Backend -->
     <repository>mvn:org.opendaylight.controller/features-restconf/${restconf.version}/xml/features</repository>
 
+    <repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.sfc/features-sfcofl2/${sfc.version}/xml/features</repository>
     <!-- The common GBP components -->
     <feature name='odl-groupbasedpolicy-base' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: Base Copmonents'>
         <feature version="${mdsal.version}">odl-mdsal-broker</feature>
         <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
         <feature version='${openflowplugin.version}'>odl-openflowplugin-nxm-extensions</feature>
         <feature version='${ovsdb.southbound.version}'>odl-ovsdb-southbound-impl</feature>
+        <feature version='${sfc.version}'>odl-sfc-core</feature>
+        <feature version='${sfc.version}'>odl-sfc-test-consumer</feature>
+        <feature version='${sfc.version}'>odl-sfc-sb-rest</feature>
+        <feature version='${sfc.version}'>odl-sfcofl2</feature>
+        <feature version='${sfc.version}'>odl-sfc-ovs</feature>
+        <feature version='${sfc.version}'>odl-sfc-netconf</feature>
+        <feature version='${sfc.version}'>odl-sfc-ui</feature>
         <bundle>mvn:org.opendaylight.groupbasedpolicy/ofoverlay-renderer/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.ofoverlayconfigfile}">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ofoverlay-config/${project.version}/xml/config</configfile>
     </feature>
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java
new file mode 100644 (file)
index 0000000..10079b8
--- /dev/null
@@ -0,0 +1,9 @@
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+
+
+public interface ActionInstanceValidator {
+
+    boolean isValid(ActionInstance actionInstance);
+}
index 6afeb3ec847ca307046b179279f302ca83d600f6..94d51d5672c52e7ac0743134f98ac316fadec698 100644 (file)
@@ -29,8 +29,14 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
 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.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -77,6 +83,7 @@ public class PolicyResolver implements AutoCloseable {
 
     protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
 
+
     /**
      * Store a policy object for each endpoint group pair. The table is stored
      * with the key as (consumer, provider). Two endpoints could appear in both
@@ -84,6 +91,13 @@ public class PolicyResolver implements AutoCloseable {
      */
     AtomicReference<PolicyInfo> policy = new AtomicReference<>();
 
+    /*
+     * Store validators for ActionDefinitions from Renderers
+     *
+     */
+
+    protected ConcurrentMap<ActionDefinitionId, ActionInstanceValidator> registeredActions = new ConcurrentHashMap<>();
+
     public PolicyResolver(DataBroker dataProvider,
             ScheduledExecutorService executor) {
         super();
@@ -134,6 +148,9 @@ public class PolicyResolver implements AutoCloseable {
         return tc.tenant.get();
     }
 
+    public void registerActionDefinitions(ActionDefinitionId actionDefinitionId, ActionInstanceValidator validator) {
+        registeredActions.putIfAbsent(actionDefinitionId, validator);
+    }
     /**
      * Register a listener to receive update events.
      *
@@ -293,19 +310,25 @@ public class PolicyResolver implements AutoCloseable {
                 }
 
                 Tenant t = InheritanceUtils.resolveTenant(result.get());
-                IndexedTenant it = new IndexedTenant(t);
-                if (!tenantRef.compareAndSet(ot, it)) {
-                    // concurrent update of tenant policy. Retry
-                    updateTenant(tenantId);
-                } else {
-                    // Update the policy cache and notify listeners
-                    WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
-                    wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true);
-                    wt.submit();
-                    updatePolicy();
+                if (isValidTenant(t)) {
+                    IndexedTenant it = new IndexedTenant(t);
+                    if (!tenantRef.compareAndSet(ot, it)) {
+                        // concurrent update of tenant policy. Retry
+                        updateTenant(tenantId);
+                    } else {
+                        // Update the policy cache and notify listeners
+                        WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
+                        wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true);
+                        wt.submit();
+                        updatePolicy();
+                    }
                 }
             }
 
+
+
+
+
             @Override
             public void onFailure(Throwable t) {
                 LOG.error("Count not get tenant {}", tenantId, t);
@@ -362,4 +385,42 @@ public class PolicyResolver implements AutoCloseable {
         }
 
     }
+
+    private boolean isValidTenant(Tenant t) {
+        if(validActionInstances(t.getSubjectFeatureInstances().getActionInstance())) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean validActionInstances(List<ActionInstance> actionInstances) {
+        for(ActionInstance actionInstance : actionInstances) {
+            if(!(registeredActions.get(actionInstance.getActionDefinitionId()).isValid(actionInstance))) {
+                return false;
+            };
+        }
+        return true;
+    }
+
+    private boolean validContracts(List<Contract> contracts) {
+        for (Contract contract: contracts) {
+            validateSubjects(contract.getSubject());
+        }
+        return false;
+    }
+
+    private void validateSubjects(List<Subject> subjects) {
+        for(Subject subject: subjects) {
+            validateRules(subject.getRule());
+        }
+
+    }
+
+    private void validateRules(List<Rule> rules) {
+
+    }
+
+    private void validateActionRefs(List<ActionRef> actionRefs) {
+
+    }
 }
index 1b7fee0afa160a99576269b959b16fa653496553..c248471e067edf7e45277798b54b366aeed88904 100644 (file)
       <groupId>org.opendaylight.openflowplugin</groupId>
       <artifactId>openflowplugin-extension-nicira</artifactId>
     </dependency>
-
+    <!-- SFC -->
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+      <version>${sfc.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-provider</artifactId>
+      <version>${sfc.version}</version>
+    </dependency>
     <!-- testing dependencies -->
     <dependency>
       <groupId>junit</groupId>
index 22763f06aa6bb2170d2f3c79b31aa6d950d02ef6..caa3cb56d9e5ad924167286497f777a8d2c0bfd6 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -34,12 +35,13 @@ import com.google.common.util.concurrent.ListenableFuture;
 /**
  * Renderer that uses OpenFlow and OVSDB to implement an overlay network
  * using Open vSwitch.
- * @author readams
+
  */
 public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
     private static final Logger LOG =
             LoggerFactory.getLogger(OFOverlayRenderer.class);
 
+    private final Uuid ID = new Uuid("934cd993-7bcc-46cf-b150-64fabc92b4e0");
     private final DataBroker dataBroker;
     private final PolicyResolver policyResolver;
     private final SwitchManager switchManager;
index beedc2a8667b46c0b5e0f9e2226c896de7ce21c0..284028d0d411b91a693551cde65682adb472ed43 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
@@ -48,6 +49,7 @@ import org.opendaylight.groupbasedpolicy.util.SingletonTask;
 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.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -118,6 +120,10 @@ public class PolicyManager
             t.submit();
         }
 
+        for(Entry<ActionDefinitionId, Action> entry : SubjectFeatures.getActions().entrySet()) {
+            policyResolver.registerActionDefinitions(entry.getKey(), entry.getValue());
+        }
+
         OfContext ctx = new OfContext(dataBroker, rpcRegistry,
                                         this, policyResolver, switchManager,
                                         endpointManager, executor);
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java
new file mode 100644 (file)
index 0000000..ca90ef2
--- /dev/null
@@ -0,0 +1,398 @@
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.opendaylight.sfc.provider.SfcProviderRpc;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopOutput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+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 exchanged with SFC
+ *
+ * For the Proof of Concept, this manages the
+ * RenderedServicePathFirstHop elements that
+ * are retrieved from SFC.
+ *
+ */
+public class SfcManager implements AutoCloseable, DataChangeListener {
+    private static final Logger LOG =
+            LoggerFactory.getLogger(SfcManager.class);
+
+    private final DataBroker dataBroker;
+    private final ExecutorService executor;
+    private final InstanceIdentifier<ActionInstance> allActionInstancesIid;
+    private final ListenerRegistration<DataChangeListener> actionListener;
+
+    /*
+     * local cache of the RSP first hops that we've requested from SFC,
+     * keyed by RSP name
+     */
+    private final ConcurrentMap<String, RenderedServicePathFirstHop> rspMap;
+
+    /*
+     *  TODO: these two String defs should move to the common
+     *        "chain" action, once we have it.
+     */
+    // the chain action
+    public static final String SFC_CHAIN_ACTION = "chain";
+    // the parameter used for storing the chain name
+    public static final String SFC_CHAIN_NAME = "sfc-chain-name";
+
+    private static enum ActionState {
+        ADD("add"),
+        CHANGE("change"),
+        DELETE("delete");
+
+        private String state;
+
+        ActionState(String state) {
+            this.state = state;
+        }
+
+        @Override
+        public String toString() {
+            return this.state;
+        }
+    }
+
+
+    public SfcManager(DataBroker dataBroker,
+                      PolicyResolver policyResolver,
+                      RpcProviderRegistry rpcRegistry,
+                      ExecutorService executor) {
+        this.dataBroker = dataBroker;
+        this.executor = executor;
+        /*
+         * Use thread-safe type only because we use an executor
+         */
+        this.rspMap = new ConcurrentHashMap<String, RenderedServicePathFirstHop>();
+
+        /*
+         * For now, listen to all changes in rules
+         */
+        allActionInstancesIid =
+                InstanceIdentifier.builder(Tenants.class)
+                    .child(Tenant.class)
+                    .child(SubjectFeatureInstances.class)
+                    .child(ActionInstance.class)
+                    .build();
+        actionListener = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                allActionInstancesIid, this, DataChangeScope.ONE);
+        LOG.debug("SfcManager: Started");
+    }
+
+    public Set<IpAddress> getSfcSourceIps() {
+        if (rspMap.isEmpty()) return null;
+
+        Set<IpAddress> ipAddresses = new HashSet<IpAddress>();
+        for (RenderedServicePathFirstHop rsp: rspMap.values()) {
+            if (rsp.getIp() != null) {
+                ipAddresses.add(rsp.getIp());
+            }
+        }
+        if (ipAddresses.isEmpty()) return null;
+        return ipAddresses;
+    }
+
+    @Override
+    public void onDataChanged(
+            AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> actionInstanceNotification) {
+
+        for (DataObject dao : actionInstanceNotification.getCreatedData().values()) {
+            if (dao instanceof ActionInstance) {
+                ActionInstance ai = (ActionInstance)dao;
+                LOG.debug("New ActionInstance created");
+                executor.execute(new MatchActionDefTask(ai, null,
+                        ActionState.ADD));
+            }
+        }
+
+        for (InstanceIdentifier<?> iid : actionInstanceNotification.getRemovedPaths()) {
+            DataObject old = actionInstanceNotification.getOriginalData().get(iid);
+            if (old instanceof ActionInstance) {
+                ActionInstance ai = (ActionInstance)old;
+                executor.execute(new MatchActionDefTask(null, ai,
+                        ActionState.DELETE));
+            }
+        }
+
+        for (Entry<InstanceIdentifier<?>, DataObject> entry:
+            actionInstanceNotification.getUpdatedData().entrySet()) {
+            DataObject dao = entry.getValue();
+            if (dao instanceof ActionInstance) {
+                ActionInstance nai = (ActionInstance)dao;
+                ActionInstance oai = null;
+                InstanceIdentifier<?> iid = entry.getKey();
+                DataObject orig = actionInstanceNotification.getOriginalData().get(iid);
+                if (orig != null) {
+                    oai = (ActionInstance)orig;
+                    /*
+                     * We may have some cleanup here.  If the reference to
+                     * the Action Definition changed, or if the Action Instance's
+                     * chain parameter  then we're no longer
+                     * an action, and we may need to remove the RSP.
+                     */
+                }
+
+                executor.execute(new MatchActionDefTask(nai, oai,
+                        ActionState.CHANGE));
+            }
+        }
+    }
+
+    /**
+     * Private internal class that gets the action definition
+     * referenced by the instance. If the definition has an
+     * action of "chain" (or whatever we decide to use
+     * here), then we need to invoke the SFC API to go
+     * get the chain information, which we'll eventually
+     * use during policy resolution.
+     *
+     */
+    private class MatchActionDefTask implements Runnable,
+                     FutureCallback<Optional<ActionDefinition>> {
+        private final ActionState state;
+        private final ActionInstance actionInstance;
+        private final ActionInstance originalInstance;
+        private final InstanceIdentifier<ActionDefinition> adIid;
+        private final ActionDefinitionId id;
+
+        public MatchActionDefTask(ActionInstance actionInstance,
+                ActionInstance originalInstance, ActionState state) {
+            this.actionInstance = actionInstance;
+            this.originalInstance = originalInstance;
+            if (actionInstance != null) {
+                this.id = actionInstance.getActionDefinitionId();
+            } else {
+                this.id = null;
+            }
+            this.state = state;
+
+            adIid = InstanceIdentifier.builder(SubjectFeatureDefinitions.class)
+                                      .child(ActionDefinition.class,
+                                             new ActionDefinitionKey(this.id))
+                                      .build();
+
+        }
+
+        /**
+         * Create read transaction with callback to look up
+         * the Action Definition that the Action Instance
+         * references.
+         */
+        @Override
+        public void run() {
+            ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
+            ListenableFuture<Optional<ActionDefinition>> dao =
+                    rot.read(LogicalDatastoreType.OPERATIONAL, adIid);
+            Futures.addCallback(dao, this, executor);
+
+        }
+
+        @Override
+        public void onFailure(Throwable arg0) {
+            LOG.error("Failure reading ActionDefinition {}", id.getValue());
+        }
+
+        /**
+         * An Action Definition exists - now we need to see
+         * if the Action Definition is for a chain action,
+         * and implement the appropriate behavior. If it's
+         * not a chain action, then we can ignore it.
+         *
+         * @param dao
+         */
+        @Override
+        public void onSuccess(Optional<ActionDefinition> dao) {
+            LOG.debug("Found ActionDefinition {}", id.getValue());
+            if (!dao.isPresent()) return;
+
+            ActionDefinition ad = dao.get();
+            if (ad.getId().getValue().equals(ChainAction.ID.getValue())) {
+                /*
+                 * We have the state we need:
+                 *  1) it's a "CHAIN" action
+                 *  2) the name is defined in the ActionInstance
+                 */
+                switch (state) {
+                case ADD:
+                    /*
+                     * Go get the RSP First Hop
+                     */
+                    getSfcChain();
+                    break;
+                case CHANGE:
+                    /*
+                     * We only care if the named chain changes
+                     */
+                    changeSfcRsp();
+                    break;
+                case DELETE:
+                    /*
+                     * If the instance is deleted, we need to remove
+                     * it from our map.
+                     */
+                    deleteSfcRsp();
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+
+        private ParameterValue getChainNameParameter(List<ParameterValue> pvl) {
+            if (pvl == null) return null;
+            for (ParameterValue pv: actionInstance.getParameterValue()) {
+                if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
+                    return pv;
+                }
+            }
+            return null;
+        }
+
+        private void changeSfcRsp() {
+            ParameterValue newPv =
+                    getChainNameParameter(actionInstance.getParameterValue());
+            ParameterValue origPv =
+                    getChainNameParameter(originalInstance.getParameterValue());
+            if (!newPv.getStringValue().equals(origPv.getStringValue())) {
+                if (rspMap.containsKey(origPv.getStringValue())) {
+                    /*
+                     * Flow cleanup will happen as part of the
+                     * resolved policy
+                     *
+                     * TODO: can we guarantee that this
+                     *       happens after we remove the RSP?).
+                     */
+                    rspMap.remove(origPv.getStringValue());
+                }
+                addSfcRsp();
+            }
+        }
+
+        private void deleteSfcRsp() {
+            ParameterValue pv =
+                    getChainNameParameter(originalInstance.getParameterValue());
+            if (pv == null) return;
+            rspMap.remove(pv.getStringValue());
+        }
+
+        /**
+         * Get the RenderedServicePathFirstHop from SFC
+         *
+         * TODO: what if SFC state isn't available at the time of
+         *       this call, but becomes available later?  Do we want
+         *       or need some sort of notification handler for this?
+         */
+        private void addSfcRsp() {
+            ParameterValue pv =
+                    getChainNameParameter(actionInstance.getParameterValue());
+            if (pv == null) return;
+
+            LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
+            ReadRenderedServicePathFirstHopInputBuilder builder =
+                new ReadRenderedServicePathFirstHopInputBuilder()
+                       .setName(pv.getStringValue());
+            // TODO: make async
+            Future<RpcResult<ReadRenderedServicePathFirstHopOutput>> result =
+                SfcProviderRpc.getSfcProviderRpc()
+                              .readRenderedServicePathFirstHop(builder.build());
+
+            try {
+                RpcResult<ReadRenderedServicePathFirstHopOutput> output =
+                        result.get();
+                if (output.isSuccessful()) {
+                    LOG.trace("RPC for chain {} succeeded!", pv.getStringValue());
+                    RenderedServicePathFirstHop rspFirstHop =
+                        output.getResult().getRenderedServicePathFirstHop();
+                    /*
+                     * We won't retry installation in the map
+                     * because the presumption is it's either
+                     * the same object or contain the same
+                     * state.
+                     */
+                    rspMap.putIfAbsent(pv.getStringValue(), rspFirstHop);
+                }
+            } catch (Exception e) {
+                LOG.warn("Failed ReadRenderedServicePathFirstHop RPC: {}", e);
+                // TODO: proper exception handling
+            }
+        }
+
+        private void getSfcChain() {
+            ParameterValue pv =
+                    getChainNameParameter(actionInstance.getParameterValue());
+            if (pv == null) return;
+
+            LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
+            String chainName=pv.getStringValue();
+            ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
+            ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+            for(ServiceFunctionPath path: paths.getServiceFunctionPath()) {
+                if(path.getServiceChainName().equals(chainName)) {
+                    LOG.info("Found path {} for chain {}",path.getName(),path.getServiceChainName());
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the first hop information for the Rendered Service Path
+     *
+     * @param rspName
+     * @return
+     */
+    public RenderedServicePathFirstHop getRspFirstHop(String rspName) {
+        return rspMap.get(rspName);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (actionListener != null) actionListener.close();
+
+    }
+}
+
index 376126b349465eb4d297e4f050eb7cd6f34b5a39..dc8e608c1a371ee0d863380c992e32ad531de8ab 100644 (file)
@@ -234,6 +234,7 @@ public class DestinationMapper extends FlowTable {
             .setInstructions(
                     instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false),
                             groupAction(Long.valueOf(epOrd.getFdId())))));
+
         return flowb.build();
     }
 
index 8b9a3fbea08b61c486076a8ab3e66a1b5652fe02..2b756eabcdcb88200d3cff055f3e73a9740e9855 100644 (file)
@@ -78,6 +78,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ge
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpShaCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpThaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCaseBuilder;
@@ -90,6 +92,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputReg;
@@ -100,6 +106,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMove;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMoveBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.SrcBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsi;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsiBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNsp;
@@ -107,10 +121,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.SrcChoice;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxArpShaCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIpv4DstCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfArpSpaCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfEthSrcCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc2Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc4Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNspKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg0Key;
@@ -122,6 +142,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg6Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg7Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxTunIdKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._1.grouping.NxmNxNshc1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._2.grouping.NxmNxNshc2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._3.grouping.NxmNxNshc3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._4.grouping.NxmNxNshc4Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsi.grouping.NxmNxNsiBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxRegBuilder;
@@ -343,6 +367,29 @@ public final class FlowUtils {
         return nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(reg).build(), value);
     }
 
+    // TODO: alagalah Li Need to address nicira yang model to make this extend an NxmNxNshFoo case
+    // class
+
+    public static Action nxLoadNshc1RegAction(Long value) {
+        NxSetNshc1 newNshc1 = new NxSetNshc1Builder().setNshc(value).build();
+        return new NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc1(newNshc1).build();
+    }
+
+    public static Action nxLoadNshc2RegAction(Long value) {
+        NxSetNshc2 newNshc2 = new NxSetNshc2Builder().setNshc(value).build();
+        return new NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc2(newNshc2).build();
+    }
+
+    public static Action nxLoadNshc3RegAction(Long value) {
+        NxSetNshc3 newNshc3 = new NxSetNshc3Builder().setNshc(value).build();
+        return new NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc3(newNshc3).build();
+    }
+
+    public static Action nxLoadNshc4RegAction(Long value) {
+        NxSetNshc4 newNshc4 = new NxSetNshc4Builder().setNshc(value).build();
+        return new NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc4(newNshc4).build();
+    }
+
     public static Action nxLoadTunIPv4Action(String ipAddress, boolean groupBucket) {
         int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress));
         long ipl = ip & 0xffffffffL;
@@ -391,6 +438,13 @@ public final class FlowUtils {
         return nxMoveRegAction(srcChoice, dstChoice, 31, false);
     }
 
+    public static Action nxMoveRegTunDstToNshc1() {
+        return nxMoveRegAction(new SrcNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),new DstNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),31,false);
+    }
+
+    public static Action nxMoveTunIdtoNshc2() {
+        return nxMoveRegAction(new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), new DstNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),31,false);
+    }
     public static Action nxMoveRegTunIdAction(Class<? extends NxmNxReg> src, boolean groupBucket) {
         return nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(src).build(),
                 new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), 31, groupBucket);
@@ -478,6 +532,112 @@ public final class FlowUtils {
         match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
     }
 
+    // TODO alagalah Be/Li: Once OFP yang refactored to support container/grouping similar to nxreg
+    // we can follow same pattern. For now its match/set per nsh header
+    public static void addNxNshc1RegMatch(MatchBuilder match, Long value) {
+        List<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+        ArrayList<ExtensionList> extensions = new ArrayList<>();
+        if(existingExtensions != null && !existingExtensions.isEmpty()) {
+            extensions.addAll(existingExtensions);
+        }
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc1(
+                new NxmNxNshc1Builder().setValue(value).build()).build();
+
+        extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc1Key.class)
+            .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build())
+            .build());
+
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(
+                extensions).build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
+    public static void addNxNshc2RegMatch(MatchBuilder match, Long value) {
+        List<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+        ArrayList<ExtensionList> extensions = new ArrayList<>();
+        if(existingExtensions != null && !existingExtensions.isEmpty()) {
+            extensions.addAll(existingExtensions);
+        }
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc2(
+                new NxmNxNshc2Builder().setValue(value).build()).build();
+
+        extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc2Key.class)
+            .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build())
+            .build());
+
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(
+                extensions).build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
+    public static void addNxNshc3RegMatch(MatchBuilder match, Long value) {
+        List<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+        ArrayList<ExtensionList> extensions = new ArrayList<>();
+        if(existingExtensions != null && !existingExtensions.isEmpty()) {
+            extensions.addAll(existingExtensions);
+        }
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc3(
+                new NxmNxNshc3Builder().setValue(value).build()).build();
+
+        extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc3Key.class)
+            .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build())
+            .build());
+
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(
+                extensions).build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
+    public static void addNxNshc4RegMatch(MatchBuilder match, Long value) {
+        List<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+        ArrayList<ExtensionList> extensions = new ArrayList<>();
+        if(existingExtensions != null && !existingExtensions.isEmpty()) {
+            extensions.addAll(existingExtensions);
+        }
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc4(
+                new NxmNxNshc4Builder().setValue(value).build()).build();
+
+        extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc4Key.class)
+            .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build())
+            .build());
+
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(
+                extensions).build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
+    public static void addNxNshcMatch(MatchBuilder match, RegMatch... matches) {
+        ArrayList<ExtensionList> extensions = new ArrayList<>();
+        for (RegMatch rm : matches) {
+            Class<? extends ExtensionKey> key;
+            if (NxmNxReg0.class.equals(rm.reg)) {
+                key = NxmNxReg0Key.class;
+            } else if (NxmNxReg1.class.equals(rm.reg)) {
+                key = NxmNxReg1Key.class;
+            } else if (NxmNxReg2.class.equals(rm.reg)) {
+                key = NxmNxReg2Key.class;
+            } else if (NxmNxReg3.class.equals(rm.reg)) {
+                key = NxmNxReg3Key.class;
+            } else if (NxmNxReg4.class.equals(rm.reg)) {
+                key = NxmNxReg4Key.class;
+            } else if (NxmNxReg5.class.equals(rm.reg)) {
+                key = NxmNxReg5Key.class;
+            } else if (NxmNxReg6.class.equals(rm.reg)) {
+                key = NxmNxReg6Key.class;
+            } else {
+                key = NxmNxReg7Key.class;
+            }
+            NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxReg(
+                    new NxmNxRegBuilder().setReg(rm.reg).setValue(rm.value).build()).build();
+            extensions.add(new ExtensionListBuilder().setExtensionKey(key)
+                .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build())
+                .build());
+        }
+        GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList(
+                extensions).build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
     public static void addNxTunIdMatch(MatchBuilder match, int tunId) {
         NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxTunId(
                 new NxmNxTunIdBuilder().setValue(BigInteger.valueOf(tunId)).build()).build();
index f6fdca2524c50787d14916697813eecd0ad5230d..3c7ab98a790127d9da841af440d2501256d9180f 100644 (file)
@@ -205,11 +205,10 @@ public class GroupTable extends OfTable {
                                     destNode);
                             continue;
                         }
+                    BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(actionList(tundstAction, outputAction(tunPort)));
+
+
 
-                        BucketBuilder bb = new BucketBuilder()
-                                .setBucketId(new BucketId(Long.valueOf(bucketId)))
-                                .setAction(actionList(tundstAction,
-                                        outputAction(tunPort)));
                         updateBucket(gctx, bb);
                     }
                 OfOverlayContext ofc =
index 212130fc8ad60f24fd7e13ffac94280d91dded0a..87a31eaf2e53b642ec7d6ad1f76611ed131b1b04 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult;
@@ -98,7 +99,7 @@ public class PolicyEnforcer extends FlowTable {
 
         flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null));
 
-        NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
+        NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class);
         if (tunPort != null) {
             flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort));
         }
@@ -122,7 +123,7 @@ public class PolicyEnforcer extends FlowTable {
                         int depgId = dstEpFwdCxtOrds.getEpgId();
                         int scgId = srcEpFwdCxtOrds.getCgId();
                         int sepgId = srcEpFwdCxtOrds.getEpgId();
-
+                        NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo);
                         fdIds.add(srcEpFwdCxtOrds.getFdId());
 
                         List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
@@ -136,7 +137,7 @@ public class PolicyEnforcer extends FlowTable {
                         if (visitedPairs.contains(p))
                             continue;
                         visitedPairs.add(p);
-                        syncPolicy(flowMap, nodeId, rgs, p);
+                        syncPolicy(flowMap, netElements, rgs, p);
 
                         // Reverse
                         policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
@@ -145,7 +146,7 @@ public class PolicyEnforcer extends FlowTable {
                         if (visitedPairs.contains(p))
                             continue;
                         visitedPairs.add(p);
-                        syncPolicy(flowMap, nodeId, rgs, p);
+                        syncPolicy(flowMap, netElements, rgs, p);
                     }
                 }
             }
@@ -237,14 +238,14 @@ public class PolicyEnforcer extends FlowTable {
 
     }
 
-    private void syncPolicy(FlowMap flowMap, NodeId nodeId, List<RuleGroup> rgs, CgPair p) {
+    private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> rgs, CgPair p) {
         int priority = 65000;
         for (RuleGroup rg : rgs) {
             TenantId tenantId = rg.getContractTenant().getId();
             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId);
             for (Rule r : rg.getRules()) {
-                syncDirection(flowMap, nodeId, tenant, p, r, Direction.In, priority);
-                syncDirection(flowMap, nodeId, tenant, p, r, Direction.Out, priority);
+                syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority);
+                syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority);
 
                 priority -= 1;
             }
@@ -271,7 +272,7 @@ public class PolicyEnforcer extends FlowTable {
 
     }
 
-    private void syncDirection(FlowMap flowMap, NodeId nodeId, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
+    private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule,
             Direction direction, int priority) {
         /*
          * Create the ordered action list. The implicit action is "allow", and
@@ -283,7 +284,7 @@ public class PolicyEnforcer extends FlowTable {
 
         // TODO: can pass Comparator ActionRefComparator to List constructor, rather than
         // referencing in sort
-        List<ActionBuilder> abl = new ArrayList<ActionBuilder>();
+        List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
         if (rule.getActionRef() != null) {
             /*
              * Pre-sort by references using order, then name
@@ -291,23 +292,23 @@ public class PolicyEnforcer extends FlowTable {
             List<ActionRef> arl = new ArrayList<ActionRef>(rule.getActionRef());
             Collections.sort(arl, ActionRefComparator.INSTANCE);
 
-            for (ActionRef ar : arl) {
-                ActionInstance ai = contractTenant.getAction(ar.getName());
-                if (ai == null) {
+            for (ActionRef actionRule : arl) {
+                ActionInstance actionInstance = contractTenant.getAction(actionRule.getName());
+                if (actionInstance == null) {
                     // XXX TODO fail the match and raise an exception
-                    LOG.warn("Action instance {} not found", ar.getName().getValue());
+                    LOG.warn("Action instance {} not found", actionRule.getName().getValue());
                     return;
                 }
-                Action act = SubjectFeatures.getAction(ai.getActionDefinitionId());
-                if (act == null) {
+                Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId());
+                if (action == null) {
                     // XXX TODO fail the match and raise an exception
-                    LOG.warn("Action definition {} not found", ai.getActionDefinitionId().getValue());
+                    LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue());
                     return;
                 }
 
                 Map<String, Object> params = new HashMap<>();
-                if (ai.getParameterValue() != null) {
-                    for (ParameterValue v : ai.getParameterValue()) {
+                if (actionInstance.getParameterValue() != null) {
+                    for (ParameterValue v : actionInstance.getParameterValue()) {
                         if (v.getName() == null)
                             continue;
                         if (v.getIntValue() != null) {
@@ -320,11 +321,11 @@ public class PolicyEnforcer extends FlowTable {
                 /*
                  * Convert the GBP Action to one or more OpenFlow Actions
                  */
-                abl = act.updateAction(abl, params, ar.getOrder());
+                actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements);
             }
         } else {
             Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId());
-            abl = act.updateAction(abl, new HashMap<String, Object>(), 0);
+            actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
         }
 
         Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
@@ -420,8 +421,8 @@ public class PolicyEnforcer extends FlowTable {
                     flow.setMatch(m)
                         .setId(flowId)
                         .setPriority(Integer.valueOf(priority))
-                        .setInstructions(instructions(applyActionIns(abl)));
-                    flowMap.writeFlow(nodeId, TABLE_ID, flow.build());
+                        .setInstructions(instructions(applyActionIns(actionBuilderList)));
+                    flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build());
                 }
             }
         }
@@ -474,4 +475,49 @@ public class PolicyEnforcer extends FlowTable {
             return true;
         }
     }
+
+    public class NetworkElements {
+        Endpoint src;
+        Endpoint dst;
+        NodeId nodeId;
+        EndpointFwdCtxOrdinals srcOrds;
+        EndpointFwdCtxOrdinals dstOrds;
+
+        public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception {
+            this.src=src;
+            this.dst=dst;
+            this.nodeId = nodeId;
+            this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src);
+            this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst);
+        }
+
+
+
+        public EndpointFwdCtxOrdinals getSrcOrds() {
+            return srcOrds;
+        }
+
+
+
+        public EndpointFwdCtxOrdinals getDstOrds() {
+            return dstOrds;
+        }
+
+
+        public Endpoint getSrc() {
+            return src;
+        }
+
+
+        public Endpoint getDst() {
+            return dst;
+        }
+
+
+        public NodeId getNodeId() {
+            return nodeId;
+        }
+
+
+    }
 }
index 9972a9d739179bf1231c37c3f84699012b9475b6..e5e297e3fbbc3847cb239cffc3ce4ac23ab1718a 100644 (file)
@@ -190,6 +190,7 @@ public class SourceMapper extends FlowTable {
 
         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
         addNxTunIdMatch(mb, tunnelId);
+
         Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
         // set condition group register to all ones to
         // bypass
index 3b9126526b67569d856c4b62007990068181ace5..8b4c8b59758fdda3b6acef92674ee767f4197452 100644 (file)
@@ -22,6 +22,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.annotation.Nullable;
 
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
@@ -428,4 +429,6 @@ public class SwitchManager implements AutoCloseable {
         READY
     }
 
+
+
 }
index c7ee7727dd69c8f56982f38d30627d56af059251..bb0641eeb263eac6193c09199af70baaeff516ee 100644 (file)
@@ -11,16 +11,20 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
 import java.util.List;
 import java.util.Map;
 
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
+import org.opendaylight.groupbasedpolicy.resolver.ActionInstanceValidator;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 
 /**
  * Represent an action definition, and provide tools for generating
  * flow instructions based on the action
  * @author tbachman
  */
-public abstract class Action {
+public abstract class Action implements ActionInstanceValidator{
     /**
      * Get the action definition for this action
      * @return the {@link ActionDefinition} for this action
@@ -43,5 +47,6 @@ public abstract class Action {
      */
     public abstract List<ActionBuilder> updateAction(List<ActionBuilder> actions,
                                                      Map<String, Object> params,
-                                                     Integer i);
+                                                     Integer order,
+                                                     NetworkElements netElements);
 }
index 8a2cc7de4e41ca2260cd31650ace1fc7f569ea6d..4b75328bd45637447335ed8fb0a80ee52be52def 100644 (file)
@@ -13,12 +13,16 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtil
 import java.util.List;
 import java.util.Map;
 
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
 
 
@@ -52,7 +56,8 @@ public class AllowAction extends Action {
     @Override
     public List<ActionBuilder> updateAction(List<ActionBuilder> actions,
                                             Map<String, Object> params,
-                                            Integer order) {
+                                            Integer order,
+                                            NetworkElements netElements) {
         /*
          * Allow action doesn't use parameters
          * TODO: check to make sure ActionBuilder w/allow isn't already present
@@ -64,4 +69,10 @@ public class AllowAction extends Action {
         return actions;
     }
 
+    @Override
+    public boolean isValid(ActionInstance actionInstance) {
+        // TODO Auto-generated method stub
+        return true;
+    }
+
 }
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java
new file mode 100644 (file)
index 0000000..44f6511
--- /dev/null
@@ -0,0 +1,277 @@
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+/*
+ * 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
+ */
+
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+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.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.net.InetAddresses;
+
+/**
+ * Chain action for the OpenFlow Overlay renderer
+ * TODO: separate the generic definition from the concrete
+ * implementation for the OpenFlow Ovelray renderer
+ */
+public class ChainAction extends Action {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
+
+    public static final ActionDefinitionId ID = new ActionDefinitionId("3d886be7-059f-4c4f-bbef-0356bea40933");
+
+    public static final Integer CHAIN_CONDITION_GROUP = 0xfffffe;
+
+    protected static final String TYPE = "type";
+
+    // the chain action
+    public static final String SFC_CHAIN_ACTION = "chain";
+    // the parameter used for storing the chain name
+    public static final String SFC_CHAIN_NAME = "sfc-chain-name";
+
+    protected static final ActionDefinition DEF = new ActionDefinitionBuilder().setId(ID)
+        .setName(new ActionName(SFC_CHAIN_ACTION))
+        .setDescription(new Description("Send the traffic through a Service Function Chain"))
+        .setParameter(
+                (ImmutableList.of(new ParameterBuilder().setName(new ParameterName(SFC_CHAIN_NAME))
+                    .setDescription(new Description("The named chain to match against"))
+                    .setIsRequired(IsRequired.Required)
+                    .setType(Type.String)
+                    .build())))
+        .build();
+
+    @Override
+    public ActionDefinitionId getId() {
+        return ID;
+    }
+
+    @Override
+    public ActionDefinition getActionDef() {
+        return DEF;
+    }
+
+    @Override
+    public List<ActionBuilder> updateAction(List<ActionBuilder> actions,
+                                            Map<String, Object> params,
+                                            Integer order,
+                                            NetworkElements netElements) {
+        /*
+         * Get the named chain
+         */
+        ServiceFunctionPath sfcPath = null;
+        String chainName = null;
+        if (params != null) {
+            LOG.debug("Searching for named chain");
+            for (String name : params.keySet()) {
+                if (name instanceof String) {
+                    if (name.equals(SFC_CHAIN_NAME)) {
+                        chainName = (String) params.get(name);
+                        if (chainName == null) {
+                            LOG.error("ChainAction: Chain name was null");
+                            return null;
+                        }
+                        sfcPath = getSfcPath(chainName);
+                    }
+                }
+            }
+        } else {
+            LOG.error("ChainAction: Parameters null for chain action");
+            return null;
+        }
+
+        if (sfcPath == null) {
+            LOG.error("ChainAction: SFC Path null for chain {}", chainName);
+            return null;
+        }
+        String rspName = sfcPath.getName() + "-gbp-rsp";
+        RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
+        if (rspFirstHop == null) {
+            LOG.info("ChainAction: Could not find RSP {} for Chain {}", rspName, chainName);
+
+            CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
+                    sfcPath.getName())
+                .setName(rspName)
+                .setSymmetric(Boolean.FALSE)
+                .build();
+            RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(
+                    sfcPath, rspInput);
+            if (renderedServicePath == null) {
+                LOG.error("Could not find or create RSP for chain {}", chainName);
+                return null;
+            }
+            rspFirstHop=SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(renderedServicePath.getName());
+        }
+
+        IpAddress sfcTunIpDst = rspFirstHop.getIp();
+        sfcTunIpDst.getIpv4Address();
+        if (sfcTunIpDst == null || sfcTunIpDst.getIpv4Address() == null || sfcTunIpDst.getIpv6Address() != null) {
+            LOG.error("Invalid IP Tunnel destination for SFC RSP First Hop {}", rspName);
+            return null;
+        }
+        PortNumber sfcTunUdpPort = rspFirstHop.getPort();
+        if (sfcTunUdpPort == null) {
+            LOG.error("Invalid UDP Port Number for SFC RSP {}", rspName);
+            return null;
+        }
+        Long sfcNsp = rspFirstHop.getPathId();
+        if (sfcNsp == null) {
+            LOG.error("Invalid NSP for SFC RSP {}", rspName);
+            return null;
+        }
+        Short sfcNsi = rspFirstHop.getStartingIndex();
+        if (sfcNsi == null) {
+            LOG.error("Invalid NSI for SFC RSP {}", rspName);
+            return null;
+        }
+
+        NodeConnectorId tunOpenFlowPort = SwitchManager.getTunnelPort(netElements.getNodeId(), TunnelTypeVxlan.class);
+
+        /*
+         * Setting NSH Network Context Headers for post-SFC encapsulation
+         * VXLAN header encap:
+         * - TunnelDestination IP: NSH C1
+         * - Tunnel ID (VNID) NSH C2
+         */
+        long postSfcTunnelDst = 999L;
+        IpAddress tunnelDest;
+
+        if (netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId().equals(netElements.getNodeId())) {
+            // Return destination is here
+            tunnelDest=SwitchManager.getTunnelIP(netElements.getNodeId(), TunnelTypeVxlan.class);
+        } else {
+            tunnelDest=SwitchManager.getTunnelIP(netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId(), TunnelTypeVxlan.class);
+        }
+        postSfcTunnelDst = (InetAddresses.coerceToInteger(InetAddresses.forString(tunnelDest.getIpv4Address().getValue()))) & 0xFFFFFFFFL;
+
+        // TunnelDestination after Chain
+        actions = addActionBuilder(actions, nxLoadNshc1RegAction(postSfcTunnelDst), order++);
+        // VNID after Chain
+        actions = addActionBuilder(actions, nxLoadNshc2RegAction((long) netElements.getSrcOrds().getTunnelId()), order++);
+
+        /*
+         * Set the tunnel destination IP
+         */
+        if (sfcTunIpDst.getIpv4Address() != null) {
+            String nextHop = sfcTunIpDst.getIpv4Address().getValue();
+            actions = addActionBuilder(actions, nxLoadTunIPv4Action(nextHop, false), order);
+        } else if (sfcTunIpDst.getIpv6Address() != null) {
+            LOG.error("IPv6 tunnel destination {} not supported", sfcTunIpDst.getIpv6Address().getValue());
+            return actions;
+        } else {
+            // this shouldn't happen
+            LOG.error("Tunnel IP is invalid");
+            return actions;
+        }
+
+        /*
+         * Put TunID - with NSH we don't really care about this.
+         */
+        actions = addActionBuilder(actions,
+                nxLoadTunIdAction(BigInteger.valueOf(netElements.getSrcOrds().getTunnelId()), false), order);
+
+        /*
+         * Set the NSH header fields, based on RSP
+         */
+         actions = addActionBuilder(actions,nxSetNsiAction(sfcNsi),order);
+         actions = addActionBuilder(actions,nxSetNspAction(sfcNsp),order);
+         /*
+         * Set up the actions to send to the destination port
+         */
+         actions = addActionBuilder(actions,outputAction(tunOpenFlowPort), order);
+
+        return actions;
+    }
+
+    private List<ActionBuilder> addActionBuilder(List<ActionBuilder> actions,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, Integer order) {
+        ActionBuilder ab = new ActionBuilder();
+        ab.setAction(action);
+        ab.setOrder(order);
+        actions.add(ab);
+        return actions;
+    }
+
+    @Override
+    public boolean isValid(ActionInstance actionInstance) {
+        return validChain(actionInstance.getParameterValue());
+    }
+
+    private boolean validChain(List<ParameterValue> paramValue) {
+        ParameterValue pv = getChainNameParameter(paramValue);
+        if (pv == null) {
+            return false;
+        }
+        LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
+        ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
+        return chain != null;
+    }
+
+    public ServiceFunctionPath getSfcPath(String chainName) {
+
+        ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
+        for (ServiceFunctionPath path : paths.getServiceFunctionPath()) {
+            if (path.getServiceChainName().equals(chainName)) {
+                return path;
+            }
+        }
+        return null;
+    }
+
+    private ParameterValue getChainNameParameter(List<ParameterValue> paramValueList) {
+        if (paramValueList == null)
+            return null;
+        for (ParameterValue pv : paramValueList) {
+            if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
+                return pv;
+            }
+        }
+        return null;
+    }
+
+}
index 64822f1ca78a458e7ef4c100aee7e3e4c0f6f92d..025d9887d43c304225b9260f210667d764571415 100644 (file)
@@ -1,3 +1,4 @@
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
 /*
  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -6,7 +7,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
 
 import java.util.List;
 import java.util.Map;
@@ -45,7 +46,8 @@ public class SubjectFeatures {
 
     private static final Map<ActionDefinitionId, Action> actions =
             ImmutableMap.<ActionDefinitionId, Action>
-                of(AllowAction.ID, new AllowAction());
+                of(AllowAction.ID, new AllowAction(),
+                   ChainAction.ID, new ChainAction());
 
     private static final List<ActionDefinition> actionDefs =
             ImmutableList.copyOf(Collections2.transform(actions.values(),
@@ -74,6 +76,10 @@ public class SubjectFeatures {
         return classifiers.get(id);
     }
 
+    public static Map<ActionDefinitionId, Action> getActions() {
+        return actions;
+    }
+
     /**
      * Get the {@link Action} associated with the given
      * {@link ActionDefinitionId}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java
new file mode 100644 (file)
index 0000000..4b6b2df
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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.sfcutils;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * @author Martin Sunal
+ */
+public class SfcDataStoreHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SfcDataStoreHelper.class);
+
+    /**
+     * Reads data from datastore as synchrone call.
+     * @return {@link Optional#isPresent()} is {@code true} if reading was successful and data exists in datastore; {@link Optional#isPresent()} is {@code false} otherwise
+     */
+    public static <U extends DataObject> U readFromDs(LogicalDatastoreType store,InstanceIdentifier<U> iid, ReadTransaction rTx) {
+        U ret = null;
+        Optional<U> optionalDataObject;
+        CheckedFuture<Optional<U>, ReadFailedException> submitFuture = rTx.read(store, iid);
+        try {
+            optionalDataObject = submitFuture.checkedGet();
+            if (optionalDataObject != null && optionalDataObject.isPresent()) {
+                ret = optionalDataObject.get();
+            } else {
+                LOG.debug("{}: Failed to read", Thread.currentThread().getStackTrace()[1]);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("failed to ....", e);
+        }
+        return ret;
+    }
+
+    /**
+     * Calls {@link WriteTransaction#submit()} on write transaction.
+     * @param wTx write transaction
+     * @return {@code true} if transaction commit was successful; {@code false} otherwise
+     */
+    public static boolean submitToDs(WriteTransaction wTx) {
+        CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
+        try {
+            submitFuture.checkedGet();
+            return true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Transaction commit failed to DS.", e);
+            return false;
+        }
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java
new file mode 100644 (file)
index 0000000..3d9bffe
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.sfcutils;
+
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChains;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChainKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SfcIidFactory {
+
+    private SfcIidFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static InstanceIdentifier<ServiceFunctionChain> sfcIid(String sfcName) {
+
+        ServiceFunctionChainKey serviceFunctionChainKey =
+                new ServiceFunctionChainKey(sfcName);
+        return InstanceIdentifier.builder(ServiceFunctionChains.class)
+                .child(ServiceFunctionChain.class, serviceFunctionChainKey).build();
+    }
+
+    public static InstanceIdentifier<ServiceFunctionPath> sfpIid(String sfpName) {
+
+        ServiceFunctionPathKey serviceFunctionPathKey = new ServiceFunctionPathKey(sfpName);
+        return InstanceIdentifier.builder(ServiceFunctionPaths.class)
+                .child(ServiceFunctionPath.class, serviceFunctionPathKey).build();
+
+    }
+}
index bf74b6b12fcfc94772b2dabc8c72891a98b891d4..9b352c17ca839382dd5762135a91e067fa41f851 100755 (executable)
@@ -49,6 +49,9 @@ public class SourceMapperTest extends FlowTableTest {
 \r
     protected static final Logger LOG = LoggerFactory.getLogger(SourceMapperTest.class);\r
 \r
+    NodeConnectorId remoteTunnelId =\r
+            new NodeConnectorId(remoteNodeId.getValue() + ":101");\r
+\r
     @Override\r
     @Before\r
     public void setup() throws Exception {\r
@@ -57,6 +60,27 @@ public class SourceMapperTest extends FlowTableTest {
         super.setup();\r
     }\r
 \r
+    private void addSwitches() {\r
+        switchManager.addSwitch(\r
+                nodeId,\r
+                tunnelId,\r
+                Collections.<NodeConnectorId>emptySet(),\r
+                new OfOverlayNodeConfigBuilder().setTunnel(\r
+                        ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.4")))\r
+                            .setTunnelType(TunnelTypeVxlan.class)\r
+                            .setNodeConnectorId(tunnelId)\r
+                            .build())).build());\r
+        switchManager.addSwitch(\r
+                remoteNodeId,\r
+                remoteTunnelId,\r
+                Collections.<NodeConnectorId>emptySet(),\r
+                new OfOverlayNodeConfigBuilder().setTunnel(\r
+                        ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.5")))\r
+                            .setTunnelType(TunnelTypeVxlan.class)\r
+                            .setNodeConnectorId(tunnelId)\r
+                            .build())).build());\r
+    }\r
+\r
     @Test\r
     public void testNoPolicy() throws Exception {\r
         endpointManager.addEndpoint(localEP().build());\r
@@ -76,17 +100,20 @@ public class SourceMapperTest extends FlowTableTest {
                             .setNodeConnectorId(tunnelId)\r
                             .build())).build());\r
         Endpoint ep = localEP().build();\r
+        switchManager.addSwitch(nodeId, null,\r
+                Collections.<NodeConnectorId> emptySet(),\r
+                null);\r
         endpointManager.addEndpoint(ep);\r
         policyResolver.addTenant(baseTenant().build());\r
 \r
         FlowMap fm = dosync(null);\r
-        assertEquals(4, fm.getTableForNode(nodeId, (short) 1).getFlow().size());\r
+        assertEquals(2, fm.getTableForNode(nodeId, (short) 1).getFlow().size());\r
 \r
         int count = 0;\r
         HashMap<String, Flow> flowMap = new HashMap<>();\r
         for (Flow f : fm.getTableForNode(nodeId, (short) 1).getFlow()) {\r
             flowMap.put(f.getId().getValue(), f);\r
-            if (f.getMatch() == null) {\r
+            if (f.getMatch() == null || f.getMatch().getEthernetMatch() == null) {\r
                 assertEquals(FlowUtils.dropInstructions(), f.getInstructions());\r
                 count += 1;\r
             } else if ((f.getMatch() !=null && f.getMatch().getEthernetMatch() != null)\r
index 6dbc6458c543c31e34caed8274b3ac14459acc64..a1c9810fe9539ebc19a464ba8ba486e819ca1961 100644 (file)
@@ -32,6 +32,7 @@ public class MockSwitchManager extends SwitchManager {
         SwitchState state = new SwitchState(node, tunnelPort,
                                             externalPorts, nodeConfig);
         state.status = SwitchStatus.READY;
+        state.setHasEndpoints(true);
         switches.put(node, state);
         for (SwitchListener listener : listeners) {
             listener.switchReady(node);