Most basic features now working, including: 72/9672/10
authorRob Adams <readams@readams.net>
Fri, 1 Aug 2014 00:50:10 +0000 (17:50 -0700)
committerRob Adams <readams@readams.net>
Fri, 8 Aug 2014 18:06:51 +0000 (11:06 -0700)
    * Bridging and routing within and across endpoint groups
    * Respond to ARP sent to the virtual router IP
    * Add nicira extension support where possible/required.
      * Sets up Nicra group actions in the group table to set tunnel
        destination and tunnel ID
      * Sets sepg, scg, depg, dcg, fd, bd, and vrf into registers
    * Enforces policy configured by contract
    * Adds a simple test script to test OF overlay with mininet

Change-Id: Ieb4633a529d529c4b3586bc8cd6d046bcad84725
Signed-off-by: Rob Adams <readams@readams.net>
34 files changed:
distribution/pom.xml
distribution/src/assemble/bin.xml
distribution/src/main/resources/configuration/initial/42-openflowplugin.xml [moved from distribution/src/main/resources/configuration/initial/42-openflow-protocol-impl.xml with 66% similarity]
distribution/src/main/resources/configuration/initial/43-openflowjava-nx-api-config.xml [new file with mode: 0644]
distribution/src/main/resources/configuration/initial/44-nicira-extension.xml [new file with mode: 0644]
distribution/src/main/resources/configuration/initial/44-openflowjava-nx-config.xml [new file with mode: 0644]
groupbasedpolicy/pom.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/EpKey.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SwitchManager.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ActionComparator.java [new file with mode: 0644]
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTable.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTable.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurity.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/RuleGroup.java
groupbasedpolicy/src/main/yang/model/policy.yang
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapperTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java [new file with mode: 0644]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/OfTableTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcerTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PortSecurityTest.java
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java
pom.xml
util/testOfOverlay/.gitignore [new file with mode: 0644]
util/testOfOverlay/config.py [new file with mode: 0644]
util/testOfOverlay/mininet_gbp.py [new file with mode: 0644]
util/testOfOverlay/odl_gbp.py [new file with mode: 0644]
util/testOfOverlay/testOfOverlay.py [new file with mode: 0755]

index b60df8717cd8eeb4e862a3b465a970e77e804277..7d979f4bd224425e43ad78362a4e9230a033d753 100644 (file)
@@ -30,12 +30,32 @@ see https://git.opendaylight.org/gerrit/#/c/390/
     <!-- openflowplugin -->
     <dependency>
       <groupId>org.opendaylight.openflowplugin</groupId>
-      <artifactId>openflowplugin</artifactId>
+      <artifactId>openflowplugin-api</artifactId>
       <version>${openflowplugin.distribution.version}</version>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.openflowplugin</groupId>
-      <artifactId>openflowplugin-api</artifactId>
+      <artifactId>openflowplugin-extension-api</artifactId>
+      <version>${openflowplugin.distribution.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin.distribution.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira-api</artifactId>
+      <version>${openflowplugin.distribution.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin.distribution.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin</artifactId>
       <version>${openflowplugin.distribution.version}</version>
     </dependency>
 
index f43fb03be70a1b48851a3799178819e8e2d798cf..3d855dce4b4988bbb0ef99643de6b2964c80b0db 100644 (file)
@@ -16,6 +16,7 @@
         <exclude>opendaylight/plugins/org.opendaylight.controller.thirdparty.org.openflow.openflowj-*.jar</exclude>
         <exclude>opendaylight/plugins/org.opendaylight.controller.protocol_plugins.openflow-*.jar</exclude>
         <exclude>opendaylight/plugins/org.opendaylight.controller.samples.*.jar</exclude>
+        <exclude>opendaylight/plugins/org.opendaylight.controller.md.statistics-manager*.jar</exclude>
         <exclude>opendaylight/configuration/initial/*toaster*.xml</exclude>
       </excludes>
     </fileSet>
similarity index 66%
rename from distribution/src/main/resources/configuration/initial/42-openflow-protocol-impl.xml
rename to distribution/src/main/resources/configuration/initial/42-openflowplugin.xml
index 7c9214518103ac371bc041e45c5ab7263b3b03f5..a8ec1ba9d81b2ad9368a2a12529ddbab13ba8d2f 100644 (file)
@@ -28,6 +28,25 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           <name>openflow-switch-connection-provider-default-impl</name>
           <port>6633</port>
           <switch-idle-timeout>15000</switch-idle-timeout>
+<!--           Exemplary TLS configuration:
+                - uncomment the <tls> tag
+                - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
+                  files into your virtual machine
+                - set VM encryption options to use copied keys
+                - start communication
+               Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
+               for detailed information regarding TLS -->
+<!--           <tls>
+                 <keystore>/exemplary-ctlKeystore</keystore>
+                 <keystore-type>JKS</keystore-type>
+                 <keystore-path-type>CLASSPATH</keystore-path-type>
+                 <keystore-password>opendaylight</keystore-password>
+                 <truststore>/exemplary-ctlTrustStore</truststore>
+                 <truststore-type>JKS</truststore-type>
+                 <truststore-path-type>CLASSPATH</truststore-path-type>
+                 <truststore-password>opendaylight</truststore-password>
+                 <certificate-password>opendaylight</certificate-password>
+               </tls> -->
         </module>
         <!-- default OF-switch-connection-provider (port 6653) -->
         <module>
@@ -35,6 +54,25 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           <name>openflow-switch-connection-provider-legacy-impl</name>
           <port>6653</port>
           <switch-idle-timeout>15000</switch-idle-timeout>
+<!--           Exemplary TLS configuration:
+                - uncomment the <tls> tag
+                - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
+                  files into your virtual machine
+                - set VM encryption options to use copied keys
+                - start communication
+               Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
+               for detailed information regarding TLS -->
+<!--           <tls>
+                 <keystore>/exemplary-ctlKeystore</keystore>
+                 <keystore-type>JKS</keystore-type>
+                 <keystore-path-type>CLASSPATH</keystore-path-type>
+                 <keystore-password>opendaylight</keystore-password>
+                 <truststore>/exemplary-ctlTrustStore</truststore>
+                 <truststore-type>JKS</truststore-type>
+                 <truststore-path-type>CLASSPATH</truststore-path-type>
+                 <truststore-password>opendaylight</truststore-password>
+                 <certificate-password>opendaylight</certificate-password>
+               </tls> -->
         </module>
 
 
diff --git a/distribution/src/main/resources/configuration/initial/43-openflowjava-nx-api-config.xml b/distribution/src/main/resources/configuration/initial/43-openflowjava-nx-api-config.xml
new file mode 100644 (file)
index 0000000..1964e4d
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<snapshot>
+  <required-capabilities>
+    <capability>urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:api:config?module=openflowjava-nx-api-config&amp;revision=2014-07-11</capability>
+  </required-capabilities>
+
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:api:config">prefix:openflowjava-extension-nicira-api</type>
+          <name>openflowjava-extension-nx-api-bundle</name>
+          <openflow-switch-connection-provider>
+            <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
+            <name>openflow-switch-connection-provider-legacy</name>
+          </openflow-switch-connection-provider>
+          <openflow-switch-connection-provider>
+            <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
+            <name>openflow-switch-connection-provider-default</name>
+          </openflow-switch-connection-provider>
+        </module>
+      </modules>
+
+      <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:api:config">prefix:nicira-extension-codec-registrator</type>
+          <instance>
+            <name>openflowjava-nicira-ext-registrator</name>
+            <provider>/modules/module[type='openflowjava-extension-nicira-api'][name='openflowjava-extension-nx-api-bundle']</provider>
+          </instance>
+        </service>
+      </services>
+    </data>
+
+  </configuration>
+</snapshot>
diff --git a/distribution/src/main/resources/configuration/initial/44-nicira-extension.xml b/distribution/src/main/resources/configuration/initial/44-nicira-extension.xml
new file mode 100644 (file)
index 0000000..8ab4fd9
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+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
+-->
+<snapshot>
+  <required-capabilities>
+  <capability>urn:opendaylight:params:xml:ns:yang:openflowplugin:nx:config:impl?module=nicira-extension-impl&amp;revision=2014-07-11</capability>
+    <!-- openflowplugin -->
+    <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config?module=openflow-provider&amp;revision=2014-03-26</capability>
+  </required-capabilities>
+
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:nx:config:impl">prefix:nicira-extension-provider-impl</type>
+          <name>nicira-extension-provider-default-impl</name>
+          
+          <openflow-plugin-provider>
+            <type xmlns:opfprov="urn:opendaylight:params:xml:ns:yang:openflow:common:config">opfprov:openflow-provider</type>
+            <name>openflow-provider</name>
+          </openflow-plugin-provider>
+        </module>
+      </modules>
+    </data>
+
+  </configuration>
+</snapshot>
diff --git a/distribution/src/main/resources/configuration/initial/44-openflowjava-nx-config.xml b/distribution/src/main/resources/configuration/initial/44-openflowjava-nx-config.xml
new file mode 100644 (file)
index 0000000..756bd15
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<snapshot>
+  <required-capabilities>
+    <capability>urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:config?module=openflowjava-nx-config&amp;revision=2014-07-11</capability>
+  </required-capabilities>
+
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:config">prefix:openflowjava-extension-nicira</type>
+          <name>openflow-nx-bundle</name>
+          <nicira-extension-codec-registrator>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:ofjava:nx:api:config">prefix:nicira-extension-codec-registrator</type>
+            <name>openflowjava-nicira-ext-registrator</name>
+          </nicira-extension-codec-registrator>
+        </module>
+      </modules>
+    </data>
+
+  </configuration>
+</snapshot>
index 8fedd9bd732302bf0aab4e56313dfc9a4c55a002..4fa01d5c312583cdcf619cd0a4b86322ba7a19ae 100644 (file)
   <packaging>bundle</packaging>
 
   <properties>
-    <sal.version>1.1-SNAPSHOT</sal.version>
-    <yangtools.binding.version>0.6.2-SNAPSHOT</yangtools.binding.version>
-    <yangtools.generator.version>0.6.2-SNAPSHOT</yangtools.generator.version>
-    <yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
+    <openflowplugin-nicira.version>0.0.3-SNAPSHOT</openflowplugin-nicira.version>
   </properties>
 
   <dependencies>
       <groupId>org.opendaylight.controller.model</groupId>
       <artifactId>model-inventory</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowplugin-extension-nicira</artifactId>
+      <version>${openflowplugin-nicira.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.openflowplugin</groupId>
+      <artifactId>openflowjava-extension-nicira</artifactId>
+      <version>${openflowplugin-nicira.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
index 58ac3d00ac3df2f231be023a7aa8d2a5572e4f6e..f29cf3ff192eb72a324568807b8edbb724a7e17d 100644 (file)
@@ -19,6 +19,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 @Immutable
 public class EpKey {
 
+    @Override
+    public String toString() {
+        return "EpKey [l2Context=" + l2Context + ", macAddress=" + macAddress +
+               "]";
+    }
+
     final L2ContextId l2Context;
     final MacAddress macAddress;
     
index f7e06d0bbff8b46ddad71d1c4d6fb34e5fc2f80e..c52fa5dd6198e055ec80b299cc64de31483cf702 100644 (file)
@@ -27,7 +27,6 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.DestinationMapper;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.GroupTable;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable.OfTableCtx;
@@ -43,22 +42,16 @@ import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyScope;
 import org.opendaylight.groupbasedpolicy.util.SetUtils;
 import org.opendaylight.groupbasedpolicy.util.SingletonTask;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Manage policies on switches by subscribing to updates from the 
@@ -71,7 +64,6 @@ public class PolicyManager
     private static final Logger LOG = 
             LoggerFactory.getLogger(PolicyManager.class);
 
-    private final DataBroker dataBroker;
     private final SwitchManager switchManager;
     private final PolicyResolver policyResolver;
     
@@ -119,7 +111,6 @@ public class PolicyManager
                          RpcProviderRegistry rpcRegistry,
                          ScheduledExecutorService executor) {
         super();
-        this.dataBroker = dataBroker;
         this.switchManager = switchManager;
         this.executor = executor;
         this.policyResolver = policyResolver;
@@ -138,10 +129,10 @@ public class PolicyManager
                                         this, policyResolver, switchManager, 
                                         endpointManager, executor);
         flowPipeline = ImmutableList.of(new PortSecurity(ctx),
+                                        new GroupTable(ctx),
                                         new SourceMapper(ctx),
                                         new DestinationMapper(ctx),
-                                        new PolicyEnforcer(ctx),
-                                        new GroupTable(ctx));
+                                        new PolicyEnforcer(ctx));
 
         policyScope = policyResolver.registerListener(this);
         if (switchManager != null)
@@ -256,7 +247,7 @@ public class PolicyManager
      * @param cg the {@link ConditionGroup}
      * @return the unique ID
      */
-    public int getConfGroupOrdinal(final ConditionGroup cg) {
+    public int getCondGroupOrdinal(final ConditionGroup cg) {
         if (cg == null) return 0;
         Integer ord = cgOrdinals.get(cg);
         if (ord == null) {
@@ -331,7 +322,7 @@ public class PolicyManager
                     table.update(nodeId, info, dirty);
                 } catch (Exception e) {
                     LOG.error("Failed to write flow table {}", 
-                              table.getClass().getName(), e);
+                              table.getClass().getSimpleName(), e);
                 }
             }
             return null;
index af90eb6950e8c42afae4e5d0621337b9cb9fc247..dffc3e207f5f89452084c71cecd8d1b0a15a04de 100644 (file)
@@ -242,7 +242,7 @@ public class SwitchManager implements AutoCloseable {
     private void updateSwitchConfig(NodeId nodeId, OfOverlayNodeConfig config) {
         SwitchState state = getSwitchState(nodeId);
         state.setConfig(config);
-            notifySwitchUpdated(nodeId);
+        notifySwitchUpdated(nodeId);
     }
 
     private void notifySwitchUpdated(NodeId nodeId) {
diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ActionComparator.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ActionComparator.java
new file mode 100644 (file)
index 0000000..3d5d0a4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+
+import java.util.Comparator;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+
+public class ActionComparator implements Comparator<Action> {
+    public static final ActionComparator INSTANCE = new ActionComparator();
+
+    @Override
+    public int compare(Action arg0, Action arg1) {
+        return ComparisonChain.start()
+                .compare(arg0.getOrder(), arg1.getOrder(), 
+                         Ordering.natural().nullsLast())
+                .result();
+    }
+
+}
index 0d7eab9752faeec900c8ed640e5d8bd2f8e3bac7..6774eb8d04e26a9655ac4ffe0e702b4b93675080 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -18,9 +19,12 @@ import java.util.Objects;
 import java.util.Set;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
@@ -39,17 +43,34 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Sets;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
 /**
  * Manage the table that maps the destination address to the next hop
  * for the path as well as applies any relevant routing transformations.
@@ -65,6 +86,8 @@ public class DestinationMapper extends FlowTable {
      */
     public static final MacAddress ROUTER_MAC = 
             new MacAddress("88:f0:31:b5:12:b5");
+    public static final MacAddress MULTICAST_MAC = 
+            new MacAddress("01:00:00:00:00:00");
 
     public DestinationMapper(OfTable.OfTableCtx ctx) {
         super(ctx);
@@ -84,12 +107,15 @@ public class DestinationMapper extends FlowTable {
         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
 
         HashSet<EgKey> visitedEgs = new HashSet<>();
+        HashSet<Integer> visitedFds = new HashSet<>();
+
         for (EgKey epg : ctx.epManager.getGroupsForNode(nodeId)) {
             Set<EgKey> peers = Sets.union(Collections.singleton(epg),
                                           policyInfo.getPeers(epg));
             for (EgKey peer : peers) {
                 syncEPG(t, tiid, flowMap, nodeId, 
-                        policyInfo, peer, visitedEgs);
+                        policyInfo, peer, 
+                        visitedEgs, visitedFds);
             }
         }
     }
@@ -101,19 +127,105 @@ public class DestinationMapper extends FlowTable {
                          Map<String, FlowCtx> flowMap, 
                          NodeId nodeId, PolicyInfo policyInfo, 
                          EgKey key,
-                         HashSet<EgKey> visitedEgs) throws Exception {
+                         HashSet<EgKey> visitedEgs,
+                         HashSet<Integer> visitedFds) throws Exception {
         if (visitedEgs.contains(key)) return;
         visitedEgs.add(key);
         
+        IndexedTenant tenant = ctx.policyResolver.getTenant(key.getTenantId());
+        EndpointGroup eg = tenant.getEndpointGroup(key.getEgId());
+        L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
+        Subnet sn = tenant.resolveSubnet(eg.getNetworkDomain());
+        L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+        int l3Id = 0;
+
+        if (l3c != null)
+            l3Id = ctx.policyManager.getContextOrdinal(key.getTenantId(),
+                                                       l3c.getId());
+
         Collection<Endpoint> egEps = ctx.epManager
                 .getEndpointsForGroup(key);
+        
         for (Endpoint e : egEps) {
             if (e.getTenant() == null || e.getEndpointGroup() == null)
                 continue;
             OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
             if (ofc == null || ofc.getNodeId() == null) continue;
             
-            syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, key);
+            syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, tenant, key);
+        }
+        
+        if (fd == null) return;
+        Integer fdId = ctx.policyManager.getContextOrdinal(key.getTenantId(),
+                                                           fd.getId());
+        if (visitedFds.contains(fdId)) return;
+        visitedFds.add(fdId);
+
+        FlowId flowId = new FlowId(new StringBuilder()
+            .append("broadcast|")
+            .append(fdId).toString());
+        if (visit(flowMap, flowId.getValue())) {
+            MatchBuilder mb = new MatchBuilder()
+                .setEthernetMatch(new EthernetMatchBuilder()
+                    .setEthernetDestination(new EthernetDestinationBuilder()
+                        .setAddress(MULTICAST_MAC)
+                        .setMask(MULTICAST_MAC)
+                        .build())
+                    .build());
+            addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class,Long.valueOf(fdId)));
+            
+            FlowBuilder flow = base()
+                .setPriority(Integer.valueOf(140))
+                .setId(flowId)
+                .setMatch(mb.build())
+                .setInstructions(instructions(applyActionIns(nxMoveRegTunIdAction(NxmNxReg0.class, false),
+                                                             groupAction(Long.valueOf(fdId)))));
+            writeFlow(t, tiid, flow.build());
+        }
+        
+        if (sn != null && sn.getVirtualRouterIp() != null) {
+            if (sn.getVirtualRouterIp().getIpv4Address() != null) {
+                String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
+                flowId = new FlowId(new StringBuffer()
+                    .append("routerarp|")
+                    .append(sn.getId().getValue())
+                    .append("|")
+                    .append(ikey)
+                    .append("|")
+                    .append(l3Id)
+                    .toString());
+                if (visit(flowMap, flowId.getValue())) {
+                    MatchBuilder mb = new MatchBuilder()
+                        .setEthernetMatch(ethernetMatch(null, null, ARP))
+                        .setLayer3Match(new ArpMatchBuilder()
+                            .setArpOp(Integer.valueOf(1))
+                            .setArpTargetTransportAddress(new Ipv4Prefix(ikey))
+                            .build());
+                    addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
+                                                  Long.valueOf(l3Id)));
+                    BigInteger routerMac = 
+                            new BigInteger(1, HexEncode
+                                           .bytesFromHexString(ROUTER_MAC
+                                                               .getValue()));
+                    /* XXX - TODO add output to inport action */
+                    FlowBuilder flowb = base()
+                         .setPriority(150)
+                         .setId(flowId)
+                         .setMatch(mb.build())
+                         .setInstructions(instructions(applyActionIns(nxMoveEthSrcToEthDstAction(),
+                                                                      setDlSrcAction(ROUTER_MAC),
+                                                                      nxLoadArpOpAction(BigInteger.valueOf(2L)),
+                                                                      nxMoveArpShaToArpThaAction(),
+                                                                      nxLoadArpShaAction(routerMac),
+                                                                      nxMoveArpSpaToArpTpaAction(),
+                                                                      nxLoadArpSpaAction(ikey),
+                                                                      outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
+                    writeFlow(t, tiid, flowb.build());
+                }
+            } else {
+                LOG.warn("IPv6 virtual router {} for subnet {} not supported",
+                         sn.getVirtualRouterIp(), sn.getId().getValue());
+            }
         }
     }
 
@@ -122,43 +234,71 @@ public class DestinationMapper extends FlowTable {
                         Map<String, FlowCtx> flowMap, 
                         NodeId nodeId, PolicyInfo policyInfo, 
                         Endpoint e, OfOverlayContext ofc,
-                        EgKey key) 
+                        IndexedTenant tenant, EgKey key) 
                                  throws Exception {
-
         ArrayList<Instruction> instructions = new ArrayList<>();
         ArrayList<Instruction> l3instructions = new ArrayList<>();
+        List<Action> applyActions = new ArrayList<>();
+        List<Action> l3ApplyActions = new ArrayList<>();
+
         int order = 0;
+        EndpointGroup eg = tenant.getEndpointGroup(e.getEndpointGroup());
+        L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+        L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
+
+        int egId = 0, bdId = 0, l3Id = 0, cgId = 0;
+        
+        egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
+                                                   e.getEndpointGroup());
+        if (bd != null)
+            bdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+                                                       bd.getId());
+        if (l3c != null)
+            l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
+                                                       l3c.getId());
 
+        List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+        ConditionGroup cg = 
+                policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
+                                                    e.getEndpointGroup()), 
+                                          conds);
+        cgId = ctx.policyManager.getCondGroupOrdinal(cg);
+        Action setdEPG = nxLoadRegAction(NxmNxReg2.class, 
+                                         BigInteger.valueOf(egId));
+        Action setdCG = nxLoadRegAction(NxmNxReg3.class, 
+                                        BigInteger.valueOf(cgId));
+        Action setNextHop;
         String nextHop;
         if (LocationType.External.equals(ofc.getLocationType())) {
             // XXX - TODO - perform NAT and send to the external network
             nextHop = "external";
             LOG.warn("External endpoints not yet supported");
             return;
-        } else {
-            Action setDlSrc = FlowUtils.setDlSrc(ROUTER_MAC);
-            Action setDlDst = FlowUtils.setDlDst(e.getMacAddress());
-            Action decTtl = FlowUtils.decNwTtl();
+        } else {            
+            Action setDlSrc = setDlSrcAction(ROUTER_MAC);
+            Action decTtl = decNwTtlAction();
 
             if (Objects.equals(ofc.getNodeId(), nodeId)) {
-                // this is a local endpoint
+                // this is a local endpoint; send to the approppriate local 
+                // port
                 nextHop = ofc.getNodeConnectorId().getValue();
 
-                // XXX - TODO - instead of outputting, write next hop
-                // to a register and output from the policy table
-                Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
+                long portNum;
+                try {
+                    portNum = getOfPortNum(ofc.getNodeConnectorId());
+                } catch (NumberFormatException ex) {
+                    LOG.warn("Could not parse port number {}", 
+                             ofc.getNodeConnectorId(), ex);
+                    return;
+                }
+                
+                setNextHop = nxLoadRegAction(NxmNxReg7.class, 
+                                             BigInteger.valueOf(portNum));
 
-                instructions.add(new InstructionBuilder()
-                    .setOrder(order)
-                    .setInstruction(FlowUtils.writeActionIns(output))
-                    .build());
-                l3instructions.add(new InstructionBuilder()
-                    .setOrder(order)
-                    .setInstruction(FlowUtils.writeActionIns(setDlSrc,
-                                                             setDlDst,
-                                                             decTtl,
-                                                             output))
-                    .build());
+                Action setDlDst = setDlDstAction(e.getMacAddress());
+                l3ApplyActions.add(setDlSrc);
+                l3ApplyActions.add(setDlDst);
+                l3ApplyActions.add(decTtl);
                 order +=1;
             } else {
                 // this endpoint is on a different switch; send to the 
@@ -171,73 +311,85 @@ public class DestinationMapper extends FlowTable {
                 if (tunDst == null) return;
                 if (tunPort == null) return;
 
+                Action tundstAction;
+
                 if (tunDst.getIpv4Address() != null) {
                     nextHop = tunDst.getIpv4Address().getValue();
-                    
-                    // XXX - TODO Add action: set tunnel dst to tunDst ipv4 
+                    tundstAction = nxLoadTunIPv4Action(nextHop, false);
                 } else if (tunDst.getIpv6Address() != null) {
-                    nextHop = tunDst.getIpv6Address().getValue();
-
-                    // XXX - TODO Add action: set tunnel dst to tunDst ipv6 
+                    // nextHop = tunDst.getIpv6Address().getValue();
+                    LOG.error("IPv6 tunnel destination {} for {} not supported",
+                              tunDst.getIpv6Address().getValue(),
+                              ofc.getNodeId());
+                    return;
                 } else {
                     // this shouldn't happen
                     LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
                     return;
                 }
 
-                Action output = FlowUtils.outputAction(tunPort);
+
+                long portNum;
+                try {
+                    portNum = getOfPortNum(tunPort);
+                } catch (NumberFormatException ex) {
+                    LOG.warn("Could not parse port number {}", 
+                             ofc.getNodeConnectorId(), ex);
+                    return;
+                }
                 
-                // XXX - TODO Add action: set tunnel_id from sEPG register
-                instructions.add(new InstructionBuilder()
-                    .setOrder(order)
-                    .setInstruction(FlowUtils.writeActionIns(output))
-                    .build());
-                l3instructions.add(new InstructionBuilder()
-                    .setOrder(order)
-                    .setInstruction(FlowUtils.writeActionIns(setDlSrc, 
-                                                             decTtl,
-                                                             output))
-                    .build());
+                setNextHop = nxLoadRegAction(NxmNxReg7.class, 
+                                             BigInteger.valueOf(portNum));
+                Action tunIdAction = 
+                        nxMoveRegTunIdAction(NxmNxReg0.class, false);
 
+                applyActions.add(tunIdAction);
+                applyActions.add(tundstAction);
+                l3ApplyActions.add(setDlSrc);
+                l3ApplyActions.add(decTtl);
                 order +=1;
             }
         }
+        applyActions.add(setdEPG);
+        applyActions.add(setdCG);
+        applyActions.add(setNextHop);
+        Instruction applyActionsIns = new InstructionBuilder()
+            .setOrder(order++)
+            .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+            .build();
+        instructions.add(applyActionsIns);
+
+        applyActions.addAll(l3ApplyActions);
+        applyActionsIns = new InstructionBuilder()
+            .setOrder(order++)
+            .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+            .build();
+        l3instructions.add(applyActionsIns);
         
-        int egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
-                                                       e.getEndpointGroup());
-        List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
-        ConditionGroup cg = 
-                policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
-                                                    e.getEndpointGroup()), 
-                                          conds);
-        int cgId = ctx.policyManager.getConfGroupOrdinal(cg);
-        
-        // XXX TODO - add action set dEPG and dCG into registers
         Instruction gotoTable = new InstructionBuilder()
             .setOrder(order++)
-            .setInstruction(FlowUtils.gotoTableIns((short)(getTableId()+1)))
+            .setInstruction(gotoTableIns((short)(getTableId()+1)))
             .build();
         instructions.add(gotoTable);
         l3instructions.add(gotoTable);
 
         FlowId flowid = new FlowId(new StringBuilder()
-            .append(e.getL2Context().getValue())
+            .append(bdId)
             .append("|l2|")
             .append(e.getMacAddress().getValue())
             .append("|")
             .append(nextHop)
             .toString());
         if (visit(flowMap, flowid.getValue())) {
-            LOG.info("{} deg:{} dcg:{}", e.getMacAddress(), egId, cgId);
-            // XXX TODO add match against bridge domain register
+            MatchBuilder mb = new MatchBuilder()
+                .setEthernetMatch(ethernetMatch(null, 
+                                                e.getMacAddress(), 
+                                                null));
+            addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(bdId)));
             FlowBuilder flowb = base()
                 .setId(flowid)
                 .setPriority(Integer.valueOf(50))
-                .setMatch(new MatchBuilder()
-                    .setEthernetMatch(FlowUtils.ethernetMatch(null, 
-                                                          e.getMacAddress(), 
-                                                          null))
-                    .build())
+                .setMatch(mb.build())
                 .setInstructions(new InstructionsBuilder()
                     .setInstruction(instructions)
                     .build());
@@ -253,13 +405,13 @@ public class DestinationMapper extends FlowTable {
             String ikey = null;
             if (l3a.getIpAddress().getIpv4Address() != null) {
                 ikey = l3a.getIpAddress().getIpv4Address().getValue();
-                etherType = FlowUtils.IPv4;
+                etherType = IPv4;
                 m = new Ipv4MatchBuilder()
                     .setIpv4Destination(new Ipv4Prefix(ikey))
                     .build();
             } else if (l3a.getIpAddress().getIpv6Address() != null) {
                 ikey = l3a.getIpAddress().getIpv6Address().getValue();
-                etherType = FlowUtils.IPv6;
+                etherType = IPv6;
                 m = new Ipv6MatchBuilder()
                     .setIpv6Destination(new Ipv6Prefix(ikey))
                     .build();
@@ -274,17 +426,17 @@ public class DestinationMapper extends FlowTable {
                 .append(nextHop)
                 .toString());
             if (visit(flowMap, flowid.getValue())) {
-                // XXX TODO add match against routing domain register
-
+                MatchBuilder mb = new MatchBuilder()
+                    .setEthernetMatch(ethernetMatch(null, 
+                                                    ROUTER_MAC, 
+                                                    etherType))
+                    .setLayer3Match(m);
+                addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, 
+                                              Long.valueOf(l3Id)));
                 FlowBuilder flowb = base()
                     .setId(flowid)
                     .setPriority(Integer.valueOf(132))
-                    .setMatch(new MatchBuilder()
-                        .setEthernetMatch(FlowUtils.ethernetMatch(null, 
-                                                                  ROUTER_MAC, 
-                                                                  etherType))
-                        .setLayer3Match(m)
-                        .build())
+                    .setMatch(mb.build())
                     .setInstructions(new InstructionsBuilder()
                         .setInstruction(l3instructions)
                         .build());
index a24aeceb89990e34dd3bc1650f59bb8b474360ac..468e3a62f80dff795deb02629010eeed8ff93c2c 100644 (file)
@@ -26,8 +26,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Base class for managing flow tables
@@ -78,8 +76,9 @@ public abstract class FlowTable extends OfTable {
             }
         }
 
-        ListenableFuture<Void> result = t.submit();
-        Futures.addCallback(result, updateCallback);
+        t.submit().get();
+        //ListenableFuture<Void> result = t.submit();
+        //Futures.addCallback(result, updateCallback);
     }
 
     // *********
index 4099b1c3bceb02f6e62189d9ac50c500710be799..a3d047e83f28aac89d64326067f899f92d4e06c0 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.math.BigInteger;
 import java.util.ArrayList;
 
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
@@ -15,11 +16,13 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.dst.action._case.SetDlDstActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.dl.src.action._case.SetDlSrcActionBuilder;
@@ -32,11 +35,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTableBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.actions._case.WriteActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
@@ -56,9 +60,65 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.grouping.ExtensionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionListBuilder;
+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.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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpOpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpSpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfArpTpaCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstOfEthDstCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegMoveNodesNodeGroupBucketsBucketActionsCaseBuilder;
+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.nx.action.output.reg.grouping.NxOutputReg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputRegBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoadBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.DstBuilder;
+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.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.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.NxmNxReg0Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg2Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg4Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg5Key;
+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.reg.grouping.NxmNxRegBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.tun.id.grouping.NxmNxTunIdBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.net.InetAddresses;
 
 /**
  * Utilities for constructing OpenFlow flows
@@ -185,12 +245,8 @@ public final class FlowUtils {
                 .build())
             .build();
     }
-    
-    public static Instruction outputActionIns(NodeConnectorId id) {
-        return writeActionIns(outputAction(id));
-    }
 
-    public static ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> writeActionList(Action... actions) {
+    public static ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actionList(Action... actions) {
         ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> alist
             = new ArrayList<>();
         int count = 0;
@@ -202,29 +258,28 @@ public final class FlowUtils {
         }
         return alist;
     }
-
-    public static Instruction writeActionIns(Action... actions) {
-        return new WriteActionsCaseBuilder()
-            .setWriteActions(new WriteActionsBuilder()
-                .setAction(writeActionList(actions))
+    public static Instruction applyActionIns(Action... actions) {
+        return new ApplyActionsCaseBuilder()
+            .setApplyActions(new ApplyActionsBuilder()
+                .setAction(actionList(actions))
                 .build())
             .build();
     }
-        
+    public static Instructions instructions(Instruction... instructions) {
+        ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> ins
+            = new ArrayList<>();
+        int order = 0;
+        for (Instruction i : instructions) {
+            ins.add(new InstructionBuilder()
+                .setOrder(order++)
+                .setInstruction(i)
+                .build());
+        }
+        return new InstructionsBuilder().setInstruction(ins).build();
+    }
+
     public static Instructions dropInstructions() {
-        return new InstructionsBuilder()
-        .setInstruction(ImmutableList.of(new InstructionBuilder()
-            .setOrder(Integer.valueOf(0))
-            .setInstruction(new WriteActionsCaseBuilder()
-                .setWriteActions(new WriteActionsBuilder()
-                    .setAction(ImmutableList.of(new ActionBuilder()
-                        .setOrder(Integer.valueOf(0))
-                        .setAction(dropAction())
-                        .build()))
-                    .build())
-                .build())
-            .build()))
-        .build();
+        return instructions(applyActionIns(dropAction()));
     }
     
     public static Action dropAction() {
@@ -242,7 +297,15 @@ public final class FlowUtils {
             .build();
     }
 
-    public static Action setDlSrc(MacAddress mac) {
+    public static Action groupAction(Long id) {
+        return new GroupActionCaseBuilder()
+            .setGroupAction(new GroupActionBuilder()
+                .setGroupId(id)
+                .build())
+            .build();
+    }
+    
+    public static Action setDlSrcAction(MacAddress mac) {
         return new SetDlSrcActionCaseBuilder()
             .setSetDlSrcAction(new SetDlSrcActionBuilder()
                 .setAddress(mac)
@@ -250,7 +313,7 @@ public final class FlowUtils {
             .build();
     }
 
-    public static Action setDlDst(MacAddress mac) {
+    public static Action setDlDstAction(MacAddress mac) {
         return new SetDlDstActionCaseBuilder()
             .setSetDlDstAction(new SetDlDstActionBuilder()
                 .setAddress(mac)
@@ -258,13 +321,231 @@ public final class FlowUtils {
             .build();
     }
 
-    public static Action decNwTtl() {
+    public static Action decNwTtlAction() {
         return new DecNwTtlCaseBuilder()
             .setDecNwTtl(new DecNwTtlBuilder()
                 .build())
             .build();
     }
 
+    public static Action nxLoadRegAction(DstChoice dstChoice,
+                                         BigInteger value,
+                                         int endOffset,
+                                         boolean groupBucket) {
+        NxRegLoad r = new NxRegLoadBuilder()
+            .setDst(new DstBuilder()
+                .setDstChoice(dstChoice)
+                .setStart(Integer.valueOf(0))
+                .setEnd(Integer.valueOf(endOffset))
+                .build())
+            .setValue(value)
+            .build();
+        if (groupBucket) {
+            return new NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder()
+                .setNxRegLoad(r).build();
+        } else {
+            return new NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder()
+                .setNxRegLoad(r).build();
+        }
+    }
+
+    public static Action nxLoadRegAction(DstChoice dstChoice,
+                                         BigInteger value) {
+        return nxLoadRegAction(dstChoice, value, 31, false);
+    }
+
+    public static Action nxLoadRegAction(Class<? extends NxmNxReg> reg,
+                                         BigInteger value) {
+        return nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(reg).build(),
+                               value);
+    }
+    public static Action nxLoadTunIPv4Action(String ipAddress, 
+                                             boolean groupBucket) {
+        int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress));
+        long ipl = ip & 0xffffffffL;
+        return nxLoadRegAction(new DstNxTunIpv4DstCaseBuilder()
+                                    .setNxTunIpv4Dst(Boolean.TRUE).build(),
+                               BigInteger.valueOf(ipl),
+                               31,
+                               groupBucket);
+    }
+
+    public static Action nxLoadArpOpAction(BigInteger value) {
+        return nxLoadRegAction(new DstOfArpOpCaseBuilder()
+            .setOfArpOp(Boolean.TRUE).build(), value, 15, false);
+    }
+
+    public static Action nxLoadArpShaAction(BigInteger value) {
+        return nxLoadRegAction(new DstNxArpShaCaseBuilder()
+            .setNxArpSha(Boolean.TRUE).build(), value, 47, false);
+    }
+
+    public static Action nxLoadArpSpaAction(BigInteger value) {
+        return nxLoadRegAction(new DstOfArpSpaCaseBuilder()
+            .setOfArpSpa(Boolean.TRUE).build(), value);
+    }
+
+    public static Action nxLoadArpSpaAction(String ipAddress) {
+        int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress));
+        long ipl = ip & 0xffffffffL;
+        return nxLoadArpSpaAction(BigInteger.valueOf(ipl));
+    }
+
+    public static Action nxMoveRegAction(SrcChoice srcChoice,
+                                         DstChoice dstChoice,
+                                         int endOffset,
+                                         boolean groupBucket) {
+        NxRegMove r = new NxRegMoveBuilder()
+            .setSrc(new SrcBuilder()
+                .setSrcChoice(srcChoice)
+                .setStart(Integer.valueOf(0))
+                .setEnd(Integer.valueOf(endOffset))
+                .build())
+            .setDst(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.DstBuilder()
+                .setDstChoice(dstChoice)
+                .setStart(Integer.valueOf(0))
+                .setEnd(Integer.valueOf(endOffset))
+                .build())
+            .build();
+        if (groupBucket) {
+            return new NxActionRegMoveNodesNodeGroupBucketsBucketActionsCaseBuilder()
+                .setNxRegMove(r).build();
+        } else {
+            return new NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder()
+                .setNxRegMove(r).build();
+        }
+    }
+    
+    public static Action nxMoveRegAction(SrcChoice srcChoice,
+                                         DstChoice dstChoice) {
+        return nxMoveRegAction(srcChoice, dstChoice, 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);
+    }
+
+    public static Action nxMoveArpShaToArpThaAction() {
+        return nxMoveRegAction(new SrcNxArpShaCaseBuilder()
+                                   .setNxArpSha(Boolean.TRUE).build(),
+                               new DstNxArpThaCaseBuilder()
+                                   .setNxArpTha(Boolean.TRUE).build(),
+                               47, false);
+    }
+
+    public static Action nxMoveEthSrcToEthDstAction() {
+        return nxMoveRegAction(new SrcOfEthSrcCaseBuilder()
+                                   .setOfEthSrc(Boolean.TRUE).build(),
+                               new DstOfEthDstCaseBuilder()
+                                   .setOfEthDst(Boolean.TRUE).build(),
+                               47, false);
+    }
+
+    public static Action nxMoveArpSpaToArpTpaAction() {
+        return nxMoveRegAction(new SrcOfArpSpaCaseBuilder()
+                                   .setOfArpSpa(Boolean.TRUE).build(),
+                               new DstOfArpTpaCaseBuilder()
+                                   .setOfArpTpa(Boolean.TRUE).build());
+    }
+
+    public static Action nxOutputRegAction(SrcChoice srcChoice) {
+        NxOutputReg r = new NxOutputRegBuilder()
+            .setSrc(new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.nx.output.reg.SrcBuilder()
+                .setSrcChoice(srcChoice)
+                .setOfsNbits(Integer.valueOf(31))
+                .build())
+            .setMaxLen(Integer.valueOf(0xffff))
+            .build();
+        return new NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder()
+            .setNxOutputReg(r).build();
+    }
+
+    public static Action nxOutputRegAction(Class<? extends NxmNxReg> reg) {
+        return nxOutputRegAction(new SrcNxRegCaseBuilder().setNxReg(reg).build());
+    }
+
+    public static class RegMatch {
+        final Class<? extends NxmNxReg> reg;
+        final Long value;
+        public RegMatch(Class<? extends NxmNxReg> reg, Long value) {
+            super();
+            this.reg = reg;
+            this.value = value;
+        }
+        public static RegMatch of(Class<? extends NxmNxReg> reg, Long value) {
+            return new RegMatch(reg, value);
+        }
+    }
+    
+    public static void addNxRegMatch(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();
+        GeneralAugMatchNodesNodeTableFlow m = 
+                new GeneralAugMatchNodesNodeTableFlowBuilder()
+            .setExtensionList(ImmutableList.of(new ExtensionListBuilder()
+                .setExtensionKey(NxmNxTunIdKey.class)
+                .setExtension(new ExtensionBuilder()
+                    .addAugmentation(NxAugMatchNodesNodeTableFlow.class, am)
+                    .build())
+                .build()))
+            .build();
+        match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m);
+    }
+
     public static EthernetMatch ethernetMatch(MacAddress srcMac, 
                                               MacAddress dstMac,
                                               Long etherType) {
index b219b9ae75d63969933b3f00dd995c51ce828396..4cb9cbd43dc6924b96d2e2a0caca98f7af3798f8 100644 (file)
@@ -45,7 +45,9 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
+import com.google.common.collect.Ordering;
+
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
 
 /**
  * Manage the group tables for handling broadcast/multicast
@@ -57,7 +59,6 @@ public class GroupTable extends OfTable {
 
     public GroupTable(OfTableCtx ctx) {
         super(ctx);
-        // TODO Auto-generated constructor stub
     }
     
     @Override
@@ -68,8 +69,7 @@ public class GroupTable extends OfTable {
         // Since this is happening concurrently with other things that are 
         // working in subtrees of nodes, we have to do two transactions
         ReadOnlyTransaction t = ctx.dataBroker.newReadOnlyTransaction();
-        InstanceIdentifier<Node> niid = 
-                FlowUtils.createNodePath(nodeId);
+        InstanceIdentifier<Node> niid = createNodePath(nodeId);
         Optional<Node> r =
                 t.read(LogicalDatastoreType.CONFIGURATION, niid).get();
         if (!r.isPresent()) return;
@@ -90,12 +90,20 @@ public class GroupTable extends OfTable {
         }
         
         sync(nodeId, policyInfo, dirty, groupMap);
-        
+
         WriteTransaction wt = ctx.dataBroker.newWriteOnlyTransaction();
+        boolean wrote = syncGroupToStore(wt, nodeId, groupMap);
+        if (wrote)
+            wt.submit().get();
+    }
+    
+    protected boolean syncGroupToStore(WriteTransaction wt,
+                                       NodeId nodeId, 
+                                       HashMap<GroupId, GroupCtx> groupMap) {
         boolean wrote = false;
         for (GroupCtx gctx : groupMap.values()) {
             InstanceIdentifier<Group> giid = 
-                    FlowUtils.createGroupPath(nodeId, gctx.groupId);
+                    createGroupPath(nodeId, gctx.groupId);
             if (!gctx.visited) {
                 // Remove group table
                 wrote = true;
@@ -109,37 +117,37 @@ public class GroupTable extends OfTable {
                     if (bctx.b != null) bid = bctx.b.getBucketId();
                     else bid = bctx.newb.getBucketId();
                     InstanceIdentifier<Bucket> biid = 
-                            FlowUtils.createBucketPath(nodeId,
-                                                       gctx.groupId, 
-                                                       bid);
+                            createBucketPath(nodeId,
+                                             gctx.groupId, 
+                                             bid);
                     if (!bctx.visited) {
                         // remove bucket
-                        LOG.info("delete {} {}", gctx.groupId, bid);
                         wrote = true;
                         wt.delete(LogicalDatastoreType.CONFIGURATION, biid);
-                    } else if (bctx.b == null || 
-                               !Objects.equal(bctx.newb, 
-                                              bctx.b)) {
+                    } else if (bctx.b == null) {
+                        // new bucket
+                        buckets.add(bctx.newb);
+                    } else if (!Objects.equal(bctx.newb.getAction(), 
+                                              Ordering.from(ActionComparator.INSTANCE)
+                                                  .sortedCopy(bctx.b.getAction()))) {
                         // update bucket
                         buckets.add(bctx.newb);
-                        LOG.info("{} {}", gctx.groupId, bctx.newb.getBucketId());
-                    }
-                    if (buckets.size() > 0) {
-                        GroupBuilder gb = new GroupBuilder()
-                            .setGroupId(gctx.groupId)
-                            .setGroupType(GroupTypes.GroupAll)
-                            .setBuckets(new BucketsBuilder()
-                            .setBucket(buckets)
-                            .build());
-                        wrote = true;
-                        wt.merge(LogicalDatastoreType.CONFIGURATION, 
-                                 giid, gb.build());
                     }
                 }
+                if (buckets.size() > 0) {
+                    GroupBuilder gb = new GroupBuilder()
+                        .setGroupId(gctx.groupId)
+                        .setGroupType(GroupTypes.GroupAll)
+                        .setBuckets(new BucketsBuilder()
+                        .setBucket(buckets)
+                        .build());
+                    wrote = true;
+                    wt.merge(LogicalDatastoreType.CONFIGURATION, 
+                             giid, gb.build());
+                }
             }
         }
-        if (wrote)
-            Futures.addCallback(wt.submit(), updateCallback);
+        return wrote;
     }
     
     protected void sync(NodeId nodeId, PolicyInfo policyInfo, Dirty dirty,
@@ -165,6 +173,8 @@ public class GroupTable extends OfTable {
             // we'll use the fdId with the high bit set for remote bucket
             // and just the local port number for local bucket
             for (NodeId destNode : ctx.epManager.getNodesForGroup(epg)) {
+                if (nodeId.equals(destNode)) continue;
+
                 long bucketId = (long)ctx.policyManager
                         .getContextOrdinal(destNode.getValue());
                 bucketId |= 1L << 31;
@@ -174,23 +184,21 @@ public class GroupTable extends OfTable {
                 NodeConnectorId tunPort =
                         ctx.switchManager.getTunnelPort(nodeId);
                 if (tunDst == null || tunPort == null) continue;
+                Action tundstAction = null;
                 if (tunDst.getIpv4Address() != null) {
-                    // XXX - TODO Add action: set tunnel dst to tunDst ipv4
-                } else if (tunDst.getIpv6Address() != null) {
-                    // XXX - TODO Add action: set tunnel dst to tunDst ipv6 
+                    String nextHop = tunDst.getIpv4Address().getValue();
+                    tundstAction = nxLoadTunIPv4Action(nextHop, true);
+                } else {
+                    LOG.error("IPv6 tunnel destination {} for {} not supported",
+                              tunDst.getIpv6Address().getValue(),
+                              destNode);
+                    continue;
                 }
 
-                int epgId = ctx.policyManager
-                        .getContextOrdinal(epg.getTenantId(),
-                                           epg.getEgId());
-
-                // TODO add action: set tunnel ID to epgId
-                
-                Action output = FlowUtils.outputAction(tunPort);
-
                 BucketBuilder bb = new BucketBuilder()
                     .setBucketId(new BucketId(Long.valueOf(bucketId)))
-                    .setAction(FlowUtils.writeActionList(output));
+                    .setAction(actionList(tundstAction,
+                                          outputAction(tunPort)));
                 updateBucket(gctx, bb);
             }
             for (Endpoint localEp : ctx.epManager.getEPsForNode(nodeId, epg)) {
@@ -199,23 +207,20 @@ public class GroupTable extends OfTable {
                 if (ofc == null || ofc.getNodeConnectorId() == null ||
                     (LocationType.External.equals(ofc.getLocationType())))
                     continue;
-                String cnid = ofc.getNodeConnectorId().getValue();
-                int ci = cnid.lastIndexOf(':');
-                if (ci < 0 || (ci+1 >= cnid.length()))
-                    continue;
+
                 long bucketId;
                 try {
-                    bucketId = Long.parseLong(cnid.substring(ci+1));                
+                    bucketId = getOfPortNum(ofc.getNodeConnectorId());
                 } catch (NumberFormatException e) {
-                    LOG.warn("Could not parse port number {}", cnid);
+                    LOG.warn("Could not parse port number {}", 
+                             ofc.getNodeConnectorId(), e);
                     continue;
                 }
 
-                Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
-
+                Action output = outputAction(ofc.getNodeConnectorId());
                 BucketBuilder bb = new BucketBuilder()
                     .setBucketId(new BucketId(Long.valueOf(bucketId)))
-                    .setAction(FlowUtils.writeActionList(output));
+                    .setAction(actionList(output));
                 updateBucket(gctx, bb);
             }
         }
@@ -231,7 +236,7 @@ public class GroupTable extends OfTable {
         bctx.newb = bb.build();        
     }
     
-    private static class BucketCtx {
+    protected static class BucketCtx {
         Bucket b;
         Bucket newb;
         boolean visited = false;
@@ -242,7 +247,7 @@ public class GroupTable extends OfTable {
         }
     }
     
-    private static class GroupCtx {
+    protected static class GroupCtx {
         GroupId groupId;
         Map<BucketId, BucketCtx> bucketMap = new HashMap<>();
         boolean visited = false;
index 45b9379414cfea58baae5cfd57a7b9246799b9dd..3e89608ec44158361832ad8f73b5b75b104e7c5a 100644 (file)
@@ -18,12 +18,11 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SwitchManager;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.util.concurrent.FutureCallback;
-
 /**
  * Manage the state of a openflow  table by reacting to any events and updating
  * the table state.  This is an abstract class that must be extended for
@@ -93,25 +92,16 @@ public abstract class OfTable {
     // Utility methods
     // ***************
 
-
     /**
-     * Generic callback for handling result of flow manipulation
-     * @author readams
-     *
-     * @param <T> the expected output type
+     * Parse an OF port number from a node connector ID
+     * @param id the ID
+     * @return the port number
      */
-    protected static class OfCallback<T> implements FutureCallback<T> {
-        @Override
-        public void onSuccess(T result) {
-        }
-
-        @Override
-        public void onFailure(Throwable t) {
-            LOG.error("Failed to add flow entry", t);
-        }
+    protected static long getOfPortNum(NodeConnectorId id) {
+        String cnid = id.getValue();
+        int ci = cnid.lastIndexOf(':');
+        if (ci < 0 || (ci+1 >= cnid.length()))
+            throw new NumberFormatException("Invalid node connector ID " + cnid);
+        return Long.parseLong(cnid.substring(ci+1));
     }
-    protected static final OfCallback<Void> updateCallback =
-            new OfCallback<>();
-
-
 }
index 6194842f48e7206309f2bc7c990ebffcb6d7cf32..2abca0faa71906067def7c696a7bad07a90e54c8 100644 (file)
@@ -19,6 +19,7 @@ import javax.annotation.concurrent.Immutable;
 
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
@@ -42,11 +43,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
 /**
  * Manage the table that enforces policy on the traffic.  Traffic is denied
  * unless specifically allowed by policy
@@ -73,6 +82,7 @@ public class PolicyEnforcer extends FlowTable {
                      PolicyInfo policyInfo, Dirty dirty)
                              throws Exception {
         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+        allowFromTunnel(t, tiid, flowMap, nodeId);
 
         HashSet<CgPair> visitedPairs = new HashSet<>();
 
@@ -98,7 +108,7 @@ public class PolicyEnforcer extends FlowTable {
                 List<ConditionName> conds = 
                         ctx.epManager.getCondsForEndpoint(src);
                 ConditionGroup scg = policyInfo.getEgCondGroup(sepg, conds);
-                int scgId = ctx.policyManager.getConfGroupOrdinal(scg);
+                int scgId = ctx.policyManager.getCondGroupOrdinal(scg);
                 
                 Set<EgKey> peers = policyInfo.getPeers(sepg);
                 for (EgKey depg : peers) {
@@ -113,7 +123,7 @@ public class PolicyEnforcer extends FlowTable {
                                 policyInfo.getEgCondGroup(new EgKey(dst.getTenant(), 
                                                                     dst.getEndpointGroup()),
                                                           conds);
-                        int dcgId = ctx.policyManager.getConfGroupOrdinal(dcg);
+                        int dcgId = ctx.policyManager.getCondGroupOrdinal(dcg);
                         
                         CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
                         if (visitedPairs.contains(p)) continue;
@@ -141,11 +151,37 @@ public class PolicyEnforcer extends FlowTable {
             .append("intraallow|")
             .append(sepgId).toString());
         if (visit(flowMap, flowId.getValue())) {
-            // XXX - TODO - add match against sepg, depg registers
-            // XXX - TOOD - add output action from destination register
+            MatchBuilder mb = new MatchBuilder();
+            addNxRegMatch(mb, 
+                          RegMatch.of(NxmNxReg0.class,Long.valueOf(sepgId)),
+                          RegMatch.of(NxmNxReg2.class,Long.valueOf(sepgId)));
+            FlowBuilder flow = base()
+                .setId(flowId)
+                .setMatch(mb.build())
+                .setPriority(65000)
+                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
+            writeFlow(t, tiid, flow.build());
+        }
+    }
+    
+    private void allowFromTunnel(ReadWriteTransaction t, 
+                                 InstanceIdentifier<Table> tiid,
+                                 Map<String, FlowCtx> flowMap, NodeId nodeId) {
+        NodeConnectorId tunPort =
+                ctx.switchManager.getTunnelPort(nodeId);
+        if (tunPort == null) return;
+
+        FlowId flowId = new FlowId("tunnelallow");
+        if (visit(flowMap, flowId.getValue())) {
+            MatchBuilder mb = new MatchBuilder()
+                .setInPort(tunPort);
+            addNxRegMatch(mb, 
+                          RegMatch.of(NxmNxReg1.class,Long.valueOf(0xffffff)));
             FlowBuilder flow = base()
                 .setId(flowId)
-                .setPriority(65000);
+                .setMatch(mb.build())
+                .setPriority(65000)
+                .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
             writeFlow(t, tiid, flow.build());
         }
     }
@@ -194,7 +230,7 @@ public class PolicyEnforcer extends FlowTable {
 
             MatchBuilder baseMatch = new MatchBuilder();
 
-            if (d.equals(Direction.Out)) {
+            if (d.equals(Direction.In)) {
                 idb.append(p.sepg)
                     .append("|")
                     .append(p.scgId)
@@ -204,8 +240,11 @@ public class PolicyEnforcer extends FlowTable {
                     .append(p.dcgId)
                     .append("|")
                     .append(priority);
-                // XXX - TODO - add match against sepg, depg, scg, and dcg
-                // registers
+                addNxRegMatch(baseMatch, 
+                              RegMatch.of(NxmNxReg0.class,Long.valueOf(p.sepg)),
+                              RegMatch.of(NxmNxReg1.class,Long.valueOf(p.scgId)),
+                              RegMatch.of(NxmNxReg2.class,Long.valueOf(p.depg)),
+                              RegMatch.of(NxmNxReg3.class,Long.valueOf(p.dcgId)));
             } else {
                 idb.append(p.depg)
                     .append("|")
@@ -216,8 +255,11 @@ public class PolicyEnforcer extends FlowTable {
                     .append(p.scgId)
                     .append("|")
                     .append(priority);                
-                // XXX - TODO - add match against sepg, depg, scg, and dcg
-                // registers
+                addNxRegMatch(baseMatch, 
+                              RegMatch.of(NxmNxReg0.class,Long.valueOf(p.depg)),
+                              RegMatch.of(NxmNxReg1.class,Long.valueOf(p.dcgId)),
+                              RegMatch.of(NxmNxReg2.class,Long.valueOf(p.sepg)),
+                              RegMatch.of(NxmNxReg3.class,Long.valueOf(p.scgId)));
             }
 
 
@@ -255,11 +297,11 @@ public class PolicyEnforcer extends FlowTable {
             for (MatchBuilder match : matches) {
                 Match m = match.build();
                 FlowId flowId = new FlowId(baseId + "|" + m.toString());
-                flow.setMatch(m)
-                    .setId(flowId)
-                    .setPriority(Integer.valueOf(priority));
                 if (visit(flowMap, flowId.getValue())) {
-                    LOG.info("{} {} {} {}", p.sepg, p.scgId, p.depg, p.dcgId);
+                    flow.setMatch(m)
+                        .setId(flowId)
+                        .setPriority(Integer.valueOf(priority))
+                        .setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
                     writeFlow(t, tiid, flow.build());
                 }
             }
index aac3a7cd5470dd00e0428a8bd5768f66f7760faf..b2c37676af91f62c33d30cf25961a3ed96e02ec8 100644 (file)
@@ -123,7 +123,7 @@ public class PortSecurity extends FlowTable {
                         Endpoint e, OfOverlayContext ofc,
                         Integer priority) {
         FlowId flowid = new FlowId(new StringBuilder()
-            .append(ofc.getNodeConnectorId())
+            .append(ofc.getNodeConnectorId().getValue())
             .append("|")
             .append(e.getMacAddress().getValue())
             .toString());
@@ -178,7 +178,7 @@ public class PortSecurity extends FlowTable {
                 continue;
             }
             FlowId flowid = new FlowId(new StringBuilder()
-                .append(ofc.getNodeConnectorId())
+                .append(ofc.getNodeConnectorId().getValue())
                 .append("|")
                 .append(e.getMacAddress().getValue())
                 .append("|")
index fb7f80453aede0e33678a43be71106743214df32..9e6f17446fdf9a255d9697d2d4e0e3aa17c0d5b6 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.math.BigInteger;
 import java.util.List;
 import java.util.Map;
 
@@ -17,6 +18,7 @@ import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
@@ -29,11 +31,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
 /**
  * Manage the table that assigns source endpoint group, bridge domain, and 
  * router domain to registers to be used by other tables.
@@ -62,16 +72,81 @@ public class SourceMapper extends FlowTable {
                      Dirty dirty) throws Exception {
         dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
 
-        // XXX TODO Set sEPG from tunnel ports using the tunnel ID
-
         for (EgKey sepg : ctx.epManager.getGroupsForNode(nodeId)) {
+            IndexedTenant tenant = 
+                    ctx.policyResolver.getTenant(sepg.getTenantId());
+            if (tenant == null) continue;
+
+            EndpointGroup eg = tenant.getEndpointGroup(sepg.getEgId());
+            L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+            L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
+            L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
+            int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
+            
+            egId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
+                                                       sepg.getEgId());
+            if (bd != null)
+                bdId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
+                                                           bd.getId());
+            if (fd != null)
+                fdId = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
+                                                           fd.getId());
+            if (l3c != null)
+                l3Id = ctx.policyManager.getContextOrdinal(sepg.getTenantId(), 
+                                                           l3c.getId());
+
+            NodeConnectorId tunPort =
+                    ctx.switchManager.getTunnelPort(nodeId);
+            if (tunPort != null) {
+                FlowId flowid = new FlowId(new StringBuilder()
+                    .append(tunPort.getValue())
+                    .append("|tunnel|")
+                    .append(egId)
+                    .append("|")
+                    .append(bdId)
+                    .append("|")
+                    .append(fdId)
+                    .append("|")
+                    .append(l3Id)
+                    .toString());
+                if (visit(flowMap, flowid.getValue())) {
+                    MatchBuilder mb = new MatchBuilder()
+                        .setInPort(tunPort);
+                    addNxTunIdMatch(mb, egId);
+                    Action segReg = nxLoadRegAction(NxmNxReg0.class, 
+                                                    BigInteger.valueOf(egId));
+                    // set condition group register to all ones to bypass
+                    // policy enforcement
+                    Action scgReg = nxLoadRegAction(NxmNxReg1.class,
+                                                    BigInteger.valueOf(0xffffff));
+                    Action bdReg = nxLoadRegAction(NxmNxReg4.class, 
+                                                   BigInteger.valueOf(bdId));
+                    Action fdReg = nxLoadRegAction(NxmNxReg5.class, 
+                                                   BigInteger.valueOf(fdId));
+                    Action vrfReg = nxLoadRegAction(NxmNxReg6.class, 
+                                                    BigInteger.valueOf(l3Id));
+                    FlowBuilder flowb = base()
+                        .setId(flowid)
+                        .setPriority(Integer.valueOf(150))
+                        .setMatch(mb.build())
+                        .setInstructions(instructions(applyActionIns(segReg,
+                                                                     scgReg,
+                                                                     bdReg,
+                                                                     fdReg,
+                                                                     vrfReg),
+                                                      gotoTableIns((short)(TABLE_ID + 1))));
+                    writeFlow(t, tiid, flowb.build());
+                }
+            }
+            
             for (Endpoint e : ctx.epManager.getEPsForNode(nodeId, sepg)) {
                 OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
                 if (ofc != null && ofc.getNodeConnectorId() != null &&
                         (ofc.getLocationType() == null ||
                         LocationType.Internal.equals(ofc.getLocationType())) &&
                         e.getTenant() != null && e.getEndpointGroup() != null) {
-                    syncEP(t, tiid, flowMap, policyInfo, nodeId, e, ofc);
+                    syncEP(t, tiid, flowMap, policyInfo, nodeId, e, ofc,
+                           egId, bdId, fdId, l3Id);
                 } 
             }
         }
@@ -81,40 +156,21 @@ public class SourceMapper extends FlowTable {
                         InstanceIdentifier<Table> tiid,
                         Map<String, FlowCtx> flowMap, 
                         PolicyInfo policyInfo,
-                        NodeId nodeId, Endpoint e, OfOverlayContext ofc) 
+                        NodeId nodeId, Endpoint e, OfOverlayContext ofc,
+                        int egId, int bdId, int fdId, int l3Id) 
                                  throws Exception {
         // Set sEPG, flood domain, bridge domain, and layer 3 context 
         // for internal endpoints by directly matching each endpoint
-        IndexedTenant tenant = ctx.policyResolver.getTenant(e.getTenant());
-        if (tenant == null) return;
-
-        EndpointGroup eg = tenant.getEndpointGroup(e.getEndpointGroup());
-        L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
-        L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
-        L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
 
-        int egId = 0, bdId = 0, fdId = 0, l3Id = 0, cgId = 0;
-        
-        egId = ctx.policyManager.getContextOrdinal(e.getTenant(), 
-                                                   e.getEndpointGroup());
-        if (bd != null)
-            bdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
-                                                       bd.getId());
-        if (fd != null)
-            fdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
-                                                       fd.getId());
-        if (l3c != null)
-            l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
-                                                       l3c.getId());
         List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
         ConditionGroup cg = 
                 policyInfo.getEgCondGroup(new EgKey(e.getTenant(), 
                                                     e.getEndpointGroup()), 
                                           conds);
-        cgId = ctx.policyManager.getConfGroupOrdinal(cg);
-        
+        int cgId = ctx.policyManager.getCondGroupOrdinal(cg);
+
         FlowId flowid = new FlowId(new StringBuilder()
-            .append(ofc.getNodeConnectorId())
+            .append(ofc.getNodeConnectorId().getValue())
             .append("|")
             .append(e.getMacAddress().getValue())
             .append("|")
@@ -129,18 +185,30 @@ public class SourceMapper extends FlowTable {
             .append(cgId)
             .toString());
         if (visit(flowMap, flowid.getValue())) {
-            LOG.info("{} seg:{} bd:{} fd:{} vrf:{} scg:{}", 
-                     e.getMacAddress(), egId, bdId, fdId, l3Id, cgId);
+            Action segReg = nxLoadRegAction(NxmNxReg0.class, 
+                                            BigInteger.valueOf(egId));
+            Action scgReg = nxLoadRegAction(NxmNxReg1.class, 
+                                            BigInteger.valueOf(cgId));
+            Action bdReg = nxLoadRegAction(NxmNxReg4.class, 
+                                           BigInteger.valueOf(bdId));
+            Action fdReg = nxLoadRegAction(NxmNxReg5.class, 
+                                           BigInteger.valueOf(fdId));
+            Action vrfReg = nxLoadRegAction(NxmNxReg6.class, 
+                                            BigInteger.valueOf(l3Id));
             FlowBuilder flowb = base()
                 .setPriority(Integer.valueOf(100))
                 .setId(flowid)
                 .setMatch(new MatchBuilder()
-                    .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(), 
-                                                              null, null))
+                    .setEthernetMatch(ethernetMatch(e.getMacAddress(), 
+                                                    null, null))
                     .setInPort(ofc.getNodeConnectorId())
                     .build())
-                // XXX TODO set sepg, bd, fd, vrf, scg into registers
-                .setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)));
+                .setInstructions(instructions(applyActionIns(segReg,
+                                                             scgReg,
+                                                             bdReg,
+                                                             fdReg,
+                                                             vrfReg),
+                                              gotoTableIns((short)(TABLE_ID + 1))));
             writeFlow(t, tiid, flowb.build());
         }
     }
index 22292d3b6211460730327075aadd7aecd5cfd56e..e3dfbe1bc91360831fc96039c79f2e2b53053b5d 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
 package org.opendaylight.groupbasedpolicy.resolver;
 
 import java.util.List;
index eda185a2c1dcb0405b76b2ca1e2cdc41efc6ec64..f8de336982231a7700de0b2ee2233362748509fe 100644 (file)
@@ -627,7 +627,7 @@ module policy {
             description
                 "A classifier is used to match traffic traveling between 
                  the endpoint groups that form the contract.
-                 Classifier defintions can define parameters that
+                 Classifier definitions can define parameters that
                  will need to be filled in when a particular rule
                  references it.";
 
@@ -800,6 +800,12 @@ module policy {
                     description "The IP prefix that defines the subnet";
                     type inet:ip-prefix;
                 }
+                leaf virtual-router-ip {
+                    description
+                        "IP address to use for a virtual gateway router
+                         for the subnet, if desired.";
+                    type inet:ip-address;
+                }
             }
 
             // ***************
index 551fe3fbb59c48d32620968f631e2df0949ef583..d5f8d00ade004e535a07c6fe8bd440ced72f9213 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.math.BigInteger;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -19,15 +20,15 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Matchers;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
@@ -37,6 +38,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeCon
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,14 +52,14 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class DestinationMapperTest extends OfTableTest {
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
+public class DestinationMapperTest extends FlowTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(DestinationMapperTest.class);
 
-    NodeConnectorId tunnelId = 
-            new NodeConnectorId(nodeId.getValue() + ":42");
     NodeConnectorId remoteTunnelId = 
-            new NodeConnectorId(remoteNodeId.getValue() + ":42");
+            new NodeConnectorId(remoteNodeId.getValue() + ":101");
 
     @Before
     public void setup() throws Exception {
@@ -87,20 +90,54 @@ public class DestinationMapperTest extends OfTableTest {
         for (Flow f : ac.getAllValues()) {
             flowMap.put(f.getId().getValue(), new FlowCtx(f));
             if (f.getMatch() == null) {
-                assertEquals(FlowUtils.dropInstructions(),
+                assertEquals(dropInstructions(),
                              f.getInstructions());
                 count += 1;
+            } else if (Objects.equals(ethernetMatch(null, null, ARP), 
+                                      f.getMatch().getEthernetMatch())) {
+                // router ARP reply
+                Instruction ins = f.getInstructions().getInstruction().get(0);
+                ins = f.getInstructions().getInstruction().get(0);
+                assertTrue(ins.getInstruction() instanceof ApplyActionsCase);
+                List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                assertEquals(nxMoveEthSrcToEthDstAction(),
+                             actions.get(0).getAction());
+                assertEquals(Integer.valueOf(0), actions.get(0).getOrder());
+                assertEquals(setDlSrcAction(DestinationMapper.ROUTER_MAC),
+                             actions.get(1).getAction());
+                assertEquals(Integer.valueOf(1), actions.get(1).getOrder());
+                assertEquals(nxLoadArpOpAction(BigInteger.valueOf(2L)),
+                             actions.get(2).getAction());
+                assertEquals(Integer.valueOf(2), actions.get(2).getOrder());
+                assertEquals(nxMoveArpShaToArpThaAction(),
+                             actions.get(3).getAction());
+                assertEquals(Integer.valueOf(3), actions.get(3).getOrder());
+                assertEquals(nxLoadArpShaAction(new BigInteger(1, HexEncode
+                                                               .bytesFromHexString(DestinationMapper.ROUTER_MAC
+                                                                                   .getValue()))),
+                             actions.get(4).getAction());
+                assertEquals(Integer.valueOf(4), actions.get(4).getOrder());
+                assertEquals(nxMoveArpSpaToArpTpaAction(),
+                             actions.get(5).getAction());
+                assertEquals(Integer.valueOf(5), actions.get(5).getOrder());
+                assertTrue(nxLoadArpSpaAction("10.0.0.1").equals(actions.get(6).getAction()) ||
+                           nxLoadArpSpaAction("10.0.0.2").equals(actions.get(6).getAction()));
+                assertEquals(Integer.valueOf(6), actions.get(6).getOrder());
+                count += 1;
             } else if (Objects.equals(localEp.getMacAddress(),
                                f.getMatch().getEthernetMatch()
                                    .getEthernetDestination().getAddress())) {
                 int icount = 0;
                 for (Instruction ins : f.getInstructions().getInstruction()) {
-                    if (ins.getInstruction() instanceof WriteActionsCase) {
-                        assertEquals(FlowUtils.outputActionIns(nodeConnectorId),
-                                     ins.getInstruction());
+                    if (ins.getInstruction() instanceof ApplyActionsCase) {
+                        long p = OfTable.getOfPortNum(nodeConnectorId);
+                        List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                        assertEquals(nxLoadRegAction(NxmNxReg7.class, 
+                                                     BigInteger.valueOf(p)),
+                                     actions.get(2).getAction());
                         icount += 1;
                     } else if (ins.getInstruction() instanceof GoToTableCase) {
-                        assertEquals(FlowUtils.gotoTableIns((short)(table.getTableId()+1)),
+                        assertEquals(gotoTableIns((short)(table.getTableId()+1)),
                                      ins.getInstruction());
                         icount += 1;
                     }
@@ -113,12 +150,15 @@ public class DestinationMapperTest extends OfTableTest {
                                       .getEthernetDestination().getAddress())) {
                 int icount = 0;
                 for (Instruction ins : f.getInstructions().getInstruction()) {
-                    if (ins.getInstruction() instanceof WriteActionsCase) {
-                        assertEquals(FlowUtils.outputActionIns(tunnelId),
-                                     ins.getInstruction());
+                    if (ins.getInstruction() instanceof ApplyActionsCase) {
+                        long p = OfTable.getOfPortNum(tunnelId);
+                        List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                        assertEquals(nxLoadRegAction(NxmNxReg7.class, 
+                                                     BigInteger.valueOf(p)),
+                                     actions.get(4).getAction());
                         icount += 1;
                     } else if (ins.getInstruction() instanceof GoToTableCase) {
-                        assertEquals(FlowUtils.gotoTableIns((short)(table.getTableId()+1)),
+                        assertEquals(gotoTableIns((short)(table.getTableId()+1)),
                                      ins.getInstruction());
                         icount += 1;
                     }
@@ -134,43 +174,61 @@ public class DestinationMapperTest extends OfTableTest {
                     // should be local port with rewrite dlsrc and dldst plus
                     // ttl decr
                     Instruction ins = f.getInstructions().getInstruction().get(0);
-                    assertTrue(ins.getInstruction() instanceof WriteActionsCase);
-                    List<Action> actions = 
-                            ((WriteActionsCase)ins.getInstruction()).getWriteActions().getAction();
-                    assertEquals(FlowUtils.setDlSrc(DestinationMapper.ROUTER_MAC),
-                                 actions.get(0).getAction());
-                    assertEquals(Integer.valueOf(0), actions.get(0).getOrder());
-                    assertEquals(FlowUtils.setDlDst(localEp.getMacAddress()),
-                                 actions.get(1).getAction());
-                    assertEquals(Integer.valueOf(1), actions.get(1).getOrder());
-                    assertEquals(FlowUtils.decNwTtl(),
+                    assertTrue(ins.getInstruction() instanceof ApplyActionsCase);
+                    List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                    long p = OfTable.getOfPortNum(nodeConnectorId);
+                    assertEquals(nxLoadRegAction(NxmNxReg7.class, 
+                                                 BigInteger.valueOf(p)),
                                  actions.get(2).getAction());
                     assertEquals(Integer.valueOf(2), actions.get(2).getOrder());
-                    assertEquals(FlowUtils.outputAction(nodeConnectorId),
+                    assertEquals(setDlSrcAction(DestinationMapper.ROUTER_MAC),
                                  actions.get(3).getAction());
                     assertEquals(Integer.valueOf(3), actions.get(3).getOrder());
+                    assertEquals(setDlDstAction(localEp.getMacAddress()),
+                                 actions.get(4).getAction());
+                    assertEquals(Integer.valueOf(4), actions.get(4).getOrder());
+                    assertEquals(decNwTtlAction(),
+                                 actions.get(5).getAction());
+                    assertEquals(Integer.valueOf(5), actions.get(5).getOrder());
                     count += 1;
                 } else if (f.getMatch().getLayer3Match() instanceof Ipv6Match) {
                     // should be remote port with rewrite dlsrc plus
                     // ttl decr
                     Instruction ins = f.getInstructions().getInstruction().get(0);
-                    assertTrue(ins.getInstruction() instanceof WriteActionsCase);
-                    List<Action> actions = 
-                            ((WriteActionsCase)ins.getInstruction()).getWriteActions().getAction();
-                    assertEquals(FlowUtils.setDlSrc(DestinationMapper.ROUTER_MAC),
-                                 actions.get(0).getAction());
-                    assertEquals(Integer.valueOf(0), actions.get(0).getOrder());
-                    assertEquals(FlowUtils.decNwTtl(),
-                                 actions.get(1).getAction());
-                    assertEquals(Integer.valueOf(1), actions.get(1).getOrder());
-                    assertEquals(FlowUtils.outputAction(tunnelId),
-                                 actions.get(2).getAction());
-                    assertEquals(Integer.valueOf(2), actions.get(2).getOrder());
+                    assertTrue(ins.getInstruction() instanceof ApplyActionsCase);
+                    List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                    long p = OfTable.getOfPortNum(tunnelId);
+                    assertEquals(nxLoadRegAction(NxmNxReg7.class, 
+                                                 BigInteger.valueOf(p)),
+                                 actions.get(4).getAction());
+                    assertEquals(Integer.valueOf(4), actions.get(4).getOrder());
+                    assertEquals(setDlSrcAction(DestinationMapper.ROUTER_MAC),
+                                 actions.get(5).getAction());
+                    assertEquals(Integer.valueOf(5), actions.get(5).getOrder());
+                    assertEquals(decNwTtlAction(),
+                                 actions.get(6).getAction());
+                    assertEquals(Integer.valueOf(6), actions.get(6).getOrder());
                     count += 1;
                 }
+            } else if (Objects.equals(DestinationMapper.MULTICAST_MAC, 
+                                      f.getMatch().getEthernetMatch()
+                                      .getEthernetDestination()
+                                      .getAddress())) {
+                // broadcast/multicast flow should output to group table
+                Instruction ins = f.getInstructions().getInstruction().get(0);
+                ins = f.getInstructions().getInstruction().get(0);
+                assertTrue(ins.getInstruction() instanceof ApplyActionsCase);
+                List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                assertEquals(nxMoveRegTunIdAction(NxmNxReg0.class, false), 
+                             actions.get(0).getAction());
+                assertEquals(Integer.valueOf(0), actions.get(0).getOrder());
+                Long v = Long.valueOf(policyManager.getContextOrdinal(tid, fd));
+                assertEquals(groupAction(v), actions.get(1).getAction());
+                assertEquals(Integer.valueOf(1), actions.get(1).getOrder());
+                count += 1;
             }
         }
-        assertEquals(5, count);
+        assertEquals(7, count);
 
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
@@ -189,7 +247,6 @@ public class DestinationMapperTest extends OfTableTest {
     @Override
     protected EndpointBuilder remoteEP(NodeId remoteNodeId) {
         return super.remoteEP(remoteNodeId)
-            .setMacAddress(new MacAddress("00:00:00:00:00:02"))
             .setL3Address(ImmutableList.of(new L3AddressBuilder()
                 .setL3Context(l3c)
                 .setIpAddress(new IpAddress(new Ipv6Address("::ffff:0:0::10.0.0.2")))
@@ -205,7 +262,7 @@ public class DestinationMapperTest extends OfTableTest {
         switchManager.addSwitch(remoteNodeId, remoteTunnelId, 
                                 Collections.<NodeConnectorId>emptySet(),
                                 new OfOverlayNodeConfigBuilder()
-                                    .setTunnelIp(new IpAddress(new Ipv6Address("::1:2:3:4")))
+                                    .setTunnelIp(new IpAddress(new Ipv4Address("1.2.3.5")))
                                     .build());
     }
     
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowTableTest.java
new file mode 100644 (file)
index 0000000..4986e80
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static org.mockito.Mockito.*;
+
+public class FlowTableTest extends OfTableTest {
+    FlowTable table;
+    InstanceIdentifier<Table> tiid;
+
+    protected void setup() throws Exception {
+        tiid = FlowUtils.createTablePath(nodeId, 
+                                         table.getTableId());
+    }
+
+    protected ReadWriteTransaction dosync(Map<String, FlowCtx> flowMap) 
+              throws Exception {
+        ReadWriteTransaction t = mock(ReadWriteTransaction.class);
+        if (flowMap == null)
+            flowMap = Collections.emptyMap();
+        table.sync(t, tiid, flowMap, nodeId, policyResolver.getCurrentPolicy(), 
+                   null);
+        return t;
+    }
+}
diff --git a/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java b/groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java
new file mode 100644 (file)
index 0000000..d1fb7dc
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+
+import java.util.Collections;
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.GroupTable.BucketCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.GroupTable.GroupCtx;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+
+import static org.junit.Assert.*;
+
+public class GroupTableTest extends OfTableTest {
+    protected static final Logger LOG = 
+            LoggerFactory.getLogger(GroupTableTest.class);
+
+    GroupTable table;
+
+    NodeConnectorId tunnelId = 
+            new NodeConnectorId(nodeId.getValue() + ":42");
+    NodeConnectorId remoteTunnelId = 
+            new NodeConnectorId(remoteNodeId.getValue() + ":101");
+
+    @Before
+    public void setup() throws Exception {
+        initCtx();
+        table = new GroupTable(ctx);
+    }
+    
+    @Test
+    public void testGroup() throws Exception {
+        Endpoint localEp = localEP().build();
+        endpointManager.addEndpoint(localEp);
+        Endpoint remoteEp = remoteEP(remoteNodeId).build();
+        endpointManager.addEndpoint(remoteEp);
+        
+        switchManager.addSwitch(nodeId, tunnelId, 
+                                Collections.<NodeConnectorId>emptySet(),
+                                new OfOverlayNodeConfigBuilder()
+                                    .setTunnelIp(new IpAddress(new Ipv4Address("1.2.3.4")))
+                                    .build());
+        switchManager.addSwitch(remoteNodeId, remoteTunnelId, 
+                                Collections.<NodeConnectorId>emptySet(),
+                                new OfOverlayNodeConfigBuilder()
+                                    .setTunnelIp(new IpAddress(new Ipv4Address("1.2.3.5")))
+                                    .build());
+
+        policyResolver.addTenant(baseTenant().build());
+
+        HashMap<GroupId, GroupCtx> groupMap = new HashMap<>();
+        table.sync(nodeId, ctx.policyResolver.getCurrentPolicy(), 
+                   null, groupMap);
+        
+        assertEquals(1, groupMap.size());
+        int fdId = ctx.policyManager.getContextOrdinal(tid, fd);
+        GroupCtx ctx = groupMap.get(new GroupId(Long.valueOf(fdId)));
+        assertNotNull(ctx);
+        long tunBucketId = 
+                (long)policyManager.getContextOrdinal(remoteNodeId.getValue());
+        tunBucketId |= 1L << 31;
+        int count = 0;
+        for (BucketCtx bctx : ctx.bucketMap.values()) {
+            if (Objects.equal(Long.valueOf(4),
+                              bctx.newb.getBucketId().getValue())) {
+                count += 1;
+            } else if (Objects.equal(Long.valueOf(tunBucketId),
+                                     bctx.newb.getBucketId().getValue())) {
+                
+                count += 1;
+            }
+        }
+        assertEquals(2, count);
+    }
+}
index ac6e59e78ed7a46f7b4942b32fd87a1196044820..0c62fd0f89f97f5911b14b03230845e03e0c8b4a 100644 (file)
@@ -8,22 +8,18 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
-import java.util.Collections;
-import java.util.Map;
-
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockEndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockSwitchManager;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OfTable.OfTableCtx;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
 import org.opendaylight.groupbasedpolicy.resolver.MockPolicyResolver;
+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.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
@@ -61,16 +57,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.collect.ImmutableList;
 
-import static org.mockito.Mockito.*;
-
 public class OfTableTest {
     OfTableCtx ctx;
-    FlowTable table;
-    
+
     MockEndpointManager endpointManager;
     MockPolicyResolver policyResolver;
     MockPolicyManager policyManager;
@@ -79,9 +71,11 @@ public class OfTableTest {
     NodeId nodeId = new NodeId("openflow:1");
     NodeId remoteNodeId = new NodeId("openflow:2");
     NodeConnectorId nodeConnectorId = 
-            new NodeConnectorId(nodeId.getValue() + ":1");
-    InstanceIdentifier<Table> tiid;
-    
+            new NodeConnectorId(nodeId.getValue() + ":4");
+
+    NodeConnectorId tunnelId = 
+            new NodeConnectorId(nodeId.getValue() + ":42");
+
     L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");
     L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");
     L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");
@@ -106,11 +100,6 @@ public class OfTableTest {
                              endpointManager, 
                              null);
     }
-    
-    protected void setup() throws Exception {
-        tiid = FlowUtils.createTablePath(nodeId, 
-                                         table.getTableId());
-    }
 
     protected TenantBuilder baseTenant() {
         return baseTenant(null);
@@ -150,11 +139,13 @@ public class OfTableTest {
                     .setId(sub2)
                     .setParent(fd)
                     .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.1.1/24")))
+                    .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.1.1")))
                     .build(),
                 new SubnetBuilder()
                     .setId(sub)
                     .setParent(fd)
                     .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.0.1/24")))
+                    .setVirtualRouterIp(new IpAddress(new Ipv4Address("10.0.0.1")))
                     .build()))
             .setSubjectFeatureInstances(new SubjectFeatureInstancesBuilder()
                 .setClassifierInstance(ImmutableList.of(new ClassifierInstanceBuilder()
@@ -215,20 +206,11 @@ public class OfTableTest {
     protected EndpointBuilder remoteEP(NodeId id) {
         OfOverlayContext ofc = new OfOverlayContextBuilder()
             .setNodeId(id)
-            .setNodeConnectorId(new NodeConnectorId(id.getValue() + ":1"))
+            .setNodeConnectorId(new NodeConnectorId(id.getValue() + ":5"))
             .build();
         return baseEP()
+            .setMacAddress(new MacAddress("00:00:00:00:00:02"))
             .addAugmentation(OfOverlayContext.class, ofc);
     }
     
-    protected ReadWriteTransaction dosync(Map<String, FlowCtx> flowMap) 
-              throws Exception {
-        ReadWriteTransaction t = mock(ReadWriteTransaction.class);
-        if (flowMap == null)
-            flowMap = Collections.emptyMap();
-        table.sync(t, tiid, flowMap, nodeId, policyResolver.getCurrentPolicy(), 
-                   null);
-        return t;
-    }
-
 }
index 33922fe87e18d82dfa74029e5e48fee503459c51..cb4e264346864ec3c9431e3edb4d2af57bce434b 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Objects;
 
@@ -18,11 +19,16 @@ import org.mockito.Matchers;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfigBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +39,9 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class PolicyEnforcerTest extends OfTableTest {
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
+public class PolicyEnforcerTest extends FlowTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(PolicyEnforcerTest.class);
 
@@ -42,13 +50,19 @@ public class PolicyEnforcerTest extends OfTableTest {
         initCtx();
         table = new PolicyEnforcer(ctx);
         super.setup();
+        
+        switchManager.addSwitch(nodeId, tunnelId, 
+                                Collections.<NodeConnectorId>emptySet(),
+                                new OfOverlayNodeConfigBuilder()
+                                    .setTunnelIp(new IpAddress(new Ipv4Address("1.2.3.4")))
+                                    .build());
     }
     
 
     @Test
     public void testNoEps() throws Exception {
         ReadWriteTransaction t = dosync(null);
-        verify(t, times(1)).put(any(LogicalDatastoreType.class), 
+        verify(t, times(2)).put(any(LogicalDatastoreType.class), 
                                 Matchers.<InstanceIdentifier<Flow>>any(), 
                                 any(Flow.class), anyBoolean());
     }
@@ -72,7 +86,6 @@ public class PolicyEnforcerTest extends OfTableTest {
         HashMap<String, FlowCtx> flowMap = new HashMap<>();
         for (Flow f : ac.getAllValues()) {
             flowMap.put(f.getId().getValue(), new FlowCtx(f));
-            // XXX - TODO check actual match/action
             if (f.getId().getValue().indexOf("intraallow") == 0)
                 count += 1;
         }
@@ -113,6 +126,11 @@ public class PolicyEnforcerTest extends OfTableTest {
             flowMap.put(f.getId().getValue(), new FlowCtx(f));
             if (f.getId().getValue().indexOf("intraallow") == 0) {
                 count += 1;
+            } else if (f.getMatch() != null &&
+                       Objects.equals(tunnelId, f.getMatch().getInPort())) {
+                assertEquals(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))),
+                             f.getInstructions());
+                count += 1;
             } else if (f.getMatch() != null &&
                        f.getMatch().getEthernetMatch() != null &&
                        Objects.equals(FlowUtils.IPv4,
@@ -124,7 +142,6 @@ public class PolicyEnforcerTest extends OfTableTest {
                        Objects.equals(Integer.valueOf(80),
                                       ((TcpMatch)f.getMatch().getLayer4Match())
                                           .getTcpDestinationPort().getValue())) {
-                // XXX - TODO - verify sepg/depg
                 count += 1;
             } else if (f.getMatch() != null &&
                        f.getMatch().getEthernetMatch() != null &&
@@ -137,14 +154,13 @@ public class PolicyEnforcerTest extends OfTableTest {
                        Objects.equals(Integer.valueOf(80),
                                       ((TcpMatch)f.getMatch().getLayer4Match())
                                           .getTcpDestinationPort().getValue())) {
-                // XXX - TODO - verify sepg/depg
                 count += 1;
-            }
+            } 
         }
         if (direction == null || direction.equals(Direction.Bidirectional))
-            assertEquals(6, count);
+            assertEquals(7, count);
         else
-            assertEquals(4, count);
+            assertEquals(5, count);
 
         t = dosync(flowMap);
         verify(t, never()).put(any(LogicalDatastoreType.class), 
index 5ab797f000b39c4000d7c07471cbf20528f52ca0..de066cda3a022704b0abadd4b42536a9f824f367 100644 (file)
@@ -47,7 +47,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class PortSecurityTest extends OfTableTest {
+public class PortSecurityTest extends FlowTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(PortSecurityTest.class);
     
index 5bd8e3783e4740e7b0e6c08c164d00d3ea7c174a..ef71152bac22f9baef9f9bdaf74a9c6833068fb3 100644 (file)
@@ -8,7 +8,9 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
+import java.math.BigInteger;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Objects;
 
 import org.junit.Before;
@@ -18,8 +20,20 @@ import org.mockito.Matchers;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,7 +44,7 @@ import static org.mockito.Matchers.*;
 
 import static org.mockito.Mockito.*;
 
-public class SourceMapperTest extends OfTableTest {
+public class SourceMapperTest extends FlowTableTest {
     protected static final Logger LOG = 
             LoggerFactory.getLogger(SourceMapperTest.class);
     @Before
@@ -72,8 +86,33 @@ public class SourceMapperTest extends OfTableTest {
             } else if (Objects.equals(ep.getMacAddress(),
                                f.getMatch().getEthernetMatch()
                                    .getEthernetSource().getAddress())) {
-                // XXX TODO verify register setting in the instructions
-                LOG.info("{}", f);
+                PolicyInfo pi = policyResolver.getCurrentPolicy();
+                List<ConditionName> cset = endpointManager.getCondsForEndpoint(ep);
+                ConditionGroup cg = pi.getEgCondGroup(new EgKey(tid, eg), cset);
+                
+                Instruction ins = f.getInstructions().getInstruction().get(0);
+                assertTrue(ins.getInstruction() instanceof ApplyActionsCase);
+                List<Action> actions = ((ApplyActionsCase)ins.getInstruction()).getApplyActions().getAction();
+                int v = policyManager.getContextOrdinal(tid, eg);
+                assertEquals(FlowUtils.nxLoadRegAction(NxmNxReg0.class, 
+                                                       BigInteger.valueOf(v)),
+                             actions.get(0).getAction());
+                v = policyManager.getCondGroupOrdinal(cg);
+                assertEquals(FlowUtils.nxLoadRegAction(NxmNxReg1.class, 
+                                                       BigInteger.valueOf(v)),
+                             actions.get(1).getAction());
+                v = policyManager.getContextOrdinal(tid, bd);
+                assertEquals(FlowUtils.nxLoadRegAction(NxmNxReg4.class, 
+                                                       BigInteger.valueOf(v)),
+                             actions.get(2).getAction());
+                v = policyManager.getContextOrdinal(tid, fd);
+                assertEquals(FlowUtils.nxLoadRegAction(NxmNxReg5.class, 
+                                                       BigInteger.valueOf(v)),
+                             actions.get(3).getAction());
+                v = policyManager.getContextOrdinal(tid, l3c);
+                assertEquals(FlowUtils.nxLoadRegAction(NxmNxReg6.class, 
+                                                       BigInteger.valueOf(v)),
+                             actions.get(4).getAction());
                 count += 1;
             }
         }
diff --git a/pom.xml b/pom.xml
index 696bc0cb90154ffa174ebe7750062ff456d6eb30..4a26a389ffc1c09eed407bd5a77648caa5f1a2f7 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -19,6 +19,7 @@
     <module>groupbasedpolicy</module>
     <module>distribution</module>
   </modules>
+
   <build>
     <plugins>
       <plugin>
diff --git a/util/testOfOverlay/.gitignore b/util/testOfOverlay/.gitignore
new file mode 100644 (file)
index 0000000..0d20b64
--- /dev/null
@@ -0,0 +1 @@
+*.pyc
diff --git a/util/testOfOverlay/config.py b/util/testOfOverlay/config.py
new file mode 100644 (file)
index 0000000..4f6875d
--- /dev/null
@@ -0,0 +1,72 @@
+
+
+TENANT="f5c7d344-d1c7-4208-8531-2c2693657e12"
+L3CTX="f2311f52-890f-4095-8b85-485ec8b92b3c"
+L2BD="70aeb9ea-4ca1-4fb9-9780-22b04b84a0d6"
+
+L2FD1="252fbac6-bb6e-4d16-808d-6f56d20e5cca"
+EG1="1eaf9a67-a171-42a8-9282-71cf702f61dd"
+L2FD2="cb5249bb-e896-45be-899d-4cdd9354b58e"
+EG2="e593f05d-96be-47ad-acd5-ba81465680d5"
+
+CONTRACT="22282cca-9a13-4d0c-a67e-a933ebb0b0ae"
+
+switches = [{'name': 's1',
+             'tunnelIp': '10.160.9.20',
+             'dpid': '1'},
+            {'name': 's2',
+             'tunnelIp': '10.160.9.21',
+             'dpid': '2'}]
+
+hosts = [{'name': 'h35_2',
+          'mac': '00:00:00:00:35:02',
+          'ip': '10.0.35.2/24',
+          'switch': 's1',
+          'tenant': TENANT,
+          'endpointGroup': EG1},
+         {'name': 'h35_3',
+          'ip': '10.0.35.3/24',
+          'mac': '00:00:00:00:35:03',
+          'switch': 's1',
+          'tenant': TENANT,
+          'endpointGroup': EG1},
+         {'name': 'h35_4',
+          'ip': '10.0.35.4/24',
+          'mac': '00:00:00:00:35:04',
+          'switch': 's2',
+          'tenant': TENANT,
+          'endpointGroup': EG1},
+         {'name': 'h35_5',
+          'ip': '10.0.35.5/24',
+          'mac': '00:00:00:00:35:05',
+          'switch': 's2',
+          'tenant': TENANT,
+          'endpointGroup': EG1},
+         {'name': 'h36_2',
+          'ip': '10.0.36.2/24',
+          'mac': '00:00:00:00:36:02',
+          'switch': 's1',
+          'tenant': TENANT,
+          'endpointGroup': EG2},
+         {'name': 'h36_3',
+          'ip': '10.0.36.3/24',
+          'mac': '00:00:00:00:36:03',
+          'switch': 's1',
+          'tenant': TENANT,
+          'endpointGroup': EG2},
+         {'name': 'h36_4',
+          'ip': '10.0.36.4/24',
+          'mac': '00:00:00:00:36:04',
+          'switch': 's2',
+          'tenant': TENANT,
+          'endpointGroup': EG2},
+         {'name': 'h36_5',
+          'ip': '10.0.36.5/24',
+          'mac': '00:00:00:00:36:05',
+          'switch': 's2',
+          'tenant': TENANT,
+          'endpointGroup': EG2}]
+
+contracts = [{'consumer': EG1,
+              'provider': EG2,
+              'id': CONTRACT}]
diff --git a/util/testOfOverlay/mininet_gbp.py b/util/testOfOverlay/mininet_gbp.py
new file mode 100644 (file)
index 0000000..7a47a26
--- /dev/null
@@ -0,0 +1,81 @@
+
+from mininet.topo import Topo
+from mininet.node import RemoteController
+from mininet.net import Mininet
+from mininet.util import dumpNodeConnections
+from mininet.log import setLogLevel
+from mininet.node import Node
+
+import re
+import time
+from subprocess import call
+from subprocess import check_output
+
+def addSwitch(net, name, dpid=None):
+    switch = net.addSwitch(name, dpid=dpid)
+    return switch
+
+def addHost(net, switch, name, ip, mac):
+    host = net.addHost(name, ip=ip, mac=mac)
+    net.addLink(host, switch)
+
+def setOFVersion(sw, version='OpenFlow13'):
+    call(['ovs-vsctl', 'set', 'bridge', sw, 'protocols={}'.format(version)])
+
+def addTunnel(sw, sourceIp=None):
+    ifaceName = '{}_vxlan0'.format(sw)
+    cmd = ['ovs-vsctl', 'add-port', sw, ifaceName,
+           '--', 'set', 'Interface', ifaceName,
+           'type=vxlan', 
+           'options:remote_ip=flow',
+           'options:key=flow']
+    if sourceIp is not None:
+        cmd.append('options:source_ip={}'.format(sourceIp))
+    call(cmd)
+
+#ovs-ofctl dump-ports-desc s1 -OOpenFlow13
+
+def startMininet(switches, hosts, contIP='127.0.0.1'):
+    setLogLevel('info')
+
+    net = Mininet(controller=None,
+                  autoSetMacs=True,
+                  listenPort=6634)
+    net.addController('c0', controller=RemoteController, 
+                      ip=contIP, port=6653)
+
+    swobjs = {}
+    swports = {}
+
+    for sw in switches:
+        swobj = addSwitch(net, sw['name'])
+        swobjs[sw['name']] = swobj
+        swports[sw['name']] = 0;
+    for host in hosts:
+        if host['switch'] not in swobjs:
+            continue
+        sw = swobjs[host['switch']]
+        swports[host['switch']] += 1;
+        port = swports[host['switch']]
+        addHost(net, sw, host['name'], host['ip'], host['mac'])
+        host['port'] = port
+
+    try:
+        net.start()
+        for sw in switches:
+            addTunnel(sw['name'], sw['tunnelIp'])
+
+        for host in net.hosts:
+            gw = re.sub(r'.\d+$', ".1", host.IP())
+            host.cmd('route add default gw {}'.format(gw))
+
+        # ODL is very fragile so let's give it some time
+        time.sleep(1)
+
+        for sw in switches:
+            setOFVersion(sw['name'])
+
+        return net
+    except Exception, e:
+        net.stop()
+        raise e
diff --git a/util/testOfOverlay/odl_gbp.py b/util/testOfOverlay/odl_gbp.py
new file mode 100644 (file)
index 0000000..c812b55
--- /dev/null
@@ -0,0 +1,195 @@
+
+import requests,json
+
+REGISTER_EP_URL="http://%s:8080/restconf/operations/endpoint:register-endpoint"
+REGISTER_TENANTS_URL="http://%s:8080/restconf/config/policy:tenants"
+REGISTER_NODES_URL="http://%s:8080/restconf/config/opendaylight-inventory:nodes"
+
+endpointGroups = {}
+
+def get_epg(tenantId, epgId):
+    k = "{}|{}".format(tenantId,epgId)
+    if k in endpointGroups:
+        return endpointGroups[k]
+    tenant = get_tenant(tenantId);
+    data = {
+        "id": epgId,
+        "consumer-named-selector": [],
+        "provider-named-selector": []
+    }
+    tenant["endpoint-group"].append(data)
+    endpointGroups[k] = data
+    return data
+
+tenants = {}
+
+def get_tenant(tenantId):
+    if tenantId in tenants: 
+        return tenants[tenantId]
+    data = {
+        "id": tenantId,
+        "l3-context": [],
+        "l2-bridge-domain": [],
+        "l2-flood-domain": [],
+        "subnet": [],
+        "endpoint-group": [],
+        "contract": [],
+        "subject-feature-instances": {
+            "classifier-instance": [
+                {"name": "http-dest",
+                "classifier-definition-id": "4250ab32-e8b8-445a-aebb-e1bd2cdd291f",
+                "parameter-value": [
+                    {"name": "type",
+                     "string-value": "TCP"}, 
+                    {"name": "destport",
+                     "int-value": "80"}
+                ]},
+                {"name": "http-src",
+                "classifier-definition-id": "4250ab32-e8b8-445a-aebb-e1bd2cdd291f",
+                "parameter-value": [
+                    {"name": "type",
+                     "string-value": "TCP"}, 
+                    {"name": "sourceport",
+                     "int-value": "80"}
+                ]},
+                {"name": "icmp",
+                "classifier-definition-id": "79c6fdb2-1e1a-4832-af57-c65baf5c2335",
+                "parameter-value": [
+                    {"name": "proto",
+                     "int-value": "1"}
+                ]},
+            ]
+        }
+    }
+    tenants[tenantId] = data
+    return data
+
+subnets = {}
+
+def get_fd(tenantId, fdId, parent):
+    tenant = get_tenant(tenantId)
+    data = {"id": fdId, 
+            "parent": parent}
+    tenant["l2-flood-domain"].append(data)
+    return data
+
+def get_bd(tenantId, bdId, parent):
+    tenant = get_tenant(tenantId)
+    data = {"id": bdId, 
+            "parent": parent}
+    tenant["l2-bridge-domain"].append(data)
+    return data
+
+def get_l3c(tenantId, l3cId):
+    tenant = get_tenant(tenantId)
+    data = {"id": l3cId}
+    tenant["l3-context"].append(data)
+    return data
+
+def get_subnet(tenantId, subnetId, parent, prefix, router):
+    k = "{}|{}".format(tenantId, subnetId)
+    if k in subnets:
+        return subnets[k]
+    tenant = get_tenant(tenantId)
+    data = {"id": subnetId, 
+            "parent": parent,
+            "ip-prefix": prefix,
+            "virtual-router-ip": router}
+    tenant["subnet"].append(data)
+    return data
+
+endpoints = []
+
+def get_ep(tenantId, groupId, l3ctx, ip, l2ctx, mac, sw, port):
+    group = get_epg(tenantId, groupId)
+    data = {"tenant": tenantId,
+            "endpoint-group": groupId,
+            "l2-context": l2ctx, 
+            "mac-address": mac, 
+            "l3-address": [{"l3-context": l3ctx,
+                            "ip-address": ip}], 
+            "ofoverlay:node-id": "openflow:{}".format(sw), 
+            "ofoverlay:node-connector-id": "openflow:{}:{}".format(sw, port)
+        }
+    endpoints.append(data)
+    return data
+
+nodes = []
+
+def get_node_config(sw, tun_ip):
+    data = {
+        "id": "openflow:{}".format(sw),
+        "ofoverlay:tunnel-ip": tun_ip
+    }
+    nodes.append(data)
+    return data
+
+def get_contract(tenantId, pgroupId, cgroupId, contractId):
+    tenant = get_tenant(tenantId)
+    pgroup = get_epg(tenantId, pgroupId)
+    cgroup = get_epg(tenantId, cgroupId)
+    data = {
+        "id": contractId,
+        "subject": [{"name": "allow-http-subject",
+                     "rule": [
+                         {"name": "allow-http-rule",
+                          "classifier-ref": [
+                              {"name": "http-dest",
+                               "direction": "in"},
+                              {"name": "http-src",
+                               "direction": "out"}
+                          ]}
+                     ]},
+                    {"name": "allow-icmp-subject",
+                     "rule": [
+                         {"name": "allow-icmp-rule",
+                          "classifier-ref": [
+                              {"name": "icmp"}
+                          ]}
+                     ]}],
+        "clause": [{"name": "allow-http-clause",
+                    "subject-refs": ["allow-http-subject", 
+                                     "allow-icmp-subject"]}]
+    }
+    tenant["contract"].append(data)
+    cgroup["consumer-named-selector"].append({
+        "name": "{}-{}-{}".format(pgroupId, cgroupId, contractId),
+        "contract": [contractId]
+    })
+    pgroup["provider-named-selector"].append({
+        "name": "{}-{}-{}".format(pgroupId, cgroupId, contractId),
+        "contract": [contractId]
+    })
+
+    return data
+
+def post(url, data):
+    headers = {'Content-type': 'application/yang.data+json',
+               'Accept': 'application/yang.data+json'}
+    print "POST %s" % url
+    print json.dumps(data, indent=4, sort_keys=True)
+    r = requests.post(url, data=json.dumps(data), headers=headers)
+    print r.text
+    r.raise_for_status()
+
+def put(url, data):
+    headers = {'Content-type': 'application/yang.data+json',
+               'Accept': 'application/yang.data+json'}
+    print "PUT %s" % url
+    print json.dumps(data, indent=4, sort_keys=True)
+    r = requests.put(url, data=json.dumps(data), headers=headers)
+    print r.text
+    r.raise_for_status()
+
+def register_tenants(contHost):
+    data = {"policy:tenants": {"tenant": tenants.values()}}
+    put(REGISTER_TENANTS_URL % contHost, data)
+
+def register_eps(contHost):
+    for ep in endpoints:
+       data = {"input": ep}
+       post(REGISTER_EP_URL % contHost, data)
+
+def register_nodes(contHost):
+    data = {"opendaylight-inventory:nodes": {"node": nodes}}
+    put(REGISTER_NODES_URL % contHost, data)
diff --git a/util/testOfOverlay/testOfOverlay.py b/util/testOfOverlay/testOfOverlay.py
new file mode 100755 (executable)
index 0000000..e2f54dc
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+
+import mininet_gbp
+import odl_gbp
+import mininet.cli
+import ipaddr
+import uuid
+import re
+import argparse, sys
+from config import *
+
+def getSubnet(ip):
+    nw = ipaddr.IPv4Network(ip)
+    return "{}/{}".format(nw.network + 1, nw.prefixlen)
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--local',
+                        help='Set up distributed mininet on local host with the specified switch')
+    parser.add_argument('--policy', action='store_true',
+                        help='Configure the policy on the controller')
+    parser.add_argument('--controller', default='127.0.0.1',
+                        help='Use the specified controller IP address')
+    args = parser.parse_args()
+
+    if (not args.local and not args.policy):
+        parser.print_help()
+        sys.exit(3)
+
+    conf_switches = []
+    if args.local:
+        for switch in switches:
+            if switch['name'] == args.local:
+                conf_switches = [switch]
+                break
+    net = None
+    if len(conf_switches) > 0:
+        net = mininet_gbp.startMininet(conf_switches, hosts, args.controller)
+    try :
+        if args.policy:
+            for switch in switches:
+                odl_gbp.get_node_config(switch['dpid'], switch['tunnelIp'])
+                
+            odl_gbp.register_nodes(args.controller)
+
+        tenant = odl_gbp.get_tenant(TENANT)
+        odl_gbp.get_l3c(TENANT, L3CTX)
+        odl_gbp.get_bd(TENANT, L2BD, L3CTX)
+       
+        subnets = {}
+        fds = {}
+        for host in hosts:
+            if args.local and host['switch'] != args.local:
+                continue
+            nw = ipaddr.IPv4Network(host['ip'])
+            snet = "{}/{}".format(nw.network + 1, nw.prefixlen)
+            router = "{}".format(nw.network + 1)
+        
+            if snet not in subnets:
+                 snid = str(uuid.uuid4())
+                 fdid = str(uuid.uuid4())
+                 fds[fdid] = odl_gbp.get_fd(TENANT, fdid, L2BD)
+        
+                 subnets[snet] = odl_gbp.get_subnet(TENANT, snid, fdid, snet, router)
+                 odl_gbp.get_epg(TENANT, host['endpointGroup'])["network-domain"] = snid
+        
+            odl_gbp.get_ep(TENANT, 
+                           host['endpointGroup'], 
+                           L3CTX, 
+                           re.sub(r'/\d+$', '', host['ip']),
+                           L2BD,
+                           host['mac'], 
+                           int(net.get(host['switch']).dpid), host['port'])
+        
+        for contract in contracts:
+             odl_gbp.get_contract(TENANT, 
+                          contract['provider'], contract['consumer'], 
+                          contract['id'])
+        
+        if args.policy:
+            odl_gbp.register_tenants(args.controller)
+
+        odl_gbp.register_eps(args.controller)
+
+        if net is not None:
+            mininet.cli.CLI(net)
+    finally:
+        if net is not None:
+            net.stop()