From fe58da37f42be82e42d3d89717c7b279090eba26 Mon Sep 17 00:00:00 2001 From: Sam Hague Date: Wed, 28 Oct 2015 21:49:16 -0400 Subject: [PATCH] Fix netvirtsfc flows Change-Id: Ife49b9150dcb99fb3097b0fe175d8e9355bdf527 Signed-off-by: Sam Hague --- .../services/ClassifierService.java | 1 + .../api/src/main/yang/netvirt-acl.yang | 2 + .../api/src/main/yang/netvirt-classifier.yang | 8 + openstack/net-virt-sfc/impl/pom.xml | 9 +- .../netvirt/sfc/NetvirtSfcAclListener.java | 5 +- .../sfc/NetvirtSfcClassifierListener.java | 8 +- .../openflow13/INetvirtSfcOF13Provider.java | 2 + .../openflow13/NetvirtSfcOF13Provider.java | 594 ++++++++++++++++-- .../netvirt/sfc/openflow13/NshUtils.java | 275 ++++++++ openstack/net-virt-sfc/it/pom.xml | 4 +- .../openstack/netvirt/sfc/NetvirtSfcIT.java | 57 +- southbound/southbound-impl/pom.xml | 1 + .../southbound/utils/SouthboundUtils.java | 7 + 13 files changed, 904 insertions(+), 69 deletions(-) create mode 100644 openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/ClassifierService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/ClassifierService.java index 126db0161..e9ee40045 100644 --- a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/ClassifierService.java +++ b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/ClassifierService.java @@ -108,6 +108,7 @@ public class ClassifierService extends AbstractServiceInstance implements Classi BigInteger.valueOf(REG_VALUE_FROM_LOCAL))); ab.setOrder(1); ab.setKey(new ActionKey(1)); + actionList.add(ab.build()); ib.setOrder(0); diff --git a/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang b/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang index 3d1a813e1..31d1e1d86 100644 --- a/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang +++ b/openstack/net-virt-sfc/api/src/main/yang/netvirt-acl.yang @@ -14,6 +14,7 @@ module netvirt-sfc-acl { //augment "/ietf-acl:access-lists/ietf-acl:access-list/ietf-acl:access-list-entries/ietf-acl:access-list-entry/ietf-acl:matches" { augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:matches" { description "Neutron network uuid"; + ext:augment-identifier "neutron-network"; leaf network-uuid { type string; } @@ -22,6 +23,7 @@ module netvirt-sfc-acl { // TODO: Add choice for Neutron and add fields there instead of at the root of matches augment "/ietf-acl:access-lists/ietf-acl:acl/ietf-acl:access-list-entries/ietf-acl:ace/ietf-acl:actions" { description "Redirect traffic to SFC identified by SFC Path ID"; + ext:augment-identifier "redirect-to-sfc"; leaf redirect-sfc { type string; } diff --git a/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang b/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang index c0aec3a36..df4dd39e8 100644 --- a/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang +++ b/openstack/net-virt-sfc/api/src/main/yang/netvirt-classifier.yang @@ -32,6 +32,14 @@ module netvirt-sfc-classifier { } } } + container bridges { + list bridge { + key "name"; + leaf name { + type string; + } + } + } } } } diff --git a/openstack/net-virt-sfc/impl/pom.xml b/openstack/net-virt-sfc/impl/pom.xml index 80f9a173c..690626c9b 100644 --- a/openstack/net-virt-sfc/impl/pom.xml +++ b/openstack/net-virt-sfc/impl/pom.xml @@ -46,6 +46,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html ${project.groupId} openstack.net-virt-providers ${project.version} + + + ${project.groupId} + southbound-api + ${project.version} ${project.groupId} @@ -158,9 +163,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html org.apache.maven.plugins maven-checkstyle-plugin - + org.apache.maven.plugins diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java index f263c0f5d..b3e50bd6d 100644 --- a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java +++ b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcAclListener.java @@ -105,9 +105,10 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener { final Acl addDataObj) { Preconditions.checkNotNull(addDataObj, "Added object can not be null!"); String aclName = addDataObj.getAclName(); - LOG.debug("Adding accesslist = {}", identifier); + LOG.debug("Adding accesslist iid = {}, dataObj = {}", identifier, addDataObj); Classifiers classifiers = dbutils.read(LogicalDatastoreType.CONFIGURATION, getClassifierIid()); if (classifiers != null) { + LOG.debug("add: Classifiers: {}", classifiers); for (Classifier classifier : classifiers.getClassifier()) { if (classifier.getAcl().equalsIgnoreCase(aclName)) { if (classifier.getSffs() != null) { @@ -117,6 +118,8 @@ public class NetvirtSfcAclListener extends AbstractDataTreeListener { } } } + } else { + LOG.debug("add: No Classifiers found"); } } diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java index af8c8968f..b3d770f1c 100644 --- a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java +++ b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcClassifierListener.java @@ -19,6 +19,7 @@ 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.AclKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.Classifiers; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.Classifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -107,6 +108,7 @@ public class NetvirtSfcClassifierListener extends AbstractDataTreeListener REG_FIELD = NxmNxReg0.class; private volatile NodeCacheManager nodeCacheManager; private volatile Southbound southbound; - private MdsalUtils dbutils; - private PipelineOrchestrator orchestrator; + private MdsalUtils mdsalUtils; + private DataBroker dataBroker; + + // TBD:: Remove these constants after integrating with openstack. + //private static final String NETWORK_TYPE_VXLAN = "vxlan"; + private static final String NETWORK_SEGMENT_ID = "10"; + private static final String LOCAL_TP_ID = "vethl-h35_2"; + private static final String INTERFACE_TYPE_VXLAN_GPE = "vxlangpe"; + private static final String GPE_IFACE_ID = "sw1-vxlangpe-0"; /** * {@link NetvirtSfcOF13Provider} constructor. @@ -80,10 +127,8 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ */ public NetvirtSfcOF13Provider(final DataBroker dataBroker) { Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!"); - - //this.dataService = dataBroker; - dbutils = new MdsalUtils(dataBroker); - + this.dataBroker = dataBroker; + mdsalUtils = new MdsalUtils(dataBroker); this.setDependencies(null); } @@ -102,62 +147,248 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId. // If OVS Bridge augmentation is configured, the following API returns NULL. - String datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder); + String datapathId = null; + Node node = null; + // TODO: Replace with OVSDB methods and not use the SFC API + datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder); if (datapathId == null) { - LOG.debug("Service Function Forwarder = {} is not augemented with " + LOG.debug("Service Function Forwarder = {} is not augmented with " + "OVS Bridge Information. Skip processing!!", sff.getName()); } // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch // SFF with matching name. From this bridge name, get the openflow data path ID. - if (datapathId == null) { - Node node = null; - final List nodes = nodeCacheManager.getBridgeNodes(); - if (nodes.isEmpty()) { - LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", sff.getName()); - } else { - for (Node dstNode : nodes) { - LOG.debug("Processing Node={}, sff={}", dstNode.getNodeId().getValue(), sff.getName()); - if (dstNode.getNodeId().getValue().equalsIgnoreCase(sff.getName())) { - LOG.debug("Found matching OVSDB Bridge Name!!= {}", dstNode.getNodeId().getValue()); - node = dstNode; - break; - } - } - } + + node = getBridgeNode(serviceForwarder.getName().toString()); + if (node == null) { + LOG.warn("Node doesn't exist for corresponding SFF={}", sff.getName()); + return; } + datapathId = getDpid(node); LOG.debug("Processing the Classifier rules on Node={}", datapathId); if (datapathId != null) { // Program the OF flow on the corresponding open flow node. Iterator itr = acl.getAccessListEntries().getAce().iterator(); while (itr.hasNext()) { Ace entry = itr.next(); - programOfRules(entry, datapathId, true); + processAclEntry(entry, node, true); } + } else { + LOG.warn("Skipping ACL processing on Node={} as DatapathID is NULL!!", sff.getName()); } } - private void programOfRules(Ace entry, String datapathId, boolean write) { - NodeBuilder nodeBuilder = new NodeBuilder(); - nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + datapathId)); - nodeBuilder.setKey(new NodeKey(nodeBuilder.getId())); + @Override + public void addClassifierRules(Bridge bridge, Acl acl) { + Preconditions.checkNotNull(bridge, "Input bridge cannot be NULL!"); + Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!"); - //Create the match using match builder, by parsing the Accesslist Entry Match. - MatchBuilder matchBuilder = null; - matchBuilder = buildMatch(entry.getRuleName(), entry.getMatches(), datapathId); + Node bridgeNode = getBridgeNode(bridge.getName()); + if (bridgeNode == null) { + LOG.debug("bridge {} not yet configured. Skip processing !!", bridge.getName()); + return; + } - InstructionsBuilder isb = null; - isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId); + // Program the OF flow on the corresponding open flow node. + for (Ace ace : acl.getAccessListEntries().getAce()) { + processAclEntry(ace, bridgeNode, true); + } + } - String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName(); + private void processAclEntry(Ace entry, Node srcNode, boolean write) { + RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class); + LOG.debug("Processing ACL entry = {} on Node = {} sfcRedirect = {}", entry.getRuleName(), + srcNode.getNodeId(), sfcRedirect); + if (sfcRedirect != null) { + // Given SFP find the corresponding RSP. + String sfcName = sfcRedirect.getRedirectSfc(); + LOG.debug("Processing Redirect to SFC = {}", sfcRedirect.getRedirectSfc()); + ServiceFunctionPath sfp = getSfp(sfcName); + if (sfp == null || sfp.getName() == null) { + LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName); + return; + } + LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcRedirect.getRedirectSfc(), sfp); + // If RSP doesn't exist, create an RSP. + String sfpName = sfp.getName().getValue(); + RenderedServicePath rsp = getRspforSfp(sfpName); + String rspName = sfp.getName().getValue() + "_rsp"; + if (rsp == null) { + LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}!!", sfpName, rspName); + // Create RSP. + CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder() + .setParentServiceFunctionPath(sfpName) + .setName(rspName) + .setSymmetric(sfp.isSymmetric()) + .build(); + rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput); + if (rsp == null) { + LOG.warn("failed to add RSP"); + return; + } + + // If SFP is symmetric, create RSP in the reverse direction. + if (sfp.isSymmetric()) { + LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName); + String rspNameRev = rspName + "-Reverse"; + RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, + this.getRspId(rspNameRev)); + if (rspReverse == null) { + rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp); + } + } + } + LOG.info("rsp: {}", rsp); + + // Find the first Hop within a RSP. + List pathHopList = rsp.getRenderedServicePathHop(); + if (pathHopList.isEmpty()) { + LOG.info("Service Path = {} has empty hops!!", sfpName); + return; + } + + RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI + .readRenderedServicePathFirstHop(new RspName(rspName)); + //String firstSff = firstHop.getServiceFunctionForwarderLocator(); + + LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(), + firstRspHop.getPort().getValue().intValue()); + OvsdbTerminationPointAugmentation tunnelPort = southbound + .getTerminationPointOfBridge(srcNode, GPE_IFACE_ID); + if (tunnelPort != null) { + long tunnelOfPort = southbound.getOFPort(tunnelPort); + LOG.debug("Tunnel Port = {}, OF Port Number = {}", tunnelPort.getName(), tunnelOfPort); + if (tunnelOfPort == 0) { + LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}", + tunnelPort.getName(), tunnelOfPort, srcNode); + return; + } + } + + Matches match = entry.getMatches(); + + NshUtils header = new NshUtils(); + // C1 is the normal overlay dest ip + header.setNshMetaC1(convertToLongIp(getDestIp(match))); + header.setNshMetaC2(Long.parseLong(NETWORK_SEGMENT_ID)); + header.setNshNsp(rsp.getPathId()); + + RenderedServicePathHop firstHop = pathHopList.get(0); + header.setNshNsi(firstHop.getServiceIndex()); + header.setNshTunIpDst(firstRspHop.getIp().getIpv4Address()); + header.setNshTunUdpPort(firstRspHop.getPort()); + + LOG.debug("The Nsh Header = {}", header); + OvsdbTerminationPointAugmentation localPort = getTerminationPoint(srcNode, LOCAL_TP_ID); + + /* String attachedMac = southbound.getInterfaceExternalIdsValue(localPort, Constants.EXTERNAL_ID_VM_MAC); + if (attachedMac == null) { + LOG.warn("No AttachedMac seen in {}", localPort); + // return; + } + */ + LOG.debug("LocalPort ID={}, IP Address = {}", localPort.getName(), getSourceIp(match)); + handleLocalInPort(southbound.getDataPathId(srcNode), TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL, + NETWORK_SEGMENT_ID, localPort.getOfport(), getSourceIp(match), true); + + // L2 Dst MAC forwarding flows. + // L2 Flood Flows. + // Set the Tunnel Destination IP, Dest MAC based on the destination IP address. + // Replace SMAC & decrement TTL. + // handleL3Flows(southbound.getDataPathId(srcNode), TABLE_1_ISOLATE_TENANT, + // TABLE_2_INGRESS_ACL, destIp, l3SegmentId, destMac); + // Set NSP & NSI values based on the Classifier Match actions. + OvsdbTerminationPointAugmentation outPort = getTerminationPoint(srcNode, INTERFACE_TYPE_VXLAN_GPE); + // TODO: commented out for test + //handleSfcClassiferFlows(entry.getRuleName(), srcNode, match, + // TABLE_3_INGR_ACL, header, outPort.getOfport(), true); + // Set NSHC1, NSHC2, Tunnel DestIP, port toward SFF1, output to Tunnel Port. + + } + } + + private OvsdbTerminationPointAugmentation getTerminationPoint(Node srcNode, String localTpId) { + List ports = southbound.extractTerminationPointAugmentations(srcNode); + if (ports != null && !ports.isEmpty()) { + for (OvsdbTerminationPointAugmentation port : ports) { + // TBD :: For Demo, use the Tunnel ID as 10. Once openstack is integrated, + // tunnel ID is created through Network Creation. + if (port.getName().contains(localTpId)) { + return port; + } + } + } + return null; + } + + private String getTunnelName(String networkTypeVxlan, Ipv4Address ipv4Address) { + return networkTypeVxlan + "-" + ipv4Address.getValue(); + } + + /* + * (TABLE:50) EGRESS VM TRAFFIC TOWARDS TEP with NSH header + * MATCH: Match fields passed through ACL entry + * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N) + * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \ + * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1" + */ + private void handleSfcClassiferFlows(String ruleName, Node node, Matches match, + short table3IngrAcl, NshUtils header, long ofPort, boolean write) { + // Build the Actions to Add the NSH Header + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load = + NshUtils.nxLoadNshc1RegAction(header.getNshMetaC1()); + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC2Load = + NshUtils.nxLoadNshc2RegAction(header.getNshMetaC2()); + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad = + NshUtils.nxSetNspAction(header.getNshNsp()); + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad = + NshUtils.nxSetNsiAction(header.getNshNsi()); + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid = + NshUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshMetaC2()), false); + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest = + NshUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false); + + int count = 0; + List actionList = Lists.newArrayList(); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nshC1Load).build()); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nshC2Load).build()); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nspLoad).build()); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nsiLoad).build()); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(loadChainTunDest).build()); + actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(loadChainTunVnid).build()); + + 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)); + + List instructions = Lists.newArrayList(); + instructions.add(ib.build()); + + // Set the Output Port/Iface + InstructionUtils.createOutputPortInstructions(ib, southbound.getDataPathId(node), ofPort); + ib.setOrder(1); + ib.setKey(new InstructionKey(1)); + instructions.add(ib.build()); + + // Add InstructionBuilder to the Instruction(s)Builder List + InstructionsBuilder isb = new InstructionsBuilder(); + isb.setInstruction(instructions); + + String flowId = "NETVIRT_SFC_FLOW" + "_" + ruleName + "_" + header.getNshNsp(); FlowBuilder flowBuilder = new FlowBuilder(); flowBuilder.setId(new FlowId(flowId)); FlowKey key = new FlowKey(new FlowId(flowId)); - flowBuilder.setMatch(matchBuilder.build()); + + MatchBuilder mb = buildMatch(match); + flowBuilder.setMatch(mb.build()); flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY); flowBuilder.setBarrier(true); - flowBuilder.setTableId(this.getTable()); + flowBuilder.setTableId(table3IngrAcl); flowBuilder.setKey(key); flowBuilder.setFlowName(flowId); flowBuilder.setHardTimeout(0); @@ -165,6 +396,175 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ flowBuilder.setInstructions(isb.build()); + if (write) { + writeFlow(flowBuilder, createNodeBuilder(node.getNodeId().getValue())); + } else { + removeFlow(flowBuilder, createNodeBuilder(node.getNodeId().getValue())); + } + } + + /* + * (TABLE:0) EGRESS VM TRAFFIC TOWARDS TEP + * MATCH: DESTINATION ETHERNET ADDR AND OPENFLOW INPORT + * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N) + * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \ + * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1" + */ + private void handleLocalInPort(long dpidLong, short writeTable, short goToTableId, + String segmentationId, Long inPort, String sourceIp, + boolean write) { + programDropSrcIface(dpidLong, inPort, true); + programLocalInPort(dpidLong, segmentationId, inPort, sourceIp, goToTableId, write); + } + + private String getDestIp(Matches match) { + if (match.getAceType() instanceof AceIp) { + AceIp aceIp = (AceIp)match.getAceType(); + if (aceIp.getAceIpVersion() instanceof AceIpv4) { + AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion(); + if (aceIpv4.getDestinationIpv4Network() != null) { + String ipAddrPrefix = aceIpv4.getDestinationIpv4Network().getValue(); + String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken(); + return ipAddr; + } + } + } + return null; + } + + private String getSourceIp(Matches match) { + if (match.getAceType() instanceof AceIp) { + AceIp aceIp = (AceIp)match.getAceType(); + if (aceIp.getAceIpVersion() instanceof AceIpv4) { + AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion(); + if (aceIpv4.getSourceIpv4Network() != null) { + String ipAddrPrefix = aceIpv4.getSourceIpv4Network().getValue(); + //String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken(); + return ipAddrPrefix; + } + } + } + return null; + } + + private long convertToLongIp(String ipaddr) { + LOG.debug("Converting String={} to Long", ipaddr); + return InetAddresses.coerceToInteger(InetAddresses.forString(ipaddr)) & 0xFFFFFFFFL; + } + + private void programLocalInPort(Long dpidLong, String segmentationId, Long inPort, + String ipAddr, short goToTableId, boolean write) { + String nodeName = OPENFLOW + dpidLong; + + MatchBuilder matchBuilder = new MatchBuilder(); + NodeBuilder nodeBuilder = createNodeBuilder(nodeName); + FlowBuilder flowBuilder = new FlowBuilder(); + + // Create the OF Match using MatchBuilder + //flowBuilder.setMatch(MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(attachedMac)).build()); + // TODO Broken In_Port Match + flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build()); + //flowBuilder.setMatch(MatchUtils.createSrcL3IPv4Match(matchBuilder, new Ipv4Prefix(ipAddr)).build()); + String flowId = "LocalSfc_" + segmentationId + "_" + inPort;// + "_" + ipAddr.split("/",2)[0]; + // Add Flow Attributes + flowBuilder.setId(new FlowId(flowId)); + FlowKey key = new FlowKey(new FlowId(flowId)); + flowBuilder.setStrict(true); + flowBuilder.setBarrier(false); + flowBuilder.setTableId((short)0);//getTable()); + flowBuilder.setKey(key); + flowBuilder.setFlowName(flowId); + flowBuilder.setPriority(8192); + flowBuilder.setHardTimeout(0); + flowBuilder.setIdleTimeout(0); + + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); + + // Instructions List Stores Individual Instructions + List instructions = Lists.newArrayList(); + + // TODO Broken SetTunID + //InstructionUtils.createSetTunnelIdInstructions(ib, new BigInteger(segmentationId)); + //ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction(); + //List actionList = aac.getApplyActions().getAction(); + + //ActionBuilder ab = new ActionBuilder(); + //ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(), + // BigInteger.valueOf(REG_VALUE_FROM_LOCAL))); + //ab.setOrder(1); + //ab.setKey(new ActionKey(1)); + + //actionList.add(ab.build()); + + //ib.setOrder(0); + //ib.setKey(new InstructionKey(0)); + //instructions.add(ib.build()); + + // Next service GOTO Instructions Need to be appended to the List + ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId); + ib.setOrder(0);//1); + ib.setKey(new InstructionKey(0));//1)); + instructions.add(ib.build()); + + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); + + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } + } + + public void programDropSrcIface(Long dpidLong, Long inPort, boolean write) { + + String nodeName = OPENFLOW + dpidLong; + + MatchBuilder matchBuilder = new MatchBuilder(); + NodeBuilder nodeBuilder = createNodeBuilder(nodeName); + FlowBuilder flowBuilder = new FlowBuilder(); + + // Create the OF Match using MatchBuilder + flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build()); + + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); + + // Instructions List Stores Individual Instructions + List instructions = Lists.newArrayList(); + + // Call the InstructionBuilder Methods Containing Actions + InstructionUtils.createDropInstructions(ib); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); + + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); + + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } + + String flowId = "DropFilter_"+inPort; + // Add Flow Attributes + flowBuilder.setId(new FlowId(flowId)); + FlowKey key = new FlowKey(new FlowId(flowId)); + flowBuilder.setStrict(true); + flowBuilder.setBarrier(false); + flowBuilder.setTableId((short)50);//getTable()); + flowBuilder.setKey(key); + flowBuilder.setFlowName(flowId); + flowBuilder.setPriority(8192); + flowBuilder.setHardTimeout(0); + flowBuilder.setIdleTimeout(0); if (write) { writeFlow(flowBuilder, nodeBuilder); } else { @@ -172,6 +572,28 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ } } + private Node getBridgeNode(String bridgeName) { + //SffOvsBridgeAugmentation sffBridge = sff.getAugmentation(SffOvsBridgeAugmentation.class); + //String brName = sffBridge.getOvsBridge().getBridgeName(); + + final List nodes = nodeCacheManager.getBridgeNodes(); + if (nodes.isEmpty()) { + LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", bridgeName); + } else { + for (Node node : nodes) { + OvsdbBridgeAugmentation bridgeAugmentation = southbound.extractBridgeAugmentation(node); + if (bridgeAugmentation != null) { + if (bridgeAugmentation.getBridgeName().getValue().equalsIgnoreCase(bridgeName)) { + LOG.info("Found matching OVSDB Bridge Name {}", node.getNodeId().getValue()); + return node; + } + } + } + } + return null; + } + +/* private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) { InstructionBuilder ib = new InstructionBuilder(); @@ -199,9 +621,37 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ InstructionsBuilder isb = new InstructionsBuilder(); isb.setInstruction(instructions); return isb; + }*/ + + private ServiceFunctionPath getSfp(String redirectSfc) { + ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths(); + if (sfps != null) { + for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) { + if (sfp.getServiceChainName().getValue().equalsIgnoreCase(redirectSfc)) { + return sfp; + } + } + } + return null; + } + + private RenderedServicePath getRspforSfp(String sfpName) { + RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId()); + if (rsps == null) { + LOG.debug("RSP has not been configured yet for SFP = {}", sfpName); + return null; + } + for (RenderedServicePath rsp : rsps.getRenderedServicePath()) { + if (rsp.getParentServiceFunctionPath() != null) { + if (rsp.getParentServiceFunctionPath().getValue().equalsIgnoreCase(sfpName)) { + return rsp; + } + } + } + return null; } - private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) { + private MatchBuilder buildMatch(Matches matches) { MatchBuilder matchBuilder = new MatchBuilder(); if (matches.getAceType() instanceof AceIp) { @@ -209,10 +659,10 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ if (aceIp.getAceIpVersion() instanceof AceIpv4) { AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion(); MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network()); - MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network()); - MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol()); + //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network()); + //MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol()); MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), - aceIp.getSourcePortRange().getLowerPort().getValue().intValue(), + 0, aceIp.getDestinationPortRange().getLowerPort().getValue().intValue()); } } else if (matches.getAceType() instanceof AceEth) { @@ -229,19 +679,37 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ @Override public void removeClassifierRules(Sff sff, Acl acl) { // TODO Auto-generated method stub - } - + /* protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) { LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}", flowBuilder.build(), nodeBuilder.build()); - dbutils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build()); - dbutils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build()); + mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build()); + mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build()); + } +*/ + protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) { + LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}", + flowBuilder.build(), nodeBuilder.build()); + WriteTransaction modification = dataBroker.newWriteOnlyTransaction(); + modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), + nodeBuilder.build(), true /*createMissingParents*/); + modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), + flowBuilder.build(), true /*createMissingParents*/); + + CheckedFuture commitFuture = modification.submit(); + try { + commitFuture.get(); // TODO: Make it async (See bug 1362) + LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName()); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + modification.cancel(); + } } protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) { - dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)); + mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)); } private String getDpid(Node node) { @@ -268,22 +736,28 @@ public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{ nodeBuilder.getKey()).build(); } - private short getTable() { - return Service.INGRESS_ACL.getTable(); + private NodeBuilder createNodeBuilder(String nodeId) { + NodeBuilder builder = new NodeBuilder(); + builder.setId(new NodeId(nodeId)); + builder.setKey(new NodeKey(builder.getId())); + return builder; } - private final InstructionBuilder getMutablePipelineInstructionBuilder() { - Service nextService = orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL); - if (nextService != null) { - return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable()); - } else { - return InstructionUtils.createDropInstructions(new InstructionBuilder()); - } + private InstanceIdentifier getRspsId() { + return InstanceIdentifier.builder(RenderedServicePaths.class).build(); + } + + private InstanceIdentifier getRspId(String rspName) { + return InstanceIdentifier.builder(RenderedServicePaths.class) + .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build(); + } + + private short getTable() { + return Service.INGRESS_ACL.getTable(); } private void setDependencies(ServiceReference serviceReference) { nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this); southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this); - orchestrator = (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this); } } diff --git a/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java new file mode 100644 index 000000000..5265235e0 --- /dev/null +++ b/openstack/net-virt-sfc/impl/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/openflow13/NshUtils.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015 Dell, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13; + +import java.math.BigInteger; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg; + +import com.google.common.net.InetAddresses; + +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.opendaylight.action.types.rev131112.action.Action; +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.DstNxRegCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.group.buckets.bucket.action.action.NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputReg; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputRegBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoadBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.nx.reg.load.DstBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsi; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsiBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNsp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNspBuilder; +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.SrcNxRegCaseBuilder; + +/** + * Open Vswitch DB OpenFlow 1.3 Networking Provider for Netvirt SFC Utilities. + * @author Arun Yerra + */ +public class NshUtils { + private Ipv4Address nshTunIpDst; + private PortNumber nshTunUdpPort; + private long nshNsp; + private short nshNsi; + private long nshMetaC1; + private long nshMetaC2; + + public NshUtils() { + super(); + } + + /** + * {@link NshUtils} constructor. + * @param nshTunIpDst Tunnel Destination IP + * @param nshTunUdpPort Tunnel Transport Port + * @param nshNsp Service Path Id + * @param nshNsi Service Path Index + * @param nshMetaC1 End point ID + * @param nshMetaC2 Tunnel Id. + */ + public NshUtils(Ipv4Address nshTunIpDst, PortNumber nshTunUdpPort, + long nshNsp, short nshNsi, long nshMetaC1, + long nshMetaC2) { + super(); + this.nshTunIpDst = nshTunIpDst; + this.nshTunUdpPort = nshTunUdpPort; + this.nshNsp = nshNsp; + this.nshNsi = nshNsi; + this.nshMetaC1 = nshMetaC1; + this.nshMetaC2 = nshMetaC2; + } + + /* + * @return the nshTunIpDst + */ + public Ipv4Address getNshTunIpDst() { + return nshTunIpDst; + } + + /* + * @param nshTunIpDst the nshTunIpDst to set + */ + public void setNshTunIpDst(Ipv4Address nshTunIpDst) { + this.nshTunIpDst = nshTunIpDst; + } + + /* + * @return the nshTunUdpPort + */ + public PortNumber getNshTunUdpPort() { + return nshTunUdpPort; + } + + /* + * @param nshTunUdpPort the nshTunUdpPort to set + */ + public void setNshTunUdpPort(PortNumber nshTunUdpPort) { + this.nshTunUdpPort = nshTunUdpPort; + } + + /* + * @return the nshNsp + */ + public long getNshNsp() { + return nshNsp; + } + + /* + * @param nshNsp the nshNsp to set + */ + public void setNshNsp(long nshNsp) { + this.nshNsp = nshNsp; + } + + /* + * @return the nshNsi + */ + public short getNshNsi() { + return nshNsi; + } + + /* + * @param nshNsi the nshNsi to set + */ + public void setNshNsi(short nshNsi) { + this.nshNsi = nshNsi; + } + + /* + * @return the nshMetaC1 + */ + public long getNshMetaC1() { + return nshMetaC1; + } + + /* + * @param nshMetaC1 the nshMetaC1 to set + */ + public void setNshMetaC1(long nshMetaC1) { + this.nshMetaC1 = nshMetaC1; + } + + /* + * @return the nshMetaC2 + */ + public long getNshMetaC2() { + return nshMetaC2; + } + + /* + * @param nshMetaC2 the nshMetaC2 to set + */ + public void setNshMetaC2(long nshMetaC2) { + this.nshMetaC2 = nshMetaC2; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "NshUtils [nshTunIpDst=" + nshTunIpDst + ", nshTunUdpPort=" + nshTunUdpPort + ", nshNsp=" + nshNsp + + ", nshNsi=" + nshNsi + ", nshMetaC1=" + nshMetaC1 + ", nshMetaC2=" + nshMetaC2 + "]"; + } + + /** + * This method loads the action into NX register. + *{@link NshUtils} Loading Register + * @param dstChoice destination + * @param value value + * @param endOffset Offset + * @param groupBucket Identifies the group + */ + public static Action nxLoadRegAction(DstChoice dstChoice, BigInteger value, int endOffset, boolean groupBucket) { + NxRegLoad reg = new NxRegLoadBuilder().setDst( + new DstBuilder().setDstChoice(dstChoice) + .setStart(Integer.valueOf(0)) + .setEnd(Integer.valueOf(endOffset)) + .build()) + .setValue(value) + .build(); + if (groupBucket) { + return new NxActionRegLoadNodesNodeGroupBucketsBucketActionsCaseBuilder().setNxRegLoad(reg).build(); + } else { + return new NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder().setNxRegLoad(reg).build(); + } + } + + public static Action nxLoadRegAction(DstChoice dstChoice, BigInteger value) { + return nxLoadRegAction(dstChoice, value, 31, false); + } + + public static Action nxLoadRegAction(Class reg, BigInteger value) { + return nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(reg).build(), value); + } + + public static Action nxSetNsiAction(Short nsi) { + NxSetNsi newNsi = new NxSetNsiBuilder().setNsi(nsi).build(); + return new NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNsi(newNsi).build(); + } + + public static Action nxSetNspAction(Long nsp) { + NxSetNsp newNsp = new NxSetNspBuilder().setNsp(nsp).build(); + return new NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNsp(newNsp).build(); + } + + public static Action nxLoadNshc1RegAction(Long value) { + NxSetNshc1 newNshc1 = new NxSetNshc1Builder().setNshc(value).build(); + return new NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc1(newNshc1).build(); + } + + public static Action nxLoadNshc2RegAction(Long value) { + NxSetNshc2 newNshc2 = new NxSetNshc2Builder().setNshc(value).build(); + return new NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc2(newNshc2).build(); + } + + public static Action nxLoadNshc3RegAction(Long value) { + NxSetNshc3 newNshc3 = new NxSetNshc3Builder().setNshc(value).build(); + return new NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc3(newNshc3).build(); + } + + public static Action nxLoadNshc4RegAction(Long value) { + NxSetNshc4 newNshc4 = new NxSetNshc4Builder().setNshc(value).build(); + return new NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc4(newNshc4).build(); + } + + /** + * This method loads Destination IPv4 address of Tunnel. + */ + public static Action nxLoadTunIPv4Action(String ipAddress, boolean groupBucket) { + int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress)); + long ipl = ip & 0xffffffffL; + return nxLoadRegAction(new DstNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(), + BigInteger.valueOf(ipl), 31, groupBucket); + } + + public static Action nxLoadTunIdAction(BigInteger tunnelId, boolean groupBucket) { + return nxLoadRegAction(new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), tunnelId, 31, groupBucket); + } + + /** + * This method loads output port. + */ + public static Action nxOutputRegAction(SrcChoice srcChoice) { + NxOutputReg reg = new NxOutputRegBuilder().setSrc( + new org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension + .nicira.action.rev140714.nx.action.output.reg.grouping.nx.output.reg + .SrcBuilder().setSrcChoice(srcChoice) + .setOfsNbits(Integer.valueOf(31)) + .build()) + .setMaxLen(Integer.valueOf(0xffff)) + .build(); + return new NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder().setNxOutputReg(reg).build(); + } + + public static Action nxOutputRegAction(Class reg) { + return nxOutputRegAction(new SrcNxRegCaseBuilder().setNxReg(reg).build()); + } +} diff --git a/openstack/net-virt-sfc/it/pom.xml b/openstack/net-virt-sfc/it/pom.xml index a9dc254eb..441bcf8be 100644 --- a/openstack/net-virt-sfc/it/pom.xml +++ b/openstack/net-virt-sfc/it/pom.xml @@ -88,11 +88,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html maven-failsafe-plugin - + diff --git a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java index 443656e68..c39bf63bf 100644 --- a/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java +++ b/openstack/net-virt-sfc/it/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/sfc/NetvirtSfcIT.java @@ -35,6 +35,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.Constants; import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils; import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils; import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils; +import org.opendaylight.ovsdb.southbound.SouthboundConstants; import org.opendaylight.ovsdb.southbound.SouthboundUtil; import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils; @@ -159,7 +160,7 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase { LogLevel.INFO.name()), editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG, "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc", - LogLevel.INFO.name()), + LogLevel.TRACE.name()), /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG, "log4j.logger.org.opendaylight.ovsdb", LogLevelOption.LogLevel.TRACE.name()),*/ @@ -364,4 +365,58 @@ public class NetvirtSfcIT extends AbstractMdsalTestBase { Thread.sleep(1000); assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo)); } + + @Test + public void testDemo() throws InterruptedException { + for (DemoVm vm : demoVms){ + ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(vm.ipAddr, vm.ipPort); + assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo)); + Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo); + assertNotNull("node is not connected", ovsdbNode); + String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode); + assertNotNull("Failed to get controller target", controllerTarget); + List setControllerEntry = southboundUtils.createControllerEntry(controllerTarget); + Uri setUri = new Uri(controllerTarget); + assertTrue(southboundUtils.addBridge(connectionInfo, null, vm.name, null, true, + SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, + setControllerEntry, null)); + + for (int i = 0; i < 10; i++) { + OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, vm.name); + assertNotNull("bridge was not found: " + vm.name, bridge); + assertNotNull("ControllerEntry was not found: " + + southboundUtils.createControllerEntry(controllerTarget), + bridge.getControllerEntry()); + List getControllerEntries = bridge.getControllerEntry(); + for (ControllerEntry entry : getControllerEntries) { + if (entry.isIsConnected()) { + assertTrue(entry.isIsConnected()); + break; + } + } + Thread.sleep(1000); + } + + assertTrue(southboundUtils.deleteBridge(connectionInfo, vm.name)); + Thread.sleep(1000); + assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo)); + } + } + + private class DemoVm { + String name; + String ipAddr; + String ipPort; + + DemoVm(String name, String ipAddr, String ipPort) { + this.name = name; + this.ipAddr = ipAddr; + this.ipPort = ipPort; + } + } + + private DemoVm[] demoVms = { + new DemoVm("sw1", "192.168.50.70", "6640"), + //new DemoVm("sw2", "192.168.50.71", "6640"), + }; } diff --git a/southbound/southbound-impl/pom.xml b/southbound/southbound-impl/pom.xml index 13d215cf9..88f724123 100644 --- a/southbound/southbound-impl/pom.xml +++ b/southbound/southbound-impl/pom.xml @@ -108,6 +108,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html + org.opendaylight.ovsdb.southbound, org.opendaylight.ovsdb.southbound.*, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.southbound.impl.rev141210.* diff --git a/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java b/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java index 7ac9a396b..76c90549d 100644 --- a/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java +++ b/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java @@ -317,6 +317,13 @@ public class SouthboundUtils { return result; } + public boolean addBridge(final ConnectionInfo connectionInfo, final String bridgeName) + throws InterruptedException { + + return addBridge(connectionInfo, null, bridgeName, null, true, + SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null); + } + private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder, final ConnectionInfo connectionInfo) { InstanceIdentifier connectionNodePath = createInstanceIdentifier(connectionInfo); -- 2.36.6