Add support for one shot action profile programming in PI

A P4 table annotated with @oneshot annotation can be programmed
only with the action profile action set. For these kind of tables
we don't issue read request for action profile groups and members.

Change-Id: I7b6a743f4f4df4190f17d958ebb4807aca5feda5
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionSetCodec.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionSetCodec.java
new file mode 100644
index 0000000..68ded36
--- /dev/null
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/ActionSetCodec.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020-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.ctl.codec;
+
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionSet;
+import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser;
+import p4.v1.P4RuntimeOuterClass;
+
+/**
+ * Codec for ActionSet.
+ */
+public class ActionSetCodec extends
+        AbstractCodec<PiActionSet, P4RuntimeOuterClass.ActionProfileActionSet, Object>  {
+
+    @Override
+    protected P4RuntimeOuterClass.ActionProfileActionSet encode(
+            PiActionSet piActionSet, Object ignored,
+            PiPipeconf pipeconf, P4InfoBrowser browser)
+            throws CodecException, P4InfoBrowser.NotFoundException {
+        final var actProActSetBuilder =
+                P4RuntimeOuterClass.ActionProfileActionSet.newBuilder();
+        for (PiActionSet.WeightedAction act : piActionSet.actions()) {
+            // TODO: currently we don't set "watch_port" field
+            final var actProfAct =
+                    P4RuntimeOuterClass.ActionProfileAction.newBuilder();
+            actProfAct.setAction(Codecs.CODECS.action().encode(
+                    act.action(), null, pipeconf));
+            actProfAct.setWeight(act.weight());
+            actProActSetBuilder.addActionProfileActions(actProfAct.build());
+        }
+        return actProActSetBuilder.build();
+    }
+
+    @Override
+    protected PiActionSet decode(
+            P4RuntimeOuterClass.ActionProfileActionSet message, Object ignored,
+            PiPipeconf pipeconf, P4InfoBrowser browser)
+            throws CodecException, P4InfoBrowser.NotFoundException {
+        final var builder = PiActionSet.builder();
+        for (P4RuntimeOuterClass.ActionProfileAction act : message.getActionProfileActionsList()) {
+            final var piAction = Codecs.CODECS.action().decode(
+                    act.getAction(), null, pipeconf);
+            builder.addWeightedAction(piAction, act.getWeight());
+        }
+        return builder.build();
+    }
+}
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/Codecs.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/Codecs.java
index 30e8d9d..06a2d18 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/Codecs.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/Codecs.java
@@ -40,6 +40,7 @@
     private final PacketMetadataCodec packetMetadata;
     private final PacketOutCodec packetOut;
     private final TableEntryCodec tableEntry;
+    private final ActionSetCodec actionSet;
 
     private Codecs() {
         this.action = new ActionCodec();
@@ -59,6 +60,7 @@
         this.packetMetadata = new PacketMetadataCodec();
         this.packetOut = new PacketOutCodec();
         this.tableEntry = new TableEntryCodec();
+        this.actionSet = new ActionSetCodec();
     }
 
     public EntityCodec entity() {
@@ -128,4 +130,8 @@
     DirectCounterEntryCodec directCounterEntry() {
         return directCounterEntry;
     }
+
+    ActionSetCodec actionSet() {
+        return actionSet;
+    }
 }
diff --git a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/TableEntryCodec.java b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/TableEntryCodec.java
index 513b4fa..a2455c9 100644
--- a/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/TableEntryCodec.java
+++ b/protocols/p4runtime/utils/src/main/java/org/onosproject/p4runtime/ctl/codec/TableEntryCodec.java
@@ -21,6 +21,7 @@
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
 import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
+import org.onosproject.net.pi.runtime.PiActionSet;
 import org.onosproject.net.pi.runtime.PiCounterCellData;
 import org.onosproject.net.pi.runtime.PiMatchKey;
 import org.onosproject.net.pi.runtime.PiTableAction;
@@ -179,6 +180,12 @@
                 tableActionMsgBuilder.setActionProfileMemberId(
                         ((PiActionProfileMemberId) piTableAction).id());
                 break;
+            case ACTION_SET:
+                P4RuntimeOuterClass.ActionProfileActionSet theActionProfileActionSet =
+                        CODECS.actionSet().encode(
+                                (PiActionSet) piTableAction, null, pipeconf);
+                tableActionMsgBuilder.setActionProfileActionSet(theActionProfileActionSet);
+                break;
             default:
                 throw new CodecException(
                         format("Building of table action type %s not implemented",
@@ -202,6 +209,9 @@
             case ACTION_PROFILE_MEMBER_ID:
                 return PiActionProfileMemberId.of(
                         tableActionMsg.getActionProfileMemberId());
+            case ACTION_PROFILE_ACTION_SET:
+                return CODECS.actionSet().decode(
+                        tableActionMsg.getActionProfileActionSet(), null, pipeconf);
             default:
                 throw new CodecException(
                         format("Decoding of table action type %s not implemented",