blob: 319afec01fa3975d48a2e9702bf7d639f04638d2 [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 Casconeb2e3dba2017-07-27 12:07:09 -040052import p4.P4RuntimeGrpc;
53import p4.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;
61import static org.onlab.util.ImmutableByteSequence.fit;
62import static org.onlab.util.ImmutableByteSequence.ofZeros;
Carmelo Cascone87892e22017-11-13 16:01:29 -080063import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040064import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
Yi Tseng82512da2017-08-16 19:46:36 -070065import static org.slf4j.LoggerFactory.getLogger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040066import static p4.P4RuntimeOuterClass.Update.Type.INSERT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040067
68/**
69 * Class used for quick testing of P4Runtime with real devices. To be removed before release.
70 */
71public class P4RuntimeTest {
Yi Tseng82512da2017-08-16 19:46:36 -070072 private static final Logger log = getLogger(P4RuntimeTest.class);
Carmelo Casconec8e84982017-07-26 15:34:42 -040073
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040074 private static final String GRPC_SERVER_ADDR = "192.168.56.102";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020075 private static final int GRPC_SERVER_PORT = 55044;
76
Carmelo Cascone87892e22017-11-13 16:01:29 -080077 private static final String DOT = ".";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020078 private static final String TABLE_0 = "table0";
79 private static final String SET_EGRESS_PORT = "set_egress_port";
80 private static final String PORT = "port";
81 private static final String ETHERNET = "ethernet";
82 private static final String DST_ADDR = "dstAddr";
83 private static final String SRC_ADDR = "srcAddr";
84 private static final String STANDARD_METADATA = "standard_metadata";
85 private static final String INGRESS_PORT = "ingress_port";
86 private static final String ETHER_TYPE = "etherType";
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040087
Andrea Campanella0288c872017-08-07 18:32:51 +020088
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070089 private final URL p4InfoUrl = this.getClass().getResource("/p4c-out/bmv2/basic.p4info");
90 private final URL jsonUrl = this.getClass().getResource("/p4c-out/bmv2/basic.json");
Carmelo Casconec8e84982017-07-26 15:34:42 -040091
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070092 private final PiPipeconf bmv2DefaultPipeconf = PipeconfLoader.BASIC_PIPECONF;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040093 private final P4RuntimeControllerImpl controller = new P4RuntimeControllerImpl();
94 private final GrpcControllerImpl grpcController = new GrpcControllerImpl();
95 private final DeviceId deviceId = DeviceId.deviceId("dummy:1");
96 private final ManagedChannelBuilder channelBuilder = NettyChannelBuilder
97 .forAddress(GRPC_SERVER_ADDR, GRPC_SERVER_PORT)
98 .usePlaintext(true);
99 private P4RuntimeClientImpl client;
Carmelo Casconec8e84982017-07-26 15:34:42 -0400100
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200101 private final ImmutableByteSequence ethAddr = fit(copyFrom(1), 48);
102 private final ImmutableByteSequence portValue = copyFrom((short) 1);
Carmelo Cascone87892e22017-11-13 16:01:29 -0800103 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + DST_ADDR);
104 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + SRC_ADDR);
105 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
106 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(ETHERNET + DOT + ETHER_TYPE);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200107 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
108 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
109 private final PiTableId tableId = PiTableId.of(TABLE_0);
110
111 private final PiTableEntry piTableEntry = PiTableEntry
112 .builder()
113 .forTable(tableId)
114 .withMatchKey(PiMatchKey.builder()
115 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofZeros(6)))
116 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofZeros(6)))
117 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofZeros(2)))
118 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofZeros(2)))
119 .build())
120 .withAction(PiAction
121 .builder()
122 .withId(outActionId)
123 .withParameter(new PiActionParam(portParamId, portValue))
124 .build())
125 .withPriority(1)
126 .withCookie(2)
127 .build();
128
129 public P4RuntimeTest() throws ImmutableByteSequence.ByteSequenceTrimException {
130 }
131
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400132 @Before
133 public void setUp() throws Exception {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400134 controller.grpcController = grpcController;
135 GrpcControllerImpl.enableMessageLog = true;
136 grpcController.activate();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400137 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400138
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200139 private void createClient()
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400140 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
141 IllegalAccessException, InstantiationException {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400142
143 assert (controller.createClient(deviceId, 1, channelBuilder));
144
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400145 client = (P4RuntimeClientImpl) controller.getClient(deviceId);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200146 }
147
148 private void setPipelineConfig(PiPipeconf pipeconf, PiPipeconf.ExtensionType extensionType)
149 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
150 IllegalAccessException, InstantiationException {
Carmelo Casconed61fdb32017-10-30 10:09:57 -0700151 // FIXME: setPipelineConfig now takes a byte buffer, not extension type
152 // assert (client.setPipelineConfig(pipeconf, extensionType).get());
Carmelo Casconec8e84982017-07-26 15:34:42 -0400153 assert (client.initStreamChannel().get());
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400154 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400155
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400156 private void testActionProfile(int actionProfileId) {
157
158 P4RuntimeGrpc.P4RuntimeBlockingStub stub = client.blockingStub();
159
160 P4RuntimeOuterClass.ActionProfileMember profileMemberMsg = P4RuntimeOuterClass.ActionProfileMember.newBuilder()
161 .setActionProfileId(actionProfileId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200162 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400163 .setAction(P4RuntimeOuterClass.Action.newBuilder()
164 .setActionId(16793508)
165 .build())
166 .build();
167
168 P4RuntimeOuterClass.ActionProfileGroup groupMsg = P4RuntimeOuterClass.ActionProfileGroup.newBuilder()
169 .setActionProfileId(actionProfileId)
170 .setGroupId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400171 .addMembers(P4RuntimeOuterClass.ActionProfileGroup.Member.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200172 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400173 .setWeight(1)
174 .build())
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200175 .setMaxSize(3)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400176 .build();
177
178 P4RuntimeOuterClass.WriteRequest writeRequest = P4RuntimeOuterClass.WriteRequest.newBuilder()
179 .setDeviceId(client.p4DeviceId())
180 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
181 .setType(INSERT)
182 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200183 .setActionProfileGroup(groupMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400184 .build())
185 .build())
186 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
187 .setType(INSERT)
188 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200189 .setActionProfileMember(profileMemberMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400190 .build())
191 .build())
192 .build();
193
194 stub.write(writeRequest);
195 }
196
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200197 private void testPacketOut() throws IllegalAccessException, InstantiationException, ExecutionException,
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400198 InterruptedException, ImmutableByteSequence.ByteSequenceTrimException {
199
200 PiPacketOperation packetOperation = PiPacketOperation.builder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200201 .withData(fit(copyFrom(1), 48 + 48 + 16))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400202 .withType(PACKET_OUT)
Carmelo Cascone87892e22017-11-13 16:01:29 -0800203 .withMetadata(PiControlMetadata.builder()
204 .withId(PiControlMetadataId.of("egress_port"))
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200205 .withValue(fit(copyFrom(255), 9))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400206 .build())
207 .build();
208
209 assert (client.packetOut(packetOperation, bmv2DefaultPipeconf).get());
Carmelo Casconea966c342017-07-30 01:56:30 -0400210
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200211 Thread.sleep(5000);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400212 }
213
214 private void testDumpTable(String tableName, PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
215 assert (client.dumpTable(PiTableId.of(tableName), pipeconf).get().size() == 0);
216 }
217
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200218 private void testAddEntry(PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
219 assert (client.writeTableEntries(Lists.newArrayList(piTableEntry), P4RuntimeClient.WriteOperationType.INSERT,
220 pipeconf).get());
221 }
222
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400223 @Test
224 @Ignore
225 public void testBmv2() throws Exception {
226
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200227 createClient();
228 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
229 testPacketOut();
230
231 // testPacketOut();
232
233 // testActionProfile(285261835);
234 }
235
236 @Test
237 @Ignore
238 public void testBmv2AddEntry() throws Exception {
239 createClient();
240 testAddEntry(bmv2DefaultPipeconf);
241 testDumpTable(TABLE_0, bmv2DefaultPipeconf);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400242 }
243
244 @Test
245 @Ignore
Yi Tseng82512da2017-08-16 19:46:36 -0700246 public void testBmv2ActionProfile() throws Exception {
247 createClient();
248 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
249 PiActionProfileId actionProfileId = PiActionProfileId.of("ecmp_selector");
250 PiActionGroupId groupId = PiActionGroupId.of(1);
251
252 Collection<PiActionGroupMember> members = Lists.newArrayList();
253
254 for (int port = 1; port <= 4; port++) {
255 PiAction memberAction = PiAction.builder()
256 .withId(PiActionId.of(SET_EGRESS_PORT))
257 .withParameter(new PiActionParam(PiActionParamId.of(PORT),
258 ImmutableByteSequence.copyFrom((short) port)))
259 .build();
260 PiActionGroupMemberId memberId = PiActionGroupMemberId.of(port);
261 PiActionGroupMember member = PiActionGroupMember.builder()
262 .withId(memberId)
263 .withAction(memberAction)
264 .withWeight(port)
265 .build();
266 members.add(member);
267 }
268 PiActionGroup actionGroup = PiActionGroup.builder()
Yi Tseng82512da2017-08-16 19:46:36 -0700269 .withActionProfileId(actionProfileId)
270 .withId(groupId)
271 .addMembers(members)
272 .build();
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200273 CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup,
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}