ONOS-7898 Action profile group/member refactoring
Also includes:
- New abstract P4Runtime codec implementation. Currently used for action
profile members/groups encoding/deconding, the plan is to handle all
other codecs via this.
- Improved read requests in P4RuntimeClientImpl
- Removed handling of max group size in P4Runtime driver. Instead, added
modified group translator to specify a max group size by using
information from the pipeline model.
Change-Id: I684bae0184d683bb448ba19863c561f9848479d2
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
index 5d7e93e..ff00a1a 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
@@ -188,9 +188,9 @@
* Performs the given write operation for the given action profile members
* and pipeconf.
*
- * @param members action profile members
- * @param opType write operation type
- * @param pipeconf the pipeconf currently deployed on the device
+ * @param members action profile members
+ * @param opType write operation type
+ * @param pipeconf the pipeconf currently deployed on the device
* @return true if the operation was successful, false otherwise
*/
CompletableFuture<Boolean> writeActionProfileMembers(
@@ -204,19 +204,15 @@
* @param group the action profile group
* @param opType write operation type
* @param pipeconf the pipeconf currently deployed on the device
- * @param maxMemberSize the maximum number of members that can be added to
- * the group. This is meaningful only if it's an INSERT
- * operation, otherwise its value should be 0
* @return true if the operation was successful, false otherwise
*/
CompletableFuture<Boolean> writeActionProfileGroup(
PiActionProfileGroup group,
WriteOperationType opType,
- PiPipeconf pipeconf,
- int maxMemberSize);
+ PiPipeconf pipeconf);
/**
- * Dumps all groups currently installed in the given action profile.
+ * Dumps all groups for a given action profile.
*
* @param actionProfileId the action profile id
* @param pipeconf the pipeconf currently deployed on the device
@@ -226,13 +222,13 @@
PiActionProfileId actionProfileId, PiPipeconf pipeconf);
/**
- * Dumps all action profile member IDs for a given action profile.
+ * Dumps all members for a given action profile.
*
* @param actionProfileId action profile ID
* @param pipeconf pipeconf
* @return future of list of action profile member ID
*/
- CompletableFuture<List<PiActionProfileMemberId>> dumpActionProfileMemberIds(
+ CompletableFuture<List<PiActionProfileMember>> dumpActionProfileMembers(
PiActionProfileId actionProfileId, PiPipeconf pipeconf);
/**
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/AbstractP4RuntimeCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/AbstractP4RuntimeCodec.java
new file mode 100644
index 0000000..a76ab7c
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/AbstractP4RuntimeCodec.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2019-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.Message;
+import com.google.protobuf.TextFormat;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiEntity;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Abstract implementation of a codec that translates PI entities into P4Runtime
+ * protobuf messages and vice versa.
+ *
+ * @param <P> PI entity class
+ * @param <M> P4Runtime protobuf message class
+ */
+abstract class AbstractP4RuntimeCodec<P extends PiEntity, M extends Message> {
+
+ protected final Logger log = getLogger(this.getClass());
+
+ protected abstract M encode(P piEntity, PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws CodecException, P4InfoBrowser.NotFoundException;
+
+ protected abstract P decode(M message, PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws CodecException, P4InfoBrowser.NotFoundException;
+
+ /**
+ * Returns a P4Runtime protobuf message that is equivalent to the given PI
+ * entity for the given pipeconf.
+ *
+ * @param piEntity PI entity instance
+ * @param pipeconf pipeconf
+ * @return P4Runtime protobuf message
+ * @throws CodecException if the given PI entity cannot be encoded (see
+ * exception message)
+ */
+ public M encode(P piEntity, PiPipeconf pipeconf)
+ throws CodecException {
+ try {
+ return encode(piEntity, pipeconf, browserOrFail(pipeconf));
+ } catch (P4InfoBrowser.NotFoundException e) {
+ throw new CodecException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a PI entity instance that is equivalent to the P4Runtime protobuf
+ * message for the given pipeconf.
+ *
+ * @param message P4Runtime protobuf message
+ * @param pipeconf pipeconf pipeconf
+ * @return PI entity instance
+ * @throws CodecException if the given protobuf message cannot be decoded
+ * (see exception message)
+ */
+ public P decode(M message, PiPipeconf pipeconf)
+ throws CodecException {
+ try {
+ return decode(message, pipeconf, browserOrFail(pipeconf));
+ } catch (P4InfoBrowser.NotFoundException e) {
+ throw new CodecException(e.getMessage());
+ }
+ }
+
+ /**
+ * Same as {@link #encode(PiEntity, PiPipeconf)} but returns null in case of
+ * exceptions, while the error message is logged.
+ *
+ * @param piEntity PI entity instance
+ * @param pipeconf pipeconf
+ * @return P4Runtime protobuf message
+ */
+ public M encodeOrNull(P piEntity, PiPipeconf pipeconf) {
+ try {
+ return encode(piEntity, pipeconf);
+ } catch (CodecException e) {
+ log.error("Unable to encode {}: {} [{}]",
+ piEntity.getClass().getSimpleName(),
+ e.getMessage(), piEntity.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Same as {@link #decode(Message, PiPipeconf)} but returns null in case of
+ * exceptions, while the error message is logged.
+ *
+ * @param message P4Runtime protobuf message
+ * @param pipeconf pipeconf pipeconf
+ * @return PI entity instance
+ */
+ public P decodeOrNull(M message, PiPipeconf pipeconf) {
+ try {
+ return decode(message, pipeconf);
+ } catch (CodecException e) {
+ log.error("Unable to decode {}: {} [{}]",
+ message.getClass().getSimpleName(),
+ e.getMessage(), TextFormat.shortDebugString(message));
+ return null;
+ }
+ }
+
+ /**
+ * Encodes the given list of PI entities, skipping those that cannot be
+ * encoded, in which case an error message is logged. For this reason, the
+ * returned list might have different size than the returned one.
+ *
+ * @param piEntities list of PI entities
+ * @param pipeconf pipeconf
+ * @return list of P4Runtime protobuf messages
+ */
+ public List<M> encodeAll(List<P> piEntities, PiPipeconf pipeconf) {
+ checkNotNull(piEntities);
+ return piEntities.stream()
+ .map(p -> encodeOrNull(p, pipeconf))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Decodes the given list of P4Runtime protobuf messages, skipping those
+ * that cannot be decoded, on which case an error message is logged. For
+ * this reason, the returned list might have different size than the
+ * returned one.
+ *
+ * @param messages list of protobuf messages
+ * @param pipeconf pipeconf
+ * @return list of PI entities
+ */
+ public List<P> decodeAll(List<M> messages, PiPipeconf pipeconf) {
+ checkNotNull(messages);
+ return messages.stream()
+ .map(m -> decodeOrNull(m, pipeconf))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Same as {@link #encodeAll(List, PiPipeconf)} but throws an exception if
+ * one or more of the given PI entities cannot be encoded. The returned list
+ * is guaranteed to have same size and order as the given one.
+ *
+ * @param piEntities list of PI entities
+ * @param pipeconf pipeconf
+ * @return list of protobuf messages
+ * @throws CodecException if one or more of the given PI entities cannot be
+ * encoded
+ */
+ public List<M> encodeAllOrFail(List<P> piEntities, PiPipeconf pipeconf)
+ throws CodecException {
+ final List<M> messages = encodeAll(piEntities, pipeconf);
+ if (piEntities.size() != messages.size()) {
+ throw new CodecException(format(
+ "Unable to encode %d entities of %d given " +
+ "(see previous logs for details)",
+ piEntities.size() - messages.size(), piEntities.size()));
+ }
+ return messages;
+ }
+
+ /**
+ * Same as {@link #decodeAll(List, PiPipeconf)} but throws an exception if
+ * one or more of the given protobuf messages cannot be decoded. The
+ * returned list is guaranteed to have same size and order as the given
+ * one.
+ *
+ * @param messages list of protobuf messages
+ * @param pipeconf pipeconf
+ * @return list of PI entities
+ * @throws CodecException if one or more of the given protobuf messages
+ * cannot be decoded
+ */
+ public List<P> decodeAllOrFail(List<M> messages, PiPipeconf pipeconf)
+ throws CodecException {
+ final List<P> piEntities = decodeAll(messages, pipeconf);
+ if (messages.size() != piEntities.size()) {
+ throw new CodecException(format(
+ "Unable to decode %d messages of %d given " +
+ "(see previous logs for details)",
+ messages.size() - piEntities.size(), messages.size()));
+ }
+ return piEntities;
+ }
+
+ private P4InfoBrowser browserOrFail(PiPipeconf pipeconf) throws CodecException {
+ final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ throw new CodecException(format(
+ "Unable to get P4InfoBrowser for pipeconf %s", pipeconf.id()));
+ }
+ return browser;
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupCodec.java
new file mode 100644
index 0000000..684ef04
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupCodec.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-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.PiActionProfileId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileGroup;
+import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
+import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
+import p4.v1.P4RuntimeOuterClass.ActionProfileGroup;
+
+/**
+ * Codec for P4Runtime ActionProfileGroup.
+ */
+final class ActionProfileGroupCodec
+ extends AbstractP4RuntimeCodec<PiActionProfileGroup, ActionProfileGroup> {
+
+ @Override
+ public ActionProfileGroup encode(
+ PiActionProfileGroup piGroup, PiPipeconf pipeconf, P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException {
+
+ final int p4ActionProfileId = browser.actionProfiles()
+ .getByName(piGroup.actionProfile().id())
+ .getPreamble().getId();
+ final ActionProfileGroup.Builder msgBuilder = ActionProfileGroup.newBuilder()
+ .setGroupId(piGroup.id().id())
+ .setActionProfileId(p4ActionProfileId)
+ .setMaxSize(piGroup.maxSize());
+ piGroup.members().forEach(m -> {
+ // TODO: currently we don't set "watch" field
+ ActionProfileGroup.Member member = ActionProfileGroup.Member.newBuilder()
+ .setMemberId(m.id().id())
+ .setWeight(m.weight())
+ .build();
+ msgBuilder.addMembers(member);
+ });
+
+ return msgBuilder.build();
+ }
+
+ @Override
+ public PiActionProfileGroup decode(
+ ActionProfileGroup msg, PiPipeconf pipeconf, P4InfoBrowser browser)
+ throws CodecException, P4InfoBrowser.NotFoundException {
+
+ final PiActionProfileGroup.Builder piGroupBuilder = PiActionProfileGroup.builder()
+ .withActionProfileId(PiActionProfileId.of(
+ browser.actionProfiles()
+ .getById(msg.getActionProfileId())
+ .getPreamble().getName()))
+ .withId(PiActionProfileGroupId.of(msg.getGroupId()))
+ .withMaxSize(msg.getMaxSize());
+
+ msg.getMembersList().forEach(m -> {
+ int weight = m.getWeight();
+ if (weight < 1) {
+ // FIXME: currently PI has a bug which will always return weight 0
+ // ONOS won't accept group buckets with weight 0
+ log.warn("Decoding ActionProfileGroup with 'weight' " +
+ "field {}, will set to 1", weight);
+ weight = 1;
+ }
+ piGroupBuilder.addMember(PiActionProfileMemberId.of(
+ m.getMemberId()), weight);
+ });
+ return piGroupBuilder.build();
+ }
+}
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
deleted file mode 100644
index 414a0e6..0000000
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.PiActionProfileId;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.runtime.PiActionProfileGroup;
-import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
-import p4.config.v1.P4InfoOuterClass;
-import p4.v1.P4RuntimeOuterClass.ActionProfileGroup;
-import p4.v1.P4RuntimeOuterClass.ActionProfileGroup.Member;
-import p4.v1.P4RuntimeOuterClass.ActionProfileMember;
-
-import java.util.Collection;
-import java.util.Map;
-
-import static java.lang.String.format;
-
-/**
- * Encoder/Decoder for action profile group.
- */
-final class ActionProfileGroupEncoder {
-
- private ActionProfileGroupEncoder() {
- // hide default constructor
- }
-
- /**
- * Encode a PI action profile group to a action profile group.
- *
- * @param piActionGroup the action profile group
- * @param pipeconf the pipeconf
- * @param maxMemberSize the max member size of action group
- * @return a action profile group encoded from PI action profile 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(PiActionProfileGroup piActionGroup, PiPipeconf pipeconf, int maxMemberSize)
- 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();
- P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
- .getByName(piActionProfileId.id());
- int actionProfileId = actionProfile.getPreamble().getId();
- ActionProfileGroup.Builder actionProfileGroupBuilder = ActionProfileGroup.newBuilder()
- .setGroupId(piActionGroup.id().id())
- .setActionProfileId(actionProfileId);
-
- 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);
- });
-
- if (maxMemberSize > 0) {
- actionProfileGroupBuilder.setMaxSize(maxMemberSize);
- }
-
- return actionProfileGroupBuilder.build();
- }
-
- /**
- * Decode an action profile group with members information to a PI action
- * profile group.
- *
- * @param actionProfileGroup the action profile group
- * @param members members of the action profile group
- * @param pipeconf the pipeconf
- * @return decoded PI action profile group
- * @throws P4InfoBrowser.NotFoundException if can't find action profile from
- * P4Info browser
- * @throws EncodeException if can't find P4Info from
- * pipeconf
- */
- static PiActionProfileGroup 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));
- }
- PiActionProfileGroup.Builder piActionGroupBuilder = PiActionProfileGroup.builder();
-
- P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
- .getById(actionProfileGroup.getActionProfileId());
- PiActionProfileId piActionProfileId = PiActionProfileId.of(actionProfile.getPreamble().getName());
-
- piActionGroupBuilder
- .withActionProfileId(piActionProfileId)
- .withId(PiActionProfileGroupId.of(actionProfileGroup.getGroupId()));
-
- 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 buckets with weight 0
- weight = 1;
- }
- memberWeights.put(member.getMemberId(), weight);
- });
-
- for (ActionProfileMember member : members) {
- if (!memberWeights.containsKey(member.getMemberId())) {
- // Not a member of this group, ignore.
- continue;
- }
- 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/ActionProfileMemberCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberCodec.java
new file mode 100644
index 0000000..9567b0a
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberCodec.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019-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.PiActionProfileId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileMember;
+import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
+import p4.config.v1.P4InfoOuterClass;
+import p4.v1.P4RuntimeOuterClass;
+import p4.v1.P4RuntimeOuterClass.ActionProfileMember;
+
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decodeActionMsg;
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encodePiAction;
+/**
+ * Codec for P4Runtime ActionProfileMember.
+ */
+final class ActionProfileMemberCodec
+ extends AbstractP4RuntimeCodec<PiActionProfileMember, ActionProfileMember> {
+
+ @Override
+ public ActionProfileMember encode(PiActionProfileMember piEntity,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws CodecException, P4InfoBrowser.NotFoundException {
+ final ActionProfileMember.Builder actionProfileMemberBuilder =
+ ActionProfileMember.newBuilder();
+ // Member ID
+ actionProfileMemberBuilder.setMemberId(piEntity.id().id());
+ // Action profile ID
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(piEntity.actionProfile().id());
+ final int actionProfileId = actionProfile.getPreamble().getId();
+ actionProfileMemberBuilder.setActionProfileId(actionProfileId);
+ // Action
+ final P4RuntimeOuterClass.Action action = encodePiAction(piEntity.action(), browser);
+ actionProfileMemberBuilder.setAction(action);
+ return actionProfileMemberBuilder.build();
+ }
+
+ @Override
+ public PiActionProfileMember decode(ActionProfileMember message,
+ PiPipeconf pipeconf,
+ P4InfoBrowser browser)
+ throws CodecException, P4InfoBrowser.NotFoundException {
+ final PiActionProfileId actionProfileId = PiActionProfileId.of(
+ browser.actionProfiles()
+ .getById(message.getActionProfileId())
+ .getPreamble()
+ .getName());
+ return PiActionProfileMember.builder()
+ .forActionProfile(actionProfileId)
+ .withId(PiActionProfileMemberId.of(message.getMemberId()))
+ .withAction(decodeActionMsg(message.getAction(), browser))
+ .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
deleted file mode 100644
index 30dd43c..0000000
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.PiActionProfileId;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.runtime.PiActionProfileMember;
-import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
-import p4.config.v1.P4InfoOuterClass;
-import p4.v1.P4RuntimeOuterClass;
-import p4.v1.P4RuntimeOuterClass.ActionProfileMember;
-
-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.
- */
-final class ActionProfileMemberEncoder {
- private ActionProfileMemberEncoder() {
- // Hide default constructor
- }
-
- /**
- * Encode a PiActionProfileMember to a ActionProfileMember.
- *
- * @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(PiActionProfileMember 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(member.actionProfile().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 profile 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 profile member
- * @throws P4InfoBrowser.NotFoundException can't find definition of action
- * from P4 info
- * @throws EncodeException can't get P4 info browser from
- * pipeconf
- */
- static PiActionProfileMember 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));
- }
-
- final PiActionProfileId actionProfileId = PiActionProfileId.of(
- browser.actionProfiles()
- .getById(member.getActionProfileId())
- .getPreamble()
- .getName());
-
- return PiActionProfileMember.builder()
- .forActionProfile(actionProfileId)
- .withId(PiActionProfileMemberId.of(member.getMemberId()))
- .withWeight(weight)
- .withAction(decodeActionMsg(member.getAction(), browser))
- .build();
- }
-}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/EncodeException.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CodecException.java
similarity index 65%
rename from protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/EncodeException.java
rename to protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CodecException.java
index 51abbb5..89d5510 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/EncodeException.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CodecException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-present Open Networking Foundation
+ * Copyright 2019-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.
@@ -17,11 +17,15 @@
package org.onosproject.p4runtime.ctl;
/**
- * Signals that the proto message cannot be build.
+ * Signals an error during encoding/decoding of a PI entity/protobuf message.
*/
-final class EncodeException extends Exception {
+public final class CodecException extends Exception {
- EncodeException(String explanation) {
+ /**
+ * Ceeates anew exception with the given explanation message.
+ * @param explanation explanation
+ */
+ public CodecException(String explanation) {
super(explanation);
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
index 6c29062..3765d24 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/CounterEntryCodec.java
@@ -80,7 +80,7 @@
.map(cellId -> {
try {
return encodePiCounterCellId(cellId, pipeconf, browser);
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ } catch (P4InfoBrowser.NotFoundException | CodecException e) {
log.warn("Unable to encode PI counter cell id: {}", e.getMessage());
return null;
}
@@ -114,7 +114,7 @@
.map(counterId -> {
try {
return readAllCellsEntity(counterId, pipeconf, browser);
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ } catch (P4InfoBrowser.NotFoundException | CodecException e) {
log.warn("Unable to encode counter ID to read-all-cells entity: {}",
e.getMessage());
return null;
@@ -152,7 +152,7 @@
.map(entity -> {
try {
return decodeCounterEntity(entity, pipeconf, browser);
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ } catch (CodecException | P4InfoBrowser.NotFoundException e) {
log.warn("Unable to decode counter entity message: {}",
e.getMessage());
return null;
@@ -165,7 +165,7 @@
private static Entity encodePiCounterCellId(PiCounterCellId cellId,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
int counterId;
Entity entity;
@@ -193,7 +193,7 @@
.build();
break;
default:
- throw new EncodeException(format(
+ throw new CodecException(format(
"Unrecognized PI counter cell ID type '%s'",
cellId.counterType()));
}
@@ -204,10 +204,10 @@
private static Entity readAllCellsEntity(PiCounterId counterId,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
if (!pipeconf.pipelineModel().counter(counterId).isPresent()) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"not such counter '%s' in pipeline model", counterId));
}
final PiCounterType counterType = pipeconf.pipelineModel()
@@ -228,7 +228,7 @@
final PiTableId tableId = pipeconf.pipelineModel()
.counter(counterId).get().table();
if (tableId == null) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"null table for direct counter '%s'", counterId));
}
final int p4TableId = browser.tables().getByName(tableId.id())
@@ -243,7 +243,7 @@
.build())
.build();
default:
- throw new EncodeException(format(
+ throw new CodecException(format(
"unrecognized PI counter type '%s'", counterType));
}
}
@@ -251,7 +251,7 @@
private static PiCounterCell decodeCounterEntity(Entity entity,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws EncodeException, P4InfoBrowser.NotFoundException {
+ throws CodecException, P4InfoBrowser.NotFoundException {
CounterData counterData;
PiCounterCellId piCellId;
@@ -271,7 +271,7 @@
piCellId = PiCounterCellId.ofDirect(piTableEntry);
counterData = entity.getDirectCounterEntry().getData();
} else {
- throw new EncodeException(format(
+ throw new CodecException(format(
"Unrecognized entity type '%s' in P4Runtime message",
entity.getEntityCase().name()));
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
index a825488..44f27d1 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MeterEntryCodec.java
@@ -80,7 +80,7 @@
.map(cellConfig -> {
try {
return encodePiMeterCellConfig(cellConfig, pipeconf, browser);
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ } catch (P4InfoBrowser.NotFoundException | CodecException e) {
log.warn("Unable to encode PI meter cell id: {}", e.getMessage());
log.debug("exception", e);
return null;
@@ -115,7 +115,7 @@
.map(meterId -> {
try {
return readAllCellsEntity(meterId, pipeconf, browser);
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ } catch (P4InfoBrowser.NotFoundException | CodecException e) {
log.warn("Unable to encode meter ID to read-all-cells entity: {}",
e.getMessage());
return null;
@@ -152,7 +152,7 @@
.map(entity -> {
try {
return decodeMeterEntity(entity, pipeconf, browser);
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ } catch (CodecException | P4InfoBrowser.NotFoundException e) {
log.warn("Unable to decode meter entity message: {}", e.getMessage());
return null;
}
@@ -164,7 +164,7 @@
private static Entity encodePiMeterCellConfig(PiMeterCellConfig config,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
int meterId;
Entity entity;
@@ -198,7 +198,7 @@
// When reading meter cells.
meterConfig = null;
} else {
- throw new EncodeException("number of meter bands should be either 2 or 0");
+ throw new CodecException("number of meter bands should be either 2 or 0");
}
switch (config.cellId().meterType()) {
@@ -226,8 +226,8 @@
.setDirectMeterEntry(dirEntryBuilder.build()).build();
break;
default:
- throw new EncodeException(format("unrecognized PI meter type '%s'",
- config.cellId().meterType()));
+ throw new CodecException(format("unrecognized PI meter type '%s'",
+ config.cellId().meterType()));
}
return entity;
@@ -236,10 +236,10 @@
private static Entity readAllCellsEntity(PiMeterId meterId,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
if (!pipeconf.pipelineModel().meter(meterId).isPresent()) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"not such meter '%s' in pipeline model", meterId));
}
final PiMeterType meterType = pipeconf.pipelineModel()
@@ -260,7 +260,7 @@
final PiTableId tableId = pipeconf.pipelineModel()
.meter(meterId).get().table();
if (tableId == null) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"null table for direct meter '%s'", meterId));
}
final int p4TableId = browser.tables().getByName(tableId.id())
@@ -275,7 +275,7 @@
.build())
.build();
default:
- throw new EncodeException(format(
+ throw new CodecException(format(
"unrecognized PI meter type '%s'", meterType));
}
}
@@ -283,7 +283,7 @@
private static PiMeterCellConfig decodeMeterEntity(Entity entity,
PiPipeconf pipeconf,
P4InfoBrowser browser)
- throws EncodeException, P4InfoBrowser.NotFoundException {
+ throws CodecException, P4InfoBrowser.NotFoundException {
MeterConfig meterConfig;
PiMeterCellId piCellId;
@@ -304,7 +304,7 @@
piCellId = PiMeterCellId.ofDirect(piTableEntry);
meterConfig = entity.getDirectMeterEntry().getConfig();
} else {
- throw new EncodeException(format(
+ throw new CodecException(format(
"unrecognized entity type '%s' in P4Runtime message",
entity.getEntityCase().name()));
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
index f2ececb..5f55c1f 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/MulticastGroupEntryCodec.java
@@ -40,9 +40,9 @@
*
* @param piEntry PiMulticastGroupEntry
* @return P4Runtime MulticastGroupEntry message
- * @throws EncodeException if the PiMulticastGroupEntry cannot be encoded.
+ * @throws CodecException if the PiMulticastGroupEntry cannot be encoded.
*/
- static MulticastGroupEntry encode(PiMulticastGroupEntry piEntry) throws EncodeException {
+ static MulticastGroupEntry encode(PiMulticastGroupEntry piEntry) throws CodecException {
final MulticastGroupEntry.Builder msgBuilder = MulticastGroupEntry.newBuilder();
msgBuilder.setMulticastGroupId(piEntry.groupId());
for (PiPreReplica replica : piEntry.replicas()) {
@@ -50,7 +50,7 @@
try {
p4PortId = Math.toIntExact(replica.egressPort().toLong());
} catch (ArithmeticException e) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"Cannot cast 64bit port value '%s' to 32bit",
replica.egressPort()));
}
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 78ea9d9..6ac478f 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
@@ -16,10 +16,8 @@
package org.onosproject.p4runtime.ctl;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -86,14 +84,21 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
+import java.util.stream.Stream;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static org.onosproject.p4runtime.ctl.P4RuntimeCodecs.CODECS;
import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_GROUP;
import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_MEMBER;
+import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.COUNTER_ENTRY;
+import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.DIRECT_COUNTER_ENTRY;
+import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.DIRECT_METER_ENTRY;
+import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.METER_ENTRY;
import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.PACKET_REPLICATION_ENGINE_ENTRY;
import static p4.v1.P4RuntimeOuterClass.Entity.EntityCase.TABLE_ENTRY;
import static p4.v1.P4RuntimeOuterClass.PacketIn;
@@ -106,10 +111,13 @@
*/
final class P4RuntimeClientImpl extends AbstractGrpcClient implements P4RuntimeClient {
+ private static final String MISSING_P4INFO_BROWSER = "Unable to get a P4Info browser for pipeconf {}";
+
private static final Metadata.Key<com.google.rpc.Status> STATUS_DETAILS_KEY =
- Metadata.Key.of("grpc-status-details-bin",
- ProtoLiteUtils.metadataMarshaller(
- com.google.rpc.Status.getDefaultInstance()));
+ Metadata.Key.of(
+ "grpc-status-details-bin",
+ ProtoLiteUtils.metadataMarshaller(
+ com.google.rpc.Status.getDefaultInstance()));
private static final Map<WriteOperationType, Update.Type> UPDATE_TYPES = ImmutableMap.of(
WriteOperationType.UNSPECIFIED, Update.Type.UNSPECIFIED,
@@ -229,9 +237,8 @@
@Override
public CompletableFuture<Boolean> writeActionProfileGroup(PiActionProfileGroup group,
WriteOperationType opType,
- PiPipeconf pipeconf,
- int maxMemberSize) {
- return supplyInContext(() -> doWriteActionProfileGroup(group, opType, pipeconf, maxMemberSize),
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doWriteActionProfileGroup(group, opType, pipeconf),
"writeActionProfileGroup-" + opType.name());
}
@@ -243,10 +250,10 @@
}
@Override
- public CompletableFuture<List<PiActionProfileMemberId>> dumpActionProfileMemberIds(
+ public CompletableFuture<List<PiActionProfileMember>> dumpActionProfileMembers(
PiActionProfileId actionProfileId, PiPipeconf pipeconf) {
- return supplyInContext(() -> doDumpActionProfileMemberIds(actionProfileId, pipeconf),
- "dumpActionProfileMemberIds-" + actionProfileId.id());
+ return supplyInContext(() -> doDumpActionProfileMembers(actionProfileId, pipeconf),
+ "dumpActionProfileMembers-" + actionProfileId.id());
}
@Override
@@ -484,8 +491,8 @@
.build())
.setType(UPDATE_TYPES.get(opType))
.build())
- .collect(Collectors.toList());
- } catch (EncodeException e) {
+ .collect(toList());
+ } catch (CodecException e) {
log.error("Unable to encode table entries, aborting {} operation: {}",
opType.name(), e.getMessage());
return false;
@@ -507,7 +514,7 @@
} else {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- log.warn("Unable to get a P4Info browser for pipeconf {}", pipeconf);
+ log.error(MISSING_P4INFO_BROWSER, pipeconf);
return Collections.emptyList();
}
piTableIds.forEach(piTableId -> {
@@ -523,36 +530,18 @@
return Collections.emptyList();
}
- ReadRequest.Builder requestMsgBuilder = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId);
- tableIds.forEach(tableId -> requestMsgBuilder.addEntities(
- Entity.newBuilder()
- .setTableEntry(
- TableEntry.newBuilder()
- .setTableId(tableId)
- .setIsDefaultAction(defaultEntries)
- .setCounterData(P4RuntimeOuterClass.CounterData.getDefaultInstance())
- .build())
+ final List<Entity> entities = tableIds.stream()
+ .map(tableId -> TableEntry.newBuilder()
+ .setTableId(tableId)
+ .setIsDefaultAction(defaultEntries)
+ .setCounterData(P4RuntimeOuterClass.CounterData.getDefaultInstance())
.build())
- .build());
+ .map(e -> Entity.newBuilder().setTableEntry(e).build())
+ .collect(toList());
- Iterator<ReadResponse> responses;
- try {
- responses = blockingStub.read(requestMsgBuilder.build());
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to dump tables from {}: {}", deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- Iterable<ReadResponse> responseIterable = () -> responses;
- List<TableEntry> tableEntryMsgs = StreamSupport
- .stream(responseIterable.spliterator(), false)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(entity -> entity.getEntityCase() == TABLE_ENTRY)
+ final List<TableEntry> tableEntryMsgs = blockingRead(entities, TABLE_ENTRY)
.map(Entity::getTableEntry)
- .collect(Collectors.toList());
+ .collect(toList());
log.debug("Retrieved {} entries from {} tables on {}...",
tableEntryMsgs.size(), tableIds.size(), deviceId);
@@ -641,61 +630,32 @@
private List<PiCounterCell> doReadCounterEntities(
List<Entity> counterEntities, PiPipeconf pipeconf) {
- if (counterEntities.size() == 0) {
- return Collections.emptyList();
- }
-
- final ReadRequest request = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId)
- .addAllEntities(counterEntities)
- .build();
-
- final Iterable<ReadResponse> responses;
- try {
- responses = () -> blockingStub.read(request);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to read counter cells from {}: {}", deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- List<Entity> entities = StreamSupport.stream(responses.spliterator(), false)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .collect(Collectors.toList());
+ final List<Entity> entities = blockingRead(
+ counterEntities, COUNTER_ENTRY, DIRECT_COUNTER_ENTRY)
+ .collect(toList());
return CounterEntryCodec.decodeCounterEntities(entities, pipeconf);
}
private boolean doWriteActionProfileMembers(List<PiActionProfileMember> members,
WriteOperationType opType, PiPipeconf pipeconf) {
- final List<ActionProfileMember> actionProfileMembers = Lists.newArrayList();
-
- for (PiActionProfileMember member : members) {
- try {
- actionProfileMembers.add(ActionProfileMemberEncoder.encode(member, pipeconf));
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Unable to encode action profile member, aborting {} operation: {} [{}]",
- opType.name(), e.getMessage(), member.toString());
- return false;
- }
+ final List<ActionProfileMember> actionProfileMembers;
+ try {
+ actionProfileMembers = CODECS.actionProfileMember()
+ .encodeAllOrFail(members, pipeconf);
+ } catch (CodecException e) {
+ log.warn("Unable to {} action profile members: {}",
+ opType.name(), e.getMessage());
+ return false;
}
-
final List<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;
- }
-
+ .map(m -> Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileMember(m)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build())
+ .collect(toList());
return write(updateMsgs, members, opType, "action profile member");
}
@@ -705,7 +665,7 @@
final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- log.warn("Unable to get a P4Info browser for pipeconf {}, aborting dump action profile", pipeconf);
+ log.warn(MISSING_P4INFO_BROWSER, pipeconf);
return Collections.emptyList();
}
@@ -721,117 +681,29 @@
return Collections.emptyList();
}
- // Prepare read request to read all groups from the given action profile.
- final ReadRequest groupRequestMsg = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId)
- .addEntities(Entity.newBuilder()
- .setActionProfileGroup(
- ActionProfileGroup.newBuilder()
- .setActionProfileId(actionProfileId)
- .build())
- .build())
+ // Read all groups from the given action profile.
+ final Entity entityToRead = Entity.newBuilder()
+ .setActionProfileGroup(
+ ActionProfileGroup.newBuilder()
+ .setActionProfileId(actionProfileId)
+ .build())
.build();
-
- // Read groups.
- final Iterator<ReadResponse> groupResponses;
- try {
- groupResponses = blockingStub.read(groupRequestMsg);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to dump action profile {} from {}: {}", piActionProfileId, deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- final List<ActionProfileGroup> groupMsgs = Tools.stream(() -> groupResponses)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(entity -> entity.getEntityCase() == ACTION_PROFILE_GROUP)
+ final List<ActionProfileGroup> groupMsgs = blockingRead(entityToRead, ACTION_PROFILE_GROUP)
.map(Entity::getActionProfileGroup)
- .collect(Collectors.toList());
+ .collect(toList());
log.debug("Retrieved {} groups from action profile {} on {}...",
groupMsgs.size(), piActionProfileId.id(), deviceId);
- // Returned groups contain only a minimal description of their members.
- // We need to issue a new request to get the full description of each member.
-
- // Keep a map of all member IDs for each group ID, will need it later.
- final Multimap<Integer, Integer> groupIdToMemberIdsMap = HashMultimap.create();
- groupMsgs.forEach(g -> groupIdToMemberIdsMap.putAll(
- g.getGroupId(),
- g.getMembersList().stream()
- .map(ActionProfileGroup.Member::getMemberId)
- .collect(Collectors.toList())));
-
- // Prepare one big read request to read all members in one shot.
- final Set<Entity> entityMsgs = groupMsgs.stream()
- .flatMap(g -> g.getMembersList().stream())
- .map(ActionProfileGroup.Member::getMemberId)
- // Prevent issuing many read requests for the same member.
- .distinct()
- .map(id -> ActionProfileMember.newBuilder()
- .setActionProfileId(actionProfileId)
- .setMemberId(id)
- .build())
- .map(m -> Entity.newBuilder()
- .setActionProfileMember(m)
- .build())
- .collect(Collectors.toSet());
- final ReadRequest memberRequestMsg = ReadRequest.newBuilder().setDeviceId(p4DeviceId)
- .addAllEntities(entityMsgs)
- .build();
-
- // Read members.
- final Iterator<ReadResponse> memberResponses;
- try {
- memberResponses = blockingStub.read(memberRequestMsg);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to read members of action profile {} from {}: {}",
- piActionProfileId, deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- final Multimap<Integer, ActionProfileMember> groupIdToMembersMap = HashMultimap.create();
- Tools.stream(() -> memberResponses)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
- .map(Entity::getActionProfileMember)
- .forEach(member -> groupIdToMemberIdsMap.asMap()
- // Get all group IDs that contain this member.
- .entrySet()
- .stream()
- .filter(entry -> entry.getValue().contains(member.getMemberId()))
- .map(Map.Entry::getKey)
- .forEach(gid -> groupIdToMembersMap.put(gid, member)));
-
- log.debug("Retrieved {} members from action profile {} on {}...",
- groupIdToMembersMap.size(), piActionProfileId.id(), deviceId);
-
- return groupMsgs.stream()
- .map(groupMsg -> {
- try {
- return ActionProfileGroupEncoder.decode(groupMsg,
- groupIdToMembersMap.get(groupMsg.getGroupId()),
- pipeconf);
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
- log.warn("Unable to decode group: {}\n {}", e.getMessage(), groupMsg);
- return null;
- }
- })
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ return CODECS.actionProfileGroup().decodeAll(groupMsgs, pipeconf);
}
- private List<PiActionProfileMemberId> doDumpActionProfileMemberIds(
+ private List<PiActionProfileMember> doDumpActionProfileMembers(
PiActionProfileId actionProfileId, PiPipeconf pipeconf) {
final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- log.warn("Unable to get a P4Info browser for pipeconf {}, " +
- "aborting cleanup of action profile members",
- pipeconf);
+ log.error(MISSING_P4INFO_BROWSER, pipeconf);
return Collections.emptyList();
}
@@ -843,40 +715,24 @@
.getPreamble()
.getId();
} catch (P4InfoBrowser.NotFoundException e) {
- log.warn("Unable to cleanup action profile members: {}", e.getMessage());
+ log.warn("Unable to dump action profile members: {}", e.getMessage());
return Collections.emptyList();
}
- final ReadRequest memberRequestMsg = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId)
- .addEntities(Entity.newBuilder().setActionProfileMember(
+ Entity entityToRead = Entity.newBuilder()
+ .setActionProfileMember(
ActionProfileMember.newBuilder()
.setActionProfileId(p4ActProfId)
- .build()).build())
+ .build())
.build();
-
- // Read members.
- final Iterator<ReadResponse> memberResponses;
- try {
- memberResponses = blockingStub.read(memberRequestMsg);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to read members of action profile {} from {}: {}",
- actionProfileId, deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- return Tools.stream(() -> memberResponses)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
+ final List<ActionProfileMember> memberMsgs = blockingRead(entityToRead, ACTION_PROFILE_MEMBER)
.map(Entity::getActionProfileMember)
- // Perhaps not needed, but better to double check to avoid
- // removing members of other groups.
- .filter(m -> m.getActionProfileId() == p4ActProfId)
- .map(ActionProfileMember::getMemberId)
- .map(PiActionProfileMemberId::of)
- .collect(Collectors.toList());
+ .collect(toList());
+
+ log.debug("Retrieved {} members from action profile {} on {}...",
+ memberMsgs.size(), actionProfileId.id(), deviceId);
+
+ return CODECS.actionProfileMember().decodeAll(memberMsgs, pipeconf);
}
private List<PiActionProfileMemberId> doRemoveActionProfileMembers(
@@ -890,9 +746,7 @@
final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- log.warn("Unable to get a P4Info browser for pipeconf {}, " +
- "aborting cleanup of action profile members",
- pipeconf);
+ log.error(MISSING_P4INFO_BROWSER, pipeconf);
return Collections.emptyList();
}
@@ -912,7 +766,7 @@
.map(m -> Entity.newBuilder().setActionProfileMember(m).build())
.map(e -> Update.newBuilder().setEntity(e)
.setType(Update.Type.DELETE).build())
- .collect(Collectors.toList());
+ .collect(toList());
log.debug("Removing {} members of action profile '{}'...",
memberIds.size(), actionProfileId);
@@ -923,23 +777,19 @@
}
private boolean doWriteActionProfileGroup(
- PiActionProfileGroup group, WriteOperationType opType, PiPipeconf pipeconf,
- int maxMemberSize) {
- final ActionProfileGroup actionProfileGroup;
- if (opType == P4RuntimeClient.WriteOperationType.INSERT && maxMemberSize < group.members().size()) {
- log.warn("Unable to encode group, since group member larger than maximum member size");
- return false;
- }
+ PiActionProfileGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
+ final ActionProfileGroup groupMsg;
try {
- actionProfileGroup = ActionProfileGroupEncoder.encode(group, pipeconf, maxMemberSize);
- } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
- log.warn("Unable to encode group, aborting {} operation: {}", e.getMessage(), opType.name());
+ groupMsg = CODECS.actionProfileGroup().encode(group, pipeconf);
+ } catch (CodecException e) {
+ log.warn("Unable to encode group, aborting {} operation: {}",
+ opType.name(), e.getMessage());
return false;
}
final Update updateMsg = Update.newBuilder()
.setEntity(Entity.newBuilder()
- .setActionProfileGroup(actionProfileGroup)
+ .setActionProfileGroup(groupMsg)
.build())
.setType(UPDATE_TYPES.get(opType))
.build();
@@ -961,7 +811,7 @@
.map(cellId -> PiMeterCellConfig.builder()
.withMeterCellId(cellId)
.build())
- .collect(Collectors.toList());
+ .collect(toList());
return doReadMeterEntities(MeterEntryCodec.encodePiMeterCellConfigs(
piMeterCellConfigs, pipeconf), pipeconf);
@@ -970,30 +820,9 @@
private List<PiMeterCellConfig> doReadMeterEntities(
List<Entity> entitiesToRead, PiPipeconf pipeconf) {
- if (entitiesToRead.size() == 0) {
- return Collections.emptyList();
- }
-
- final ReadRequest request = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId)
- .addAllEntities(entitiesToRead)
- .build();
-
- final Iterable<ReadResponse> responses;
- try {
- responses = () -> blockingStub.read(request);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to read meter cells: {}", e.getMessage());
- log.debug("exception", e);
- return Collections.emptyList();
- }
-
- List<Entity> responseEntities = StreamSupport
- .stream(responses.spliterator(), false)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .collect(Collectors.toList());
+ final List<Entity> responseEntities = blockingRead(
+ entitiesToRead, METER_ENTRY, DIRECT_METER_ENTRY)
+ .collect(toList());
return MeterEntryCodec.decodeMeterEntities(responseEntities, pipeconf);
}
@@ -1007,7 +836,7 @@
.setEntity(meterEntryMsg)
.setType(UPDATE_TYPES.get(WriteOperationType.MODIFY))
.build())
- .collect(Collectors.toList());
+ .collect(toList());
if (updateMsgs.size() == 0) {
return true;
@@ -1024,7 +853,7 @@
.map(piEntry -> {
try {
return MulticastGroupEntryCodec.encode(piEntry);
- } catch (EncodeException e) {
+ } catch (CodecException e) {
log.warn("Unable to encode PiMulticastGroupEntry: {}", e.getMessage());
return null;
}
@@ -1040,7 +869,7 @@
.setEntity(entityMsg)
.setType(UPDATE_TYPES.get(opType))
.build())
- .collect(Collectors.toList());
+ .collect(toList());
return write(updateMsgs, entries, opType, "multicast group entry");
}
@@ -1055,32 +884,12 @@
.build())
.build();
- final ReadRequest req = ReadRequest.newBuilder()
- .setDeviceId(p4DeviceId)
- .addEntities(entity)
- .build();
-
- Iterator<ReadResponse> responses;
- try {
- responses = blockingStub.read(req);
- } catch (StatusRuntimeException e) {
- checkGrpcException(e);
- log.warn("Unable to read multicast group entries from {}: {}", deviceId, e.getMessage());
- return Collections.emptyList();
- }
-
- Iterable<ReadResponse> responseIterable = () -> responses;
- final List<PiMulticastGroupEntry> mcEntries = StreamSupport
- .stream(responseIterable.spliterator(), false)
- .map(ReadResponse::getEntitiesList)
- .flatMap(List::stream)
- .filter(e -> e.getEntityCase()
- .equals(PACKET_REPLICATION_ENGINE_ENTRY))
+ final List<PiMulticastGroupEntry> mcEntries = blockingRead(entity, PACKET_REPLICATION_ENGINE_ENTRY)
.map(Entity::getPacketReplicationEngineEntry)
.filter(e -> e.getTypeCase().equals(MULTICAST_GROUP_ENTRY))
.map(PacketReplicationEngineEntry::getMulticastGroupEntry)
.map(MulticastGroupEntryCodec::decode)
- .collect(Collectors.toList());
+ .collect(toList());
log.debug("Retrieved {} multicast group entries from {}...",
mcEntries.size(), deviceId);
@@ -1126,6 +935,46 @@
.build();
}
+ private Stream<Entity> blockingRead(Entity entity, Entity.EntityCase entityCase) {
+ return blockingRead(singletonList(entity), entityCase);
+ }
+
+ private Stream<Entity> blockingRead(Iterable<Entity> entities,
+ Entity.EntityCase... entityCases) {
+ // Build read request making sure we are reading what declared.
+ final ReadRequest.Builder reqBuilder = ReadRequest.newBuilder()
+ .setDeviceId(p4DeviceId);
+ final Set<Entity.EntityCase> entityCaseSet = Sets.newHashSet(entityCases);
+ for (Entity e : entities) {
+ checkArgument(entityCaseSet.contains(e.getEntityCase()),
+ "Entity case mismatch");
+ reqBuilder.addEntities(e);
+ }
+ final ReadRequest readRequest = reqBuilder.build();
+ if (readRequest.getEntitiesCount() == 0) {
+ return Stream.empty();
+ }
+ // Issue read.
+ final Iterator<ReadResponse> responseIterator;
+ try {
+ responseIterator = blockingStub.read(readRequest);
+ } catch (StatusRuntimeException e) {
+ checkGrpcException(e);
+ final String caseString = entityCaseSet.stream()
+ .map(Entity.EntityCase::name)
+ .collect(joining("/"));
+ log.warn("Unable to read {} from {}: {}",
+ caseString, deviceId, e.getMessage());
+ log.debug("Exception during read", e);
+ return Stream.empty();
+ }
+ // Filter results.
+ return Tools.stream(() -> responseIterator)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(e -> entityCaseSet.contains(e.getEntityCase()));
+ }
+
protected Void doShutdown() {
streamChannelManager.complete();
return super.doShutdown();
@@ -1195,7 +1044,7 @@
}
})
.filter(Objects::nonNull)
- .collect(Collectors.toList());
+ .collect(toList());
}
private String parseP4Error(P4RuntimeOuterClass.Error err) {
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeCodecs.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeCodecs.java
new file mode 100644
index 0000000..1126fef
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeCodecs.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019-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;
+
+/**
+ * Utility class that provides access to P4Runtime codec instances.
+ */
+final class P4RuntimeCodecs {
+
+ static final P4RuntimeCodecs CODECS = new P4RuntimeCodecs();
+
+ private final ActionProfileMemberCodec actionProfileMember;
+ private final ActionProfileGroupCodec actionProfileGroup;
+
+ private P4RuntimeCodecs() {
+ this.actionProfileMember = new ActionProfileMemberCodec();
+ this.actionProfileGroup = new ActionProfileGroupCodec();
+ }
+
+ ActionProfileMemberCodec actionProfileMember() {
+ return actionProfileMember;
+ }
+
+ ActionProfileGroupCodec actionProfileGroup() {
+ return actionProfileGroup;
+ }
+}
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
index 5dafe2b..604b1f0 100644
--- 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
@@ -31,20 +31,21 @@
}
static void assertSize(String entityDescr, ByteString value, int bitWidth)
- throws EncodeException {
+ throws CodecException {
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()));
+ throw new CodecException(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 {
+ throws CodecException {
if (prefixLength > bitWidth) {
- throw new EncodeException(format(
+ throw new CodecException(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 3294a6d..357e41d 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
@@ -81,16 +81,16 @@
* @param piTableEntries PI table entries
* @param pipeconf PI pipeconf
* @return collection of P4Runtime table entry protobuf messages
- * @throws EncodeException if a PI table entry cannot be encoded
+ * @throws CodecException if a PI table entry cannot be encoded
*/
static List<TableEntry> encode(List<PiTableEntry> piTableEntries,
PiPipeconf pipeconf)
- throws EncodeException {
+ throws CodecException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- throw new EncodeException(format(
+ throw new CodecException(format(
"Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
}
@@ -100,7 +100,7 @@
try {
tableEntryMsgListBuilder.add(encodePiTableEntry(piTableEntry, browser));
} catch (P4InfoBrowser.NotFoundException e) {
- throw new EncodeException(e.getMessage());
+ throw new CodecException(e.getMessage());
}
}
@@ -113,15 +113,15 @@
* @param piTableEntry table entry
* @param pipeconf pipeconf
* @return encoded table entry message
- * @throws EncodeException if entry cannot be encoded
+ * @throws CodecException if entry cannot be encoded
* @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
*/
static TableEntry encode(PiTableEntry piTableEntry, PiPipeconf pipeconf)
- throws EncodeException, P4InfoBrowser.NotFoundException {
+ throws CodecException, P4InfoBrowser.NotFoundException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
+ throw new CodecException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
}
return encodePiTableEntry(piTableEntry, browser);
@@ -152,7 +152,7 @@
for (TableEntry tableEntryMsg : tableEntryMsgs) {
try {
piTableEntryListBuilder.add(decodeTableEntryMsg(tableEntryMsg, browser));
- } catch (P4InfoBrowser.NotFoundException | EncodeException e) {
+ } catch (P4InfoBrowser.NotFoundException | CodecException e) {
log.error("Unable to decode table entry message: {}", e.getMessage());
}
}
@@ -166,15 +166,15 @@
* @param tableEntryMsg table entry message
* @param pipeconf pipeconf
* @return decoded PI table entry
- * @throws EncodeException if message cannot be decoded
+ * @throws CodecException if message cannot be decoded
* @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
*/
static PiTableEntry decode(TableEntry tableEntryMsg, PiPipeconf pipeconf)
- throws EncodeException, P4InfoBrowser.NotFoundException {
+ throws CodecException, P4InfoBrowser.NotFoundException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
if (browser == null) {
- throw new EncodeException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
+ throw new CodecException(format("Unable to get a P4Info browser for pipeconf %s", pipeconf.id()));
}
return decodeTableEntryMsg(tableEntryMsg, browser);
}
@@ -188,11 +188,11 @@
* @param matchKey match key
* @param pipeconf pipeconf
* @return table entry message
- * @throws EncodeException if message cannot be encoded
+ * @throws CodecException if message cannot be encoded
* @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
*/
static TableEntry encode(PiTableId tableId, PiMatchKey matchKey, PiPipeconf pipeconf)
- throws EncodeException, P4InfoBrowser.NotFoundException {
+ throws CodecException, P4InfoBrowser.NotFoundException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
@@ -215,7 +215,7 @@
}
private static TableEntry encodePiTableEntry(PiTableEntry piTableEntry, P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
TableEntry.Builder tableEntryMsgBuilder = TableEntry.newBuilder();
@@ -259,7 +259,7 @@
}
private static PiTableEntry decodeTableEntryMsg(TableEntry tableEntryMsg, P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
PiTableEntry.Builder piTableEntryBuilder = PiTableEntry.builder();
@@ -295,7 +295,7 @@
private static FieldMatch encodePiFieldMatch(PiFieldMatch piFieldMatch, P4InfoOuterClass.Table tableInfo,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
FieldMatch.Builder fieldMatchMsgBuilder = FieldMatch.newBuilder();
@@ -359,7 +359,7 @@
.build())
.build();
default:
- throw new EncodeException(format(
+ throw new CodecException(format(
"Building of match type %s not implemented", piFieldMatch.type()));
}
}
@@ -370,11 +370,11 @@
* @param tableEntryMsg table entry message
* @param pipeconf pipeconf
* @return PI match key
- * @throws EncodeException if message cannot be decoded
+ * @throws CodecException if message cannot be decoded
* @throws P4InfoBrowser.NotFoundException if the required information cannot be find in the pipeconf's P4info
*/
static PiMatchKey decodeMatchKey(TableEntry tableEntryMsg, PiPipeconf pipeconf)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
P4InfoOuterClass.Table tableInfo = browser.tables().getById(tableEntryMsg.getTableId());
if (tableEntryMsg.getMatchCount() == 0) {
@@ -386,7 +386,7 @@
private static PiMatchKey decodeFieldMatchMsgs(List<FieldMatch> fieldMatchs, P4InfoOuterClass.Table tableInfo,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
// Match key for field matches.
PiMatchKey.Builder piMatchKeyBuilder = PiMatchKey.builder();
for (FieldMatch fieldMatchMsg : fieldMatchs) {
@@ -397,7 +397,7 @@
private static PiFieldMatch decodeFieldMatchMsg(FieldMatch fieldMatchMsg, P4InfoOuterClass.Table tableInfo,
P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
int tableId = tableInfo.getPreamble().getId();
String fieldMatchName = browser.matchFields(tableId).getById(fieldMatchMsg.getFieldId()).getName();
@@ -426,13 +426,13 @@
ImmutableByteSequence rangeLowValue = copyFrom(rangeFieldMatch.getLow().asReadOnlyByteBuffer());
return new PiRangeFieldMatch(headerFieldId, rangeLowValue, rangeHighValue);
default:
- throw new EncodeException(format(
+ throw new CodecException(format(
"Decoding of field match type '%s' not implemented", typeCase.name()));
}
}
static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
checkNotNull(piTableAction, "Cannot encode null PiTableAction");
TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
@@ -451,7 +451,7 @@
tableActionMsgBuilder.setActionProfileMemberId(actionProfileMemberId.id());
break;
default:
- throw new EncodeException(
+ throw new CodecException(
format("Building of table action type %s not implemented", piTableAction.type()));
}
@@ -459,7 +459,7 @@
}
static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
switch (typeCase) {
case ACTION:
@@ -470,13 +470,13 @@
case ACTION_PROFILE_MEMBER_ID:
return PiActionProfileMemberId.of(tableActionMsg.getActionProfileMemberId());
default:
- throw new EncodeException(
+ throw new CodecException(
format("Decoding of table action type %s not implemented", typeCase.name()));
}
}
static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
- throws P4InfoBrowser.NotFoundException, EncodeException {
+ throws P4InfoBrowser.NotFoundException, CodecException {
int actionId = browser.actions().getByName(piAction.id().toString()).getPreamble().getId();
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
index b51a2c3..a7f7183 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
@@ -84,15 +84,19 @@
private static final PiActionParamId PORT_PARAM_ID = PiActionParamId.of("port");
private static final int BASE_MEM_ID = 65535;
private static final List<Integer> MEMBER_IDS = ImmutableList.of(65536, 65537, 65538);
- private static final List<PiActionProfileMember> GROUP_MEMBERS =
+ private static final List<PiActionProfileMember> GROUP_MEMBER_INSTANCES =
Lists.newArrayList(
outputMember((short) 1),
outputMember((short) 2),
outputMember((short) 3)
);
+ private static final List<PiActionProfileGroup.WeightedMember> GROUP_WEIGHTED_MEMBERS =
+ GROUP_MEMBER_INSTANCES.stream()
+ .map(m -> new PiActionProfileGroup.WeightedMember(m, DEFAULT_MEMBER_WEIGHT))
+ .collect(Collectors.toList());
private static final PiActionProfileGroup GROUP = PiActionProfileGroup.builder()
.withId(GROUP_ID)
- .addMembers(GROUP_MEMBERS)
+ .addMembers(GROUP_MEMBER_INSTANCES)
.withActionProfileId(ACT_PROF_ID)
.build();
private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
@@ -121,7 +125,6 @@
.forActionProfile(ACT_PROF_ID)
.withAction(piAction)
.withId(PiActionProfileMemberId.of(BASE_MEM_ID + portNum))
- .withWeight(DEFAULT_MEMBER_WEIGHT)
.build();
}
@@ -163,7 +166,7 @@
@Test
public void testInsertPiActionProfileGroup() throws Exception {
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- client.writeActionProfileGroup(GROUP, INSERT, PIPECONF, 3);
+ client.writeActionProfileGroup(GROUP, INSERT, PIPECONF);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
assertEquals(1, result.getDeviceId());
@@ -192,7 +195,7 @@
@Test
public void testInsertPiActionMembers() throws Exception {
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- client.writeActionProfileMembers(GROUP_MEMBERS, INSERT, PIPECONF);
+ client.writeActionProfileMembers(GROUP_MEMBER_INSTANCES, INSERT, PIPECONF);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
assertEquals(1, result.getDeviceId());
@@ -224,15 +227,41 @@
.setGroupId(GROUP_ID.id())
.setActionProfileId(P4_INFO_ACT_PROF_ID);
- List<ActionProfileMember> members = Lists.newArrayList();
-
MEMBER_IDS.forEach(id -> {
ActionProfileGroup.Member member = ActionProfileGroup.Member.newBuilder()
.setMemberId(id)
.setWeight(DEFAULT_MEMBER_WEIGHT)
.build();
group.addMembers(member);
+ });
+ List<ReadResponse> responses = Lists.newArrayList();
+ responses.add(ReadResponse.newBuilder()
+ .addEntities(Entity.newBuilder().setActionProfileGroup(group))
+ .build()
+ );
+
+ p4RuntimeServerImpl.willReturnReadResult(responses);
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
+ CompletableFuture<List<PiActionProfileGroup>> groupsComplete = client.dumpActionProfileGroups(
+ ACT_PROF_ID, PIPECONF);
+ complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+
+ Collection<PiActionProfileGroup> groups = groupsComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+ assertEquals(1, groups.size());
+ PiActionProfileGroup piActionGroup = groups.iterator().next();
+ assertEquals(ACT_PROF_ID, piActionGroup.actionProfile());
+ assertEquals(GROUP_ID, piActionGroup.id());
+ assertEquals(3, piActionGroup.members().size());
+ assertTrue(GROUP_WEIGHTED_MEMBERS.containsAll(piActionGroup.members()));
+ assertTrue(piActionGroup.members().containsAll(GROUP_WEIGHTED_MEMBERS));
+ }
+
+ @Test
+ public void testReadMembers() throws Exception {
+ List<ActionProfileMember> members = Lists.newArrayList();
+
+ MEMBER_IDS.forEach(id -> {
byte outPort = (byte) (id - BASE_MEM_ID);
ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
Action.Param param = Action.Param.newBuilder()
@@ -256,11 +285,6 @@
List<ReadResponse> responses = Lists.newArrayList();
responses.add(ReadResponse.newBuilder()
- .addEntities(Entity.newBuilder().setActionProfileGroup(group))
- .build()
- );
-
- responses.add(ReadResponse.newBuilder()
.addAllEntities(members.stream()
.map(m -> Entity.newBuilder()
.setActionProfileMember(m).build())
@@ -268,18 +292,14 @@
.build());
p4RuntimeServerImpl.willReturnReadResult(responses);
- CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(2);
- CompletableFuture<List<PiActionProfileGroup>> groupsComplete = client.dumpActionProfileGroups(
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
+ CompletableFuture<List<PiActionProfileMember>> membersComplete = client.dumpActionProfileMembers(
ACT_PROF_ID, PIPECONF);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
- Collection<PiActionProfileGroup> groups = groupsComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
- assertEquals(1, groups.size());
- PiActionProfileGroup piActionGroup = groups.iterator().next();
- assertEquals(ACT_PROF_ID, piActionGroup.actionProfileId());
- assertEquals(GROUP_ID, piActionGroup.id());
- assertEquals(3, piActionGroup.members().size());
- assertTrue(GROUP_MEMBERS.containsAll(piActionGroup.members()));
- assertTrue(piActionGroup.members().containsAll(GROUP_MEMBERS));
+ Collection<PiActionProfileMember> piMembers = membersComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+ assertEquals(3, piMembers.size());
+ assertTrue(GROUP_MEMBER_INSTANCES.containsAll(piMembers));
+ assertTrue(piMembers.containsAll(GROUP_MEMBER_INSTANCES));
}
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
index 5417d44..443d407 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
@@ -32,14 +32,17 @@
private final PiActionProfileId id;
private final ImmutableSet<PiTableId> tables;
private final boolean hasSelector;
- private final long maxSize;
+ private final long size;
+ private final int maxGroupSize;
P4ActionProfileModel(PiActionProfileId id,
- ImmutableSet<PiTableId> tables, boolean hasSelector, long maxSize) {
+ ImmutableSet<PiTableId> tables, boolean hasSelector,
+ long size, int maxGroupSize) {
this.id = id;
this.tables = tables;
this.hasSelector = hasSelector;
- this.maxSize = maxSize;
+ this.size = size;
+ this.maxGroupSize = maxGroupSize;
}
@Override
@@ -58,13 +61,18 @@
}
@Override
- public long maxSize() {
- return maxSize;
+ public long size() {
+ return size;
+ }
+
+ @Override
+ public int maxGroupSize() {
+ return maxGroupSize;
}
@Override
public int hashCode() {
- return Objects.hash(id, tables, hasSelector, maxSize);
+ return Objects.hash(id, tables, hasSelector, size, maxGroupSize);
}
@Override
@@ -79,6 +87,7 @@
return Objects.equals(this.id, other.id)
&& Objects.equals(this.tables, other.tables)
&& Objects.equals(this.hasSelector, other.hasSelector)
- && Objects.equals(this.maxSize, other.maxSize);
+ && Objects.equals(this.size, other.size)
+ && Objects.equals(this.maxGroupSize, other.maxGroupSize);
}
}
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 ff49928..ef8cb36 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
@@ -332,7 +332,8 @@
PiActionProfileId.of(actProfileMsg.getPreamble().getName()),
tableIdSetBuilder.build(),
actProfileMsg.getWithSelector(),
- actProfileMsg.getSize()));
+ actProfileMsg.getSize(),
+ actProfileMsg.getMaxGroupSize()));
}
return actProfileMap;
}
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java
index 3042414..021d341 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java
@@ -21,7 +21,6 @@
import org.onosproject.net.pi.model.PiActionProfileId;
import org.onosproject.net.pi.model.PiTableId;
-
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
/**
@@ -52,17 +51,17 @@
private final PiActionProfileId id2 = PiActionProfileId.of("name2");
private final P4ActionProfileModel metadataModel = new P4ActionProfileModel(id, tables,
- true, 64);
+ true, 64, 10);
private final P4ActionProfileModel sameAsMetadataModel = new P4ActionProfileModel(id, sameAsTables,
- true, 64);
+ true, 64, 10);
private final P4ActionProfileModel metadataModel2 = new P4ActionProfileModel(id, tables2,
- true, 64);
+ true, 64, 10);
private final P4ActionProfileModel metadataModel3 = new P4ActionProfileModel(id2, tables,
- true, 64);
+ true, 64, 10);
private final P4ActionProfileModel metadataModel4 = new P4ActionProfileModel(id, tables,
- false, 64);
+ false, 64, 10);
private final P4ActionProfileModel metadataModel5 = new P4ActionProfileModel(id, tables,
- true, 32);
+ true, 32, 5);
/**
* Checks that the P4ActionProfileModel class is immutable.
@@ -85,4 +84,4 @@
.addEqualityGroup(metadataModel5)
.testEquals();
}
-}
\ No newline at end of file
+}
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 3a803d4..9d696e2 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
@@ -70,6 +70,7 @@
private static final Long DEFAULT_MAX_TABLE_SIZE = 1024L;
private static final Long DEFAULT_MAX_ACTION_PROFILE_SIZE = 64L;
+ private static final int DEFAULT_MAX_GROUP_SIZE = 0;
/**
* Tests parse method.
@@ -205,7 +206,8 @@
ImmutableSet<PiTableId> tableIds = new ImmutableSet.Builder<PiTableId>().add(tableId).build();
PiActionProfileId actionProfileId = PiActionProfileId.of("wcmp_control.wcmp_selector");
PiActionProfileModel wcmpSelector3 = new P4ActionProfileModel(actionProfileId, tableIds,
- true, DEFAULT_MAX_ACTION_PROFILE_SIZE);
+ true, DEFAULT_MAX_ACTION_PROFILE_SIZE,
+ DEFAULT_MAX_GROUP_SIZE);
PiActionProfileModel wcmpSelector = model.actionProfiles(actionProfileId).orElse(null);
PiActionProfileModel wcmpSelector2 = model2.actionProfiles(actionProfileId).orElse(null);
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 da10762..8576e84 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
@@ -75,12 +75,17 @@
private static final long ACTION_MAX_SIZE_1 = 100;
private static final long ACTION_MAX_SIZE_2 = 200;
+ private static final int ACTION_MAX_GROUP_SIZE_1 = 10;
+ private static final int ACTION_MAX_GROUP_SIZE_2 = 20;
+
private static final PiActionProfileModel P4_ACTION_PROFILE_MODEL_1 =
new P4ActionProfileModel(PI_ACTION_PROFILE_ID_1, ACTION_TABLES_1,
- ACTION_HAS_SELECTOR_1, ACTION_MAX_SIZE_1);
+ ACTION_HAS_SELECTOR_1, ACTION_MAX_SIZE_1,
+ ACTION_MAX_GROUP_SIZE_1);
private static final PiActionProfileModel P4_ACTION_PROFILE_MODEL_2 =
new P4ActionProfileModel(PI_ACTION_PROFILE_ID_2, ACTION_TABLES_2,
- ACTION_HAS_SELECTOR_2, ACTION_MAX_SIZE_2);
+ ACTION_HAS_SELECTOR_2, ACTION_MAX_SIZE_2,
+ ACTION_MAX_GROUP_SIZE_2);
/* Counters */
private static final PiCounterId PI_COUNTER_ID_1 = PiCounterId.of("Counter1");
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4TableModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4TableModelTest.java
index 89b10d0..797abe4 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4TableModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4TableModelTest.java
@@ -67,12 +67,17 @@
private static final long ACTION_MAX_SIZE_1 = 100;
private static final long ACTION_MAX_SIZE_2 = 200;
+ private static final int ACTION_MAX_GROUP_SIZE_1 = 10;
+ private static final int ACTION_MAX_GROUP_SIZE_2 = 20;
+
private static final PiActionProfileModel P4_ACTION_PROFILE_MODEL_1 =
new P4ActionProfileModel(PI_ACTION_PROFILE_ID_1, ACTION_TABLES_1,
- ACTION_HAS_SELECTOR_1, ACTION_MAX_SIZE_1);
+ ACTION_HAS_SELECTOR_1, ACTION_MAX_SIZE_1,
+ ACTION_MAX_GROUP_SIZE_1);
private static final PiActionProfileModel P4_ACTION_PROFILE_MODEL_2 =
new P4ActionProfileModel(PI_ACTION_PROFILE_ID_2, ACTION_TABLES_2,
- ACTION_HAS_SELECTOR_2, ACTION_MAX_SIZE_2);
+ ACTION_HAS_SELECTOR_2, ACTION_MAX_SIZE_2,
+ ACTION_MAX_GROUP_SIZE_2);
/* Counters */
private static final PiCounterId PI_COUNTER_ID_1 = PiCounterId.of("Counter1");