Charles M.C. Chan
Committed by Gerrit Code Review

ONOS-1756: Improve CLI auto completers

- Add more ICMP types and codes
- Add completer for --icmp6Type
- Add completer for --icmp6Code
- Add completer for --extHdr
    It is a multiValued option.
    For example, the following command will match an IPv6 packet with both fragment and routing extension header:
    add-point-intent --ethType IPV6 --extHdr FRAG --extHdr ROUTING
    NOTE: OVS 2.3.1 does not support OFPXMC_OFB_IPV6_EXTHDR match field yet.
- Change parameter of TrafficSelector.matchIPv6ExthdrFlags() from int to short since that field is 9 bits only

Change-Id: I55944399f3985f2cc09330a726f21983de273341
......@@ -104,8 +104,8 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
private String dstTcpString = null;
@Option(name = "--extHdr", description = "IPv6 Extension Header Pseudo-field",
required = false, multiValued = false)
private String extHdrString = null;
required = false, multiValued = true)
private List<String> extHdrStringList = null;
@Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth",
required = false, multiValued = false)
......@@ -217,11 +217,13 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
}
if (!isNullOrEmpty(icmp6TypeString)) {
selectorBuilder.matchIcmpv6Type((byte) Integer.parseInt(icmp6TypeString));
byte icmp6Type = Icmp6Type.parseFromString(icmp6TypeString);
selectorBuilder.matchIcmpv6Type(icmp6Type);
}
if (!isNullOrEmpty(icmp6CodeString)) {
selectorBuilder.matchIcmpv6Code((byte) Integer.parseInt(icmp6CodeString));
byte icmp6Code = Icmp6Code.parseFromString(icmp6CodeString);
selectorBuilder.matchIcmpv6Code(icmp6Code);
}
if (!isNullOrEmpty(ndTargetString)) {
......@@ -244,8 +246,12 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
selectorBuilder.matchTcpDst((short) Integer.parseInt(dstTcpString));
}
if (!isNullOrEmpty(extHdrString)) {
selectorBuilder.matchIPv6ExthdrFlags(Integer.parseInt(extHdrString));
if (extHdrStringList != null) {
short extHdr = 0;
for (String extHdrString : extHdrStringList) {
extHdr = (short) (extHdr | ExtHeader.parseFromString(extHdrString));
}
selectorBuilder.matchIPv6ExthdrFlags(extHdr);
}
return selectorBuilder.build();
......
/*
* Copyright 2014 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;
/**
* Known values for IPv6 extension header field that can be supplied to the CLI.
*/
public enum ExtHeader {
/** No next header. */
NOEXT((short) (1 << 0)),
/** Encapsulated Security Payload. */
ESP((short) (1 << 1)),
/** Authentication header. */
AUTH((short) (1 << 2)),
/** Destination header. */
DEST((short) (1 << 3)),
/** Fragment header. */
FRAG((short) (1 << 4)),
/** Router header. */
ROUTE((short) (1 << 5)),
/** Hop-by-hop header. */
HOP((short) (1 << 6)),
/** Unexpected repeats encountered. */
UNREP((short) (1 << 7)),
/** Unexpected sequencing encountered. */
UNSEQ((short) (1 << 8));
private short value;
/**
* Constructs an ExtHeader with the given value.
*
* @param value value to use when this ExtHeader is seen
*/
private ExtHeader(short value) {
this.value = value;
}
/**
* Gets the value to use for this ExtHeader.
*
* @return short value to use for this ExtHeader
*/
public short value() {
return this.value;
}
/**
* Parse a string input that could contain an ExtHeader value. The value
* may appear in the string either as a known exntension header name (one of the
* values of this enum), or a numeric extension header value.
*
* @param input the input string to parse
* @return the numeric value of the parsed IPv6 extension header
* @throws IllegalArgumentException if the input string does not contain a
* value that can be parsed into an IPv6 extension header
*/
public static short parseFromString(String input) {
try {
return valueOf(input).value();
} catch (IllegalArgumentException e) {
// The input is not a known IPv6 extension header name, let's see if
// it's an IPv6 extension header value (short).
// We parse with Short to handle unsigned values correctly.
try {
return Short.parseShort(input);
} catch (NumberFormatException e1) {
throw new IllegalArgumentException(
"ExtHeader value must be either a string extension header name"
+ " or an 8-bit extension header value");
}
}
}
}
/*
* Copyright 2014 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.console.Completer;
import org.apache.karaf.shell.console.completer.StringsCompleter;
import java.util.List;
import java.util.SortedSet;
/**
* IPv6 extension header completer.
*/
public class ExtHeaderCompleter implements Completer {
@Override
public int complete(String buffer, int cursor, List<String> candidates) {
// Delegate string completer
StringsCompleter delegate = new StringsCompleter();
SortedSet<String> strings = delegate.getStrings();
for (ExtHeader extHeader : ExtHeader.values()) {
strings.add(extHeader.toString());
}
// Now let the completer do the work for figuring out what to offer.
return delegate.complete(buffer, cursor, candidates);
}
}
/*
* Copyright 2014 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.onlab.packet.ICMP6;
/**
* Known values for ICMPv6 code field that can be supplied to the CLI.
*/
public enum Icmp6Code {
// Code for DEST_UNREACH
/** No route to destination. */
NO_ROUTE(ICMP6.NO_ROUTE),
/** Communication with destination administratively prohibited. */
COMM_PROHIBIT(ICMP6.COMM_PROHIBIT),
/** Beyond scope of source address. */
BEYOND_SCOPE(ICMP6.BEYOND_SCOPE),
/** Address unreachable. */
ADDR_UNREACH(ICMP6.ADDR_UNREACH),
/** Port unreachable. */
PORT_UNREACH(ICMP6.PORT_UNREACH),
/** Source address failed ingress/egress policy. */
FAIL_POLICY(ICMP6.FAIL_POLICY),
/** Reject route to destination. */
REJECT_ROUTE(ICMP6.REJECT_ROUTE),
/** Error in Source Routing Header. */
SRC_ROUTING_HEADER_ERR(ICMP6.SRC_ROUTING_HEADER_ERR),
// Code for TIME_EXCEED
/** Hop limit exceeded in transit. */
HOP_LIMIT_EXCEED(ICMP6.HOP_LIMIT_EXCEED),
/** Fragment reassembly time exceeded. */
DEFRAG_TIME_EXCEED(ICMP6.DEFRAG_TIME_EXCEED),
// Code for PARAM_ERR
/** Erroneous header field encountered. */
HDR_FIELD_ERR(ICMP6.HDR_FIELD_ERR),
/** Unrecognized Next Header type encountered. */
NEXT_HEADER_ERR(ICMP6.NEXT_HEADER_ERR),
/** Unrecognized IPv6 option encountered. */
IPV6_OPT_ERR(ICMP6.IPV6_OPT_ERR);
private byte value;
/**
* Constructs an Icmp6Code with the given value.
*
* @param value value to use when this Icmp6Code is seen
*/
private Icmp6Code(byte value) {
this.value = value;
}
/**
* Gets the value to use for this Icmp6Code.
*
* @return short value to use for this Icmp6Code
*/
public byte value() {
return this.value;
}
/**
* Parse a string input that could contain an Icmp6Code value. The value
* may appear in the string either as a known code name (one of the
* values of this enum), or a numeric code value.
*
* @param input the input string to parse
* @return the numeric value of the parsed ICMPv6 code
* @throws IllegalArgumentException if the input string does not contain a
* value that can be parsed into an ICMPv6 code
*/
public static byte parseFromString(String input) {
try {
return valueOf(input).value();
} catch (IllegalArgumentException e) {
// The input is not a known ICMPv6 code name, let's see if it's an ICMP6
// code value (byte). We parse with Byte to handle unsigned values
// correctly.
try {
return Byte.parseByte(input);
} catch (NumberFormatException e1) {
throw new IllegalArgumentException(
"Icmp6Code value must be either a string code name"
+ " or an 8-bit code value");
}
}
}
}
/*
* Copyright 2014 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.console.Completer;
import org.apache.karaf.shell.console.completer.StringsCompleter;
import java.util.List;
import java.util.SortedSet;
/**
* ICMPv6 type completer.
*/
public class Icmp6CodeCompleter implements Completer {
@Override
public int complete(String buffer, int cursor, List<String> candidates) {
// Delegate string completer
StringsCompleter delegate = new StringsCompleter();
SortedSet<String> strings = delegate.getStrings();
for (Icmp6Code code : Icmp6Code.values()) {
strings.add(code.toString());
}
// Now let the completer do the work for figuring out what to offer.
return delegate.complete(buffer, cursor, candidates);
}
}
/*
* Copyright 2014 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.onlab.packet.ICMP6;
/**
* Known values for ICMPv6 type field that can be supplied to the CLI.
*/
public enum Icmp6Type {
/** Destination Unreachable. */
DEST_UNREACH(ICMP6.DEST_UNREACH),
/** Packet Too Big. */
PKT_TOO_BIG(ICMP6.PKT_TOO_BIG),
/** Time Exceeded. */
TIME_EXCEED(ICMP6.TIME_EXCEED),
/** Parameter Problem. */
PARAM_ERR(ICMP6.PARAM_ERR),
/** Echo Request. */
ECHO_REQUEST(ICMP6.ECHO_REQUEST),
/** Echo Reply. */
ECHO_REPLY(ICMP6.ECHO_REPLY),
/** Multicast Listener Query. */
MCAST_QUERY(ICMP6.MCAST_QUERY),
/** Multicast Listener Report. */
MCAST_REPORT(ICMP6.MCAST_REPORT),
/** Multicast Listener Done. */
MCAST_DONE(ICMP6.MCAST_DONE),
/** Router Solicitation. */
ROUTER_SOLICITATION(ICMP6.ROUTER_SOLICITATION),
/** Router Advertisement. */
ROUTER_ADVERTISEMENT(ICMP6.ROUTER_ADVERTISEMENT),
/** Neighbor Solicitation. */
NEIGHBOR_SOLICITATION(ICMP6.NEIGHBOR_SOLICITATION),
/** Neighbor Advertisement. */
NEIGHBOR_ADVERTISEMENT(ICMP6.NEIGHBOR_ADVERTISEMENT),
/** Redirect Message. */
REDIRECT(ICMP6.REDIRECT);
private byte value;
/**
* Constructs an Icmp6Type with the given value.
*
* @param value value to use when this Icmp6Type is seen
*/
private Icmp6Type(byte value) {
this.value = value;
}
/**
* Gets the value to use for this Icmp6Type.
*
* @return short value to use for this Icmp6Type
*/
public byte value() {
return this.value;
}
/**
* Parse a string input that could contain an Icmp6Type value. The value
* may appear in the string either as a known type name (one of the
* values of this enum), or a numeric type value.
*
* @param input the input string to parse
* @return the numeric value of the parsed ICMPv6 type
* @throws IllegalArgumentException if the input string does not contain a
* value that can be parsed into an ICMPv6 type
*/
public static byte parseFromString(String input) {
try {
return valueOf(input).value();
} catch (IllegalArgumentException e) {
// The input is not a known ICMPv6 type name, let's see if it's an ICMP6
// type value (byte). We parse with Byte to handle unsigned values
// correctly.
try {
return Byte.parseByte(input);
} catch (NumberFormatException e1) {
throw new IllegalArgumentException(
"Icmp6Type value must be either a string type name"
+ " or an 8-bit type value");
}
}
}
}
/*
* Copyright 2014 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.console.Completer;
import org.apache.karaf.shell.console.completer.StringsCompleter;
import java.util.List;
import java.util.SortedSet;
/**
* ICMPv6 type completer.
*/
public class Icmp6TypeCompleter implements Completer {
@Override
public int complete(String buffer, int cursor, List<String> candidates) {
// Delegate string completer
StringsCompleter delegate = new StringsCompleter();
SortedSet<String> strings = delegate.getStrings();
for (Icmp6Type type : Icmp6Type.values()) {
strings.add(type.toString());
}
// Now let the completer do the work for figuring out what to offer.
return delegate.complete(buffer, cursor, candidates);
}
}
......@@ -49,14 +49,6 @@
<command>
<action class="org.onosproject.cli.NodesListCommand"/>
</command>
<!--
<command>
<action class="org.onosproject.cli.NodeAddCommand"/>
</command>
<command>
<action class="org.onosproject.cli.NodeRemoveCommand"/>
</command>
-->
<command>
<action class="org.onosproject.cli.RolesCommand"/>
......@@ -165,6 +157,9 @@
<optional-completers>
<entry key="-t" value-ref="ethTypeCompleter"/>
<entry key="--ipProto" value-ref="ipProtocolCompleter"/>
<entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/>
<entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/>
<entry key="--extHdr" value-ref="ExtHeaderCompleter"/>
<entry key="-a" value-ref="allAppNameCompleter"/>
</optional-completers>
</command>
......@@ -193,6 +188,9 @@
<optional-completers>
<entry key="-t" value-ref="ethTypeCompleter"/>
<entry key="--ipProto" value-ref="ipProtocolCompleter"/>
<entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/>
<entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/>
<entry key="--extHdr" value-ref="ExtHeaderCompleter"/>
<entry key="-a" value-ref="allAppNameCompleter"/>
</optional-completers>
</command>
......@@ -204,6 +202,9 @@
<optional-completers>
<entry key="-t" value-ref="ethTypeCompleter"/>
<entry key="--ipProto" value-ref="ipProtocolCompleter"/>
<entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/>
<entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/>
<entry key="--extHdr" value-ref="ExtHeaderCompleter"/>
<entry key="-a" value-ref="allAppNameCompleter"/>
</optional-completers>
</command>
......@@ -327,6 +328,11 @@
<null/>
</completers>
<optional-completers>
<entry key="-t" value-ref="ethTypeCompleter"/>
<entry key="--ipProto" value-ref="ipProtocolCompleter"/>
<entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/>
<entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/>
<entry key="--extHdr" value-ref="ExtHeaderCompleter"/>
<entry key="-a" value-ref="allAppNameCompleter"/>
</optional-completers>
</command>
......@@ -351,6 +357,9 @@
<bean id="ethTypeCompleter" class="org.onosproject.cli.net.EthTypeCompleter"/>
<bean id="ipProtocolCompleter" class="org.onosproject.cli.net.IpProtocolCompleter"/>
<bean id="driverNameCompleter" class="org.onosproject.cli.net.DriverNameCompleter"/>
<bean id="Icmp6TypeCompleter" class="org.onosproject.cli.net.Icmp6TypeCompleter"/>
<bean id="Icmp6CodeCompleter" class="org.onosproject.cli.net.Icmp6CodeCompleter"/>
<bean id="ExtHeaderCompleter" class="org.onosproject.cli.net.ExtHeaderCompleter"/>
<bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/>
<bean id="upDownCompleter" class="org.onosproject.cli.UpDownCompleter"/>
......
......@@ -293,7 +293,7 @@ public final class DefaultTrafficSelector implements TrafficSelector {
}
@Override
public Builder matchIPv6ExthdrFlags(int exthdrFlags) {
public Builder matchIPv6ExthdrFlags(short exthdrFlags) {
return add(Criteria.matchIPv6ExthdrFlags(exthdrFlags));
}
......
......@@ -306,7 +306,7 @@ public interface TrafficSelector {
* @param exthdrFlags the IPv6 Extension Header pseudo-field fiags
* @return a selection builder
*/
public Builder matchIPv6ExthdrFlags(int exthdrFlags);
public Builder matchIPv6ExthdrFlags(short exthdrFlags);
/**
* Matches an optical signal ID or lambda.
......
......@@ -145,27 +145,27 @@ public interface Criterion {
*/
public enum IPv6ExthdrFlags {
/** "No next header" encountered. */
NONEXT(1 << 0),
NONEXT((short) (1 << 0)),
/** Encrypted Sec Payload header present. */
ESP(1 << 1),
ESP((short) (1 << 1)),
/** Authentication header present. */
AUTH(1 << 2),
AUTH((short) (1 << 2)),
/** 1 or 2 dest headers present. */
DEST(1 << 3),
DEST((short) (1 << 3)),
/** Fragment header present. */
FRAG(1 << 4),
FRAG((short) (1 << 4)),
/** Router header present. */
ROUTER(1 << 5),
ROUTER((short) (1 << 5)),
/** Hop-by-hop header present. */
HOP(1 << 6),
HOP((short) (1 << 6)),
/** Unexpected repeats encountered. */
UNREP(1 << 7),
UNREP((short) (1 << 7)),
/** Unexpected sequencing encountered. */
UNSEQ(1 << 8);
UNSEQ((short) (1 << 8));
private int value;
private short value;
IPv6ExthdrFlags(int value) {
IPv6ExthdrFlags(short value) {
this.value = value;
}
......@@ -174,7 +174,7 @@ public interface Criterion {
*
* @return the value as an integer
*/
public int getValue() {
public short getValue() {
return this.value;
}
}
......
......@@ -622,7 +622,7 @@ public class FlowEntryBuilder {
builder.matchIPv6NDTargetLinkLayerAddress(mac);
break;
case IPV6_EXTHDR:
builder.matchIPv6ExthdrFlags((int) match.get(MatchField.IPV6_EXTHDR)
builder.matchIPv6ExthdrFlags((short) match.get(MatchField.IPV6_EXTHDR)
.getValue());
break;
case OCH_SIGID:
......
......@@ -34,13 +34,68 @@ import java.util.Map;
public class ICMP6 extends BasePacket {
public static final byte HEADER_LENGTH = 4; // bytes
// Type
/** Destination Unreachable. */
public static final byte DEST_UNREACH = (byte) 0x01;
/** Packet Too Big. */
public static final byte PKT_TOO_BIG = (byte) 0x02;
/** Time Exceeded. */
public static final byte TIME_EXCEED = (byte) 0x03;
/** Parameter Problem. */
public static final byte PARAM_ERR = (byte) 0x04;
/** Echo Request. */
public static final byte ECHO_REQUEST = (byte) 0x80;
/** Echo Reply. */
public static final byte ECHO_REPLY = (byte) 0x81;
/** Multicast Listener Query. */
public static final byte MCAST_QUERY = (byte) 0x82;
/** Multicast Listener Report. */
public static final byte MCAST_REPORT = (byte) 0x83;
/** Multicast Listener Done. */
public static final byte MCAST_DONE = (byte) 0x84;
/** Router Solicitation. */
public static final byte ROUTER_SOLICITATION = (byte) 0x85;
/** Router Advertisement. */
public static final byte ROUTER_ADVERTISEMENT = (byte) 0x86;
/** Neighbor Solicitation. */
public static final byte NEIGHBOR_SOLICITATION = (byte) 0x87;
/** Neighbor Advertisement. */
public static final byte NEIGHBOR_ADVERTISEMENT = (byte) 0x88;
/** Redirect Message. */
public static final byte REDIRECT = (byte) 0x89;
// Code for DEST_UNREACH
/** No route to destination. */
public static final byte NO_ROUTE = (byte) 0x00;
/** Communication with destination administratively prohibited. */
public static final byte COMM_PROHIBIT = (byte) 0x01;
/** Beyond scope of source address. */
public static final byte BEYOND_SCOPE = (byte) 0x02;
/** Address unreachable. */
public static final byte ADDR_UNREACH = (byte) 0x03;
/** Port unreachable. */
public static final byte PORT_UNREACH = (byte) 0x04;
/** Source address failed ingress/egress policy. */
public static final byte FAIL_POLICY = (byte) 0x05;
/** Reject route to destination. */
public static final byte REJECT_ROUTE = (byte) 0x06;
/** Error in Source Routing Header. */
public static final byte SRC_ROUTING_HEADER_ERR = (byte) 0x07;
// Code for TIME_EXCEED
/** Hop limit exceeded in transit. */
public static final byte HOP_LIMIT_EXCEED = (byte) 0x00;
/** Fragment reassembly time exceeded. */
public static final byte DEFRAG_TIME_EXCEED = (byte) 0x01;
// Code for PARAM_ERR
/** Erroneous header field encountered. */
public static final byte HDR_FIELD_ERR = (byte) 0x00;
/** Unrecognized Next Header type encountered. */
public static final byte NEXT_HEADER_ERR = (byte) 0x01;
/** Unrecognized IPv6 option encountered. */
public static final byte IPV6_OPT_ERR = (byte) 0x01;
public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
new HashMap<>();
......