Add support for arbitrary bitwidth packet metadata

This patch is related to #24172

Change-Id: I29fc82bd3944b7fc9f58021df56cadd209cac190
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
index 76fdbe4..6cf2f499 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPacketMetadataModel.java
@@ -37,4 +37,12 @@
      * @return size in bit
      */
     int bitWidth();
+
+    /**
+     * Return true is the packet metadata has a fixed bit width.
+     * It returns false if it can have flexible bit width.
+     *
+     * @return True if the packet metadata has fixed bit width, false otherwise
+     */
+    boolean hasBitWidth();
 }
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 b2f662b..0bb0360 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
@@ -413,7 +413,9 @@
                     ImmutableList.builder();
             ctrlPktMetaMsg.getMetadataList().forEach(metadataMsg -> metadataListBuilder.add(
                     new P4PacketMetadataModel(PiPacketMetadataId.of(metadataMsg.getName()),
-                                               metadataMsg.getBitwidth())));
+                                              isFieldString(p4info, metadataMsg.getTypeName().getName()) ?
+                                                      P4PacketMetadataModel.BIT_WIDTH_UNDEFINED :
+                                                      metadataMsg.getBitwidth())));
             packetOpMap.put(
                     mapPacketOpType(ctrlPktMetaMsg.getPreamble().getName()),
                     new P4PacketOperationModel(mapPacketOpType(ctrlPktMetaMsg.getPreamble().getName()),
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketMetadataModel.java
similarity index 92%
rename from protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java
rename to protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketMetadataModel.java
index 19a6fa7..65867ff 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketMetadataModel.java
@@ -28,6 +28,8 @@
  */
 final class P4PacketMetadataModel implements PiPacketMetadataModel {
 
+    static final int BIT_WIDTH_UNDEFINED = -1;
+
     private final PiPacketMetadataId id;
     private final int bitWidth;
 
@@ -47,6 +49,11 @@
     }
 
     @Override
+    public boolean hasBitWidth() {
+        return bitWidth != BIT_WIDTH_UNDEFINED;
+    }
+
+    @Override
     public int hashCode() {
         return Objects.hash(id, bitWidth);
     }
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PacketOperationModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PacketOperationModelTest.java
index 5d760e8..6fa2889 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PacketOperationModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PacketOperationModelTest.java
@@ -22,6 +22,7 @@
 import org.onosproject.net.pi.model.PiPacketMetadataId;
 import org.onosproject.net.pi.model.PiPacketMetadataModel;
 import org.onosproject.net.pi.model.PiPacketOperationType;
+
 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
 
 /**
@@ -42,6 +43,9 @@
         new P4PacketMetadataModel(PI_CONTROL_METADATA_ID_1, BIT_WIDTH_1);
     private static final PiPacketMetadataModel PI_CONTROL_METADATA_MODEL_2 =
         new P4PacketMetadataModel(PI_CONTROL_METADATA_ID_2, BIT_WIDTH_2);
+    private static final PiPacketMetadataModel PI_CONTROL_METADATA_MODEL_3 =
+            new P4PacketMetadataModel(
+                    PI_CONTROL_METADATA_ID_2, P4PacketMetadataModel.BIT_WIDTH_UNDEFINED);
 
     private static final ImmutableList<PiPacketMetadataModel> METADATAS_1 =
         new ImmutableList.Builder<PiPacketMetadataModel>()
@@ -58,6 +62,11 @@
             .add(PI_CONTROL_METADATA_MODEL_1)
             .add(PI_CONTROL_METADATA_MODEL_2)
             .build();
+    private static final ImmutableList<PiPacketMetadataModel> METADATAS_4 =
+            new ImmutableList.Builder<PiPacketMetadataModel>()
+                    .add(PI_CONTROL_METADATA_MODEL_1)
+                    .add(PI_CONTROL_METADATA_MODEL_3)
+                    .build();
 
     private static final P4PacketOperationModel P4_PACKET_OPERATION_MODEL_1 =
         new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_1, METADATAS_1);
@@ -67,6 +76,8 @@
         new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_2, METADATAS_2);
     private static final P4PacketOperationModel P4_PACKET_OPERATION_MODEL_3 =
         new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_2, METADATAS_3);
+    private static final P4PacketOperationModel P4_PACKET_OPERATION_MODEL_4 =
+            new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_2, METADATAS_4);
 
     /**
      * Checks that the P4PacketOperationModel class is immutable.
@@ -85,6 +96,7 @@
             .addEqualityGroup(P4_PACKET_OPERATION_MODEL_1, SAME_AS_P4_PACKET_OPERATION_MODEL_1)
             .addEqualityGroup(P4_PACKET_OPERATION_MODEL_2)
             .addEqualityGroup(P4_PACKET_OPERATION_MODEL_3)
+            .addEqualityGroup(P4_PACKET_OPERATION_MODEL_4)
             .testEquals();
     }
 }
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 a6bd76f..fdc3d2e 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
@@ -297,6 +297,8 @@
             new P4PacketMetadataModel(PI_CONTROL_METADATA_ID_1, META_BIT_WIDTH_1);
     private static final PiPacketMetadataModel P4_CONTROL_METADATA_MODEL_2 =
             new P4PacketMetadataModel(PI_CONTROL_METADATA_ID_2, META_BIT_WIDTH_2);
+    private static final PiPacketMetadataModel P4_CONTROL_METADATA_MODEL_3 =
+            new P4PacketMetadataModel(PI_CONTROL_METADATA_ID_2, P4PacketMetadataModel.BIT_WIDTH_UNDEFINED);
 
     /* Pipeline Models */
     private static final ImmutableMap<PiTableId, PiTableModel> TABLES_1 =
@@ -325,11 +327,17 @@
             new ImmutableList.Builder<PiPacketMetadataModel>()
                     .add(P4_CONTROL_METADATA_MODEL_2)
                     .build();
+    private static final ImmutableList<PiPacketMetadataModel> METADATAS_3 =
+            new ImmutableList.Builder<PiPacketMetadataModel>()
+                    .add(P4_CONTROL_METADATA_MODEL_3)
+                    .build();
 
     private static final PiPacketOperationModel P4_PACKET_OPERATION_MODEL_1 =
             new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_1, METADATAS_1);
     private static final PiPacketOperationModel P4_PACKET_OPERATION_MODEL_2 =
             new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_2, METADATAS_2);
+    private static final PiPacketOperationModel P4_PACKET_OPERATION_MODEL_3 =
+            new P4PacketOperationModel(PI_PACKET_OPERATION_TYPE_1, METADATAS_3);
 
     private static final ImmutableMap<PiPacketOperationType, PiPacketOperationModel> PACKET_OPERATIONS_1 =
             new ImmutableMap.Builder<PiPacketOperationType, PiPacketOperationModel>()
@@ -339,6 +347,10 @@
             new ImmutableMap.Builder<PiPacketOperationType, PiPacketOperationModel>()
                     .put(PI_PACKET_OPERATION_TYPE_2, P4_PACKET_OPERATION_MODEL_2)
                     .build();
+    private static final ImmutableMap<PiPacketOperationType, PiPacketOperationModel> PACKET_OPERATIONS_3 =
+            new ImmutableMap.Builder<PiPacketOperationType, PiPacketOperationModel>()
+                    .put(PI_PACKET_OPERATION_TYPE_1, P4_PACKET_OPERATION_MODEL_3)
+                    .build();
 
     private static final int FINGER_PRINT_1 = 0;
     private static final int FINGER_PRINT_2 = 1;
@@ -352,6 +364,9 @@
     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);
+    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);
 
     /**
      * Checks that the P4PipelineModel class is immutable.
@@ -369,6 +384,7 @@
         new EqualsTester()
                 .addEqualityGroup(P4_PIPELINE_MODEL_1, SAME_AS_P4_PIPELINE_MODEL_1)
                 .addEqualityGroup(P4_PIPELINE_MODEL_2)
+                .addEqualityGroup(P4_PIPELINE_MODEL_3)
                 .testEquals();
     }
 }