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