Add chain egress classifier support 64/60764/5
authorJaime Caamaño Ruiz <jaime.caamano.ruiz@ericsson.com>
Fri, 14 Jul 2017 17:10:51 +0000 (19:10 +0200)
committerSam Hague <shague@redhat.com>
Mon, 7 Aug 2017 20:15:18 +0000 (20:15 +0000)
On scenarios where origin and destination of traffic are on the same
node, there is no tunnel id metadata to help steer the traffic back
to the destination on chain egress, thus SFC cannot take care of
this by itself. In a general case, the classifier is in a better
position to steer traffic to destination as it is aware on how it
was intercepted on the first place.

For netvirt classifier and the scenario mentioned above, the
classifier will copy the REG6 to NSH C4 on interception. On chain
egress, SFC will send the encapsulated packet back to the origin node
(only when C2 is 0, which will only happen when origin and destination
node are the same). There, the classifier will restore the
de-encapsulated packet to the egress dispatcher table with the proper
REG6 value taken from NSH C4. REG6 contains the the egress ifindex plus
the nex egress service in sequence from the classifier egress service
to handle the packet. This effectively restore the packet processing
where it left off on interception.

Change-Id: I1c494f24c5af530849faabcbfa8efcaa9cd4344a
Signed-off-by: Jaime Caamaño Ruiz <jaime.caamano.ruiz@ericsson.com>
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/OpenflowRenderer.java
vpnservice/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/OpenFlow13Utils.java
vpnservice/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProviderTest.java
vpnservice/sfc/classifier/impl/src/test/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13ProviderTest.java

index 542e04815446450c53b6453d3981cba59e3f39fa..7d23246868fb1edd1522b3b0e45b0daa41d8c24c 100644 (file)
@@ -148,33 +148,16 @@ public class GeniusProvider {
         return Optional.of(new NodeId("openflow:" + dpnId.getValue()));
     }
 
-    public Optional<String> getIpFromInterfaceName(String interfaceName) {
-        Optional<DpnIdType> dpnId = getDpnIdFromInterfaceName(interfaceName);
-        if (!dpnId.isPresent()) {
-            LOG.warn("getIpFromInterfaceName empty dpnId for interfaceName [{}]", interfaceName);
-            return Optional.empty();
-        }
-
-        List<IpAddress> ipList = getIpFromDpnId(dpnId.get());
-        if (ipList.isEmpty()) {
-            LOG.warn("getIpFromInterfaceName empty ipList for interfaceName [{}]", interfaceName);
-            return Optional.empty();
-        }
-
-        // TODO need to figure out why it returns a list, using first entry for now
-        return Optional.ofNullable(ipList.get(0).getIpv4Address().getValue());
-    }
-
     // TODO Should better use the Genius InterfaceManager to avoid duplicate code
     //      https://bugs.opendaylight.org/show_bug.cgi?id=8127
-    public List<IpAddress> getIpFromDpnId(DpnIdType dpnid) {
+    public Optional<String> getIpFromDpnId(DpnIdType dpnid) {
         GetEndpointIpForDpnInputBuilder builder = new GetEndpointIpForDpnInputBuilder();
         builder.setDpid(dpnid.getValue());
         GetEndpointIpForDpnInput input = builder.build();
 
         if (interfaceManagerRpcService == null) {
             LOG.error("getIpFromDpnId({}) failed (service couldn't be retrieved)", input);
-            return Collections.emptyList();
+            return Optional.empty();
         }
 
         try {
@@ -182,18 +165,22 @@ public class GeniusProvider {
             RpcResult<GetEndpointIpForDpnOutput> output = interfaceManagerRpcService.getEndpointIpForDpn(input).get();
             if (!output.isSuccessful()) {
                 LOG.error("getIpFromDpnId({}) failed: {}", input, output);
-                return Collections.emptyList();
+                return Optional.empty();
             }
-            List<IpAddress> localIps = output.getResult().getLocalIps();
             LOG.debug("getDpnIdFromInterfaceName({}) succeeded: {}", input, output);
-            if (localIps != null) {
-                return localIps;
-            }
+            List<IpAddress> localIps = output.getResult().getLocalIps();
+
+            // TODO need to figure out why it returns a list, using first entry for now
+            return Optional.ofNullable(localIps)
+                    .filter(ipAddresses -> !ipAddresses.isEmpty())
+                    .map(ipAddresses -> ipAddresses.get(0))
+                    .map(IpAddress::getIpv4Address)
+                    .map(Ipv4Address::getValue);
         } catch (InterruptedException | ExecutionException e) {
             LOG.error("getDpnIdFromInterfaceName failed to retrieve target interface name: ", e);
         }
 
-        return Collections.emptyList();
+        return Optional.empty();
     }
 
     public Optional<DpnIdType> getDpnIdFromInterfaceName(String interfaceName) {
index f0d35c907e29bdc5687dd42c88d4217c030f2d85..099aba57f89b7377604ec8ed48a148f65ce9ad9a 100644 (file)
@@ -42,6 +42,7 @@ public class OpenFlow13Provider {
     public static final BigInteger EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE = new BigInteger("F005BA1100000005", 16);
 
     // Priorities for each flow
+    public static final int INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY = 520;
     public static final int INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 510;
     public static final int INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 500;
     public static final int INGRESS_CLASSIFIER_ACL_PRIORITY = 500;
@@ -54,6 +55,8 @@ public class OpenFlow13Provider {
     public static final int EGRESS_CLASSIFIER_EGRESS_REMOTE_PRIORITY = 250;
 
     // Flow names for each table
+    public static final String INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME =
+            "nvsfc_ingr_class_filter_chain_egress";
     public static final String INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME = "nvsfc_ingr_class_filter_vxgpe";
     public static final String INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME = "nvsfc_ingr_class_filter_eth";
     public static final String INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_ingr_class_filter_nonsh";
@@ -145,6 +148,31 @@ public class OpenFlow13Provider {
             INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME, flowIdStr, match, isb).build();
     }
 
+    /*
+     * Classifier chain termination flow:
+     *     Handle packets at the end of the chain
+     *     Match C1 on local IP, NSP and ending NSI, restore metadata and
+     *     resubmit to egress dispatcher
+     */
+    public Flow createIngressClassifierFilterChainEgressFlow(NodeId nodeId, long nsp) {
+
+        MatchBuilder match = new MatchBuilder();
+        OpenFlow13Utils.addMatchNsp(match, nsp);
+
+        List<Action> actionList = new ArrayList<>();
+        actionList.add(OpenFlow13Utils.createActionNxMoveNsc4ToReg6Register(actionList.size()));
+        actionList.add(OpenFlow13Utils.createActionNxPopNsh(actionList.size()));
+        actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
+                actionList.size()));
+
+        InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
+        String flowIdStr = INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
+
+        return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
+                INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
+                INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME, flowIdStr, match, isb).build();
+    }
+
     /*
      * Ingress Classifier Filter No NSH flow:
      *     Only allows Non-NSH packets to proceed in the classifier
@@ -281,6 +309,7 @@ public class OpenFlow13Provider {
         List<Action> actionList = new ArrayList<>();
         actionList.add(OpenFlow13Utils.createActionNxMoveReg0ToNsc1Register(actionList.size()));
         actionList.add(OpenFlow13Utils.createActionNxMoveTunIdToNsc2Register(actionList.size()));
+        actionList.add(OpenFlow13Utils.createActionNxMoveReg6ToNsc4Register(actionList.size()));
         actionList.add(OpenFlow13Utils.createActionNxLoadTunId(SFC_TUNNEL_ID, actionList.size()));
 
         InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
index b1114dc68eda42a5eeefeaad30b9096cf7d06c28..7405d1de248f4dc421e868da49f6dd485f72642b 100644 (file)
@@ -35,8 +35,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.sfc.acl.rev150105.NetvirtsfcAclActions;
@@ -53,6 +51,7 @@ public class ConfigurationClassifierImpl implements ClassifierState {
     private final GeniusProvider geniusProvider;
     private final NetvirtProvider netvirtProvider;
     private static final Logger LOG = LoggerFactory.getLogger(ConfigurationClassifierImpl.class);
+    private static final String LOCAL_HOST_IP = "127.0.0.1";
 
     public ConfigurationClassifierImpl(GeniusProvider geniusProvider,
                                        NetvirtProvider netvirtProvider,
@@ -115,15 +114,16 @@ public class ConfigurationClassifierImpl implements ClassifierState {
             return Collections.emptySet();
         }
 
-        String firstHopIp = sfcProvider.getFirstHopSfInterfaceFromRsp(rsp)
-                .flatMap(geniusProvider::getIpFromInterfaceName)
+        DpnIdType firstHopDpn = sfcProvider.getFirstHopSfInterfaceFromRsp(rsp)
+                .flatMap(geniusProvider::getDpnIdFromInterfaceName)
                 .orElse(null);
 
-        if (firstHopIp == null) {
-            LOG.trace("Could not acquire a valid first RSP hop destination ip");
+        if (firstHopDpn == null) {
+            LOG.error("RSP has no valid first hop DPN");
             return Collections.emptySet();
         }
 
+
         Map<NodeId, List<InterfaceKey>> nodeToInterfaces = new HashMap<>();
         NeutronNetwork neutronNetwork = matches.getAugmentation(NeutronNetwork.class);
         if (neutronNetwork != null) {
@@ -136,19 +136,15 @@ public class ConfigurationClassifierImpl implements ClassifierState {
 
         LOG.trace("Got classifier nodes and interfaces: {}", nodeToInterfaces);
 
+        String firstHopIp = geniusProvider.getIpFromDpnId(firstHopDpn).orElse(null);
         Set<ClassifierRenderableEntry> entries = new HashSet<>();
         nodeToInterfaces.forEach((nodeId, ifaces) -> {
             // Get node info
-            DpnIdType dpnIdType = new DpnIdType(OpenFlow13Provider.getDpnIdFromNodeId(nodeId));
-            List<String> nodeIps = geniusProvider.getIpFromDpnId(dpnIdType).stream()
-                    .map(IpAddress::getIpv4Address)
-                    .filter(Objects::nonNull)
-                    .map(Ipv4Address::getValue)
-                    .collect(Collectors.toList());
-            String nodeIp = nodeIps.isEmpty() ? null : nodeIps.get(0);
-
-            if (nodeIp == null) {
-                LOG.trace("Could not get IP address for node {}, skipping", nodeId.getValue());
+            DpnIdType nodeDpn = new DpnIdType(OpenFlow13Provider.getDpnIdFromNodeId(nodeId));
+            String nodeIp = geniusProvider.getIpFromDpnId(nodeDpn).orElse(LOCAL_HOST_IP);
+
+            if (firstHopIp == null && !nodeDpn.equals(firstHopDpn)) {
+                LOG.warn("Classifier on node {} has no IP to reach first hop on node {}", nodeDpn, firstHopDpn);
                 return;
             }
 
@@ -157,7 +153,7 @@ public class ConfigurationClassifierImpl implements ClassifierState {
             entries.add(ClassifierEntry.buildPathEntry(
                     nodeId,
                     nsp,
-                    nodeIps.contains(firstHopIp) ? null : firstHopIp));
+                    nodeDpn.equals(firstHopDpn) ? null : firstHopIp));
 
             // Add entries based on ingress interface
             ifaces.forEach(interfaceKey -> {
index e33ba9267d08b447b6310371f6da164fa5d9a8a8..e1b8ee5ca75a8b0f8d4d0c52c484c46155b979ff 100644 (file)
@@ -63,20 +63,26 @@ public class OpenflowRenderer implements ClassifierEntryRenderer {
 
     @Override
     public void renderPath(NodeId nodeId, Long nsp, String firstHopIp) {
-        Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId))
-                .orElse(null);
 
-        if (port == null) {
-            LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue());
-            return;
+        List<Flow> flows = new ArrayList<>();
+        if (firstHopIp != null) {
+            Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId))
+                    .orElse(null);
+            if (port == null) {
+                LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue());
+                return;
+            }
+            Flow flow;
+            flow = openFlow13Provider.createEgressClassifierTransportEgressRemoteFlow(nodeId, nsp, port, firstHopIp);
+            flows.add(flow);
+        } else {
+            Flow flow;
+            flow = openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp);
+            flows.add(flow);
         }
-
-        Flow flow = firstHopIp == null
-                ? openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp)
-                : openFlow13Provider.createEgressClassifierTransportEgressRemoteFlow(nodeId, nsp, port, firstHopIp);
-
+        flows.add(openFlow13Provider.createIngressClassifierFilterChainEgressFlow(nodeId, nsp));
         WriteTransaction tx = this.dataBroker.newWriteOnlyTransaction();
-        this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx);
+        flows.forEach(flow -> this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx));
         tx.submit();
     }
 
@@ -121,20 +127,25 @@ public class OpenflowRenderer implements ClassifierEntryRenderer {
 
     @Override
     public void suppressPath(NodeId nodeId, Long nsp, String firstHopIp) {
-        Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId))
-                .orElse(null);
-
-        if (port == null) {
-            LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue());
-            return;
+        List<Flow> flows = new ArrayList<>();
+        if (firstHopIp != null) {
+            Long port = geniusProvider.getEgressVxlanPortForNode(OpenFlow13Provider.getDpnIdFromNodeId(nodeId))
+                    .orElse(null);
+            if (port == null) {
+                LOG.error("OpenflowRenderer: cant get egressPort for nodeId [{}]", nodeId.getValue());
+                return;
+            }
+            Flow flow;
+            flow = openFlow13Provider.createEgressClassifierTransportEgressRemoteFlow(nodeId, nsp, port, firstHopIp);
+            flows.add(flow);
+        } else {
+            Flow flow;
+            flow = openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp);
+            flows.add(flow);
         }
-
-        Flow flow = firstHopIp == null
-                ? openFlow13Provider.createEgressClassifierTransportEgressLocalFlow(nodeId, nsp)
-                : openFlow13Provider.createEgressClassifierTransportEgressRemoteFlow(nodeId, nsp, port, firstHopIp);
-
+        flows.add(openFlow13Provider.createIngressClassifierFilterChainEgressFlow(nodeId, nsp));
         WriteTransaction tx = this.dataBroker.newWriteOnlyTransaction();
-        this.openFlow13Provider.appendFlowForCreate(nodeId, flow, tx);
+        flows.forEach(flow -> this.openFlow13Provider.appendFlowForDelete(nodeId, flow, tx));
         tx.submit();
     }
 
index b22ebb87d5e321ccdb3fc1d2e5b12e4f30075904..1f76f58deb06b3f998ea353b15b7058d5087c303 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 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.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;
@@ -44,6 +45,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshNpCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
@@ -51,10 +53,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 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.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.NxActionPopNshNodesNodeTableFlowApplyActionsCaseBuilder;
 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.NxActionPushNshNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.write.actions._case.write.actions.action.action.NxActionResubmitNodesNodeTableFlowWriteActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.pop.nsh.grouping.NxPopNsh;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.pop.nsh.grouping.NxPopNshBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.push.nsh.grouping.NxPushNsh;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.push.nsh.grouping.NxPushNshBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
@@ -66,6 +71,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.SrcBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.resubmit.grouping.NxResubmitBuilder;
 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.SrcNxNshc4CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow;
@@ -113,6 +119,12 @@ public final class OpenFlow13Utils {
         match.setInPort(new NodeConnectorId(nodeId.getValue() + ":" + inPort));
     }
 
+    public static void addMatchNsp(MatchBuilder match, long nsp) {
+        NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
+                .setNxmNxNsp(new NxmNxNspBuilder().setValue(nsp).build()).build();
+        addExtension(match, NxmNxNspKey.class, am);
+    }
+
     public static void addMatchNshNsc1(MatchBuilder match, long nsc) {
         NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder()
             .setNxmNxNshc1(new NxmNxNshc1Builder().setValue(nsc).build()).build();
@@ -230,6 +242,16 @@ public final class OpenFlow13Utils {
         return ab.build();
     }
 
+    public static Action createActionNxPopNsh(int order) {
+        NxPopNshBuilder builder = new NxPopNshBuilder();
+        NxPopNsh nxPopNsh = builder.build();
+
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(new NxActionPopNshNodesNodeTableFlowApplyActionsCaseBuilder().setNxPopNsh(nxPopNsh).build());
+
+        return ab.build();
+    }
+
     public static Action createActionNxMoveTunIdToNsc2Register(int order) {
         ActionBuilder ab = createActionBuilder(order);
         ab.setAction(nxMoveRegAction(new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(),
@@ -246,6 +268,22 @@ public final class OpenFlow13Utils {
         return ab.build();
     }
 
+    public static Action createActionNxMoveReg6ToNsc4Register(int order) {
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(NxmNxReg6.class).build(),
+                new DstNxNshc4CaseBuilder().setNxNshc4Dst(Boolean.TRUE).build(), 31, false));
+
+        return ab.build();
+    }
+
+    public static Action createActionNxMoveNsc4ToReg6Register(int order) {
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(nxMoveRegAction(new SrcNxNshc4CaseBuilder().setNxNshc4Dst(Boolean.TRUE).build(),
+                new DstNxRegCaseBuilder().setNxReg(NxmNxReg6.class).build(), 31, false));
+
+        return ab.build();
+    }
+
     public static org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nxLoadRegAction(
         DstChoice dstChoice, BigInteger value, int endOffset, boolean groupBucket) {
         NxRegLoad regLoad = new NxRegLoadBuilder()
index d94d7d0d17568d2ba78126190a379b40abb13f97..856ea423b9ac4ac035d801948dd6c97690b6496f 100644 (file)
@@ -106,20 +106,20 @@ public class GeniusProviderTest extends ConstantSchemaAbstractDataBrokerTest {
     }
 
     @Test
-    public void getIpFromInterfaceName() {
+    public void getIpFromDpnId() {
         // Test that it correctly handles the case when the ifName doesnt exist
-        Optional<String> ipStr = this.geniusProvider.getIpFromInterfaceName(
-                GeniusProviderTestParams.INTERFACE_NAME_NO_EXIST);
+        Optional<String> ipStr = this.geniusProvider.getIpFromDpnId(
+                new DpnIdType(GeniusProviderTestParams.DPN_ID_NO_EXIST));
         assertFalse(ipStr.isPresent());
 
         // Test that it correctly handles RPC errors
-        ipStr = this.geniusProvider.getIpFromInterfaceName(
-                GeniusProviderTestParams.INTERFACE_NAME_INVALID);
+        ipStr = this.geniusProvider.getIpFromDpnId(
+                new DpnIdType(GeniusProviderTestParams.DPN_ID_INVALID));
         assertFalse(ipStr.isPresent());
 
         // Test that it correctly returns the ipStr when everything is correct
-        ipStr = this.geniusProvider.getIpFromInterfaceName(
-                GeniusProviderTestParams.INTERFACE_NAME);
+        ipStr = this.geniusProvider.getIpFromDpnId(
+                new DpnIdType(GeniusProviderTestParams.DPN_ID));
         assertTrue(ipStr.isPresent());
         assertEquals(ipStr.get(), GeniusProviderTestParams.IPV4_ADDRESS_STR);
     }
index 0156a508eba6ca482ec4d13173a3bb8fd25b30ce..cd4495210a178ddd2a1864fcd60c813c9288a35b 100644 (file)
@@ -32,7 +32,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.NxmNxReg6;
 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.general.extension.grouping.Extension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList;
@@ -40,17 +42,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshNpCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1Case;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2Case;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc4Case;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNsiCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNspCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCase;
+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.NxActionPopNshNodesNodeTableFlowApplyActionsCase;
 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.NxActionPushNshNodesNodeTableFlowApplyActionsCase;
 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.NxActionRegLoadNodesNodeTableFlowApplyActionsCase;
 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.NxActionRegMoveNodesNodeTableFlowApplyActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.write.actions._case.write.actions.action.action.NxActionResubmitNodesNodeTableFlowWriteActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc1Case;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc2Case;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc4Case;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow;
@@ -110,6 +115,27 @@ public class OpenFlow13ProviderTest {
                 NwConstants.LPORT_DISPATCHER_TABLE);
     }
 
+    @Test
+    public void createIngressClassifierFilterChainEgressFlow() {
+        Flow flow = openflowProvider.createIngressClassifierFilterChainEgressFlow(nodeId, NSP);
+
+        assertEquals(flow.getTableId().shortValue(), NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE);
+        assertEquals(flow.getPriority().intValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_CHAIN_EGRESS_PRIORITY);
+        assertEquals(flow.getId().getValue(),
+                OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_NSH_CHAIN_EGRESS_FLOW_NAME
+                        + nodeId.getValue() + "_" + NSP);
+        assertEquals(flow.getCookie().getValue(), OpenFlow13Provider.INGRESS_CLASSIFIER_FILTER_COOKIE);
+
+        checkMatchNsp(flow.getMatch(), NSP);
+        assertEquals(1, flow.getInstructions().getInstruction().size());
+        Instruction curInstruction = flow.getInstructions().getInstruction().get(0).getInstruction();
+        List<Action> actionList = checkApplyActionSize(curInstruction, 3);
+        checkActionMoveNsc4(actionList.get(0), true);
+        checkActionMoveTunReg(actionList.get(0), NxmNxReg6.class, false);
+        checkActionPopNsh(actionList.get(1));
+        checkActionResubmit(curInstruction, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE);
+    }
+
     @Test
     public void createIngressClassifierFilterNoNshFlow() {
         Flow flow = openflowProvider.createIngressClassifierFilterNoNshFlow(nodeId);
@@ -231,13 +257,15 @@ public class OpenFlow13ProviderTest {
 
         assertEquals(2, flow.getInstructions().getInstruction().size());
         Instruction curInstruction = flow.getInstructions().getInstruction().get(0).getInstruction();
-        List<Action> actionList = checkApplyActionSize(curInstruction, 3);
+        List<Action> actionList = checkApplyActionSize(curInstruction, 4);
 
-        checkActionMoveTunReg0(actionList.get(0), true);
+        checkActionMoveTunReg(actionList.get(0), NxmNxReg0.class, true);
         checkActionMoveNsc1(actionList.get(0), false);
         checkActionMoveTunId(actionList.get(1), true);
         checkActionMoveNsc2(actionList.get(1), false);
-        checkActionLoadTunId(actionList.get(2), OpenFlow13Provider.SFC_TUNNEL_ID);
+        checkActionMoveTunReg(actionList.get(2), NxmNxReg6.class, true);
+        checkActionMoveNsc4(actionList.get(2), false);
+        checkActionLoadTunId(actionList.get(3), OpenFlow13Provider.SFC_TUNNEL_ID);
 
         curInstruction = flow.getInstructions().getInstruction().get(1).getInstruction();
         checkActionGotoTable(curInstruction, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
@@ -457,6 +485,12 @@ public class OpenFlow13ProviderTest {
         assertNotNull(pushNshCase.getNxPushNsh());
     }
 
+    private void checkActionPopNsh(Action action) {
+        NxActionPopNshNodesNodeTableFlowApplyActionsCase popNshCase =
+                (NxActionPopNshNodesNodeTableFlowApplyActionsCase) action.getAction();
+        assertNotNull(popNshCase.getNxPopNsh());
+    }
+
     private void checkActionLoadTunIpv4(Action action, String ip) {
         long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(ip)) & 0xffffffffL;
         NxActionRegLoadNodesNodeTableFlowApplyActionsCase regLoad =
@@ -547,6 +581,18 @@ public class OpenFlow13ProviderTest {
         }
     }
 
+    private void checkActionMoveNsc4(Action action, boolean checkSrc) {
+        NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove =
+                (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction();
+        if (checkSrc) {
+            SrcNxNshc4Case src = (SrcNxNshc4Case) regMove.getNxRegMove().getSrc().getSrcChoice();
+            assertTrue(src.isNxNshc4Dst());
+        } else {
+            DstNxNshc4Case dst = (DstNxNshc4Case) regMove.getNxRegMove().getDst().getDstChoice();
+            assertTrue(dst.isNxNshc4Dst());
+        }
+    }
+
     private void checkActionMoveTunId(Action action, boolean checkSrc) {
         NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove =
                 (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction();
@@ -559,15 +605,16 @@ public class OpenFlow13ProviderTest {
         }
     }
 
-    private void checkActionMoveTunReg0(Action action, boolean checkSrc) {
+    private void checkActionMoveTunReg(Action action, Class<? extends NxmNxReg> reg, boolean checkSrc) {
         NxActionRegMoveNodesNodeTableFlowApplyActionsCase regMove =
                 (NxActionRegMoveNodesNodeTableFlowApplyActionsCase) action.getAction();
         if (checkSrc) {
             SrcNxRegCase src = (SrcNxRegCase) regMove.getNxRegMove().getSrc().getSrcChoice();
-            assertTrue(src.getNxReg() == NxmNxReg0.class);
+            assertTrue(src.getNxReg() == reg);
         } else {
             DstNxRegCase dst = (DstNxRegCase) regMove.getNxRegMove().getDst().getDstChoice();
-            assertTrue(dst.getNxReg() == NxmNxReg0.class);
+            assertTrue(dst.getNxReg() == reg);
         }
     }
+
 }