Improvements for the ofdpa driver.
New driver for ofdpa emulation with cpqd switch.

Change-Id: I5221069e07abe57538d4e988cdb7190b50c595f7
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java
new file mode 100644
index 0000000..769f3b1
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA1Pipeline.java
@@ -0,0 +1,158 @@
+package org.onosproject.driver.pipeline;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.slf4j.Logger;
+
+
+/**
+ * Driver for software switch emulation of the OFDPA 1.0 pipeline.
+ * The software switch is the CPqD OF 1.3 switch.
+ */
+public class CpqdOFDPA1Pipeline extends OFDPA1Pipeline {
+
+    private final Logger log = getLogger(getClass());
+
+    @Override
+    protected void initializePipeline() {
+        processPortTable();
+        //processVlanTable();
+        processTmacTable();
+        processIpTable();
+        //processMcastTable();
+        processBridgingTable();
+        //processAclTable();
+        //processGroupTable();
+    }
+
+    @Override
+    protected void processPortTable() {
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(VLAN_TABLE);
+        FlowRule tmisse = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(LOWEST_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(PORT_TABLE).build();
+        ops = ops.add(tmisse);
+
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized port table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize port table");
+            }
+        }));
+    }
+
+    @Override
+    protected void processTmacTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector = DefaultTrafficSelector.builder();
+        treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(BRIDGING_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(LOWEST_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(TMAC_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized tmac table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize tmac table");
+            }
+        }));
+    }
+
+    @Override
+    protected void processIpTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector = DefaultTrafficSelector.builder();
+        treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(ACL_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(LOWEST_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(UNICAST_ROUTING_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized IP table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize unicast IP table");
+            }
+        }));
+    }
+
+    private void processBridgingTable() {
+        //table miss entry
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        selector = DefaultTrafficSelector.builder();
+        treatment = DefaultTrafficTreatment.builder();
+        treatment.transition(ACL_TABLE);
+        FlowRule rule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(LOWEST_PRIORITY)
+                .fromApp(driverId)
+                .makePermanent()
+                .forTable(BRIDGING_TABLE).build();
+        ops =  ops.add(rule);
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.info("Initialized Bridging table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.info("Failed to initialize Bridging table");
+            }
+        }));
+
+    }
+
+}
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
index fb5d701..07983a3 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
@@ -105,7 +105,7 @@
 
     private static final int HIGHEST_PRIORITY = 0xffff;
     private static final int DEFAULT_PRIORITY = 0x8000;
-    private static final int LOWEST_PRIORITY = 0x0;
+    protected static final int LOWEST_PRIORITY = 0x0;
 
     /*
      * Group keys are normally generated by using the next Objective id. In the
@@ -130,12 +130,12 @@
 
     private final Logger log = getLogger(getClass());
     private ServiceDirectory serviceDirectory;
-    private FlowRuleService flowRuleService;
+    protected FlowRuleService flowRuleService;
     private CoreService coreService;
     private GroupService groupService;
     private FlowObjectiveStore flowObjectiveStore;
-    private DeviceId deviceId;
-    private ApplicationId driverId;
+    protected DeviceId deviceId;
+    protected ApplicationId driverId;
 
     private KryoNamespace appKryo = new KryoNamespace.Builder()
         .register(KryoNamespaces.API)
@@ -610,7 +610,7 @@
     }
 
 
-    private void initializePipeline() {
+    protected void initializePipeline() {
         processPortTable();
         processVlanTable();
         processTmacTable();
@@ -621,7 +621,7 @@
         //processGroupTable();
     }
 
-    private void processPortTable() {
+    protected void processPortTable() {
         //XXX is table miss entry enough or do we need to do the maskable in-port 0?
         FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
@@ -653,56 +653,12 @@
     }
 
     private void processVlanTable() {
-        // make these up for now - should really be filtering rules
-        /*FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        selector.matchInPort(PortNumber.portNumber(10));
-        selector.matchVlanId(VlanId.vlanId((short) 100));
-        treatment.transition(TMAC_TABLE);
-        FlowRule rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DEFAULT_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(VLAN_TABLE).build();
-        ops =  ops.add(rule);
-        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-            @Override
-            public void onSuccess(FlowRuleOperations ops) {
-                log.info("Initialized vlan table");
-            }
-
-            @Override
-            public void onError(FlowRuleOperations ops) {
-                log.info("Failed to initialize vlan table");
-            }
-        }));*/
-
         // Table miss entry is not required as ofdpa default is to drop
         // In OF terms, the absence of a t.m.e. also implies drop
     }
 
 
-    private void processTmacTable() {
-        // this is made up as well -- should be a filtering rule
-        /*selector.matchInPort(PortNumber.portNumber(10));
-        selector.matchVlanId(VlanId.vlanId((short) 100));
-        selector.matchEthType(Ethernet.TYPE_IPV4);
-        selector.matchEthDst(MacAddress.valueOf("00:00:00:ba:ba:00"));
-        treatment.transition(UNICAST_ROUTING_TABLE);
-        FlowRule rule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DEFAULT_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(TMAC_TABLE).build();
-        ops =  ops.add(rule);*/
-
+    protected void processTmacTable() {
         //table miss entry
         FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
@@ -732,7 +688,7 @@
         }));*/
     }
 
-    private void processIpTable() {
+    protected void processIpTable() {
         //table miss entry
         FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
@@ -762,72 +718,16 @@
         }));*/
     }
 
-    @SuppressWarnings("unused")
-    private void processGroupTable() {
-        // Creating a dummy L2 group as per OFDPA requirements
-       /* TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                                        .setOutput(PortNumber.portNumber(10))
-                                        .build();
-        NextObjective nextObjective = DefaultNextObjective.builder()
-                .addTreatment(treatment)
-                .fromApp(appId)
-                .withId(678) // dummy next objective id
-                .withType(NextObjective.Type.SIMPLE)
-                .add();
-        Integer l2groupId = 0x0064000a;
-        GroupBucket bucket =
-                DefaultGroupBucket.createIndirectGroupBucket(treatment);
-        final GroupKey key = new DefaultGroupKey(appKryo.serialize(678));
-        GroupDescription groupDescriptionl2
-            = new DefaultGroupDescription(deviceId,
-                                      GroupDescription.Type.INDIRECT,
-                                      new GroupBuckets(Collections
-                                                       .singletonList(bucket)),
-                                      key,
-                                      l2groupId,
-                                      appId);
-        groupService.addGroup(groupDescriptionl2);*/
-        //pendingNextObjectives.put(key, nextObjective);
-
-    }
-
-    @SuppressWarnings("unused")
-    private void tryGroupChain() {
-      //Create a dummy L3 group as per OFDPA requirements
-        /*TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
-                .setEthDst(MacAddress.valueOf("00:00:00:aa:aa:aa"))
-                .setEthSrc(MacAddress.valueOf("00:00:00:dd:dd:dd"))
-                .setVlanId(VlanId.vlanId((short) 100))
-                .group(new DefaultGroupId(0x0064000a))
-                .build();
-        NextObjective nextObjective2 = DefaultNextObjective.builder()
-                .addTreatment(treatment2)
-                .fromApp(appId)
-                .withId(67800) // another dummy next objective id
-                .withType(NextObjective.Type.SIMPLE)
-                .add();
-        Integer l3groupId = 0x2000000a;
-        GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(treatment2);
-        final GroupKey key2 = new DefaultGroupKey(appKryo.serialize(67800));
-        GroupDescription groupDescriptionl3
-               = new DefaultGroupDescription(deviceId,
-                                  GroupDescription.Type.INDIRECT,
-                                  new GroupBuckets(Collections
-                                                   .singletonList(bucket2)),
-                                  key2,
-                                  l3groupId,
-                                  appId);
-        groupService.addGroup(groupDescriptionl3);
-        pendingNextObjectives.put(key2, nextObjective2);
-    */
-    }
-
     private class GroupChecker implements Runnable {
         @Override
         public void run() {
             Set<GroupKey> keys = pendingGroups.keySet().stream()
                     .filter(key -> groupService.getGroup(deviceId, key) != null)
                     .collect(Collectors.toSet());
+            Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream()
+                    .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null)
+                    .collect(Collectors.toSet());
+            keys.addAll(otherkeys);
 
             keys.stream().forEach(key -> {
                 //first check for group chain
@@ -856,7 +756,7 @@
     private class InnerGroupListener implements GroupListener {
         @Override
         public void event(GroupEvent event) {
-            log.info("received group event of type {}", event.type());
+            log.debug("received group event of type {}", event.type());
             if (event.type() == GroupEvent.Type.GROUP_ADDED) {
                 GroupKey key = event.subject().appCookie();
                 // first check for group chain
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index b442b0e..f9c648e 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -63,9 +63,10 @@
                    impl="org.onosproject.driver.pipeline.OFDPA1Pipeline"/>
     </driver>
     <!--  The SoftRouter driver is meant to be used by any software/NPU based
-       ~  switch that wishes to implement a simple 2-table router. ONOS needs to
-       ~  be configured with the dpid of such a device to attach this driver
-       ~  to the device.
+       ~  switch that wishes to implement a simple 2-table router. To use this
+       ~  driver, configure ONOS with the dpid of the device, or extend the
+       ~  driver declaration with the manufacturer/hwVersion/swVersion of the
+       ~  device (see 'noviflow' example).
       -->
     <driver name="softrouter" extends="default"
             manufacturer="Various" hwVersion="various" swVersion="0.0.0">
@@ -85,5 +86,14 @@
     <driver name="noviflow" extends="softrouter"
             manufacturer="NoviFlow Inc" hwVersion="NS1132" swVersion="NW250.4.4">
     </driver>
+    <!--  Emulation of the ofdpa pipeline using a CPqD OF 1.3 software switch.
+       ~  To use this driver, configure ONOS with the dpid of the device.
+      -->
+    <driver name="ofdpa-cpqd" extends="default"
+            manufacturer="ONF"
+            hwVersion="OF1.3 Software Switch from CPqD" swVersion="for Group Chaining">
+        <behaviour api="org.onosproject.net.behaviour.Pipeliner"
+                   impl="org.onosproject.driver.pipeline.CpqdOFDPA1Pipeline"/>
+    </driver>
 </drivers>