/* * Copyright 2014-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.cli.net; import org.apache.karaf.shell.commands.Option; import org.onlab.packet.Ip6Address; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; import org.onlab.util.Bandwidth; import org.onosproject.cli.AbstractShellCommand; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.EncapsulationType; import org.onosproject.net.PortNumber; import org.onosproject.net.ResourceGroup; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.intent.Constraint; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.Key; import org.onosproject.net.intent.constraint.BandwidthConstraint; import org.onosproject.net.intent.constraint.DomainConstraint; import org.onosproject.net.intent.constraint.EncapsulationConstraint; import org.onosproject.net.intent.constraint.HashedPathSelectionConstraint; import org.onosproject.net.intent.constraint.PartialFailureConstraint; import java.util.LinkedList; import java.util.List; import static com.google.common.base.Strings.isNullOrEmpty; import static org.onosproject.net.flow.DefaultTrafficTreatment.builder; /** * Base class for command line operations for connectivity based intents. */ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { // Selectors @Option(name = "-s", aliases = "--ethSrc", description = "Source MAC Address", required = false, multiValued = false) private String srcMacString = null; @Option(name = "-d", aliases = "--ethDst", description = "Destination MAC Address", required = false, multiValued = false) private String dstMacString = null; @Option(name = "-t", aliases = "--ethType", description = "Ethernet Type", required = false, multiValued = false) private String ethTypeString = null; @Option(name = "-v", aliases = "--vlan", description = "VLAN ID", required = false, multiValued = false) private String vlanString = null; @Option(name = "--ipProto", description = "IP Protocol", required = false, multiValued = false) private String ipProtoString = null; @Option(name = "--ipSrc", description = "Source IP Prefix", required = false, multiValued = false) private String srcIpString = null; @Option(name = "--ipDst", description = "Destination IP Prefix", required = false, multiValued = false) private String dstIpString = null; @Option(name = "--fLabel", description = "IPv6 Flow Label", required = false, multiValued = false) private String fLabelString = null; @Option(name = "--icmp6Type", description = "ICMPv6 Type", required = false, multiValued = false) private String icmp6TypeString = null; @Option(name = "--icmp6Code", description = "ICMPv6 Code", required = false, multiValued = false) private String icmp6CodeString = null; @Option(name = "--ndTarget", description = "IPv6 Neighbor Discovery Target Address", required = false, multiValued = false) private String ndTargetString = null; @Option(name = "--ndSLL", description = "IPv6 Neighbor Discovery Source Link-Layer", required = false, multiValued = false) private String ndSllString = null; @Option(name = "--ndTLL", description = "IPv6 Neighbor Discovery Target Link-Layer", required = false, multiValued = false) private String ndTllString = null; @Option(name = "--tcpSrc", description = "Source TCP Port", required = false, multiValued = false) private String srcTcpString = null; @Option(name = "--tcpDst", description = "Destination TCP Port", required = false, multiValued = false) private String dstTcpString = null; @Option(name = "--extHdr", description = "IPv6 Extension Header Pseudo-field", required = false, multiValued = true) private List<String> extHdrStringList = null; @Option(name = "-a", aliases = "--appId", description = "Application Id", required = false, multiValued = false) private String appId = null; @Option(name = "-k", aliases = "--key", description = "Intent Key", required = false, multiValued = false) private String intentKey = null; // Treatments @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", required = false, multiValued = false) private String setEthSrcString = null; @Option(name = "--setEthDst", description = "Rewrite Destination MAC Address", required = false, multiValued = false) private String setEthDstString = null; @Option(name = "--setIpSrc", description = "Rewrite Source IP Address", required = false, multiValued = false) private String setIpSrcString = null; @Option(name = "--setIpDst", description = "Rewrite Destination IP Address", required = false, multiValued = false) private String setIpDstString = null; @Option(name = "--setVlan", description = "Rewrite VLAN ID", required = false, multiValued = false) private String setVlan = null; @Option(name = "--popVlan", description = "Pop VLAN Tag", required = false, multiValued = false) private boolean popVlan = false; @Option(name = "--pushVlan", description = "Push VLAN ID", required = false, multiValued = false) private String pushVlan = null; @Option(name = "--setQueue", description = "Set Queue ID (for OpenFlow 1.0, " + "also the port has to be specified, i.e., <port>/<queue>", required = false, multiValued = false) private String setQueue = null; // Priorities @Option(name = "-p", aliases = "--priority", description = "Priority", required = false, multiValued = false) private int priority = Intent.DEFAULT_INTENT_PRIORITY; // Constraints @Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth", required = false, multiValued = false) private String bandwidthString = null; @Option(name = "--partial", description = "Allow partial installation", required = false, multiValued = false) private boolean partial = false; @Option(name = "-e", aliases = "--encapsulation", description = "Encapsulation type", required = false, multiValued = false) private String encapsulationString = null; @Option(name = "--hashed", description = "Hashed path selection", required = false, multiValued = false) private boolean hashedPathSelection = false; @Option(name = "--domains", description = "Allow domain delegation", required = false, multiValued = false) private boolean domains = false; // Resource Group @Option(name = "-r", aliases = "--resourceGroup", description = "Resource Group Id", required = false, multiValued = false) private String resourceGroupId = null; /** * Constructs a traffic selector based on the command line arguments * presented to the command. * @return traffic selector */ protected TrafficSelector buildTrafficSelector() { IpPrefix srcIpPrefix = null; IpPrefix dstIpPrefix = null; TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); if (!isNullOrEmpty(srcIpString)) { srcIpPrefix = IpPrefix.valueOf(srcIpString); if (srcIpPrefix.isIp4()) { selectorBuilder.matchIPSrc(srcIpPrefix); } else { selectorBuilder.matchIPv6Src(srcIpPrefix); } } if (!isNullOrEmpty(dstIpString)) { dstIpPrefix = IpPrefix.valueOf(dstIpString); if (dstIpPrefix.isIp4()) { selectorBuilder.matchIPDst(dstIpPrefix); } else { selectorBuilder.matchIPv6Dst(dstIpPrefix); } } if ((srcIpPrefix != null) && (dstIpPrefix != null) && (srcIpPrefix.version() != dstIpPrefix.version())) { // ERROR: IP src/dst version mismatch throw new IllegalArgumentException( "IP source and destination version mismatch"); } // // Set the default EthType based on the IP version if the matching // source or destination IP prefixes. // Short ethType = null; if ((srcIpPrefix != null) && srcIpPrefix.isIp6()) { ethType = EthType.IPV6.value(); } if ((dstIpPrefix != null) && dstIpPrefix.isIp6()) { ethType = EthType.IPV6.value(); } if (!isNullOrEmpty(ethTypeString)) { ethType = EthType.parseFromString(ethTypeString); } if (ethType != null) { selectorBuilder.matchEthType(ethType); } if (!isNullOrEmpty(vlanString)) { selectorBuilder.matchVlanId(VlanId.vlanId(Short.parseShort(vlanString))); } if (!isNullOrEmpty(srcMacString)) { selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString)); } if (!isNullOrEmpty(dstMacString)) { selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString)); } if (!isNullOrEmpty(ipProtoString)) { short ipProtoShort = IpProtocol.parseFromString(ipProtoString); selectorBuilder.matchIPProtocol((byte) ipProtoShort); } if (!isNullOrEmpty(fLabelString)) { selectorBuilder.matchIPv6FlowLabel(Integer.parseInt(fLabelString)); } if (!isNullOrEmpty(icmp6TypeString)) { byte icmp6Type = Icmp6Type.parseFromString(icmp6TypeString); selectorBuilder.matchIcmpv6Type(icmp6Type); } if (!isNullOrEmpty(icmp6CodeString)) { byte icmp6Code = Icmp6Code.parseFromString(icmp6CodeString); selectorBuilder.matchIcmpv6Code(icmp6Code); } if (!isNullOrEmpty(ndTargetString)) { selectorBuilder.matchIPv6NDTargetAddress(Ip6Address.valueOf(ndTargetString)); } if (!isNullOrEmpty(ndSllString)) { selectorBuilder.matchIPv6NDSourceLinkLayerAddress(MacAddress.valueOf(ndSllString)); } if (!isNullOrEmpty(ndTllString)) { selectorBuilder.matchIPv6NDTargetLinkLayerAddress(MacAddress.valueOf(ndTllString)); } if (!isNullOrEmpty(srcTcpString)) { selectorBuilder.matchTcpSrc(TpPort.tpPort(Integer.parseInt(srcTcpString))); } if (!isNullOrEmpty(dstTcpString)) { selectorBuilder.matchTcpDst(TpPort.tpPort(Integer.parseInt(dstTcpString))); } if (extHdrStringList != null) { short extHdr = 0; for (String extHdrString : extHdrStringList) { extHdr = (short) (extHdr | ExtHeader.parseFromString(extHdrString)); } selectorBuilder.matchIPv6ExthdrFlags(extHdr); } return selectorBuilder.build(); } /** * Generates a traffic treatment for this intent based on command line * arguments presented to the command. * * @return traffic treatment */ protected TrafficTreatment buildTrafficTreatment() { final TrafficTreatment.Builder treatmentBuilder = builder(); boolean emptyTreatment = true; if (!isNullOrEmpty(setEthSrcString)) { treatmentBuilder.setEthSrc(MacAddress.valueOf(setEthSrcString)); emptyTreatment = false; } if (!isNullOrEmpty(setEthDstString)) { treatmentBuilder.setEthDst(MacAddress.valueOf(setEthDstString)); emptyTreatment = false; } if (!isNullOrEmpty(setIpSrcString)) { treatmentBuilder.setIpSrc(IpAddress.valueOf(setIpSrcString)); emptyTreatment = false; } if (!isNullOrEmpty(setIpDstString)) { treatmentBuilder.setIpDst(IpAddress.valueOf(setIpDstString)); emptyTreatment = false; } if (!isNullOrEmpty(setVlan)) { treatmentBuilder.setVlanId(VlanId.vlanId(Short.parseShort(setVlan))); emptyTreatment = false; } if (popVlan) { treatmentBuilder.popVlan(); emptyTreatment = false; } if (!isNullOrEmpty(pushVlan)) { treatmentBuilder.pushVlan(); treatmentBuilder.setVlanId(VlanId.vlanId(Short.parseShort(pushVlan))); emptyTreatment = false; } if (!isNullOrEmpty(setQueue)) { // OpenFlow 1.0 notation (for ENQUEUE): <port>/<queue> if (setQueue.contains("/")) { String[] queueConfig = setQueue.split("/"); PortNumber port = PortNumber.portNumber(Long.parseLong(queueConfig[0])); long queueId = Long.parseLong(queueConfig[1]); treatmentBuilder.setQueue(queueId, port); } else { treatmentBuilder.setQueue(Long.parseLong(setQueue)); } emptyTreatment = false; } if (emptyTreatment) { return DefaultTrafficTreatment.emptyTreatment(); } else { return treatmentBuilder.build(); } } /** * Builds the constraint list for this command based on the command line * parameters. * * @return List of constraint objects describing the constraints requested */ protected List<Constraint> buildConstraints() { final List<Constraint> constraints = new LinkedList<>(); // Check for a bandwidth specification if (!isNullOrEmpty(bandwidthString)) { Bandwidth bandwidth; try { bandwidth = Bandwidth.bps(Long.parseLong(bandwidthString)); // when the string can't be parsed as long, then try to parse as double } catch (NumberFormatException e) { bandwidth = Bandwidth.bps(Double.parseDouble(bandwidthString)); } constraints.add(new BandwidthConstraint(bandwidth)); } // Check for partial failure specification if (partial) { constraints.add(new PartialFailureConstraint()); } // Check for encapsulation specification if (!isNullOrEmpty(encapsulationString)) { final EncapsulationType encapType = EncapsulationType.valueOf(encapsulationString); constraints.add(new EncapsulationConstraint(encapType)); } // Check for hashed path selection if (hashedPathSelection) { constraints.add(new HashedPathSelectionConstraint()); } // Check for domain processing if (domains) { constraints.add(DomainConstraint.domain()); } return constraints; } @Override protected ApplicationId appId() { ApplicationId appIdForIntent; if (appId == null) { appIdForIntent = super.appId(); } else { CoreService service = get(CoreService.class); appIdForIntent = service.getAppId(appId); } return appIdForIntent; } protected ResourceGroup resourceGroup() { if (resourceGroupId != null) { if (resourceGroupId.toLowerCase().startsWith("0x")) { return ResourceGroup.of(Long.parseUnsignedLong(resourceGroupId.substring(2), 16)); } else { return ResourceGroup.of(Long.parseUnsignedLong(resourceGroupId)); } } else { return null; } } /** * Creates a key for an intent based on command line arguments. If a key * has been specified, it is returned. If no key is specified, null * is returned. * * @return intent key if specified, null otherwise */ protected Key key() { Key key = null; if (intentKey != null) { key = Key.of(intentKey, appId()); } return key; } /** * Gets the priority to use for the intent. * * @return priority */ protected int priority() { return priority; } }