workaround for sfc part 2
authorSam Hague <shague@redhat.com>
Wed, 11 Nov 2015 20:53:10 +0000 (15:53 -0500)
committerSam Hague <shague@redhat.com>
Wed, 11 Nov 2015 20:53:10 +0000 (15:53 -0500)
Change-Id: Ib733682492ede0985dae97bbe3add80b359add1f
Signed-off-by: Sam Hague <shague@redhat.com>
openstack/net-virt-sfc/impl/pom.xml
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/ISfcClassifierService.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/SfcUtils.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/standalone/openflow13/services/SfcClassifierService.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/NetvirtSfcWorkaroundOF13Provider.java
openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/workaround/services/SfcClassifierService.java
openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/FlowUtils.java
utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java

index 147c80673ad106baec2f5300329b4699d8905d5c..21cdee3e26f5c434e1b77584853e5ef735b07d79 100644 (file)
@@ -193,13 +193,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
+      <!--<plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
-        <!--<configuration>
+        <configuration>
           <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
-        </configuration>-->
-      </plugin>
+        </configuration>
+      </plugin>-->
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
index 626b1cceaca25b63781d6210f60e0b32d1b8cb4d..806e7c6387afdb8c5d44b9b5ee05c0de52d9d365 100644 (file)
@@ -8,7 +8,9 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.sfc;
 
+import java.net.InetAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 
 public interface ISfcClassifierService {
     void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
@@ -23,4 +25,10 @@ public interface ISfcClassifierService {
                                   int tunnelOfPort, int tunnelId, boolean write);
 
     void program_sfEgress(long dataPathId, int dstPort, boolean write);
+
+    void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                           String ipAddress, String sfDplName, boolean write);
+
+    void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                               String ipAddress, boolean write);
 }
index f7f0f31aa047c32dd5c90bd69adad397c8094d37..3983fa125086fbdd98c4f64d927ef8d2f026bf91 100644 (file)
@@ -92,7 +92,27 @@ public class SfcUtils {
             return null;
         }
 
+        return getSfIp(serviceFunction);
+    }
+
+    public IpAddress getSfIp(ServiceFunction serviceFunction) {
+        if (serviceFunction == null) {
+            LOG.info("getSfIp: Servicefunction is null");
+            return null;
+        }
+
         Ip ipLocator = (Ip) serviceFunction.getSfDataPlaneLocator().get(0).getLocatorType();
         return ipLocator.getIp();
     }
+
+    public String getSfDplName(ServiceFunction serviceFunction) {
+        String sfDplName = null;
+        if (serviceFunction == null) {
+            LOG.warn("getSfDplName: Servicefunction is null");
+            return null;
+        }
+
+        sfDplName = serviceFunction.getSfDataPlaneLocator().get(0).getName().getValue();
+        return sfDplName;
+    }
 }
index 944a4824c688c8cb946f6027c589825e22f5f3f2..7ebdd6dfcd1b095490e0141d22d44c38852f6e25 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -62,4 +63,14 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
     public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
 
     }
+
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort, String ipAddress, String sfDplName, boolean write) {
+
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr, String ipAddress, boolean write) {
+
+    }
 }
index a452442093d3ab99c916bd91ce49bd0921de4471..4f5b5d49d2b1df30345b2e6ca2cecfd75393f3e0 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import java.util.List;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.openstack.netvirt.sfc.INetvirtSfcOF13Provider;
@@ -23,11 +24,14 @@ import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
@@ -42,6 +46,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
 import org.osgi.framework.ServiceReference;
@@ -56,11 +61,6 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
     private static final short SFC_TABLE = 150;
     private static final int GPE_PORT = 6633;
     private static final String NETWORK_TYPE_VXLAN = "vxlan";
-
-    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
-        this.sfcClassifierService = sfcClassifierService;
-    }
-
     private MdsalUtils mdsalUtils;
     private SfcUtils sfcUtils;
     private static final String VXGPE = "vxgpe";
@@ -77,6 +77,10 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         //this.setDependencies(null);
     }
 
+    public void setSfcClassifierService(ISfcClassifierService sfcClassifierService) {
+        this.sfcClassifierService = sfcClassifierService;
+    }
+
     @Override
     public void addClassifierRules(Bridge bridge, Acl acl) {
 
@@ -188,10 +192,21 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
 
             RenderedServicePathHop firstHop = pathHopList.get(0);
             RenderedServicePathHop lastHop = pathHopList.get(pathHopList.size()-1);
+            ServiceFunction serviceFunction =
+                    SfcProviderServiceFunctionAPI.readServiceFunction(
+                            SfName.getDefaultInstance(firstHop.getServiceFunctionName().getValue()));
+            if (serviceFunction == null) {
+                LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
+                        firstHop.getServiceFunctionName().getValue(), bridgeNode);
+                continue;
+            }
+
             nshHeader.setNshNsi(firstHop.getServiceIndex());
             // workaround: bypass sff and got directly to sf
             //nshHeader.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
-            IpAddress sfIpAddress = sfcUtils.getSfIp(firstHop.getServiceFunctionName().getValue());
+            IpAddress sfIpAddress = sfcUtils.getSfIp(serviceFunction);
+            String sfDplName = sfcUtils.getSfDplName(serviceFunction);
+            //sfcUtils.getSfIp(firstHop.getServiceFunctionName().getValue());
             nshHeader.setNshTunIpDst(sfIpAddress.getIpv4Address());
             nshHeader.setNshTunUdpPort(firstRspHop.getPort());
             LOG.debug("handleIngressClassifier: NSH Header = {}", nshHeader);
@@ -201,26 +216,31 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
 
             sfcClassifierService.program_sfEgress(dataPathId, GPE_PORT, true);
             //not needed if ip route and arp can be added to stack
-            //sfcClassifierService.program_sfIngress(dataPathId, true);
-            //sfcClassifierService.program_sfArp(dataPathId, true);
+            long sfOfPort = getSfPort(bridgeNode, sfDplName);
+
+            String sfMac = getMacFromExternalIds(bridgeNode, sfDplName);
+            String sfIpString = new String(sfIpAddress.getValue());
+            LOG.info("handleIngressClassifier: sfDplName: {}, sfMac: {}, sfOfPort: {}, sfIpAddress: {}",
+                    sfDplName, sfMac, sfOfPort, sfIpString);
+            if (sfMac != null) { // install if the sf is on this bridge, expand when using multiple bridges
+                sfcClassifierService.program_sfIngress(dataPathId, GPE_PORT, sfOfPort, sfIpString, sfDplName, true);
+                sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpString, true);
+            }
 
             short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
-            long tunnelOfPort = getTunnelOfPort(bridgeNode, VXGPE);
             sfcClassifierService.programEgressClassifier1(dataPathId, vxGpeOfPort, rsp.getPathId(),
-                    lastServiceindex, (int)tunnelOfPort, 0, (short)0, true);
+                    lastServiceindex, (int)sfOfPort, 0, (short)0, true);
             sfcClassifierService.programEgressClassifier2(dataPathId, vxGpeOfPort, rsp.getPathId(),
-                    lastServiceindex, (int) tunnelOfPort, 0, true);
+                    lastServiceindex, (int)sfOfPort, 0, true);
 
             sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
         }
     }
 
-    // loop through sf's:
-    // - program arp responder
-    // - program sf to sff
-    // - program sff to sf
-    private void handleSfWorkaround(RenderedServicePath rsp) {
+    private String getSfPortName(SfName sfName) {
+        String sfPortName = null;
 
+        return sfPortName;
     }
 
     private RenderedServicePath getRenderedServicePath (Ace entry) {
@@ -295,38 +315,74 @@ public class NetvirtSfcWorkaroundOF13Provider implements INetvirtSfcOF13Provider
         return port;
     }
 
+    private long getSfPort(Node bridgeNode, String sfPortName) {
+        long port = 0L;
+        port = getOFPort(bridgeNode, sfPortName);
+        return port;
+    }
+
     private long getOFPort(Node bridgeNode, String portName) {
         long ofPort = 0L;
         OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(bridgeNode, portName);
         if (port != null) {
             ofPort = southbound.getOFPort(port);
         }
-        for (int i = 0; i < 5; i++) {
-            LOG.info("Looking for ofPort {}, try: {}", portName, i);
-            if (ofPort == 0L) {
-                TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
-                if (tp != null) {
-                    port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
-                    if (port != null) {
-                        ofPort = southbound.getOFPort(port);
-                        break;
+        if (ofPort == 0L) {
+            for (int i = 0; i < 5; i++) {
+                LOG.info("Looking for ofPort {}, try: {}", portName, i);
+                if (ofPort == 0L) {
+                    TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
+                    if (tp != null) {
+                        port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                        if (port != null) {
+                            ofPort = southbound.getOFPort(port);
+                            break;
+                        }
                     }
                 }
-            }
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
             }
         }
         return ofPort;
     }
 
+    private String getMacFromOptions(Node bridgeNode, String portName) {
+        String mac = null;
+        OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(bridgeNode, portName);
+        LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
+        if (port != null && port.getOptions() != null) {
+            //mac = southbound.getOptionsValue(port.getOptions(), EXTERNAL_ID_VM_MAC);
+            for (Options option : port.getOptions()) {
+                LOG.info("getMac: option: {}", option);
+                if (option.getOption().equals(Constants.EXTERNAL_ID_VM_MAC)) {
+                    mac = option.getValue();
+                    break;
+                }
+            }
+        }
+        return mac;
+    }
+
+    private String getMacFromExternalIds(Node bridgeNode, String portName) {
+        String mac = null;
+        OvsdbTerminationPointAugmentation port = southbound.extractTerminationPointAugmentation(bridgeNode, portName);
+        LOG.info("getMac: portName: {}, bridgeNode: {},,, port: {}", portName, bridgeNode, port);
+        if (port != null && port.getInterfaceExternalIds() != null) {
+            mac = southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_VM_MAC);
+        }
+        return mac;
+    }
+
     @Override
     public void setDependencies(ServiceReference serviceReference) {
         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
-        sfcClassifierService = (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
+        sfcClassifierService =
+                (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
         LOG.info("sfcClassifierService= {}", sfcClassifierService);
     }
 }
index 0c00852e1f4ba89433d16419a827453e17bc5ae5..693104d76de6219a7f9c6ca6ec145b69b571c7aa 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.collect.Lists;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
@@ -25,6 +26,8 @@ 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.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+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;
 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.action.types.rev131112.action.list.ActionBuilder;
@@ -32,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.acti
 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.FlowBuilder;
 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.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.ApplyActionsCaseBuilder;
@@ -40,6 +44,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -73,7 +78,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         FlowBuilder flowBuilder = new FlowBuilder();
 
         MatchBuilder matchBuilder = buildMatch(matches);
-        flowBuilder.setMatch(matchBuilder.build());
+        //flowBuilder.setMatch(matchBuilder.build());
         flowBuilder.setMatch(MatchUtils.addNxRegMatch(
                 matchBuilder,
                 new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).build());
@@ -166,8 +171,8 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         FlowBuilder flowBuilder = new FlowBuilder();
 
         MatchBuilder matchBuilder = new MatchBuilder();
-        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).build());
-        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nsp).build());
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
         flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).build());
 
         String flowId = "sfcEgressClass1_" + vxGpeOfPort;
@@ -183,7 +188,9 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         if (write) {
             InstructionsBuilder isb = new InstructionsBuilder();
             List<Instruction> instructions = Lists.newArrayList();
-            List<Action> actionList = Lists.newArrayList();
+            InstructionBuilder ib = new InstructionBuilder();
+
+            /*List<Action> actionList = Lists.newArrayList();
 
             ActionBuilder ab = new ActionBuilder();
             ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
@@ -193,16 +200,15 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
             ApplyActionsBuilder aab = new ApplyActionsBuilder();
             aab.setAction(actionList);
-            InstructionBuilder ib = new InstructionBuilder();
             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
 
-            ib.setOrder(0);
-            ib.setKey(new InstructionKey(0));
-            instructions.add(ib.build());
+            ib.setOrder(instructions.size());
+            ib.setKey(new InstructionKey(instructions.size()));
+            instructions.add(ib.build());*/
 
             ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
-            ib.setOrder(1);
-            ib.setKey(new InstructionKey(1));
+            ib.setOrder(instructions.size());
+            ib.setKey(new InstructionKey(instructions.size()));
             instructions.add(ib.build());
 
             isb.setInstruction(instructions);
@@ -220,8 +226,8 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         FlowBuilder flowBuilder = new FlowBuilder();
 
         MatchBuilder matchBuilder = new MatchBuilder();
-        flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).build());
-        flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nsp).build());
+        MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort);
+        MatchUtils.addNxNspMatch(matchBuilder, nsp);
         flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).build());
 
         String flowId = "sfcEgressClass2_" + vxGpeOfPort;
@@ -263,6 +269,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         }
     }
 
+    // packet from sf to sff that need to go out local
     @Override
     public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
@@ -270,7 +277,7 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
 
         MatchBuilder matchBuilder = new MatchBuilder();
         MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
-        flowBuilder.setMatch(MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort).build());
+        MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort);
         flowBuilder.setMatch(MatchUtils.addNxRegMatch(
                 matchBuilder, new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).build());
 
@@ -301,6 +308,143 @@ public class SfcClassifierService extends AbstractServiceInstance implements Con
         }
     }
 
+    // looped back sff to sf packets
+    @Override
+    public void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+                                  String ipAddress, String sfDplName, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
+        Ipv4Prefix ipCidr = MatchUtils.iPv4PrefixFromIPv4Address(ipAddress);
+        MatchUtils.createDstL3IPv4Match(matchBuilder, new Ipv4Prefix(ipCidr));
+        flowBuilder.setMatch(MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort).build());
+
+        String flowId = "sfIngress_" + dstPort + "_" + ipAddress;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            InstructionUtils.createOutputPortInstructions(ib, dataPathId, sfOfPort);
+
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    @Override
+    public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+                                      String ipAddress, boolean write) {
+        NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        MacAddress macAddress = new MacAddress(macAddressStr);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        MatchUtils.createEtherTypeMatch(matchBuilder, new EtherType(Constants.ARP_ETHERTYPE));
+        MatchUtils.createArpDstIpv4Match(matchBuilder, MatchUtils.iPv4PrefixFromIPv4Address(ipAddress));
+        flowBuilder.setMatch(matchBuilder.build());
+
+        String flowId = "ArpResponder_" + ipAddress;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(TABLE_0);
+        flowBuilder.setKey(key);
+        flowBuilder.setPriority(1024);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write == true) {
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+            ApplyActionsBuilder aab = new ApplyActionsBuilder();
+            ActionBuilder ab = new ActionBuilder();
+            List<Action> actionList = Lists.newArrayList();
+
+            // Move Eth Src to Eth Dst
+            ab.setAction(ActionUtils.nxMoveEthSrcToEthDstAction());
+            ab.setOrder(0);
+            ab.setKey(new ActionKey(0));
+            actionList.add(ab.build());
+
+            // Set Eth Src
+            ab.setAction(ActionUtils.setDlSrcAction(new MacAddress(macAddress)));
+            ab.setOrder(1);
+            ab.setKey(new ActionKey(1));
+            actionList.add(ab.build());
+
+            // Set ARP OP
+            ab.setAction(ActionUtils.nxLoadArpOpAction(BigInteger.valueOf(0x02L)));
+            ab.setOrder(2);
+            ab.setKey(new ActionKey(2));
+            actionList.add(ab.build());
+
+            // Move ARP SHA to ARP THA
+            ab.setAction(ActionUtils.nxMoveArpShaToArpThaAction());
+            ab.setOrder(3);
+            ab.setKey(new ActionKey(3));
+            actionList.add(ab.build());
+
+            // Move ARP SPA to ARP TPA
+            ab.setAction(ActionUtils.nxMoveArpSpaToArpTpaAction());
+            ab.setOrder(4);
+            ab.setKey(new ActionKey(4));
+            actionList.add(ab.build());
+
+            // Load Mac to ARP SHA
+            ab.setAction(ActionUtils.nxLoadArpShaAction(macAddress));
+            ab.setOrder(5);
+            ab.setKey(new ActionKey(5));
+            actionList.add(ab.build());
+
+            // Load IP to ARP SPA
+            ab.setAction(ActionUtils.nxLoadArpSpaAction(ipAddress));
+            ab.setOrder(6);
+            ab.setKey(new ActionKey(6));
+            actionList.add(ab.build());
+
+            // Output of InPort
+            ab.setAction(ActionUtils.outputAction(
+                    FlowUtils.getSpecialNodeConnectorId(dataPathId, OutputPortValues.INPORT.toString())));
+            ab.setOrder(7);
+            ab.setKey(new ActionKey(7));
+            actionList.add(ab.build());
+
+            // Create Apply Actions Instruction
+            aab.setAction(actionList);
+            ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            isb.setInstruction(instructions);
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
     private List<Action> getNshAction(NshUtils header, List<Action> actionList) {
         // Build the Actions to Add the NSH Header
         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
index 1505dfde17e5b06f5a23064fbb467c58a98122a9..1629bde4ffead693fd2047ae47b2f5c8e0f5b8a9 100644 (file)
@@ -25,10 +25,12 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configure
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
 
+import com.google.common.collect.Maps;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.junit.Assert;
@@ -154,12 +156,12 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private static final String OVSDB_TRACE = "ovsdb.trace";
     private static final String SF1NAME = "firewall-72";
     private static final String SF2NAME = "dpi-72";
-    private static final String SF1IP = "127.0.0.1";//"192.168.50.70";//"192.168.120.31";
-    private static final String SF2IP = "192.168.120.32";
-    private static final String SF1DPLNAME = "1";
-    private static final String SF2DPLNAME = "2";
-    private static final String SFF1IP = "192.168.120.31";
-    private static final String SFF2IP = "192.168.120.32";
+    private static final String SF1IP = "10.2.1.1";//"192.168.50.70";//"192.168.120.31";
+    private static final String SF2IP = "10.2.1.2";
+    private static final String SF1DPLNAME = "sf1";
+    private static final String SF2DPLNAME = "sf2";
+    private static final String SFF1IP = "127.0.0.1";
+    private static final String SFF2IP = "127.0.0.1";
     private static final String SFF1NAME = "SFF1";
     private static final String SFF2NAME = "SFF2";
     private static final String SFFDPL1NAME = "vxgpe";
@@ -246,6 +248,9 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
                         LogLevel.TRACE.name()),
+                editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+                        "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13",
+                        LogLevel.TRACE.name()),
                 editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
                         "log4j.logger.org.opendaylight.sfc",
                         LogLevel.TRACE.name()),
@@ -434,20 +439,20 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         String sf1Ip = SF1IP;
         String sff1Ip = SF1IP;
         String sff1Name = SFF1NAME;
-        String sffDpl1Name = SFFDPL1NAME;
+        String sf1DplName = SF1DPLNAME;
         String sn1Name = SN1NAME;
         String bridge1Name= BRIDGE1NAME;
         String sf2Name = SF2NAME;
         String sf2Ip = SF2IP;
         String sff2Ip = SF2IP;
         String sff2Name = SFF2NAME;
-        String sffDpl2Name = SFFDPL2NAME;
+        String sf2DplName = SF2DPLNAME;
         String sn2Name = SN2NAME;
         String bridge2Name= BRIDGE2NAME;
         int port = GPEPORT;
 
         ServiceFunctionBuilder serviceFunctionBuilder =
-                serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sffDpl1Name, sff1Name, sf1Name);
+                serviceFunctionUtils.serviceFunctionBuilder(sf1Ip, port, sf1DplName, sff1Name, sf1Name);
         List<ServiceFunction> serviceFunctionList = serviceFunctionUtils.list(
                 new ArrayList<ServiceFunction>(), serviceFunctionBuilder);
 
@@ -466,14 +471,14 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
     private ServiceFunctionForwardersBuilder serviceFunctionForwardersBuilder() {
         String sf1Name = SF1NAME;
         String sf1Ip = SF1IP;
-        String sff1Ip = SF1IP;
+        String sff1Ip = SFF1IP;
         String sff1Name = SFF1NAME;
         String sffDpl1Name = SFFDPL1NAME;
         String sn1Name = SN1NAME;
         String bridge1Name= BRIDGE1NAME;
         String sf2Name = SF2NAME;
         String sf2Ip = SF2IP;
-        String sff2Ip = SF2IP;
+        String sff2Ip = SFF2IP;
         String sff2Name = SFF2NAME;
         String sffDpl2Name = SFFDPL2NAME;
         String sn2Name = SN2NAME;
@@ -483,7 +488,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
         ServiceFunctionForwarderBuilder serviceFunctionForwarderBuilder =
                 serviceFunctionForwarderUtils.serviceFunctionForwarderBuilder(
-                        sff1Name, sff1Ip, port, sffDpl1Name, sf1Name, sff1Ip, sn1Name, bridge1Name, Firewall.class);
+                        sff1Name, sff1Ip, port, sffDpl1Name, sf1Name, sf1Ip, sn1Name, bridge1Name, Firewall.class);
         List<ServiceFunctionForwarder>  serviceFunctionForwarderList = serviceFunctionForwarderUtils.list(
                 new ArrayList<ServiceFunctionForwarder>(), serviceFunctionForwarderBuilder);
 
@@ -559,6 +564,20 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
         assertNotNull("node is not connected", ovsdbNode);
 
         Thread.sleep(5000);
+        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
+        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
+        long datapathId = southbound.getDataPathId(bridgeNode);
+
+        Map<String, String> externalIds = Maps.newHashMap();
+        externalIds.put("attached-mac", "01:02:03:04:05:06");
+        southboundUtils.addTerminationPoint(bridgeNode, null, SF1DPLNAME, "internal", null, externalIds);
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vm1", "internal");
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vm2", "internal");
+        Map<String, String> options = Maps.newHashMap();
+        options.put("key", "flow");
+        options.put("remote_ip", "192.168.120.32");
+        southboundUtils.addTerminationPoint(bridgeNode, null, "vx", "vxlan", options, null);
+        Thread.sleep(1000);
 
         testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
         testModelPut(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
@@ -572,10 +591,6 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase {
 
         Thread.sleep(10000);
 
-        Node bridgeNode = southbound.getBridgeNode(ovsdbNode, bridgeName);
-        assertNotNull("bridge " + bridgeName + " was not found", bridgeNode);
-        long datapathId = southbound.getDataPathId(bridgeNode);
-
         ISfcClassifierService sfcClassifierService = (ISfcClassifierService) ServiceHelper.getGlobalInstance(ISfcClassifierService.class, this);
         LOG.info("SfcClassifierService: {}", sfcClassifierService);
         readwait();
index 915c997ba9c65a1d8e1a614fa5406116b92c67be..c11a620a5ee6d2e23eaea3c940fe4af3e4fdbb96 100644 (file)
@@ -19,6 +19,7 @@ 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.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 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.OutputPortValues;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -47,6 +48,10 @@ public class FlowUtils {
         return new NodeConnectorId(nodeName + ":" + ofPort);
     }
 
+    public static NodeConnectorId getSpecialNodeConnectorId(long dpidLong, String portName) {
+        return new NodeConnectorId(getNodeName(dpidLong) + ":" + portName);
+    }
+
     public static NodeConnectorId getNodeConnectorId(long dpidLong, long ofPort) {
         return getNodeConnectorId(ofPort, getNodeName(dpidLong));
     }
index 81ed0bdd76727b24e2327cf50239f8d4f880ca28..9111acc92e35f5b81e5b8e7873461039f6d52bfa 100644 (file)
@@ -14,6 +14,7 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 
 import java.util.List;
+import java.util.Map;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
@@ -30,13 +31,24 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,11 +59,31 @@ public class SouthboundUtils {
     private static final String DEFAULT_OPENFLOW_PORT = "6653";
     private static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
     private MdsalUtils mdsalUtils;
+    public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
 
     public SouthboundUtils(MdsalUtils mdsalUtils) {
         this.mdsalUtils = mdsalUtils;
     }
 
+    public static final ImmutableBiMap<String, Class<? extends InterfaceTypeBase>> OVSDB_INTERFACE_TYPE_MAP
+            = new ImmutableBiMap.Builder<String, Class<? extends InterfaceTypeBase>>()
+            .put("internal", InterfaceTypeInternal.class)
+            .put("vxlan", InterfaceTypeVxlan.class)
+            .put("patch", InterfaceTypePatch.class)
+            .put("system", InterfaceTypeSystem.class)
+            .put("tap", InterfaceTypeTap.class)
+            .put("geneve", InterfaceTypeGeneve.class)
+            .put("gre", InterfaceTypeGre.class)
+            .put("ipsec_gre", InterfaceTypeIpsecGre.class)
+            .put("gre64", InterfaceTypeGre64.class)
+            .put("ipsec_gre64", InterfaceTypeIpsecGre64.class)
+            .put("lisp", InterfaceTypeLisp.class)
+            .put("dpdk", InterfaceTypeDpdk.class)
+            .put("dpdkr", InterfaceTypeDpdkr.class)
+            .put("dpdkvhost", InterfaceTypeDpdkvhost.class)
+            .put("dpdkvhostuser", InterfaceTypeDpdkvhostuser.class)
+            .build();
+
     public NodeId createNodeId(IpAddress ip, PortNumber port) {
         String uriString = SouthboundConstants.OVSDB_URI_PREFIX + "://"
                 + new String(ip.getValue()) + ":" + port.getValue();
@@ -89,6 +121,18 @@ public class SouthboundUtils {
         return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName));
     }
 
+    public InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
+
+        InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID))
+                .child(Node.class,node.getKey())
+                .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+        LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath);
+        return terminationPointPath;
+    }
+
     public NodeKey createNodeKey(IpAddress ip, PortNumber port) {
         return new NodeKey(createNodeId(ip, port));
     }
@@ -336,4 +380,61 @@ public class SouthboundUtils {
         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(connectionInfo);
         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
     }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName,
+                                       String type, Map<String, String> options,
+                                       Map<String, String> externalIds) {
+        InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName);
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
+
+        tpAugmentationBuilder.setName(portName);
+        if (type != null) {
+            tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type));
+        }
+
+        if (options != null && options.size() > 0) {
+            List<Options> optionsList = new ArrayList<>();
+            for (Map.Entry<String, String> entry : options.entrySet()) {
+                OptionsBuilder optionsBuilder = new OptionsBuilder();
+                optionsBuilder.setKey(new OptionsKey(entry.getKey()));
+                optionsBuilder.setOption(entry.getKey());
+                optionsBuilder.setValue(entry.getValue());
+                optionsList.add(optionsBuilder.build());
+            }
+            tpAugmentationBuilder.setOptions(optionsList);
+        }
+
+        if (externalIds != null && externalIds.size() > 0) {
+            List<InterfaceExternalIds> externalIdsList = new ArrayList<>();
+            for (Map.Entry<String, String> entry : externalIds.entrySet()) {
+                InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = new InterfaceExternalIdsBuilder();
+                interfaceExternalIdsBuilder.setKey(new InterfaceExternalIdsKey(entry.getKey()));
+                interfaceExternalIdsBuilder.setExternalIdKey(entry.getKey());
+                interfaceExternalIdsBuilder.setExternalIdValue(entry.getValue());
+                externalIdsList.add(interfaceExternalIdsBuilder.build());
+            }
+            tpAugmentationBuilder.setInterfaceExternalIds(externalIdsList);
+        }
+
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
+        tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
+        /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */
+        return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build());
+    }
+
+    public TerminationPoint readTerminationPoint(Node bridgeNode, String bridgeName, String portName) {
+        InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
+                bridgeNode, portName);
+        return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, tpIid);
+    }
+
+    public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type) {
+        return addTerminationPoint(bridgeNode, bridgeName, portName, type, null, null);
+    }
+
+    public Boolean addTunnelTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type,
+                                             Map<String, String> options) {
+        return addTerminationPoint(bridgeNode, bridgeName, portName, type, options, null);
+    }
 }