Merge "Add L2 selector options to connectivity intents"
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
index 56bbdaf..089db99 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
@@ -2,18 +2,15 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
-import org.onlab.onos.cli.AbstractShellCommand;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
-import org.onlab.onos.net.flow.DefaultTrafficSelector;
 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
-import org.onlab.packet.Ethernet;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -26,7 +23,7 @@
  */
 @Command(scope = "onos", name = "add-multi-to-single-intent",
          description = "Installs point-to-point connectivity intent")
-public class AddMultiPointToSinglePointIntentCommand extends AbstractShellCommand {
+public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentCommand {
 
     @Argument(index = 0, name = "ingressDevices",
               description = "Ingress Device/Port Description",
@@ -55,9 +52,7 @@
             ingressPoints.add(ingress);
         }
 
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .build();
+        TrafficSelector selector = buildTrafficSelector();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
 
         Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment,
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
index bd24366..9e037d2 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
@@ -2,18 +2,16 @@
 
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
-import org.onlab.onos.cli.AbstractShellCommand;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
-import org.onlab.onos.net.flow.DefaultTrafficSelector;
-import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
-import org.onlab.packet.Ethernet;
+
+import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
 
 import static org.onlab.onos.net.DeviceId.deviceId;
 import static org.onlab.onos.net.PortNumber.portNumber;
@@ -23,7 +21,7 @@
  */
 @Command(scope = "onos", name = "add-point-intent",
          description = "Installs point-to-point connectivity intent")
-public class AddPointToPointIntentCommand extends AbstractShellCommand {
+public class AddPointToPointIntentCommand extends ConnectivityIntentCommand {
 
     @Argument(index = 0, name = "ingressDevice",
               description = "Ingress Device/Port Description",
@@ -47,10 +45,8 @@
         PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
         ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
 
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .build();
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+        TrafficSelector selector = buildTrafficSelector();
+        TrafficTreatment treatment = builder().build();
 
         Intent intent = new PointToPointIntent(appId(), selector, treatment,
                                                ingress, egress);
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
new file mode 100644
index 0000000..dca30ca
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
@@ -0,0 +1,54 @@
+package org.onlab.onos.cli.net;
+
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.onos.cli.AbstractShellCommand;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
+
+import com.google.common.base.Strings;
+
+/**
+ * Base class for command line operations for connectivity based intents.
+ */
+public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
+
+    @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 = "";
+
+    /**
+     * Constructs a traffic selector based on the command line arguments
+     * presented to the command.
+     */
+    protected TrafficSelector buildTrafficSelector() {
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+
+        Short ethType = Ethernet.TYPE_IPV4;
+        if (!Strings.isNullOrEmpty(ethTypeString)) {
+            EthType ethTypeParameter = EthType.valueOf(ethTypeString);
+            ethType = ethTypeParameter.value();
+        }
+        selectorBuilder.matchEthType(ethType);
+
+        if (!Strings.isNullOrEmpty(srcMacString)) {
+            selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString));
+        }
+
+        if (!Strings.isNullOrEmpty(dstMacString)) {
+            selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString));
+        }
+
+        return selectorBuilder.build();
+    }
+
+}
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/EthType.java b/cli/src/main/java/org/onlab/onos/cli/net/EthType.java
new file mode 100644
index 0000000..e7ae79e
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/EthType.java
@@ -0,0 +1,40 @@
+package org.onlab.onos.cli.net;
+
+import org.onlab.packet.Ethernet;
+
+/**
+ * Allowed values for Ethernet types.  Used by the CLI completer for
+ * connectivity based intent L2 parameters.
+ */
+public enum EthType {
+    /** ARP. */
+    ARP(Ethernet.TYPE_ARP),
+    /** RARP. */
+    RARP(Ethernet.TYPE_RARP),
+    /** IPV4. */
+    IPV4(Ethernet.TYPE_IPV4),
+    /** LLDP. */
+    LLDP(Ethernet.TYPE_LLDP),
+    /** BSN. */
+    BSN(Ethernet.TYPE_BSN);
+
+    private short value;
+
+    /**
+     * Constructs an EthType with the given value.
+     *
+     * @param value value to use when this EthType is seen.
+     */
+    private EthType(short value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value to use for this EthType.
+     *
+     * @return short value to use for this EthType
+     */
+    public short value() {
+        return this.value;
+    }
+}
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/EthTypeCompleter.java b/cli/src/main/java/org/onlab/onos/cli/net/EthTypeCompleter.java
new file mode 100644
index 0000000..51513ae
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/EthTypeCompleter.java
@@ -0,0 +1,28 @@
+package org.onlab.onos.cli.net;
+
+import java.util.List;
+import java.util.SortedSet;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+
+/**
+ * Ethernet type completer.
+ */
+public class EthTypeCompleter 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();
+        strings.add(EthType.ARP.toString());
+        strings.add(EthType.BSN.toString());
+        strings.add(EthType.IPV4.toString());
+        strings.add(EthType.LLDP.toString());
+        strings.add(EthType.RARP.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 3c75bf9..bab4f74 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -96,12 +96,18 @@
                 <ref component-id="connectPointCompleter"/>
                 <null/>
             </completers>
+            <optional-completers>
+                <entry key="-t" value-ref="ethTypeCompleter"/>
+            </optional-completers>
         </command>
         <command>
             <action class="org.onlab.onos.cli.net.AddMultiPointToSinglePointIntentCommand"/>
             <completers>
                 <ref component-id="connectPointCompleter"/>
             </completers>
+            <optional-completers>
+                <entry key="-t" value-ref="ethTypeCompleter"/>
+            </optional-completers>
         </command>
         <command>
             <action class="org.onlab.onos.cli.net.IntentPushTestCommand"/>
@@ -158,5 +164,6 @@
     <bean id="flowRuleStatusCompleter" class="org.onlab.onos.cli.net.FlowRuleStatusCompleter"/>
     <bean id="connectPointCompleter" class="org.onlab.onos.cli.net.ConnectPointCompleter"/>
     <bean id="nullCompleter" class="org.apache.karaf.shell.console.completer.NullCompleter"/>
+    <bean id="ethTypeCompleter" class="org.onlab.onos.cli.net.EthTypeCompleter"/>
 
 </blueprint>