For TcpProxy SFs, reply to the SF ARP messages 25/21625/4
authorRicardo Noriega <[email protected]>
Tue, 2 Jun 2015 09:49:15 +0000 (11:49 +0200)
committerRicardo Noriega <[email protected]>
Wed, 3 Jun 2015 14:12:35 +0000 (14:12 +0000)
Bug ID 3294

https://bugs.opendaylight.org/show_bug.cgi?id=3294

Change-Id: I6da52c8333360e7928fc3b1d2ea3d2c992beef6b
Signed-off-by: Ricardo Noriega <[email protected]>
sfcofl2/src/main/java/org/opendaylight/sfc/l2renderer/SfcL2FlowProgrammerInterface.java
sfcofl2/src/main/java/org/opendaylight/sfc/l2renderer/SfcL2RspProcessor.java
sfcofl2/src/main/java/org/opendaylight/sfc/l2renderer/openflow/SfcL2FlowProgrammerOFimpl.java
sfcofl2/src/main/java/org/opendaylight/sfc/l2renderer/openflow/SfcOpenflowUtils.java
sfcofl2/src/test/java/org/opendaylight/sfc/l2renderer/RspBuilder.java
sfcofl2/src/test/java/org/opendaylight/sfc/l2renderer/SfcL2FlowProgrammerTestMoc.java
sfcofl2/src/test/java/org/opendaylight/sfc/l2renderer/SfcL2RspProcessorTest.java

index 665c8553ee2379f9fd1de4063e2134d175be0ee5..8bbdb849b61e7a13164c5a173a9de9c6c0956f3c 100644 (file)
@@ -38,6 +38,8 @@ public interface SfcL2FlowProgrammerInterface {
 
     public void configureMplsTransportIngressFlow(final String sffNodeName, final boolean isAddFlow);
 
+    public void configureArpTransportIngressFlow(final String sffNodeName, final String mac, final boolean isAddFlow);
+
     //
     // Configure Table 1, Path Mapper
     //
@@ -49,6 +51,7 @@ public interface SfcL2FlowProgrammerInterface {
 
     public void configureVxlanGpePathMapperFlow(final String sffNodeName, long nsp, short nsi, long pathId, final boolean isAddFlow);
 
+
     //
     // Table 2, NextHop
     //
index 5f792184b359e23a6e3433070a5a3fcd89badb25..0ce067a437bf2c4db5a1e8d379d412c996624387 100644 (file)
@@ -300,6 +300,19 @@ public class SfcL2RspProcessor {
             }
         }
 
+        //ARP flows for TcpProxy type of SFFasd
+        ServiceFunction sf = sfcL2ProviderUtils.getServiceFunction(entry.getSf(), entry.getPathId());
+        if(sf.getType() == TcpProxy.class){
+            ServiceFunctionDictionary sffSfDict = sfcL2ProviderUtils.getSffSfDictionary(sffDst, entry.getSf());
+            String sffMac = sfcL2ProviderUtils.getDictPortInfoMac(sffSfDict);
+            // If the SF is a TCP Proxy, then we need to reply to the ARP Request messages
+            if (sffMac != null){
+                this.sfcL2FlowProgrammer.configureArpTransportIngressFlow(
+                        sfcL2ProviderUtils.getSffOpenFlowNodeName(sffDstName, entry.getPathId()),
+                        sffMac,
+                        this.addFlow);
+            }
+        }
         // Configure the Service Chain Ingress flow(s)
         if(entry.getSrcSff().equals(SffGraph.INGRESS)) {
             // configure the SFF Transport Ingress Flow using the dstHopIngressDpl
index 3b749e5787117f8e62a2a133a37c885a47e3116e..771c6948304de13da52596dbb1df96372dbae4c7 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
 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.GoToTableCaseBuilder;
@@ -437,6 +438,79 @@ public class SfcL2FlowProgrammerOFimpl implements SfcL2FlowProgrammerInterface {
         }
     }
 
+    //Thread to create ARP flows
+    public void configureArpTransportIngressFlow(final String sffNodeName, final String mac, final boolean isAddFlow) {
+
+        ConfigureTransportArpIngressThread configureArpIngressTransportThread =
+                new ConfigureTransportArpIngressThread(sffNodeName, mac, isAddFlow);
+        try {
+            threadPoolExecutorService.execute(configureArpIngressTransportThread);
+        } catch (Exception ex) {
+            LOG.error(LOGSTR_THREAD_QUEUE_FULL, ex.toString());
+        }
+    }
+
+    private class ConfigureTransportArpIngressThread implements Runnable {
+        String sffNodeName;
+        String mac;
+        boolean isAddFlow;
+
+        public ConfigureTransportArpIngressThread(final String sffNodeName, final String mac, final boolean isAddFlow) {
+            this.sffNodeName = sffNodeName;
+            this.mac = mac;
+            this.isAddFlow = isAddFlow;
+        }
+
+        @Override
+        public void run() {
+            try {
+                LOG.info("SfcProviderSffFlowWriter.ConfigureTransportArpIngressThread, sff [{}] mac [{}]",
+                        this.sffNodeName, this.mac);
+
+                // Create the matching criteria
+                MatchBuilder match = new MatchBuilder();
+                SfcOpenflowUtils.addMatchEtherType(match, SfcOpenflowUtils.ETHERTYPE_ARP);
+                SfcOpenflowUtils.addMatchArpRequest(match);
+
+                int order = 0;
+                List<Action> actionList = new ArrayList<Action>();
+                actionList.add(SfcOpenflowUtils.createActionNxMoveEthSrcToEthDstAction(order++));
+                actionList.add(SfcOpenflowUtils.createActionSetDlSrc(mac, order++));
+                actionList.add(SfcOpenflowUtils.createActionNxLoadArpOpAction(SfcOpenflowUtils.ARP_REPLY, order++));
+                actionList.add(SfcOpenflowUtils.createActionNxMoveArpShaToArpThaAction(order++));
+                actionList.add(SfcOpenflowUtils.createActionOutPort(OutputPortValues.INPORT.toString(), order++));
+
+                ApplyActionsBuilder aab = new ApplyActionsBuilder();
+                aab.setAction(actionList);
+
+                int ibOrder = 0;
+                InstructionBuilder actionsIb = new InstructionBuilder();
+                actionsIb.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+                actionsIb.setKey(new InstructionKey(ibOrder));
+                actionsIb.setOrder(ibOrder++);
+
+                // Put our Instruction in a list of Instructions
+                InstructionsBuilder isb = SfcOpenflowUtils.createInstructionsBuilder(actionsIb);
+
+                // Create and configure the FlowBuilder
+                FlowBuilder transportIngressFlow =
+                        SfcOpenflowUtils.createFlowBuilder(
+                                TABLE_INDEX_INGRESS_TRANSPORT_TABLE,
+                                FLOW_PRIORITY_TRANSPORT_INGRESS,
+                                "ingress_Transport_Default_Flow",
+                                match,
+                                isb);
+
+                if (isAddFlow) {
+                    writeFlowToConfig(sffNodeName, transportIngressFlow);
+                } else {
+                    removeFlowFromConfig(sffNodeName, transportIngressFlow);
+                }
+            } catch (Exception e) {
+                LOG.error("ConfigureTransportArpIngress writer caught an Exception: ", e);
+            }
+        }
+    }
 
     //
     // Configure Table 1, PathMapper
index fb0bf7ed93b27d28e3cd5c2e7deb22f796571359..7b839ac1f193db193aaf673b5a2623460ce52215 100644 (file)
@@ -77,18 +77,22 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TcpFlagMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+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.Ipv4Match;
 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._4.match.UdpMatchBuilder;
 
 // Import Nicira extension
 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.DstNxArpThaCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.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.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.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.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder;
@@ -106,11 +110,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.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.SrcNxNspCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc1CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNshc2CaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxNsiCaseBuilder;
+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.NxmNxNspKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey;
@@ -133,10 +139,13 @@ public class SfcOpenflowUtils {
     public static final int ETHERTYPE_IPV4 = 0x0800;
     public static final int ETHERTYPE_VLAN = 0x8100;
     public static final int ETHERTYPE_MPLS_UCAST = 0x8847;
+    public static final int ETHERTYPE_ARP = 0x0806;
     public static final short IP_PROTOCOL_TCP = (short) 6;
     public static final short IP_PROTOCOL_UDP = (short) 17;
     public static final int PKT_LENGTH_IP_HEADER = 20+14; // ether + IP header
     public static final int TCP_FLAG_SYN = 0x0002;
+    public static final int ARP_REQUEST = 1;
+    public static final int ARP_REPLY = 2;
 
     private static final int COOKIE_BIGINT_INT_RADIX = 10;
     private static AtomicLong flowIdInc = new AtomicLong();
@@ -321,6 +330,12 @@ public class SfcOpenflowUtils {
         match.setVlanMatch(vlanMatchBuilder.build());
     }
 
+    public static void addMatchArpRequest(MatchBuilder match){
+        ArpMatchBuilder arpmatch = new ArpMatchBuilder();
+        arpmatch.setArpOp(ARP_REQUEST);
+        match.setLayer3Match(arpmatch.build());
+    }
+
     // If we call multiple Layer3 match methods, the MatchBuilder
     // Ipv4Match object gets overwritten each time, when we actually
     // want to set additional fields on the existing Ipv4Match object
@@ -815,6 +830,43 @@ public class SfcOpenflowUtils {
         return ab.build();
     }
 
+    public static Action createActionNxLoadArpOpAction(int value, int order) {
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(
+                nxLoadRegAction(
+                        new DstOfArpOpCaseBuilder().setOfArpOp(Boolean.TRUE).build(),
+                        BigInteger.valueOf(value),
+                        15,
+                        false));
+
+        return ab.build();
+    }
+
+    // Used for ARP to move the Source HW Address (Sha) to the Target HW address (Tha)
+    public static Action createActionNxMoveArpShaToArpThaAction(int order) {
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(
+                nxMoveRegAction(
+                        new SrcNxArpShaCaseBuilder().setNxArpSha(Boolean.TRUE).build(),
+                        new DstNxArpThaCaseBuilder().setNxArpTha(Boolean.TRUE).build(),
+                        47,
+                        false));
+
+        return ab.build();
+    }
+
+    public static Action createActionNxMoveEthSrcToEthDstAction(int order) {
+        ActionBuilder ab = createActionBuilder(order);
+        ab.setAction(
+                nxMoveRegAction(
+                        new SrcOfEthSrcCaseBuilder().setOfEthSrc(Boolean.TRUE).build(),
+                        new DstOfEthDstCaseBuilder().setOfEthDst(Boolean.TRUE).build(),
+                        47,
+                        false));
+
+        return ab.build();
+    }
+
     public static WriteMetadataCase createInstructionMetadata(int order, BigInteger metadataVal, BigInteger metadataMask) {
         WriteMetadataBuilder wmb = new WriteMetadataBuilder();
         wmb.setMetadata(metadataVal);
index 2756570dcfaa244572378f21a7c945a1ef23cfe3..248377ecc254dcc36fd05a20d5a924251c318861 100644 (file)
@@ -49,6 +49,11 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 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.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.ServiceFunctionDictionary1Builder;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.ServiceFunctionDictionary1;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.SffDataPlaneLocator1;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.SffDataPlaneLocator1Builder;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.port.details.OfsPortBuilder;
 
 public class RspBuilder {
 
@@ -63,6 +68,7 @@ public class RspBuilder {
     private static int VLAN_BASE = 1;
     private static int MPLS_BASE = 1;
     private static int VXLAN_UDP_PORT = 6633;
+    private static String SWITCH_PORT_STR = "1";
 
     private long RSP_PATHID_INDEX = 0;
     private int SF_NAME_INDEX = 0;
@@ -244,6 +250,17 @@ public class RspBuilder {
             dplBuilder.setTransport(transportType);
             sffDplBuilder.setDataPlaneLocator(dplBuilder.build());
 
+            // Augment the SFF DPL if its not VxLan
+            if(!transportType.equals(VxlanGpe.class)) {
+
+                SffDataPlaneLocator1Builder ofsSffDplBuilder = new SffDataPlaneLocator1Builder();
+                OfsPortBuilder ofsPortBuilder = new OfsPortBuilder();
+                ofsPortBuilder.setMacAddress(new MacAddress(getNextMacAddress()));
+                ofsPortBuilder.setPortId(SWITCH_PORT_STR);
+                ofsSffDplBuilder.setOfsPort(ofsPortBuilder.build());
+                sffDplBuilder.addAugmentation(SffDataPlaneLocator1.class, ofsSffDplBuilder.build());
+            }
+
             sffDpls.add(sffDplBuilder.build());
         }
 
@@ -255,7 +272,6 @@ public class RspBuilder {
         Class<? extends SlTransportType> sfTransportType =
                 (transportType.equals(VxlanGpe.class) ? transportType : Mac.class);
 
-        // TODO this needs to be an augmented SFF-OFS DPL
         SffSfDataPlaneLocatorBuilder sffSfDplBuilder = new SffSfDataPlaneLocatorBuilder();
         // TODO the vlanId needs to be the same as on the SF
         sffSfDplBuilder.setLocatorType(buildSfLocatorType(sfTransportType));
@@ -267,8 +283,19 @@ public class RspBuilder {
         sfDictBuilder.setSffSfDataPlaneLocator(sffSfDplBuilder.build());
         sfDictBuilder.setKey(new ServiceFunctionDictionaryKey(sf.getName()));
 
+        // Augment the dictionary with an OfsPortBuilder if its not VxLan
+        if(!transportType.equals(VxlanGpe.class)) {
+            ServiceFunctionDictionary1Builder ofsSfDictBuilder = new ServiceFunctionDictionary1Builder();
+            OfsPortBuilder ofsPortBuilder = new OfsPortBuilder();
+            ofsPortBuilder.setMacAddress(new MacAddress(getNextMacAddress()));
+            ofsPortBuilder.setPortId(SWITCH_PORT_STR);
+            ofsSfDictBuilder.setOfsPort(ofsPortBuilder.build());
+            sfDictBuilder.addAugmentation(ServiceFunctionDictionary1.class, ofsSfDictBuilder.build());
+        }
+
         List<ServiceFunctionDictionary> sfDictList = new ArrayList<ServiceFunctionDictionary>();
         sfDictList.add(sfDictBuilder.build());
+
         return sfDictList;
     }
 
index 960129a45acce8aa8c1420226ffeb8631967d995..66d9948ae993f878d5014facdf30f39918f8f171 100644 (file)
@@ -18,6 +18,7 @@ public class SfcL2FlowProgrammerTestMoc implements SfcL2FlowProgrammerInterface
         configureVlanTransportIngressFlowMethodIndex,
         configureVxlanGpeTransportIngressFlowMethodIndex,
         configureMplsTransportIngressFlowMethodIndex,
+        configureArpTransportIngressFlowMethodIndex,
 
         configureMacPathMapperFlowMethodIndex,
         configureMplsPathMapperFlowMethodIndex,
@@ -297,4 +298,10 @@ public class SfcL2FlowProgrammerTestMoc implements SfcL2FlowProgrammerInterface
             String groupName, boolean isAddFlow) {
         incrementMethodCalled(MethodIndeces.configureGroupNextHopFlow);
     }
+
+    @Override
+    public void configureArpTransportIngressFlow(String sffNodeName,
+            String mac, boolean isAddFlow) {
+        incrementMethodCalled(MethodIndeces.configureArpTransportIngressFlowMethodIndex);
+    }
 }
index 3c3a796dbf736d1ba74aa4a4bf3717702295b742..e2a48f4aecc0d455a6db6a974c4c2e8559100bb0 100644 (file)
@@ -183,6 +183,8 @@ public class SfcL2RspProcessorTest {
         assertMatchAnyMethodsCalled();
         assertMethodCallCount(
                 SfcL2FlowProgrammerTestMoc.MethodIndeces.configureVlanTransportIngressFlowMethodIndex, 3);
+        assertMethodCallCount(
+                SfcL2FlowProgrammerTestMoc.MethodIndeces.configureArpTransportIngressFlowMethodIndex, 2);
         assertMethodCallCount(
                 SfcL2FlowProgrammerTestMoc.MethodIndeces.configureVlanPathMapperFlowMethodIndex, 5);
         assertMethodCallCount(