blob: 1e980e3dda908010d572e2f0bd188cbec2296121 [file] [log] [blame]
Carmelo Casconec8e84982017-07-26 15:34:42 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Casconec8e84982017-07-26 15:34:42 -04003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.p4runtime.test;
18
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020019import com.google.common.collect.Lists;
Carmelo Casconec8e84982017-07-26 15:34:42 -040020import io.grpc.ManagedChannelBuilder;
21import io.grpc.netty.NettyChannelBuilder;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040022import org.junit.Before;
Carmelo Casconec8e84982017-07-26 15:34:42 -040023import org.junit.Ignore;
24import org.junit.Test;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040025import org.onlab.util.ImmutableByteSequence;
Carmelo Casconec8e84982017-07-26 15:34:42 -040026import org.onosproject.grpc.ctl.GrpcControllerImpl;
27import org.onosproject.net.DeviceId;
Carmelo Cascone87892e22017-11-13 16:01:29 -080028import org.onosproject.net.pi.model.PiActionId;
29import org.onosproject.net.pi.model.PiActionParamId;
30import org.onosproject.net.pi.model.PiActionProfileId;
31import org.onosproject.net.pi.model.PiControlMetadataId;
32import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Casconec8e84982017-07-26 15:34:42 -040033import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Casconec8e84982017-07-26 15:34:42 -040034import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone87892e22017-11-13 16:01:29 -080035import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020036import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070037import org.onosproject.net.pi.runtime.PiActionGroup;
38import org.onosproject.net.pi.runtime.PiActionGroupId;
39import org.onosproject.net.pi.runtime.PiActionGroupMember;
40import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020041import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone87892e22017-11-13 16:01:29 -080042import org.onosproject.net.pi.runtime.PiControlMetadata;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020043import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040044import org.onosproject.net.pi.runtime.PiPacketOperation;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020045import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020046import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
47import org.onosproject.p4runtime.api.P4RuntimeClient;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040048import org.onosproject.p4runtime.ctl.P4RuntimeClientImpl;
Carmelo Casconec8e84982017-07-26 15:34:42 -040049import org.onosproject.p4runtime.ctl.P4RuntimeControllerImpl;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070050import org.onosproject.pipelines.basic.PipeconfLoader;
Yi Tseng82512da2017-08-16 19:46:36 -070051import org.slf4j.Logger;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020052import p4.v1.P4RuntimeGrpc;
53import p4.v1.P4RuntimeOuterClass;
Carmelo Casconec8e84982017-07-26 15:34:42 -040054
55import java.net.URL;
Yi Tseng82512da2017-08-16 19:46:36 -070056import java.util.Collection;
57import java.util.concurrent.CompletableFuture;
Carmelo Casconec8e84982017-07-26 15:34:42 -040058import java.util.concurrent.ExecutionException;
59
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070060import static org.onlab.util.ImmutableByteSequence.copyFrom;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070061import static org.onlab.util.ImmutableByteSequence.ofZeros;
Carmelo Cascone87892e22017-11-13 16:01:29 -080062import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040063import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
Yi Tseng82512da2017-08-16 19:46:36 -070064import static org.slf4j.LoggerFactory.getLogger;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020065import static p4.v1.P4RuntimeOuterClass.Update.Type.INSERT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040066
67/**
68 * Class used for quick testing of P4Runtime with real devices. To be removed before release.
69 */
70public class P4RuntimeTest {
Yi Tseng82512da2017-08-16 19:46:36 -070071 private static final Logger log = getLogger(P4RuntimeTest.class);
Carmelo Casconec8e84982017-07-26 15:34:42 -040072
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040073 private static final String GRPC_SERVER_ADDR = "192.168.56.102";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020074 private static final int GRPC_SERVER_PORT = 55044;
75
Carmelo Cascone87892e22017-11-13 16:01:29 -080076 private static final String DOT = ".";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020077 private static final String TABLE_0 = "table0";
78 private static final String SET_EGRESS_PORT = "set_egress_port";
79 private static final String PORT = "port";
80 private static final String ETHERNET = "ethernet";
81 private static final String DST_ADDR = "dstAddr";
82 private static final String SRC_ADDR = "srcAddr";
83 private static final String STANDARD_METADATA = "standard_metadata";
84 private static final String INGRESS_PORT = "ingress_port";
85 private static final String ETHER_TYPE = "etherType";
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040086
Andrea Campanella0288c872017-08-07 18:32:51 +020087
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070088 private final URL p4InfoUrl = this.getClass().getResource("/p4c-out/bmv2/basic.p4info");
89 private final URL jsonUrl = this.getClass().getResource("/p4c-out/bmv2/basic.json");
Carmelo Casconec8e84982017-07-26 15:34:42 -040090
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070091 private final PiPipeconf bmv2DefaultPipeconf = PipeconfLoader.BASIC_PIPECONF;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040092 private final P4RuntimeControllerImpl controller = new P4RuntimeControllerImpl();
93 private final GrpcControllerImpl grpcController = new GrpcControllerImpl();
94 private final DeviceId deviceId = DeviceId.deviceId("dummy:1");
95 private final ManagedChannelBuilder channelBuilder = NettyChannelBuilder
96 .forAddress(GRPC_SERVER_ADDR, GRPC_SERVER_PORT)
97 .usePlaintext(true);
98 private P4RuntimeClientImpl client;
Carmelo Casconec8e84982017-07-26 15:34:42 -040099
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700100 private final ImmutableByteSequence ethAddr = copyFrom(1).fit(48);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200101 private final ImmutableByteSequence portValue = copyFrom((short) 1);
Carmelo Cascone87892e22017-11-13 16:01:29 -0800102 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + DST_ADDR);
103 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + SRC_ADDR);
104 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
105 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(ETHERNET + DOT + ETHER_TYPE);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200106 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
107 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
108 private final PiTableId tableId = PiTableId.of(TABLE_0);
109
110 private final PiTableEntry piTableEntry = PiTableEntry
111 .builder()
112 .forTable(tableId)
113 .withMatchKey(PiMatchKey.builder()
114 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofZeros(6)))
115 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofZeros(6)))
116 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofZeros(2)))
117 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofZeros(2)))
118 .build())
119 .withAction(PiAction
120 .builder()
121 .withId(outActionId)
122 .withParameter(new PiActionParam(portParamId, portValue))
123 .build())
124 .withPriority(1)
125 .withCookie(2)
126 .build();
127
128 public P4RuntimeTest() throws ImmutableByteSequence.ByteSequenceTrimException {
129 }
130
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400131 @Before
132 public void setUp() throws Exception {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400133 controller.grpcController = grpcController;
134 GrpcControllerImpl.enableMessageLog = true;
135 grpcController.activate();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400136 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400137
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200138 private void createClient()
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400139 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
140 IllegalAccessException, InstantiationException {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400141
142 assert (controller.createClient(deviceId, 1, channelBuilder));
143
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400144 client = (P4RuntimeClientImpl) controller.getClient(deviceId);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200145 }
146
147 private void setPipelineConfig(PiPipeconf pipeconf, PiPipeconf.ExtensionType extensionType)
148 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
149 IllegalAccessException, InstantiationException {
Carmelo Casconed61fdb32017-10-30 10:09:57 -0700150 // FIXME: setPipelineConfig now takes a byte buffer, not extension type
151 // assert (client.setPipelineConfig(pipeconf, extensionType).get());
Carmelo Casconec8e84982017-07-26 15:34:42 -0400152 assert (client.initStreamChannel().get());
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400153 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400154
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400155 private void testActionProfile(int actionProfileId) {
156
157 P4RuntimeGrpc.P4RuntimeBlockingStub stub = client.blockingStub();
158
159 P4RuntimeOuterClass.ActionProfileMember profileMemberMsg = P4RuntimeOuterClass.ActionProfileMember.newBuilder()
160 .setActionProfileId(actionProfileId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200161 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400162 .setAction(P4RuntimeOuterClass.Action.newBuilder()
163 .setActionId(16793508)
164 .build())
165 .build();
166
167 P4RuntimeOuterClass.ActionProfileGroup groupMsg = P4RuntimeOuterClass.ActionProfileGroup.newBuilder()
168 .setActionProfileId(actionProfileId)
169 .setGroupId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400170 .addMembers(P4RuntimeOuterClass.ActionProfileGroup.Member.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200171 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400172 .setWeight(1)
173 .build())
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200174 .setMaxSize(3)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400175 .build();
176
177 P4RuntimeOuterClass.WriteRequest writeRequest = P4RuntimeOuterClass.WriteRequest.newBuilder()
178 .setDeviceId(client.p4DeviceId())
179 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
180 .setType(INSERT)
181 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200182 .setActionProfileGroup(groupMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400183 .build())
184 .build())
185 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
186 .setType(INSERT)
187 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200188 .setActionProfileMember(profileMemberMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400189 .build())
190 .build())
191 .build();
192
193 stub.write(writeRequest);
194 }
195
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200196 private void testPacketOut() throws IllegalAccessException, InstantiationException, ExecutionException,
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400197 InterruptedException, ImmutableByteSequence.ByteSequenceTrimException {
198
199 PiPacketOperation packetOperation = PiPacketOperation.builder()
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700200 .withData(copyFrom(1).fit(48 + 48 + 16))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400201 .withType(PACKET_OUT)
Carmelo Cascone87892e22017-11-13 16:01:29 -0800202 .withMetadata(PiControlMetadata.builder()
203 .withId(PiControlMetadataId.of("egress_port"))
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700204 .withValue(copyFrom(255).fit(9))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400205 .build())
206 .build();
207
208 assert (client.packetOut(packetOperation, bmv2DefaultPipeconf).get());
Carmelo Casconea966c342017-07-30 01:56:30 -0400209
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200210 Thread.sleep(5000);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400211 }
212
213 private void testDumpTable(String tableName, PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
214 assert (client.dumpTable(PiTableId.of(tableName), pipeconf).get().size() == 0);
215 }
216
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200217 private void testAddEntry(PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
218 assert (client.writeTableEntries(Lists.newArrayList(piTableEntry), P4RuntimeClient.WriteOperationType.INSERT,
219 pipeconf).get());
220 }
221
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400222 @Test
223 @Ignore
224 public void testBmv2() throws Exception {
225
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200226 createClient();
227 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
228 testPacketOut();
229
230 // testPacketOut();
231
232 // testActionProfile(285261835);
233 }
234
235 @Test
236 @Ignore
237 public void testBmv2AddEntry() throws Exception {
238 createClient();
239 testAddEntry(bmv2DefaultPipeconf);
240 testDumpTable(TABLE_0, bmv2DefaultPipeconf);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400241 }
242
243 @Test
244 @Ignore
Yi Tseng82512da2017-08-16 19:46:36 -0700245 public void testBmv2ActionProfile() throws Exception {
246 createClient();
247 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
248 PiActionProfileId actionProfileId = PiActionProfileId.of("ecmp_selector");
249 PiActionGroupId groupId = PiActionGroupId.of(1);
250
251 Collection<PiActionGroupMember> members = Lists.newArrayList();
252
253 for (int port = 1; port <= 4; port++) {
254 PiAction memberAction = PiAction.builder()
255 .withId(PiActionId.of(SET_EGRESS_PORT))
256 .withParameter(new PiActionParam(PiActionParamId.of(PORT),
257 ImmutableByteSequence.copyFrom((short) port)))
258 .build();
259 PiActionGroupMemberId memberId = PiActionGroupMemberId.of(port);
260 PiActionGroupMember member = PiActionGroupMember.builder()
261 .withId(memberId)
262 .withAction(memberAction)
263 .withWeight(port)
264 .build();
265 members.add(member);
266 }
267 PiActionGroup actionGroup = PiActionGroup.builder()
Yi Tseng82512da2017-08-16 19:46:36 -0700268 .withActionProfileId(actionProfileId)
269 .withId(groupId)
270 .addMembers(members)
271 .build();
Yi Tseng8d355132018-04-13 01:40:48 +0800272 CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup.actionProfileId(),
273 actionGroup.members(),
Yi Tseng82512da2017-08-16 19:46:36 -0700274 P4RuntimeClient.WriteOperationType.INSERT,
275 bmv2DefaultPipeconf);
276 assert (success.get());
277
278 success = client.writeActionGroup(actionGroup, P4RuntimeClient.WriteOperationType.INSERT, bmv2DefaultPipeconf);
279 assert (success.get());
280
281 CompletableFuture<Collection<PiActionGroup>> piGroups = client.dumpGroups(actionProfileId, bmv2DefaultPipeconf);
282
283 log.info("Number of groups: {}", piGroups.get().size());
284 piGroups.get().forEach(piGroup -> {
285 log.info("Group {}", piGroup);
286 log.info("------");
287 piGroup.members().forEach(piMem -> {
288 log.info(" {}", piMem);
289 });
290 });
291 }
292
293 @Test
294 @Ignore
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400295 public void testTofino() throws Exception {
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200296 createClient();
297 setPipelineConfig(bmv2DefaultPipeconf, null);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400298 }
299
300// OLD STUFF
Carmelo Casconec8e84982017-07-26 15:34:42 -0400301// log.info("++++++++++++++++++++++++++++");
302//
303// PiPipelineInterpreter interpreter = (PiPipelineInterpreter) defaultPipeconf
304// .implementation(PiPipelineInterpreter.class)
305// .orElse(null)
306// .newInstance();
307//
308// TrafficTreatment t = DefaultTrafficTreatment.builder()
309// .setOutput(PortNumber.portNumber(830L)).build();
310// byte[] payload = new byte[1000];
311//// payload[0] = 1;
312// Arrays.fill( payload, (byte) 1 );
313//
314// OutboundPacket packet = new DefaultOutboundPacket(
315// deviceId, t, ByteBuffer.wrap(payload));
316//
317//
318// Collection<PiPacketOperation> operations = interpreter.mapOutboundPacket(packet,defaultPipeconf);
319// log.info("{}", operations);
320// operations.forEach(piPacketOperation -> {
321// try {
322// client.packetOut(piPacketOperation, defaultPipeconf).get();
323// } catch (InterruptedException | ExecutionException e) {
324// log.error("{}",e);
325// }
326// });
327
328// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 0);
329
330// assert(client.writeTableEntries(Lists.newArrayList(piTableEntry), INSERT, defaultPipeconf).get());
331
332// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 1);
Carmelo Casconec8e84982017-07-26 15:34:42 -0400333}