blob: 45a871601b6c6e5a635ccebf5feda9ebe77f1993 [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 Casconea62ac3d2017-08-30 03:19:00 +020026import org.onosproject.drivers.bmv2.Bmv2DefaultPipeconfFactory;
Carmelo Casconec8e84982017-07-26 15:34:42 -040027import org.onosproject.grpc.ctl.GrpcControllerImpl;
28import org.onosproject.net.DeviceId;
Carmelo Casconec8e84982017-07-26 15:34:42 -040029import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Casconec8e84982017-07-26 15:34:42 -040030import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020031import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070032import org.onosproject.net.pi.runtime.PiActionGroup;
33import org.onosproject.net.pi.runtime.PiActionGroupId;
34import org.onosproject.net.pi.runtime.PiActionGroupMember;
35import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020036import org.onosproject.net.pi.runtime.PiActionId;
37import org.onosproject.net.pi.runtime.PiActionParam;
38import org.onosproject.net.pi.runtime.PiActionParamId;
Yi Tseng82512da2017-08-16 19:46:36 -070039import org.onosproject.net.pi.runtime.PiActionProfileId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020040import org.onosproject.net.pi.runtime.PiHeaderFieldId;
41import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040042import org.onosproject.net.pi.runtime.PiPacketMetadata;
43import org.onosproject.net.pi.runtime.PiPacketMetadataId;
44import org.onosproject.net.pi.runtime.PiPacketOperation;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020045import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040046import org.onosproject.net.pi.runtime.PiTableId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020047import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
48import org.onosproject.p4runtime.api.P4RuntimeClient;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040049import org.onosproject.p4runtime.ctl.P4RuntimeClientImpl;
Carmelo Casconec8e84982017-07-26 15:34:42 -040050import org.onosproject.p4runtime.ctl.P4RuntimeControllerImpl;
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 Cascone2cad9ef2017-08-01 21:52:07 +020060import static org.onlab.util.ImmutableByteSequence.*;
Carmelo Casconec8e84982017-07-26 15:34:42 -040061import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040062import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
Yi Tseng82512da2017-08-16 19:46:36 -070063import static org.slf4j.LoggerFactory.getLogger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040064import static p4.P4RuntimeOuterClass.ActionProfileGroup.Type.SELECT;
65import static p4.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
76 private static final String TABLE_0 = "table0";
77 private static final String SET_EGRESS_PORT = "set_egress_port";
78 private static final String PORT = "port";
79 private static final String ETHERNET = "ethernet";
80 private static final String DST_ADDR = "dstAddr";
81 private static final String SRC_ADDR = "srcAddr";
82 private static final String STANDARD_METADATA = "standard_metadata";
83 private static final String INGRESS_PORT = "ingress_port";
84 private static final String ETHER_TYPE = "etherType";
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040085
Andrea Campanella0288c872017-08-07 18:32:51 +020086
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040087 private final URL p4InfoUrl = this.getClass().getResource("/bmv2/default.p4info");
88 private final URL jsonUrl = this.getClass().getResource("/bmv2/default.json");
Carmelo Casconec8e84982017-07-26 15:34:42 -040089
Carmelo Casconea62ac3d2017-08-30 03:19:00 +020090 private final PiPipeconf bmv2DefaultPipeconf = Bmv2DefaultPipeconfFactory.get();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040091 private final P4RuntimeControllerImpl controller = new P4RuntimeControllerImpl();
92 private final GrpcControllerImpl grpcController = new GrpcControllerImpl();
93 private final DeviceId deviceId = DeviceId.deviceId("dummy:1");
94 private final ManagedChannelBuilder channelBuilder = NettyChannelBuilder
95 .forAddress(GRPC_SERVER_ADDR, GRPC_SERVER_PORT)
96 .usePlaintext(true);
97 private P4RuntimeClientImpl client;
Carmelo Casconec8e84982017-07-26 15:34:42 -040098
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020099 private final ImmutableByteSequence ethAddr = fit(copyFrom(1), 48);
100 private final ImmutableByteSequence portValue = copyFrom((short) 1);
101 private final PiHeaderFieldId ethDstAddrFieldId = PiHeaderFieldId.of(ETHERNET, DST_ADDR);
102 private final PiHeaderFieldId ethSrcAddrFieldId = PiHeaderFieldId.of(ETHERNET, SRC_ADDR);
103 private final PiHeaderFieldId inPortFieldId = PiHeaderFieldId.of(STANDARD_METADATA, INGRESS_PORT);
104 private final PiHeaderFieldId ethTypeFieldId = PiHeaderFieldId.of(ETHERNET, ETHER_TYPE);
105 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
106 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
107 private final PiTableId tableId = PiTableId.of(TABLE_0);
108
109 private final PiTableEntry piTableEntry = PiTableEntry
110 .builder()
111 .forTable(tableId)
112 .withMatchKey(PiMatchKey.builder()
113 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofZeros(6)))
114 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofZeros(6)))
115 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofZeros(2)))
116 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofZeros(2)))
117 .build())
118 .withAction(PiAction
119 .builder()
120 .withId(outActionId)
121 .withParameter(new PiActionParam(portParamId, portValue))
122 .build())
123 .withPriority(1)
124 .withCookie(2)
125 .build();
126
127 public P4RuntimeTest() throws ImmutableByteSequence.ByteSequenceTrimException {
128 }
129
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400130 @Before
131 public void setUp() throws Exception {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400132 controller.grpcController = grpcController;
133 GrpcControllerImpl.enableMessageLog = true;
134 grpcController.activate();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400135 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400136
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200137 private void createClient()
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400138 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
139 IllegalAccessException, InstantiationException {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400140
141 assert (controller.createClient(deviceId, 1, channelBuilder));
142
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400143 client = (P4RuntimeClientImpl) controller.getClient(deviceId);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200144 }
145
146 private void setPipelineConfig(PiPipeconf pipeconf, PiPipeconf.ExtensionType extensionType)
147 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
148 IllegalAccessException, InstantiationException {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400149
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400150 assert (client.setPipelineConfig(pipeconf, extensionType).get());
Carmelo Casconec8e84982017-07-26 15:34:42 -0400151 assert (client.initStreamChannel().get());
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400152 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400153
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400154 private void testActionProfile(int actionProfileId) {
155
156 P4RuntimeGrpc.P4RuntimeBlockingStub stub = client.blockingStub();
157
158 P4RuntimeOuterClass.ActionProfileMember profileMemberMsg = P4RuntimeOuterClass.ActionProfileMember.newBuilder()
159 .setActionProfileId(actionProfileId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200160 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400161 .setAction(P4RuntimeOuterClass.Action.newBuilder()
162 .setActionId(16793508)
163 .build())
164 .build();
165
166 P4RuntimeOuterClass.ActionProfileGroup groupMsg = P4RuntimeOuterClass.ActionProfileGroup.newBuilder()
167 .setActionProfileId(actionProfileId)
168 .setGroupId(1)
169 .setType(SELECT)
170 .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 Cascone2cad9ef2017-08-01 21:52:07 +0200200 .withData(fit(copyFrom(1), 48 + 48 + 16))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400201 .withType(PACKET_OUT)
202 .withMetadata(PiPacketMetadata.builder()
203 .withId(PiPacketMetadataId.of("egress_port"))
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200204 .withValue(fit(copyFrom(255), 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()
268 .withType(PiActionGroup.Type.SELECT)
269 .withActionProfileId(actionProfileId)
270 .withId(groupId)
271 .addMembers(members)
272 .build();
273 CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup, members,
274 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}