Creating a p4runtime default driver to avoid code duplication between bmv2 and barefoot drivers

Change-Id: Id7f16a284c65278ec1a9ec682da01ddf020343c8
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeFlowRuleWrapper.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeFlowRuleWrapper.java
new file mode 100644
index 0000000..d076cb4
--- /dev/null
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeFlowRuleWrapper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.p4runtime.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.flow.FlowRule;
+
+/**
+ * A wrapper for a ONOS flow rule installed on a P4Runtime device.
+ */
+@Beta
+public final class P4RuntimeFlowRuleWrapper {
+
+    private final FlowRule rule;
+    private final long installedOnMillis;
+
+    /**
+     * Creates a new flow rule wrapper.
+     *
+     * @param rule              a flow rule
+     * @param installedOnMillis the time (in milliseconds, since January 1, 1970 UTC) when the flow rule was installed
+     *                          on the device
+     */
+    public P4RuntimeFlowRuleWrapper(FlowRule rule, long installedOnMillis) {
+        this.rule = rule;
+        this.installedOnMillis = installedOnMillis;
+    }
+
+    /**
+     * Returns the flow rule contained by this wrapper.
+     *
+     * @return a flow rule
+     */
+    public FlowRule rule() {
+        return rule;
+    }
+
+    /**
+     * Return the number of seconds since when this flow rule was installed on the device.
+     *
+     * @return an integer value
+     */
+    public long lifeInSeconds() {
+        return (System.currentTimeMillis() - installedOnMillis) / 1000;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(rule, installedOnMillis);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final P4RuntimeFlowRuleWrapper other = (P4RuntimeFlowRuleWrapper) obj;
+        return Objects.equal(this.rule, other.rule)
+                && Objects.equal(this.installedOnMillis, other.installedOnMillis);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("rule", rule)
+                .add("installedOnMillis", installedOnMillis)
+                .toString();
+    }
+}
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeTableEntryReference.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeTableEntryReference.java
new file mode 100644
index 0000000..5a0e9ca
--- /dev/null
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeTableEntryReference.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.p4runtime.api;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.runtime.PiMatchKey;
+import org.onosproject.net.pi.runtime.PiTableId;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Class containing the reference for a table entry in P4Runtime.
+ */
+public final class P4RuntimeTableEntryReference {
+
+    private final DeviceId deviceId;
+    private final PiTableId tableId;
+    private final PiMatchKey matchKey;
+
+    /**
+     * Creates a new table entry reference.
+     *
+     * @param deviceId a device ID
+     * @param tableId  a table name
+     * @param matchKey a match key
+     */
+    public P4RuntimeTableEntryReference(DeviceId deviceId, PiTableId tableId, PiMatchKey matchKey) {
+        this.deviceId = checkNotNull(deviceId);
+        this.tableId = checkNotNull(tableId);
+        this.matchKey = checkNotNull(matchKey);
+    }
+
+    /**
+     * Returns the device ID of this table entry reference.
+     *
+     * @return a device ID
+     */
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    /**
+     * Returns the table id of this table entry reference.
+     *
+     * @return a table name
+     */
+    public PiTableId tableId() {
+        return tableId;
+    }
+
+    /**
+     * Returns the match key of this table entry reference.
+     *
+     * @return a match key
+     */
+    public PiMatchKey matchKey() {
+        return matchKey;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(deviceId, tableId, matchKey);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final P4RuntimeTableEntryReference other = (P4RuntimeTableEntryReference) obj;
+        return Objects.equal(this.deviceId, other.deviceId)
+                && Objects.equal(this.tableId, other.tableId)
+                && Objects.equal(this.matchKey, other.matchKey);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("deviceId", deviceId)
+                .add("tableId", tableId)
+                .add("matchKey", matchKey)
+                .toString();
+    }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index ff083c3..7f88249 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -208,34 +208,40 @@
             return false;
         }
 
-        if (!pipeconf.extension(targetConfigExtType).isPresent()) {
-            log.warn("Missing extension {} in pipeconf {}", targetConfigExtType, pipeconf.id());
-            return false;
-        }
 
-        InputStream targetConfig = pipeconf.extension(targetConfigExtType).get();
-        P4Config.P4DeviceConfig p4DeviceConfigMsg;
-        try {
-            p4DeviceConfigMsg = P4Config.P4DeviceConfig
-                    .newBuilder()
-                    .setExtras(P4Config.P4DeviceConfig.Extras.getDefaultInstance())
-                    .setReassign(true)
-                    .setDeviceData(ByteString.readFrom(targetConfig))
-                    .build();
-        } catch (IOException ex) {
-            log.warn("Unable to load target-specific config for {}: {}", deviceId, ex.getMessage());
-            return false;
+        ForwardingPipelineConfig.Builder pipelineConfigBuilder = ForwardingPipelineConfig
+                .newBuilder()
+                .setDeviceId(p4DeviceId)
+                .setP4Info(p4Info);
+
+        //if the target config extension is null we don't want to add the config.
+        if (targetConfigExtType != null) {
+            if (!pipeconf.extension(targetConfigExtType).isPresent()) {
+                log.warn("Missing extension {} in pipeconf {}", targetConfigExtType, pipeconf.id());
+                return false;
+            }
+            InputStream targetConfig = pipeconf.extension(targetConfigExtType).get();
+            P4Config.P4DeviceConfig p4DeviceConfigMsg;
+            try {
+                p4DeviceConfigMsg = P4Config.P4DeviceConfig
+                        .newBuilder()
+                        .setExtras(P4Config.P4DeviceConfig.Extras.getDefaultInstance())
+                        .setReassign(true)
+                        .setDeviceData(ByteString.readFrom(targetConfig))
+                        .build();
+
+                pipelineConfigBuilder.setP4DeviceConfig(p4DeviceConfigMsg.toByteString());
+
+            } catch (IOException ex) {
+                log.warn("Unable to load target-specific config for {}: {}", deviceId, ex.getMessage());
+                return false;
+            }
         }
 
         SetForwardingPipelineConfigRequest request = SetForwardingPipelineConfigRequest
                 .newBuilder()
                 .setAction(VERIFY_AND_COMMIT)
-                .addConfigs(ForwardingPipelineConfig
-                                    .newBuilder()
-                                    .setDeviceId(p4DeviceId)
-                                    .setP4Info(p4Info)
-                                    .setP4DeviceConfig(p4DeviceConfigMsg.toByteString())
-                                    .build())
+                .addConfigs(pipelineConfigBuilder.build())
                 .build();
 
         try {
@@ -434,7 +440,7 @@
 
         private void doNext(StreamMessageResponse message) {
             try {
-                log.info("Received message on stream channel from {}: {}", deviceId, message.getUpdateCase());
+                log.debug("Received message on stream channel from {}: {}", deviceId, message.getUpdateCase());
                 switch (message.getUpdateCase()) {
                     case PACKET:
                         // Packet-in
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
index 6b345eb..0dd82f3 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
@@ -140,6 +140,7 @@
 
         TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
 
+        //FIXME this thorws some kind of NPE
         P4InfoOuterClass.Table tableInfo = browser.tables().getByName(piTableEntry.table().id());
 
         // Table id.