New P4RuntimeClient implementation that supports batching and error reporting
The new client API supports batching and provides detailed response for
write requests (e.g. if entity already exists when inserting), which was
not possible with the old one.
This patch includes:
- New more efficient implementation of P4RuntimeClient (no more locking,
use native gRPC executor, use stub deadlines)
- Ported all codecs to new AbstractCodec-based implementation (needed to
implement codec cache in the future)
- Uses batching in P4RuntimeFlowRuleProgrammable and
P4RuntimeGroupActionProgrammable
- Minor changes to PI framework runtime classes
Change-Id: I3fac42057bb4e1389d761006a32600c786598683
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java
index 99b60c4..e956fd7 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java
@@ -79,6 +79,8 @@
@Override
public void write(WriteRequest request, StreamObserver<WriteResponse> responseObserver) {
writeReqs.add(request);
+ responseObserver.onNext(WriteResponse.getDefaultInstance());
+ responseObserver.onCompleted();
complete();
}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockPipeconfService.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockPipeconfService.java
new file mode 100644
index 0000000..0569761
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockPipeconfService.java
@@ -0,0 +1,66 @@
+/*
+ * 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.DeviceId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.service.PiPipeconfService;
+
+import java.util.Optional;
+
+public class MockPipeconfService implements PiPipeconfService {
+ @Override
+ public void register(PiPipeconf pipeconf) throws IllegalStateException {
+
+ }
+
+ @Override
+ public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
+
+ }
+
+ @Override
+ public Iterable<PiPipeconf> getPipeconfs() {
+ return null;
+ }
+
+ @Override
+ public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<PiPipeconf> getPipeconf(DeviceId deviceId) {
+ return Optional.empty();
+ }
+
+ @Override
+ public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
+
+ }
+
+ @Override
+ public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
+ return null;
+ }
+
+ @Override
+ public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
+ return Optional.empty();
+ }
+}
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 a7f7183..c6a43cb 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
@@ -45,6 +45,8 @@
import org.onosproject.net.pi.runtime.PiActionProfileMember;
import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
import org.onosproject.p4runtime.api.P4RuntimeClientKey;
+import org.onosproject.p4runtime.ctl.client.P4RuntimeClientImpl;
+import org.onosproject.p4runtime.ctl.controller.P4RuntimeControllerImpl;
import p4.v1.P4RuntimeOuterClass.ActionProfileGroup;
import p4.v1.P4RuntimeOuterClass.ActionProfileMember;
import p4.v1.P4RuntimeOuterClass.Entity;
@@ -65,7 +67,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
-import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
import static p4.v1.P4RuntimeOuterClass.Action;
import static p4.v1.P4RuntimeOuterClass.ReadResponse;
@@ -108,7 +109,7 @@
private static final String P4R_IP = "127.0.0.1";
private static final int P4R_PORT = 50010;
- private P4RuntimeClientImpl client;
+ private org.onosproject.p4runtime.ctl.client.P4RuntimeClientImpl client;
private P4RuntimeControllerImpl controller;
private static MockP4RuntimeServer p4RuntimeServerImpl = new MockP4RuntimeServer();
private static Server grpcServer;
@@ -157,16 +158,16 @@
@Before
public void setup() {
- controller = niceMock(P4RuntimeControllerImpl.class);
+ controller = niceMock(org.onosproject.p4runtime.ctl.controller.P4RuntimeControllerImpl.class);
P4RuntimeClientKey clientKey = new P4RuntimeClientKey(DEVICE_ID, P4R_IP, P4R_PORT, P4_DEVICE_ID);
- client = new P4RuntimeClientImpl(clientKey, grpcChannel, controller);
- client.becomeMaster();
+ client = new P4RuntimeClientImpl(clientKey, grpcChannel, controller, new MockPipeconfService());
}
@Test
public void testInsertPiActionProfileGroup() throws Exception {
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- client.writeActionProfileGroup(GROUP, INSERT, PIPECONF);
+ client.write(PIPECONF).insert(GROUP).submitSync();
+ assertTrue(client.write(PIPECONF).insert(GROUP).submitSync().isSuccess());
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
assertEquals(1, result.getDeviceId());
@@ -195,7 +196,8 @@
@Test
public void testInsertPiActionMembers() throws Exception {
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- client.writeActionProfileMembers(GROUP_MEMBER_INSTANCES, INSERT, PIPECONF);
+ assertTrue(client.write(PIPECONF).insert(GROUP_MEMBER_INSTANCES)
+ .submitSync().isSuccess());
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
assertEquals(1, result.getDeviceId());
@@ -243,11 +245,10 @@
p4RuntimeServerImpl.willReturnReadResult(responses);
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- CompletableFuture<List<PiActionProfileGroup>> groupsComplete = client.dumpActionProfileGroups(
- ACT_PROF_ID, PIPECONF);
+ Collection<PiActionProfileGroup> groups = client.read(PIPECONF)
+ .actionProfileGroups(ACT_PROF_ID)
+ .submitSync().all(PiActionProfileGroup.class);
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());
@@ -293,11 +294,10 @@
p4RuntimeServerImpl.willReturnReadResult(responses);
CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
- CompletableFuture<List<PiActionProfileMember>> membersComplete = client.dumpActionProfileMembers(
- ACT_PROF_ID, PIPECONF);
+ Collection<PiActionProfileMember> piMembers = client.read(PIPECONF)
+ .actionProfileMembers(ACT_PROF_ID).submitSync()
+ .all(PiActionProfileMember.class);
complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
-
- 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/ctl/src/test/java/org/onosproject/p4runtime/ctl/PacketInEventTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/PacketInEventTest.java
index 0a1f82e..b73f4b5 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/PacketInEventTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/PacketInEventTest.java
@@ -21,9 +21,10 @@
import org.junit.Test;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.pi.model.PiControlMetadataId;
-import org.onosproject.net.pi.runtime.PiControlMetadata;
+import org.onosproject.net.pi.model.PiPacketMetadataId;
+import org.onosproject.net.pi.runtime.PiPacketMetadata;
import org.onosproject.net.pi.runtime.PiPacketOperation;
+import org.onosproject.p4runtime.ctl.controller.PacketInEvent;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_IN;
@@ -46,9 +47,9 @@
private PiPacketOperation packetOperation2;
private PiPacketOperation nullPacketOperation = null;
- private PacketInEvent packetIn;
- private PacketInEvent sameAsPacketIn;
- private PacketInEvent packetIn2;
+ private org.onosproject.p4runtime.ctl.controller.PacketInEvent packetIn;
+ private org.onosproject.p4runtime.ctl.controller.PacketInEvent sameAsPacketIn;
+ private org.onosproject.p4runtime.ctl.controller.PacketInEvent packetIn2;
private PacketInEvent packetIn3;
/**
@@ -59,29 +60,27 @@
public void setup() throws ImmutableByteSequence.ByteSequenceTrimException {
packetOperation = PiPacketOperation.builder()
- .forDevice(deviceId)
.withData(ImmutableByteSequence.ofOnes(512))
.withType(PACKET_OUT)
- .withMetadata(PiControlMetadata.builder()
- .withId(PiControlMetadataId.of("egress_port"))
+ .withMetadata(PiPacketMetadata.builder()
+ .withId(PiPacketMetadataId.of("egress_port"))
.withValue(copyFrom(DEFAULT_ORIGINAL_VALUE).fit(DEFAULT_BIT_WIDTH))
.build())
.build();
packetOperation2 = PiPacketOperation.builder()
- .forDevice(deviceId2)
.withData(ImmutableByteSequence.ofOnes(512))
.withType(PACKET_IN)
- .withMetadata(PiControlMetadata.builder()
- .withId(PiControlMetadataId.of("ingress_port"))
+ .withMetadata(PiPacketMetadata.builder()
+ .withId(PiPacketMetadataId.of("ingress_port"))
.withValue(copyFrom(DEFAULT_ORIGINAL_VALUE).fit(DEFAULT_BIT_WIDTH))
.build())
.build();
- packetIn = new PacketInEvent(deviceId, packetOperation);
- sameAsPacketIn = new PacketInEvent(sameDeviceId, packetOperation);
- packetIn2 = new PacketInEvent(deviceId2, packetOperation);
- packetIn3 = new PacketInEvent(deviceId, packetOperation2);
+ packetIn = new org.onosproject.p4runtime.ctl.controller.PacketInEvent(deviceId, packetOperation);
+ sameAsPacketIn = new org.onosproject.p4runtime.ctl.controller.PacketInEvent(sameDeviceId, packetOperation);
+ packetIn2 = new org.onosproject.p4runtime.ctl.controller.PacketInEvent(deviceId2, packetOperation);
+ packetIn3 = new org.onosproject.p4runtime.ctl.controller.PacketInEvent(deviceId, packetOperation2);
}
/**
@@ -105,7 +104,7 @@
@Test(expected = NullPointerException.class)
public void testConstructorWithNullDeviceId() {
- new PacketInEvent(nullDeviceId, packetOperation);
+ new org.onosproject.p4runtime.ctl.controller.PacketInEvent(nullDeviceId, packetOperation);
}
/**
@@ -114,7 +113,7 @@
@Test(expected = NullPointerException.class)
public void testConstructorWithNullPacketOperation() {
- new PacketInEvent(deviceId, nullPacketOperation);
+ new org.onosproject.p4runtime.ctl.controller.PacketInEvent(deviceId, nullPacketOperation);
}
/**
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java
similarity index 88%
rename from protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
rename to protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java
index 278e050..0619f6a 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.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.
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package org.onosproject.p4runtime.ctl;
+package org.onosproject.p4runtime.ctl.codec;
-import com.google.common.collect.Lists;
import com.google.common.testing.EqualsTester;
import org.easymock.EasyMock;
import org.junit.Test;
@@ -37,22 +36,20 @@
import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
+import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser;
+import org.onosproject.p4runtime.ctl.utils.PipeconfHelper;
import p4.v1.P4RuntimeOuterClass.Action;
import p4.v1.P4RuntimeOuterClass.CounterData;
import p4.v1.P4RuntimeOuterClass.TableEntry;
import java.net.URL;
-import java.util.Collection;
import java.util.Random;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onlab.util.ImmutableByteSequence.ofOnes;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
-import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
-import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
/**
* Test for P4 runtime table entry encoder.
@@ -169,13 +166,10 @@
@Test
public void testTableEntryEncoder() throws Exception {
- Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntry), defaultPipeconf);
- assertThat(result, hasSize(1));
-
- TableEntry tableEntryMsg = result.iterator().next();
-
- Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
- PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
+ TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
+ piTableEntry, null, defaultPipeconf);
+ PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
+ tableEntryMsg, null, defaultPipeconf);
// Test equality for decoded entry.
new EqualsTester()
@@ -218,13 +212,10 @@
@Test
public void testActopProfileGroup() throws Exception {
- Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithGroupAction), defaultPipeconf);
- assertThat(result, hasSize(1));
-
- TableEntry tableEntryMsg = result.iterator().next();
-
- Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
- PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
+ TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
+ piTableEntryWithGroupAction, null, defaultPipeconf);
+ PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
+ tableEntryMsg, null, defaultPipeconf);
// Test equality for decoded entry.
new EqualsTester()
@@ -247,13 +238,10 @@
@Test
public void testEncodeWithNoAction() throws Exception {
- Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithoutAction), defaultPipeconf);
- assertThat(result, hasSize(1));
-
- TableEntry tableEntryMsg = result.iterator().next();
-
- Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
- PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
+ TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
+ piTableEntryWithoutAction, null, defaultPipeconf);
+ PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
+ tableEntryMsg, null, defaultPipeconf);
// Test equality for decoded entry.
new EqualsTester()