Changes to vRouter to accomodate ofdpa and softrouter pipelines.
Adding arp-spa to flow from vRouter to distinguish between multiple untagged
interfaces with the same macAddress.

Change-Id: Ifd6e00f70c538c780c0f5728d9ba960a4c70b1db
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
index 1cfb937..ba54fac 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
@@ -584,34 +584,59 @@
                     + "nextId or Treatment", fwd.selector(), fwd.appId());
             return Collections.emptySet();
         }
+
         // XXX driver does not currently do type checking as per Tables 65-67 in
         // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
-        if (fwd.treatment() != null &&
-                fwd.treatment().allInstructions().size() == 1 &&
-                fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
-            OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
-            if (o.port() == PortNumber.CONTROLLER) {
-                FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
-                        .fromApp(fwd.appId())
-                        .withPriority(fwd.priority())
-                        .forDevice(deviceId)
-                        .withSelector(fwd.selector())
-                        .withTreatment(fwd.treatment())
-                        .makePermanent()
-                        .forTable(ACL_TABLE);
-                return Collections.singletonList(ruleBuilder.build());
-            } else {
-                log.warn("Only allowed treatments in versatile forwarding "
-                        + "objectives are punts to the controller");
-                return Collections.emptySet();
+        TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
+        if (fwd.treatment() != null) {
+            for (Instruction ins : fwd.treatment().allInstructions()) {
+                if (ins instanceof OutputInstruction) {
+                    OutputInstruction o = (OutputInstruction) ins;
+                    if (o.port() == PortNumber.CONTROLLER) {
+                        ttBuilder.add(o);
+                    } else {
+                        log.warn("Only allowed treatments in versatile forwarding "
+                                + "objectives are punts to the controller");
+                    }
+                } else {
+                    log.warn("Cannot process instruction in versatile fwd {}", ins);
+                }
             }
         }
-
         if (fwd.nextId() != null) {
-            // XXX overide case
-            log.warn("versatile objective --> next Id not yet implemeted");
+            // overide case
+            NextGroup next = getGroupForNextObjective(fwd.nextId());
+            List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
+            // we only need the top level group's key to point the flow to it
+            Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
+            if (group == null) {
+                log.warn("Group with key:{} for next-id:{} not found in dev:{}",
+                         gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
+                fail(fwd, ObjectiveError.GROUPMISSING);
+                return Collections.emptySet();
+            }
+            ttBuilder.deferred().group(group.id());
         }
-        return Collections.emptySet();
+       // ensure that match does not include vlan = NONE as OF-DPA does not
+       // match untagged packets this way in the ACL table.
+       TrafficSelector.Builder selBuilder = DefaultTrafficSelector.builder();
+       for (Criterion criterion : fwd.selector().criteria()) {
+           if (criterion instanceof VlanIdCriterion &&
+               ((VlanIdCriterion) criterion).vlanId() == VlanId.NONE) {
+               continue;
+           }
+           selBuilder.add(criterion);
+       }
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .fromApp(fwd.appId())
+                .withPriority(fwd.priority())
+                .forDevice(deviceId)
+                .withSelector(selBuilder.build())
+                .withTreatment(ttBuilder.build())
+                .makePermanent()
+                .forTable(ACL_TABLE);
+        return Collections.singletonList(ruleBuilder.build());
     }
 
     /**
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
index 8e5ce91..6aa7f91 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
@@ -42,6 +42,8 @@
 import org.onosproject.net.flow.criteria.IPCriterion;
 import org.onosproject.net.flow.criteria.PortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flowobjective.FilteringObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveStore;
 import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -50,6 +52,7 @@
 import org.onosproject.net.flowobjective.ObjectiveError;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.slf4j.Logger;
+import static org.onlab.util.Tools.delay;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -314,19 +317,50 @@
     }
 
     /**
-     * SoftRouter has a single versatile table - the filter table. All versatile
-     * flow rules must include the filtering rules.
+     * SoftRouter has a single versatile table - the filter table.
+     * This table can be used to filter entries that reach the next table (FIB table).
+     * It can also be used to punt packets to the controller and/or bypass
+     * the FIB table to forward out of a port.
      *
      * @param fwd The forwarding objective of type versatile
      * @return  A collection of flow rules meant to be delivered to the flowrule
      *          subsystem. May return empty collection in case of failures.
      */
     private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
+        log.debug("Received versatile fwd: to next:{}", fwd.nextId());
         Collection<FlowRule> flowrules = new ArrayList<>();
+        if (fwd.nextId() == null && fwd.treatment() == null) {
+            log.error("Forwarding objective {} from {} must contain "
+                    + "nextId or Treatment", fwd.selector(), fwd.appId());
+            return Collections.emptySet();
+        }
+        TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
+        if (fwd.treatment() != null) {
+            fwd.treatment().immediate().forEach(ins -> ttBuilder.add(ins));
+        }
+        //convert nextId to flow actions
+        if (fwd.nextId() != null) {
+            // only acceptable value is output to port
+            NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
+            if (next == null) {
+                log.error("next-id {} does not exist in store", fwd.nextId());
+                return Collections.emptySet();
+            }
+            TrafficTreatment nt = appKryo.deserialize(next.data());
+            if (nt == null)  {
+                log.error("Error in deserializing next-id {}", fwd.nextId());
+                return Collections.emptySet();
+            }
+            for (Instruction ins : nt.allInstructions()) {
+                if (ins instanceof OutputInstruction) {
+                    ttBuilder.add(ins);
+                }
+            }
+        }
 
         FlowRule rule = DefaultFlowRule.builder()
                 .withSelector(fwd.selector())
-                .withTreatment(fwd.treatment())
+                .withTreatment(ttBuilder.build())
                 .makePermanent()
                 .forDevice(deviceId)
                 .fromApp(fwd.appId())
@@ -350,7 +384,7 @@
      *
      */
     private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
-        log.debug("Processing specific forwarding objective");
+        log.debug("Processing specific forwarding objective to next:{}", fwd.nextId());
         TrafficSelector selector = fwd.selector();
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
@@ -411,6 +445,9 @@
      */
     private void processSimpleNextObjective(NextObjective nextObj) {
         // Simple next objective has a single treatment (not a collection)
+        log.debug("Received nextObj {}", nextObj.id());
+        // delay processing to emulate group creation
+        delay(50);
         TrafficTreatment treatment = nextObj.next().iterator().next();
         flowObjectiveStore.putNextGroup(nextObj.id(),
                                         new DummyGroup(treatment));