[ONOS-6935] ActionProfile supports in P4RuntimeClient
Change-Id: I9f0ac307985c03b7ed93e14e41ba468c481a4e4f
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
new file mode 100644
index 0000000..472bf8e
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
@@ -0,0 +1,144 @@
+/*
+ * 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.ctl;
+
+import com.google.common.collect.Maps;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
+import p4.P4RuntimeOuterClass.ActionProfileGroup;
+import p4.P4RuntimeOuterClass.ActionProfileGroup.Member;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
+import p4.config.P4InfoOuterClass;
+
+import java.util.Collection;
+import java.util.Map;
+
+import static java.lang.String.format;
+
+/**
+ * Encoder/Decoder for action profile group.
+ */
+public final class ActionProfileGroupEncoder {
+ private ActionProfileGroupEncoder() {
+ // hide default constructor
+ }
+
+ /**
+ * Encode a PI action group to a action profile group.
+ *
+ * @param piActionGroup the action profile group
+ * @param pipeconf the pipeconf
+ * @return a action profile group encoded from PI action group
+ * @throws P4InfoBrowser.NotFoundException if can't find action profile from P4Info browser
+ * @throws EncodeException if can't find P4Info from pipeconf
+ */
+ static ActionProfileGroup encode(PiActionGroup piActionGroup, PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+
+ PiActionProfileId piActionProfileId = piActionGroup.actionProfileId();
+ int actionProfileId;
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(piActionProfileId.id());
+ actionProfileId = actionProfile.getPreamble().getId();
+ ActionProfileGroup.Builder actionProfileGroupBuilder =
+ ActionProfileGroup.newBuilder()
+ .setGroupId(piActionGroup.id().id())
+ .setActionProfileId(actionProfileId);
+
+ switch (piActionGroup.type()) {
+ case SELECT:
+ actionProfileGroupBuilder.setType(ActionProfileGroup.Type.SELECT);
+ break;
+ default:
+ throw new EncodeException(format("Unsupported pi action group type %s",
+ piActionGroup.type()));
+ }
+
+ piActionGroup.members().forEach(m -> {
+ // TODO: currently we don't set "watch" field of member
+ Member member = Member.newBuilder()
+ .setMemberId(m.id().id())
+ .setWeight(m.weight())
+ .build();
+ actionProfileGroupBuilder.addMembers(member);
+ });
+
+ return actionProfileGroupBuilder.build();
+ }
+
+ /**
+ * Decode an action profile group with members information to a PI action group.
+ *
+ * @param actionProfileGroup the action profile group
+ * @param members members of the action profile group
+ * @param pipeconf the pipeconf
+ * @return decoded PI action group
+ * @throws P4InfoBrowser.NotFoundException if can't find action profile from P4Info browser
+ * @throws EncodeException if can't find P4Info from pipeconf
+ */
+ static PiActionGroup decode(ActionProfileGroup actionProfileGroup,
+ Collection<ActionProfileMember> members,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+ PiActionGroup.Builder piActionGroupBuilder = PiActionGroup.builder();
+
+ P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
+ .getById(actionProfileGroup.getActionProfileId());
+ PiActionProfileId piActionProfileId = PiActionProfileId.of(actionProfile.getPreamble().getName());
+ piActionGroupBuilder.withActionProfileId(piActionProfileId)
+ .withId(PiActionGroupId.of(actionProfileGroup.getGroupId()));
+
+ switch (actionProfileGroup.getType()) {
+ case SELECT:
+ piActionGroupBuilder.withType(PiActionGroup.Type.SELECT);
+ break;
+ default:
+ throw new EncodeException(format("Unsupported action profile type %s",
+ actionProfileGroup.getType()));
+ }
+
+ Map<Integer, Integer> memberWeights = Maps.newHashMap();
+ actionProfileGroup.getMembersList().forEach(member -> {
+ int weight = member.getWeight();
+ if (weight < 1) {
+ // FIXME: currently PI has a bug which will always return weight 0
+ // ONOS won't accept group member with weight 0
+ weight = 1;
+ }
+ memberWeights.put(member.getMemberId(), weight);
+ });
+
+ for (ActionProfileMember member : members) {
+ int weight = memberWeights.get(member.getMemberId());
+ piActionGroupBuilder
+ .addMember(ActionProfileMemberEncoder.decode(member, weight, pipeconf));
+ }
+
+ return piActionGroupBuilder.build();
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
new file mode 100644
index 0000000..2f08a59
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
@@ -0,0 +1,112 @@
+/*
+ * 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.ctl;
+
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
+import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
+import p4.P4RuntimeOuterClass;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
+import p4.config.P4InfoOuterClass;
+
+import static java.lang.String.format;
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decodeActionMsg;
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encodePiAction;
+
+/**
+ * Encoder/Decoder of action profile member.
+ */
+public final class ActionProfileMemberEncoder {
+ private ActionProfileMemberEncoder() {
+ // Hide default constructor
+ }
+
+ /**
+ * Encode a PiActionGroupMember to a ActionProfileMember.
+ *
+ * @param group the PI action group of members
+ * @param member the member to encode
+ * @param pipeconf the pipeconf
+ * @return encoded member
+ */
+ /**
+ * Encode a PiActionGroupMember to a ActionProfileMember.
+ *
+ * @param group the PI action group of members
+ * @param member the member to encode
+ * @param pipeconf the pipeconf, as encode spec
+ * @return encoded member
+ * @throws P4InfoBrowser.NotFoundException can't find action profile from P4Info browser
+ * @throws EncodeException can't find P4Info from pipeconf
+ */
+ static ActionProfileMember encode(PiActionGroup group,
+ PiActionGroupMember member,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+
+ ActionProfileMember.Builder actionProfileMemberBuilder =
+ ActionProfileMember.newBuilder();
+
+ // member id
+ actionProfileMemberBuilder.setMemberId(member.id().id());
+
+ // action profile id
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(group.actionProfileId().id());
+
+ int actionProfileId = actionProfile.getPreamble().getId();
+ actionProfileMemberBuilder.setActionProfileId(actionProfileId);
+
+ // Action
+ P4RuntimeOuterClass.Action action = encodePiAction(member.action(), browser);
+ actionProfileMemberBuilder.setAction(action);
+
+ return actionProfileMemberBuilder.build();
+ }
+
+ /**
+ * Decode an action profile member to PI action group member.
+ *
+ * @param member the action profile member
+ * @param weight the weight of the member
+ * @param pipeconf the pipeconf, as decode spec
+ * @return decoded PI action group member
+ * @throws P4InfoBrowser.NotFoundException can't find definition of action from P4 info
+ * @throws EncodeException can't get P4 info browser from pipeconf
+ */
+ static PiActionGroupMember decode(ActionProfileMember member,
+ int weight,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+ return PiActionGroupMember.builder().withId(PiActionGroupMemberId.of(member.getMemberId()))
+ .withWeight(weight)
+ .withAction(decodeActionMsg(member.getAction(), browser))
+ .build();
+ }
+}
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 a9adf55..7f22e79 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
@@ -17,7 +17,10 @@
package org.onosproject.p4runtime.ctl;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
import io.grpc.Context;
@@ -26,13 +29,17 @@
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.util.Tools;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiDirectCounterCellId;
import org.onosproject.net.pi.runtime.PiIndirectCounterCellId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -41,6 +48,8 @@
import org.onosproject.p4runtime.api.P4RuntimeEvent;
import org.slf4j.Logger;
import p4.P4RuntimeGrpc;
+import p4.P4RuntimeOuterClass.ActionProfileGroup;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
import p4.P4RuntimeOuterClass.Entity;
import p4.P4RuntimeOuterClass.ForwardingPipelineConfig;
import p4.P4RuntimeOuterClass.MasterArbitrationUpdate;
@@ -53,6 +62,7 @@
import p4.P4RuntimeOuterClass.TableEntry;
import p4.P4RuntimeOuterClass.Update;
import p4.P4RuntimeOuterClass.WriteRequest;
+import p4.config.P4InfoOuterClass;
import p4.config.P4InfoOuterClass.P4Info;
import p4.tmp.P4Config;
@@ -69,6 +79,8 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -78,6 +90,8 @@
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
import static org.slf4j.LoggerFactory.getLogger;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_GROUP;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_MEMBER;
import static p4.P4RuntimeOuterClass.Entity.EntityCase.TABLE_ENTRY;
import static p4.P4RuntimeOuterClass.PacketOut;
import static p4.P4RuntimeOuterClass.SetForwardingPipelineConfigRequest.Action.VERIFY_AND_COMMIT;
@@ -106,7 +120,14 @@
private final Lock writeLock = new ReentrantLock();
private final StreamObserver<StreamMessageRequest> streamRequestObserver;
-
+ /**
+ * Default constructor.
+ *
+ * @param deviceId the ONOS device id
+ * @param p4DeviceId the P4 device id
+ * @param channel gRPC channel
+ * @param controller runtime client controller
+ */
P4RuntimeClientImpl(DeviceId deviceId, long p4DeviceId, ManagedChannel channel,
P4RuntimeControllerImpl controller) {
this.deviceId = deviceId;
@@ -216,6 +237,30 @@
"readAllCounterCells-" + cellIds.hashCode());
}
+ @Override
+ public CompletableFuture<Boolean> writeActionGroupMembers(PiActionGroup group,
+ Collection<PiActionGroupMember> members,
+ WriteOperationType opType,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doWriteActionGroupMembers(group, members, opType, pipeconf),
+ "writeActionGroupMembers-" + opType.name());
+ }
+
+ @Override
+ public CompletableFuture<Boolean> writeActionGroup(PiActionGroup group,
+ WriteOperationType opType,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doWriteActionGroup(group, opType, pipeconf),
+ "writeActionGroup-" + opType.name());
+ }
+
+ @Override
+ public CompletableFuture<Collection<PiActionGroup>> dumpGroups(PiActionProfileId actionProfileId,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doDumpGroups(actionProfileId, pipeconf),
+ "dumpGroups-" + actionProfileId.id());
+ }
+
/* Blocking method implementations below */
private boolean doInitStreamChannel() {
@@ -464,6 +509,191 @@
return CounterEntryCodec.decodeCounterEntities(entities, counterIdMap, pipeconf);
}
+ private boolean doWriteActionGroupMembers(PiActionGroup group, Collection<PiActionGroupMember> members,
+ WriteOperationType opType, PiPipeconf pipeconf) {
+ WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
+
+ Collection<ActionProfileMember> actionProfileMembers = Lists.newArrayList();
+ try {
+ for (PiActionGroupMember member : members) {
+ actionProfileMembers.add(
+ ActionProfileMemberEncoder.encode(group, member, pipeconf)
+ );
+ }
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't encode group member {} due to {}", members, e.getMessage());
+ return false;
+ }
+
+ Collection<Update> updateMsgs = actionProfileMembers.stream()
+ .map(actionProfileMember ->
+ Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileMember(actionProfileMember)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build())
+ .collect(Collectors.toList());
+
+ if (updateMsgs.size() == 0) {
+ // Nothing to update
+ return true;
+ }
+
+ writeRequestBuilder
+ .setDeviceId(p4DeviceId)
+ .addAllUpdates(updateMsgs);
+ try {
+ blockingStub.write(writeRequestBuilder.build());
+ return true;
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ return false;
+ }
+ }
+
+ private Collection<PiActionGroup> doDumpGroups(PiActionProfileId piActionProfileId, PiPipeconf pipeconf) {
+ log.debug("Dumping groups from action profile {} from {} (pipeconf {})...",
+ piActionProfileId.id(), deviceId, pipeconf.id());
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ log.warn("Unable to get a P4Info browser for pipeconf {}, skipping dump action profile {}",
+ pipeconf, piActionProfileId);
+ return Collections.emptySet();
+ }
+
+ int actionProfileId;
+ try {
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(piActionProfileId.id());
+ actionProfileId = actionProfile.getPreamble().getId();
+ } catch (P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't find action profile {} from p4info", piActionProfileId);
+ return Collections.emptySet();
+ }
+
+ ActionProfileGroup actionProfileGroup =
+ ActionProfileGroup.newBuilder()
+ .setActionProfileId(actionProfileId)
+ .build();
+
+ ReadRequest requestMsg = ReadRequest.newBuilder()
+ .setDeviceId(p4DeviceId)
+ .addEntities(Entity.newBuilder()
+ .setActionProfileGroup(actionProfileGroup)
+ .build())
+ .build();
+
+ Iterator<ReadResponse> responses;
+ try {
+ responses = blockingStub.read(requestMsg);
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read action profile {} due to {}", piActionProfileId, e.getMessage());
+ return Collections.emptySet();
+ }
+
+ List<ActionProfileGroup> actionProfileGroups =
+ Tools.stream(() -> responses)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(entity -> entity.getEntityCase() == ACTION_PROFILE_GROUP)
+ .map(Entity::getActionProfileGroup)
+ .collect(Collectors.toList());
+
+ log.debug("Retrieved {} groups from action profile {} on {}...",
+ actionProfileGroups.size(), piActionProfileId.id(), deviceId);
+
+ // group id -> members
+ Multimap<Integer, ActionProfileMember> actionProfileMemberMap = HashMultimap.create();
+ AtomicLong memberCount = new AtomicLong(0);
+ AtomicBoolean success = new AtomicBoolean(true);
+ actionProfileGroups.forEach(actProfGrp -> {
+ actProfGrp.getMembersList().forEach(member -> {
+ ActionProfileMember actProfMember =
+ ActionProfileMember.newBuilder()
+ .setActionProfileId(actProfGrp.getActionProfileId())
+ .setMemberId(member.getMemberId())
+ .build();
+ Entity entity = Entity.newBuilder()
+ .setActionProfileMember(actProfMember)
+ .build();
+
+ ReadRequest reqMsg = ReadRequest.newBuilder().setDeviceId(p4DeviceId)
+ .addEntities(entity)
+ .build();
+
+ Iterator<ReadResponse> resps;
+ try {
+ resps = blockingStub.read(reqMsg);
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read member {} from action profile {} due to {}",
+ member, piActionProfileId, e.getMessage());
+ success.set(false);
+ return;
+ }
+ Tools.stream(() -> resps)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
+ .map(Entity::getActionProfileMember)
+ .forEach(m -> {
+ actionProfileMemberMap.put(actProfGrp.getGroupId(), m);
+ memberCount.incrementAndGet();
+ });
+ });
+ });
+
+ if (!success.get()) {
+ // Can't read members
+ return Collections.emptySet();
+ }
+ log.info("Retrieved {} group members from action profile {} on {}...",
+ memberCount.get(), piActionProfileId.id(), deviceId);
+
+ Collection<PiActionGroup> piActionGroups = Sets.newHashSet();
+
+ for (ActionProfileGroup apg : actionProfileGroups) {
+ try {
+ Collection<ActionProfileMember> members = actionProfileMemberMap.get(apg.getGroupId());
+ PiActionGroup decodedGroup =
+ ActionProfileGroupEncoder.decode(apg, members, pipeconf);
+ piActionGroups.add(decodedGroup);
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't decode group {} due to {}", apg, e.getMessage());
+ return Collections.emptySet();
+ }
+ }
+
+ return piActionGroups;
+ }
+
+ private boolean doWriteActionGroup(PiActionGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
+ WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
+ ActionProfileGroup actionProfileGroup;
+ try {
+ actionProfileGroup = ActionProfileGroupEncoder.encode(group, pipeconf);
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't encode group {} due to {}", e.getMessage());
+ return false;
+ }
+ Update updateMessage = Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileGroup(actionProfileGroup)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build();
+ writeRequestBuilder
+ .setDeviceId(p4DeviceId)
+ .addUpdates(updateMessage);
+ try {
+ blockingStub.write(writeRequestBuilder.build());
+ return true;
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ return false;
+ }
+ }
+
/**
* Returns the internal P4 device ID associated with this client.
*
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
index e26341b..383b857 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
@@ -186,7 +186,7 @@
}
}
- void postEvent(P4RuntimeEvent event) {
+ public void postEvent(P4RuntimeEvent event) {
post(event);
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
new file mode 100644
index 0000000..411e1fb
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ctl;
+
+import com.google.protobuf.ByteString;
+
+import static java.lang.String.format;
+
+/**
+ * Utilities for P4 runtime control.
+ */
+public final class P4RuntimeUtils {
+
+ private P4RuntimeUtils() {
+ // Hide default construction
+ }
+
+ static void assertSize(String entityDescr, ByteString value, int bitWidth)
+ throws EncodeException {
+
+ int byteWidth = (int) Math.ceil((float) bitWidth / 8);
+ if (value.size() != byteWidth) {
+ throw new EncodeException(format("Wrong size for %s, expected %d bytes, but found %d",
+ entityDescr, byteWidth, value.size()));
+ }
+ }
+
+ static void assertPrefixLen(String entityDescr, int prefixLength, int bitWidth)
+ throws EncodeException {
+
+ if (prefixLength > bitWidth) {
+ throw new EncodeException(format(
+ "wrong prefix length for %s, field size is %d bits, but found one is %d",
+ entityDescr, bitWidth, prefixLength));
+ }
+ }
+}
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 9ffc18f..8278b3e 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
@@ -17,10 +17,13 @@
package org.onosproject.p4runtime.ctl;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import com.google.protobuf.ByteString;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
+import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
import org.onosproject.net.pi.runtime.PiActionId;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiActionParamId;
@@ -36,25 +39,26 @@
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.runtime.PiValidFieldMatch;
import org.slf4j.Logger;
-import p4.P4RuntimeOuterClass.Action;
import p4.P4RuntimeOuterClass.FieldMatch;
import p4.P4RuntimeOuterClass.TableAction;
import p4.P4RuntimeOuterClass.TableEntry;
+import p4.P4RuntimeOuterClass.Action;
import p4.config.P4InfoOuterClass;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertPrefixLen;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertSize;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Encoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
+ * Encoder/Decoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
*/
final class TableEntryEncoder {
-
-
private static final Logger log = getLogger(TableEntryEncoder.class);
private static final String HEADER_PREFIX = "hdr.";
@@ -422,7 +426,7 @@
}
}
- private static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
+ static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
@@ -430,24 +434,17 @@
switch (piTableAction.type()) {
case ACTION:
PiAction piAction = (PiAction) piTableAction;
- int actionId = browser.actions().getByName(piAction.id().name()).getPreamble().getId();
-
- Action.Builder actionMsgBuilder = Action.newBuilder().setActionId(actionId);
-
- for (PiActionParam p : piAction.parameters()) {
- P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().name());
- ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
- assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
- paramValue, paramInfo.getBitwidth());
- actionMsgBuilder.addParams(Action.Param.newBuilder()
- .setParamId(paramInfo.getId())
- .setValue(paramValue)
- .build());
- }
-
- tableActionMsgBuilder.setAction(actionMsgBuilder.build());
+ Action theAction = encodePiAction(piAction, browser);
+ tableActionMsgBuilder.setAction(theAction);
break;
-
+ case ACTION_GROUP_ID:
+ PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
+ tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
+ break;
+ case GROUP_MEMBER_ID:
+ PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
+ tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
+ break;
default:
throw new EncodeException(
format("Building of table action type %s not implemented", piTableAction.type()));
@@ -456,50 +453,56 @@
return tableActionMsgBuilder.build();
}
- private static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
+ static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
-
TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
-
switch (typeCase) {
case ACTION:
- PiAction.Builder piActionBuilder = PiAction.builder();
Action actionMsg = tableActionMsg.getAction();
- // Action ID.
- int actionId = actionMsg.getActionId();
- String actionName = browser.actions().getById(actionId).getPreamble().getName();
- piActionBuilder.withId(PiActionId.of(actionName));
- // Params.
- for (Action.Param paramMsg : actionMsg.getParamsList()) {
- String paramName = browser.actionParams(actionId).getById(paramMsg.getParamId()).getName();
- ImmutableByteSequence paramValue = copyFrom(paramMsg.getValue().asReadOnlyByteBuffer());
- piActionBuilder.withParameter(new PiActionParam(PiActionParamId.of(paramName), paramValue));
- }
- return piActionBuilder.build();
-
+ return decodeActionMsg(actionMsg, browser);
default:
throw new EncodeException(
format("Decoding of table action type %s not implemented", typeCase.name()));
}
}
- private static void assertSize(String entityDescr, ByteString value, int bitWidth)
- throws EncodeException {
+ static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
- int byteWidth = (int) Math.ceil((float) bitWidth / 8);
- if (value.size() != byteWidth) {
- throw new EncodeException(format("Wrong size for %s, expected %d bytes, but found %d",
- entityDescr, byteWidth, value.size()));
+ int actionId = browser.actions().getByName(piAction.id().name()).getPreamble().getId();
+
+ Action.Builder actionMsgBuilder =
+ Action.newBuilder().setActionId(actionId);
+
+ for (PiActionParam p : piAction.parameters()) {
+ P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().name());
+ ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
+ assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
+ paramValue, paramInfo.getBitwidth());
+ actionMsgBuilder.addParams(Action.Param.newBuilder()
+ .setParamId(paramInfo.getId())
+ .setValue(paramValue)
+ .build());
}
+
+ return actionMsgBuilder.build();
}
- private static void assertPrefixLen(String entityDescr, int prefixLength, int bitWidth)
- throws EncodeException {
+ static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException {
+ P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
+ browser.actionParams(action.getActionId());
+ String actionName = browser.actions()
+ .getById(action.getActionId())
+ .getPreamble().getName();
+ PiActionId id = PiActionId.of(actionName);
+ List<PiActionParam> params = Lists.newArrayList();
- if (prefixLength > bitWidth) {
- throw new EncodeException(format(
- "wrong prefix length for %s, field size is %d bits, but found one is %d",
- entityDescr, bitWidth, prefixLength));
+ for (Action.Param p : action.getParamsList()) {
+ String paramName = paramInfo.getById(p.getParamId()).getName();
+ ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
+ params.add(new PiActionParam(PiActionParamId.of(paramName), value));
}
+ return PiAction.builder().withId(id).withParameters(params).build();
}
}