blob: bfef3737d58ba481c8f5195b7c397333b2028ded [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.PiActionGroupType;
29import org.onosproject.net.pi.model.PiActionId;
30import org.onosproject.net.pi.model.PiActionParamId;
31import org.onosproject.net.pi.model.PiActionProfileId;
32import org.onosproject.net.pi.model.PiControlMetadataId;
33import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Casconec8e84982017-07-26 15:34:42 -040034import org.onosproject.net.pi.model.PiPipeconf;
Carmelo Casconec8e84982017-07-26 15:34:42 -040035import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone87892e22017-11-13 16:01:29 -080036import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020037import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070038import org.onosproject.net.pi.runtime.PiActionGroup;
39import org.onosproject.net.pi.runtime.PiActionGroupId;
40import org.onosproject.net.pi.runtime.PiActionGroupMember;
41import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020042import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Cascone87892e22017-11-13 16:01:29 -080043import org.onosproject.net.pi.runtime.PiControlMetadata;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020044import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040045import org.onosproject.net.pi.runtime.PiPacketOperation;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020046import org.onosproject.net.pi.runtime.PiTableEntry;
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;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070051import org.onosproject.pipelines.basic.PipeconfLoader;
Yi Tseng82512da2017-08-16 19:46:36 -070052import org.slf4j.Logger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040053import p4.P4RuntimeGrpc;
54import p4.P4RuntimeOuterClass;
Carmelo Casconec8e84982017-07-26 15:34:42 -040055
56import java.net.URL;
Yi Tseng82512da2017-08-16 19:46:36 -070057import java.util.Collection;
58import java.util.concurrent.CompletableFuture;
Carmelo Casconec8e84982017-07-26 15:34:42 -040059import java.util.concurrent.ExecutionException;
60
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070061import static org.onlab.util.ImmutableByteSequence.copyFrom;
62import static org.onlab.util.ImmutableByteSequence.fit;
63import static org.onlab.util.ImmutableByteSequence.ofZeros;
Carmelo Cascone87892e22017-11-13 16:01:29 -080064import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040065import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
Yi Tseng82512da2017-08-16 19:46:36 -070066import static org.slf4j.LoggerFactory.getLogger;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040067import static p4.P4RuntimeOuterClass.ActionProfileGroup.Type.SELECT;
68import static p4.P4RuntimeOuterClass.Update.Type.INSERT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040069
70/**
71 * Class used for quick testing of P4Runtime with real devices. To be removed before release.
72 */
73public class P4RuntimeTest {
Yi Tseng82512da2017-08-16 19:46:36 -070074 private static final Logger log = getLogger(P4RuntimeTest.class);
Carmelo Casconec8e84982017-07-26 15:34:42 -040075
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040076 private static final String GRPC_SERVER_ADDR = "192.168.56.102";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020077 private static final int GRPC_SERVER_PORT = 55044;
78
Carmelo Cascone87892e22017-11-13 16:01:29 -080079 private static final String DOT = ".";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020080 private static final String TABLE_0 = "table0";
81 private static final String SET_EGRESS_PORT = "set_egress_port";
82 private static final String PORT = "port";
83 private static final String ETHERNET = "ethernet";
84 private static final String DST_ADDR = "dstAddr";
85 private static final String SRC_ADDR = "srcAddr";
86 private static final String STANDARD_METADATA = "standard_metadata";
87 private static final String INGRESS_PORT = "ingress_port";
88 private static final String ETHER_TYPE = "etherType";
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040089
Andrea Campanella0288c872017-08-07 18:32:51 +020090
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070091 private final URL p4InfoUrl = this.getClass().getResource("/p4c-out/bmv2/basic.p4info");
92 private final URL jsonUrl = this.getClass().getResource("/p4c-out/bmv2/basic.json");
Carmelo Casconec8e84982017-07-26 15:34:42 -040093
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070094 private final PiPipeconf bmv2DefaultPipeconf = PipeconfLoader.BASIC_PIPECONF;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040095 private final P4RuntimeControllerImpl controller = new P4RuntimeControllerImpl();
96 private final GrpcControllerImpl grpcController = new GrpcControllerImpl();
97 private final DeviceId deviceId = DeviceId.deviceId("dummy:1");
98 private final ManagedChannelBuilder channelBuilder = NettyChannelBuilder
99 .forAddress(GRPC_SERVER_ADDR, GRPC_SERVER_PORT)
100 .usePlaintext(true);
101 private P4RuntimeClientImpl client;
Carmelo Casconec8e84982017-07-26 15:34:42 -0400102
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200103 private final ImmutableByteSequence ethAddr = fit(copyFrom(1), 48);
104 private final ImmutableByteSequence portValue = copyFrom((short) 1);
Carmelo Cascone87892e22017-11-13 16:01:29 -0800105 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + DST_ADDR);
106 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + SRC_ADDR);
107 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
108 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(ETHERNET + DOT + ETHER_TYPE);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200109 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
110 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
111 private final PiTableId tableId = PiTableId.of(TABLE_0);
112
113 private final PiTableEntry piTableEntry = PiTableEntry
114 .builder()
115 .forTable(tableId)
116 .withMatchKey(PiMatchKey.builder()
117 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofZeros(6)))
118 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofZeros(6)))
119 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofZeros(2)))
120 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofZeros(2)))
121 .build())
122 .withAction(PiAction
123 .builder()
124 .withId(outActionId)
125 .withParameter(new PiActionParam(portParamId, portValue))
126 .build())
127 .withPriority(1)
128 .withCookie(2)
129 .build();
130
131 public P4RuntimeTest() throws ImmutableByteSequence.ByteSequenceTrimException {
132 }
133
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400134 @Before
135 public void setUp() throws Exception {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400136 controller.grpcController = grpcController;
137 GrpcControllerImpl.enableMessageLog = true;
138 grpcController.activate();
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400139 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400140
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200141 private void createClient()
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400142 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
143 IllegalAccessException, InstantiationException {
Carmelo Casconec8e84982017-07-26 15:34:42 -0400144
145 assert (controller.createClient(deviceId, 1, channelBuilder));
146
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400147 client = (P4RuntimeClientImpl) controller.getClient(deviceId);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200148 }
149
150 private void setPipelineConfig(PiPipeconf pipeconf, PiPipeconf.ExtensionType extensionType)
151 throws ExecutionException, InterruptedException, PiPipelineInterpreter.PiInterpreterException,
152 IllegalAccessException, InstantiationException {
Carmelo Casconed61fdb32017-10-30 10:09:57 -0700153 // FIXME: setPipelineConfig now takes a byte buffer, not extension type
154 // assert (client.setPipelineConfig(pipeconf, extensionType).get());
Carmelo Casconec8e84982017-07-26 15:34:42 -0400155 assert (client.initStreamChannel().get());
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400156 }
Carmelo Casconec8e84982017-07-26 15:34:42 -0400157
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400158 private void testActionProfile(int actionProfileId) {
159
160 P4RuntimeGrpc.P4RuntimeBlockingStub stub = client.blockingStub();
161
162 P4RuntimeOuterClass.ActionProfileMember profileMemberMsg = P4RuntimeOuterClass.ActionProfileMember.newBuilder()
163 .setActionProfileId(actionProfileId)
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200164 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400165 .setAction(P4RuntimeOuterClass.Action.newBuilder()
166 .setActionId(16793508)
167 .build())
168 .build();
169
170 P4RuntimeOuterClass.ActionProfileGroup groupMsg = P4RuntimeOuterClass.ActionProfileGroup.newBuilder()
171 .setActionProfileId(actionProfileId)
172 .setGroupId(1)
173 .setType(SELECT)
174 .addMembers(P4RuntimeOuterClass.ActionProfileGroup.Member.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200175 .setMemberId(1)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400176 .setWeight(1)
177 .build())
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200178 .setMaxSize(3)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400179 .build();
180
181 P4RuntimeOuterClass.WriteRequest writeRequest = P4RuntimeOuterClass.WriteRequest.newBuilder()
182 .setDeviceId(client.p4DeviceId())
183 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
184 .setType(INSERT)
185 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200186 .setActionProfileGroup(groupMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400187 .build())
188 .build())
189 .addUpdates(P4RuntimeOuterClass.Update.newBuilder()
190 .setType(INSERT)
191 .setEntity(P4RuntimeOuterClass.Entity.newBuilder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200192 .setActionProfileMember(profileMemberMsg)
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400193 .build())
194 .build())
195 .build();
196
197 stub.write(writeRequest);
198 }
199
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200200 private void testPacketOut() throws IllegalAccessException, InstantiationException, ExecutionException,
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400201 InterruptedException, ImmutableByteSequence.ByteSequenceTrimException {
202
203 PiPacketOperation packetOperation = PiPacketOperation.builder()
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200204 .withData(fit(copyFrom(1), 48 + 48 + 16))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400205 .withType(PACKET_OUT)
Carmelo Cascone87892e22017-11-13 16:01:29 -0800206 .withMetadata(PiControlMetadata.builder()
207 .withId(PiControlMetadataId.of("egress_port"))
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200208 .withValue(fit(copyFrom(255), 9))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400209 .build())
210 .build();
211
212 assert (client.packetOut(packetOperation, bmv2DefaultPipeconf).get());
Carmelo Casconea966c342017-07-30 01:56:30 -0400213
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200214 Thread.sleep(5000);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400215 }
216
217 private void testDumpTable(String tableName, PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
218 assert (client.dumpTable(PiTableId.of(tableName), pipeconf).get().size() == 0);
219 }
220
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200221 private void testAddEntry(PiPipeconf pipeconf) throws ExecutionException, InterruptedException {
222 assert (client.writeTableEntries(Lists.newArrayList(piTableEntry), P4RuntimeClient.WriteOperationType.INSERT,
223 pipeconf).get());
224 }
225
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400226 @Test
227 @Ignore
228 public void testBmv2() throws Exception {
229
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200230 createClient();
231 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
232 testPacketOut();
233
234 // testPacketOut();
235
236 // testActionProfile(285261835);
237 }
238
239 @Test
240 @Ignore
241 public void testBmv2AddEntry() throws Exception {
242 createClient();
243 testAddEntry(bmv2DefaultPipeconf);
244 testDumpTable(TABLE_0, bmv2DefaultPipeconf);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400245 }
246
247 @Test
248 @Ignore
Yi Tseng82512da2017-08-16 19:46:36 -0700249 public void testBmv2ActionProfile() throws Exception {
250 createClient();
251 setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
252 PiActionProfileId actionProfileId = PiActionProfileId.of("ecmp_selector");
253 PiActionGroupId groupId = PiActionGroupId.of(1);
254
255 Collection<PiActionGroupMember> members = Lists.newArrayList();
256
257 for (int port = 1; port <= 4; port++) {
258 PiAction memberAction = PiAction.builder()
259 .withId(PiActionId.of(SET_EGRESS_PORT))
260 .withParameter(new PiActionParam(PiActionParamId.of(PORT),
261 ImmutableByteSequence.copyFrom((short) port)))
262 .build();
263 PiActionGroupMemberId memberId = PiActionGroupMemberId.of(port);
264 PiActionGroupMember member = PiActionGroupMember.builder()
265 .withId(memberId)
266 .withAction(memberAction)
267 .withWeight(port)
268 .build();
269 members.add(member);
270 }
271 PiActionGroup actionGroup = PiActionGroup.builder()
Carmelo Cascone87892e22017-11-13 16:01:29 -0800272 .withType(PiActionGroupType.SELECT)
Yi Tseng82512da2017-08-16 19:46:36 -0700273 .withActionProfileId(actionProfileId)
274 .withId(groupId)
275 .addMembers(members)
276 .build();
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200277 CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup,
Yi Tseng82512da2017-08-16 19:46:36 -0700278 P4RuntimeClient.WriteOperationType.INSERT,
279 bmv2DefaultPipeconf);
280 assert (success.get());
281
282 success = client.writeActionGroup(actionGroup, P4RuntimeClient.WriteOperationType.INSERT, bmv2DefaultPipeconf);
283 assert (success.get());
284
285 CompletableFuture<Collection<PiActionGroup>> piGroups = client.dumpGroups(actionProfileId, bmv2DefaultPipeconf);
286
287 log.info("Number of groups: {}", piGroups.get().size());
288 piGroups.get().forEach(piGroup -> {
289 log.info("Group {}", piGroup);
290 log.info("------");
291 piGroup.members().forEach(piMem -> {
292 log.info(" {}", piMem);
293 });
294 });
295 }
296
297 @Test
298 @Ignore
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400299 public void testTofino() throws Exception {
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200300 createClient();
301 setPipelineConfig(bmv2DefaultPipeconf, null);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400302 }
303
304// OLD STUFF
Carmelo Casconec8e84982017-07-26 15:34:42 -0400305// log.info("++++++++++++++++++++++++++++");
306//
307// PiPipelineInterpreter interpreter = (PiPipelineInterpreter) defaultPipeconf
308// .implementation(PiPipelineInterpreter.class)
309// .orElse(null)
310// .newInstance();
311//
312// TrafficTreatment t = DefaultTrafficTreatment.builder()
313// .setOutput(PortNumber.portNumber(830L)).build();
314// byte[] payload = new byte[1000];
315//// payload[0] = 1;
316// Arrays.fill( payload, (byte) 1 );
317//
318// OutboundPacket packet = new DefaultOutboundPacket(
319// deviceId, t, ByteBuffer.wrap(payload));
320//
321//
322// Collection<PiPacketOperation> operations = interpreter.mapOutboundPacket(packet,defaultPipeconf);
323// log.info("{}", operations);
324// operations.forEach(piPacketOperation -> {
325// try {
326// client.packetOut(piPacketOperation, defaultPipeconf).get();
327// } catch (InterruptedException | ExecutionException e) {
328// log.error("{}",e);
329// }
330// });
331
332// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 0);
333
334// assert(client.writeTableEntries(Lists.newArrayList(piTableEntry), INSERT, defaultPipeconf).get());
335
336// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 1);
Carmelo Casconec8e84982017-07-26 15:34:42 -0400337}