blob: 7b4c668d94f96c90b577f85279914a0161c48cca [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 Casconec8e84982017-07-26 15:34:42 -040028import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Casconec8e84982017-07-26 15:34:42 -040029import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020030import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070031import org.onosproject.net.pi.runtime.PiActionGroup;
32import org.onosproject.net.pi.runtime.PiActionGroupId;
33import org.onosproject.net.pi.runtime.PiActionGroupMember;
34import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020035import org.onosproject.net.pi.runtime.PiActionId;
36import org.onosproject.net.pi.runtime.PiActionParam;
37import org.onosproject.net.pi.runtime.PiActionParamId;
Yi Tseng82512da2017-08-16 19:46:36 -070038import org.onosproject.net.pi.runtime.PiActionProfileId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020039import org.onosproject.net.pi.runtime.PiHeaderFieldId;
40import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040041import org.onosproject.net.pi.runtime.PiPacketMetadata;
42import org.onosproject.net.pi.runtime.PiPacketMetadataId;
43import org.onosproject.net.pi.runtime.PiPacketOperation;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020044import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040045import org.onosproject.net.pi.runtime.PiTableId;
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 Casconec8e84982017-07-26 15:34:42 -040063import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040064import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
Yi Tseng82512da2017-08-16 19:46:36 -070065import static org.slf4j.LoggerFactory.getLogger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040066import static p4.P4RuntimeOuterClass.ActionProfileGroup.Type.SELECT;
67import static p4.P4RuntimeOuterClass.Update.Type.INSERT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040068
69/**
70 * Class used for quick testing of P4Runtime with real devices. To be removed before release.
71 */
72public class P4RuntimeTest {
Yi Tseng82512da2017-08-16 19:46:36 -070073 private static final Logger log = getLogger(P4RuntimeTest.class);
Carmelo Casconec8e84982017-07-26 15:34:42 -040074
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040075 private static final String GRPC_SERVER_ADDR = "192.168.56.102";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020076 private static final int GRPC_SERVER_PORT = 55044;
77
78 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);
103 private final PiHeaderFieldId ethDstAddrFieldId = PiHeaderFieldId.of(ETHERNET, DST_ADDR);
104 private final PiHeaderFieldId ethSrcAddrFieldId = PiHeaderFieldId.of(ETHERNET, SRC_ADDR);
105 private final PiHeaderFieldId inPortFieldId = PiHeaderFieldId.of(STANDARD_METADATA, INGRESS_PORT);
106 private final PiHeaderFieldId ethTypeFieldId = PiHeaderFieldId.of(ETHERNET, ETHER_TYPE);
107 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)
171 .setType(SELECT)
172 .addMembers(P4RuntimeOuterClass.ActionProfileGroup.Member.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200173 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400174 .setWeight(1)
175 .build())
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200176 .setMaxSize(3)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400177 .build();
178
179 P4RuntimeOuterClass.WriteRequest writeRequest = P4RuntimeOuterClass.WriteRequest.newBuilder()
180 .setDeviceId(client.p4DeviceId())
181 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
182 .setType(INSERT)
183 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200184 .setActionProfileGroup(groupMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400185 .build())
186 .build())
187 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
188 .setType(INSERT)
189 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200190 .setActionProfileMember(profileMemberMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400191 .build())
192 .build())
193 .build();
194
195 stub.write(writeRequest);
196 }
197
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200198 private void testPacketOut() throws IllegalAccessException, InstantiationException, ExecutionException,
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400199 InterruptedException, ImmutableByteSequence.ByteSequenceTrimException {
200
201 PiPacketOperation packetOperation = PiPacketOperation.builder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200202 .withData(fit(copyFrom(1), 48 + 48 + 16))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400203 .withType(PACKET_OUT)
204 .withMetadata(PiPacketMetadata.builder()
205 .withId(PiPacketMetadataId.of("egress_port"))
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200206 .withValue(fit(copyFrom(255), 9))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400207 .build())
208 .build();
209
210 assert (client.packetOut(packetOperation, bmv2DefaultPipeconf).get());
Carmelo Casconea966c342017-07-30 01:56:30 -0400211
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200212 Thread.sleep(5000);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400213 }
214
215 private void testDumpTable(String tableName, PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
216 assert (client.dumpTable(PiTableId.of(tableName), pipeconf).get().size() == 0);
217 }
218
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200219 private void testAddEntry(PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
220 assert (client.writeTableEntries(Lists.newArrayList(piTableEntry), P4RuntimeClient.WriteOperationType.INSERT,
221 pipeconf).get());
222 }
223
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400224 @Test
225 @Ignore
226 public void testBmv2() throws Exception {
227
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200228 createClient();
229 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
230 testPacketOut();
231
232 // testPacketOut();
233
234 // testActionProfile(285261835);
235 }
236
237 @Test
238 @Ignore
239 public void testBmv2AddEntry() throws Exception {
240 createClient();
241 testAddEntry(bmv2DefaultPipeconf);
242 testDumpTable(TABLE_0, bmv2DefaultPipeconf);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400243 }
244
245 @Test
246 @Ignore
Yi Tseng82512da2017-08-16 19:46:36 -0700247 public void testBmv2ActionProfile() throws Exception {
248 createClient();
249 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
250 PiActionProfileId actionProfileId = PiActionProfileId.of("ecmp_selector");
251 PiActionGroupId groupId = PiActionGroupId.of(1);
252
253 Collection<PiActionGroupMember> members = Lists.newArrayList();
254
255 for (int port = 1; port <= 4; port++) {
256 PiAction memberAction = PiAction.builder()
257 .withId(PiActionId.of(SET_EGRESS_PORT))
258 .withParameter(new PiActionParam(PiActionParamId.of(PORT),
259 ImmutableByteSequence.copyFrom((short) port)))
260 .build();
261 PiActionGroupMemberId memberId = PiActionGroupMemberId.of(port);
262 PiActionGroupMember member = PiActionGroupMember.builder()
263 .withId(memberId)
264 .withAction(memberAction)
265 .withWeight(port)
266 .build();
267 members.add(member);
268 }
269 PiActionGroup actionGroup = PiActionGroup.builder()
270 .withType(PiActionGroup.Type.SELECT)
271 .withActionProfileId(actionProfileId)
272 .withId(groupId)
273 .addMembers(members)
274 .build();
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200275 CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup,
Yi Tseng82512da2017-08-16 19:46:36 -0700276 P4RuntimeClient.WriteOperationType.INSERT,
277 bmv2DefaultPipeconf);
278 assert (success.get());
279
280 success = client.writeActionGroup(actionGroup, P4RuntimeClient.WriteOperationType.INSERT, bmv2DefaultPipeconf);
281 assert (success.get());
282
283 CompletableFuture<Collection<PiActionGroup>> piGroups = client.dumpGroups(actionProfileId, bmv2DefaultPipeconf);
284
285 log.info("Number of groups: {}", piGroups.get().size());
286 piGroups.get().forEach(piGroup -> {
287 log.info("Group {}", piGroup);
288 log.info("------");
289 piGroup.members().forEach(piMem -> {
290 log.info(" {}", piMem);
291 });
292 });
293 }
294
295 @Test
296 @Ignore
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400297 public void testTofino() throws Exception {
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200298 createClient();
299 setPipelineConfig(bmv2DefaultPipeconf, null);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400300 }
301
302// OLD STUFF
Carmelo Casconec8e84982017-07-26 15:34:42 -0400303// log.info("++++++++++++++++++++++++++++");
304//
305// PiPipelineInterpreter interpreter = (PiPipelineInterpreter) defaultPipeconf
306// .implementation(PiPipelineInterpreter.class)
307// .orElse(null)
308// .newInstance();
309//
310// TrafficTreatment t = DefaultTrafficTreatment.builder()
311// .setOutput(PortNumber.portNumber(830L)).build();
312// byte[] payload = new byte[1000];
313//// payload[0] = 1;
314// Arrays.fill( payload, (byte) 1 );
315//
316// OutboundPacket packet = new DefaultOutboundPacket(
317// deviceId, t, ByteBuffer.wrap(payload));
318//
319//
320// Collection<PiPacketOperation> operations = interpreter.mapOutboundPacket(packet,defaultPipeconf);
321// log.info("{}", operations);
322// operations.forEach(piPacketOperation -> {
323// try {
324// client.packetOut(piPacketOperation, defaultPipeconf).get();
325// } catch (InterruptedException | ExecutionException e) {
326// log.error("{}",e);
327// }
328// });
329
330// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 0);
331
332// assert(client.writeTableEntries(Lists.newArrayList(piTableEntry), INSERT, defaultPipeconf).get());
333
334// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 1);
Carmelo Casconec8e84982017-07-26 15:34:42 -0400335}