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
diff --git a/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
index 10889fe..d21321b 100644
--- a/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java
@@ -104,8 +104,8 @@
     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 @@
         }
 
         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 @@
             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();
diff --git a/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java b/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java
new file mode 100644
index 0000000..e27332e
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java
@@ -0,0 +1,87 @@
+/*
+ * 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");
+            }
+        }
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java b/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java
new file mode 100644
index 0000000..1242e11
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java
@@ -0,0 +1,42 @@
+/*
+ * 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);
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java b/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java
new file mode 100644
index 0000000..8568ec6
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java
@@ -0,0 +1,102 @@
+/*
+ * 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");
+            }
+        }
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java b/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java
new file mode 100644
index 0000000..bf32d4f
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java
@@ -0,0 +1,42 @@
+/*
+ * 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);
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java b/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java
new file mode 100644
index 0000000..a9bffd0
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java
@@ -0,0 +1,100 @@
+/*
+ * 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");
+            }
+        }
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java b/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java
new file mode 100644
index 0000000..8871388
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java
@@ -0,0 +1,42 @@
+/*
+ * 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);
+    }
+
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index da9f95d..0fd2238 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -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"/>