| /* |
| * 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; |
| ApplicationId appIdForIntent; |
| |
| 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; |
| } |
| } |