Add architecture method to PiPipelineModel Interface.

The field `pkg_info:arch` is now parsed, when parsing a P4Info file.

Change-Id: Ia1b24b929fe4ed8ac2a2becfa0ce7678642e9037
(cherry picked from commit ce9942049825c51c0a0818ad4b89395321aa82b3)
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java
index bddbae8..2efa40f 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineModel.java
@@ -28,6 +28,13 @@
 public interface PiPipelineModel {
 
     /**
+     * Returns the data plane target architecture supported by this pipeline model.
+     *
+     * @return optional architecture string.
+     */
+    Optional<String> architecture();
+
+    /**
      * Returns the table model associated with the given ID, if present.
      *
      * @param tableId table ID
diff --git a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java
index db438b5..2560346 100644
--- a/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java
+++ b/pipelines/fabric/impl/src/test/java/org/onosproject/pipelines/fabric/impl/behaviour/upf/MockPiPipelineModel.java
@@ -49,6 +49,11 @@
     }
 
     @Override
+    public Optional<String> architecture() {
+        return Optional.empty();
+    }
+
+    @Override
     public Optional<PiTableModel> table(PiTableId tableId) {
         return Optional.ofNullable(tableMap.getOrDefault(tableId, null));
     }
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
index cbe1d6e..f47a0b7 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
@@ -160,6 +160,8 @@
         // Start by parsing and mapping instances to to their integer P4Info IDs.
         // Convenient to build the table model at the end.
 
+        final String architecture = parseArchitecture(p4info);
+
         // Counters.
         final Map<Integer, PiCounterModel> counterMap = Maps.newHashMap();
         counterMap.putAll(parseCounters(p4info));
@@ -269,9 +271,16 @@
                 registerImmMap,
                 actProfileImmMap,
                 ImmutableMap.copyOf(pktOpMap),
+                architecture,
                 fingerprint);
     }
 
+    private static String parseArchitecture(P4Info p4info) {
+        if (p4info.hasPkgInfo()) {
+            return p4info.getPkgInfo().getArch();
+        }
+        return null;
+    }
 
     private static Map<Integer, PiCounterModel> parseCounters(P4Info p4info)
             throws P4InfoParserException {
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
index 28e5372..46889a6 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
@@ -48,6 +48,7 @@
     private final ImmutableMap<PiRegisterId, PiRegisterModel> registers;
     private final ImmutableMap<PiActionProfileId, PiActionProfileModel> actionProfiles;
     private final ImmutableMap<PiPacketOperationType, PiPacketOperationModel> packetOperations;
+    private final String architecture;
     private final int fingerprint;
 
     P4PipelineModel(
@@ -57,6 +58,7 @@
             ImmutableMap<PiRegisterId, PiRegisterModel> registers,
             ImmutableMap<PiActionProfileId, PiActionProfileModel> actionProfiles,
             ImmutableMap<PiPacketOperationType, PiPacketOperationModel> packetOperations,
+            String architecture,
             int fingerprint) {
         this.tables = tables;
         this.counters = counters;
@@ -65,6 +67,12 @@
         this.actionProfiles = actionProfiles;
         this.packetOperations = packetOperations;
         this.fingerprint = fingerprint;
+        this.architecture = architecture;
+    }
+
+    @Override
+    public Optional<String> architecture() {
+        return Optional.ofNullable(this.architecture);
     }
 
     @Override
@@ -160,6 +168,7 @@
                 .add("actionProfiles", actionProfiles.values())
                 .add("packetOperations", packetOperations.values())
                 .add("fingerprint", fingerprint)
+                .add("architecture", architecture)
                 .toString();
     }
 }
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java
index 3785c96..27bffc8 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java
@@ -59,6 +59,7 @@
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
 
 /**
  * Test for P4Info Parser.
@@ -75,16 +76,46 @@
     private static final int DEFAULT_MAX_GROUP_SIZE = 16;
 
     /**
+     * Tests the parsing of the architecture field.
+     * @throws Exception if the equality group objects does not match expected
+     */
+    @Test
+    public void testParseArchitecture() throws Exception {
+        // Generate two PiPipelineModels from the same p4Info file
+        PiPipelineModel model = P4InfoParser.parse(p4InfoUrl);
+        PiPipelineModel sameAsModel = P4InfoParser.parse(p4InfoUrl);
+
+        PiPipelineModel model3 = P4InfoParser.parse(p4InfoUrl2);
+
+        String architecture1 = model.architecture().orElse(null);
+        String architecture2 = sameAsModel.architecture().orElse(null);
+
+        assertThat("null value is returned if `arch` not present in P4Info",
+                   architecture1,
+                   is(nullValue()));
+        assertThat("null value is returned if `arch` not present in P4Info",
+                   architecture2,
+                   is(nullValue()));
+
+        String architecture3 = model3.architecture().orElse(null);
+        assertThat("test that `arch` field is correctly parsed",
+                   architecture3,
+                   is("v1model"));
+    }
+
+    /**
      * Tests parse method.
      * @throws Exception if equality group objects dose not match as expected
      */
     @Test
     public void testParse() throws Exception {
-        // Generate two PiPipelineModels from p4Info file
+        // Generate two PiPipelineModels from the same p4Info file
         PiPipelineModel model = P4InfoParser.parse(p4InfoUrl);
-        PiPipelineModel model2 = P4InfoParser.parse(p4InfoUrl);
+        PiPipelineModel sameAsModel = P4InfoParser.parse(p4InfoUrl);
+
         // Check equality
-        new EqualsTester().addEqualityGroup(model, model2).testEquals();
+        new EqualsTester().addEqualityGroup(model, sameAsModel).testEquals();
+
         // Generate a P4Info object from the file
         final P4Info p4info;
         try {
@@ -100,8 +131,9 @@
         PiTableModel table0Model = model.table(table0Id).orElse(null);
         PiTableModel wcmpTableModel = model.table(wcmpTableId).orElse(null);
         PiTableModel wcmpTableOneShotModel = model.table(wcmpTableOneShotId).orElse(null);
-        PiTableModel table0Model2 = model2.table(table0Id).orElse(null);
-        PiTableModel wcmpTableModel2 = model2.table(wcmpTableId).orElse(null);
+        PiTableModel table0Model2 = sameAsModel.table(table0Id).orElse(null);
+        PiTableModel wcmpTableModel2 = sameAsModel.table(wcmpTableId).orElse(null);
+
         new EqualsTester().addEqualityGroup(table0Model, table0Model2)
                 .addEqualityGroup(wcmpTableModel, wcmpTableModel2).testEquals();
         // Check existence
@@ -142,18 +174,15 @@
                 piMatchFieldList.get(6), piMatchFieldList.get(7),
                 piMatchFieldList.get(8)));
         assertThat("Incorrect size for matchFields", wcmpTableModel.matchFields().size(), is(equalTo(1)));
-
         // check if matchFields are in order
         matchFieldList = tableMsgs.get(1).getMatchFieldsList();
         assertThat("Incorrect order for matchFields",
                    wcmpTableModel.matchFields(), IsIterableContainingInOrder.contains(
                         new P4MatchFieldModel(PiMatchFieldId.of(matchFieldList.get(0).getName()),
                                               matchFieldList.get(0).getBitwidth(), PiMatchType.EXACT)));
-
         //check table0 actionsRefs
         List<ActionRef> actionRefList = tableMsgs.get(0).getActionRefsList();
         assertThat("Incorrect size for actionRefs", actionRefList.size(), is(equalTo(4)));
-
         //create action instances
         PiActionId actionId = PiActionId.of("set_egress_port");
         PiActionParamId piActionParamId = PiActionParamId.of("port");
@@ -168,15 +197,12 @@
         actionId = PiActionId.of("send_to_cpu");
         PiActionModel sendToCpuAction =
                 new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
-
         actionId = PiActionId.of("_drop");
         PiActionModel dropAction =
                 new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
-
         actionId = PiActionId.of("NoAction");
         PiActionModel noAction =
                 new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
-
         actionId = PiActionId.of("table0_control.set_next_hop_id");
         piActionParamId = PiActionParamId.of("next_hop_id");
         bitWitdth = 16;
@@ -190,7 +216,6 @@
         assertThat("action dose not match",
                    table0Model.actions(), IsIterableContainingInAnyOrder.containsInAnyOrder(
                         setEgressPortAction, sendToCpuAction, setNextHopIdAction, dropAction));
-
         //check wcmp_table actions
         assertThat("actions dose not match",
                    wcmpTableModel.actions(), IsIterableContainingInAnyOrder.containsInAnyOrder(
@@ -211,7 +236,7 @@
                                                                       true, DEFAULT_MAX_ACTION_PROFILE_SIZE,
                                                                       DEFAULT_MAX_GROUP_SIZE);
         PiActionProfileModel wcmpSelector = model.actionProfiles(actionProfileId).orElse(null);
-        PiActionProfileModel wcmpSelector2 = model2.actionProfiles(actionProfileId).orElse(null);
+        PiActionProfileModel wcmpSelector2 = sameAsModel.actionProfiles(actionProfileId).orElse(null);
 
         new EqualsTester().addEqualityGroup(wcmpSelector, wcmpSelector2, wcmpSelector3).testEquals();
 
@@ -232,13 +257,13 @@
                 model.counter(PiCounterId.of("wcmp_control.wcmp_table_counter")).orElse(null);
 
         PiCounterModel ingressPortCounterModel2 =
-                model2.counter(PiCounterId.of("port_counters_ingress.ingress_port_counter")).orElse(null);
+                sameAsModel.counter(PiCounterId.of("port_counters_ingress.ingress_port_counter")).orElse(null);
         PiCounterModel egressPortCounterModel2 =
-                model2.counter(PiCounterId.of("port_counters_egress.egress_port_counter")).orElse(null);
+                sameAsModel.counter(PiCounterId.of("port_counters_egress.egress_port_counter")).orElse(null);
         PiCounterModel table0CounterModel2 =
-                model2.counter(PiCounterId.of("table0_control.table0_counter")).orElse(null);
+                sameAsModel.counter(PiCounterId.of("table0_control.table0_counter")).orElse(null);
         PiCounterModel wcmpTableCounterModel2 =
-                model2.counter(PiCounterId.of("wcmp_control.wcmp_table_counter")).orElse(null);
+                sameAsModel.counter(PiCounterId.of("wcmp_control.wcmp_table_counter")).orElse(null);
 
         new EqualsTester()
                 .addEqualityGroup(ingressPortCounterModel, ingressPortCounterModel2)
@@ -254,7 +279,7 @@
 
         //Parse meters
         Collection<PiMeterModel> meterModel = model.meters();
-        Collection<PiMeterModel> meterModel2 = model2.meters();
+        Collection<PiMeterModel> meterModel2 = sameAsModel.meters();
 
         assertThat("model parsed meter collection should be empty", meterModel.isEmpty(), is(true));
         assertThat("model parsed meter collection should be empty", meterModel2.isEmpty(), is(true));
@@ -266,9 +291,9 @@
                 model.packetOperationModel(PiPacketOperationType.PACKET_OUT).orElse(null);
 
         PiPacketOperationModel packetInOperationalModel2 =
-                model2.packetOperationModel(PiPacketOperationType.PACKET_IN).orElse(null);
+                sameAsModel.packetOperationModel(PiPacketOperationType.PACKET_IN).orElse(null);
         PiPacketOperationModel packetOutOperationalModel2 =
-                model2.packetOperationModel(PiPacketOperationType.PACKET_OUT).orElse(null);
+                sameAsModel.packetOperationModel(PiPacketOperationType.PACKET_OUT).orElse(null);
 
         new EqualsTester()
                 .addEqualityGroup(packetInOperationalModel, packetInOperationalModel2)
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
index 3da1ffb..57c3a87 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
@@ -364,21 +364,25 @@
     private static final int FINGER_PRINT_1 = 0;
     private static final int FINGER_PRINT_2 = 1;
 
+    private static final String ARCHITECTURE_ID_1 = "tna";
+    private static final String ARCHITECTURE_ID_2 = "v1model";
+
+
     private static final PiPipelineModel P4_PIPELINE_MODEL_1 =
             new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1,
-                                FINGER_PRINT_1);
+                                ARCHITECTURE_ID_1, FINGER_PRINT_1);
     private static final PiPipelineModel SAME_AS_P4_PIPELINE_MODEL_1 =
             new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1,
-                                FINGER_PRINT_1);
+                                ARCHITECTURE_ID_1, FINGER_PRINT_1);
     private static final PiPipelineModel P4_PIPELINE_MODEL_2 =
             new P4PipelineModel(TABLES_2, COUNTERS_2, METERS_2, REGISTERS_1, ACTION_PROFILES_2, PACKET_OPERATIONS_2,
-                                FINGER_PRINT_2);
+                                ARCHITECTURE_ID_2, FINGER_PRINT_2);
     private static final PiPipelineModel P4_PIPELINE_MODEL_3 =
             new P4PipelineModel(TABLES_2, COUNTERS_2, METERS_2, REGISTERS_1, ACTION_PROFILES_2, PACKET_OPERATIONS_3,
-                                FINGER_PRINT_2);
+                                ARCHITECTURE_ID_2, FINGER_PRINT_2);
     private static final PiPipelineModel P4_PIPELINE_MODEL_4 =
             new P4PipelineModel(TABLES_3, COUNTERS_2, METERS_2, REGISTERS_1, ACTION_PROFILES_2, PACKET_OPERATIONS_3,
-                                FINGER_PRINT_2);
+                                ARCHITECTURE_ID_2, FINGER_PRINT_2);
 
     /**
      * Checks that the P4PipelineModel class is immutable.