blob: 9e7e9f8c35c19da02229dcc8da3f9ddd6df7cb86 [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.bmv2.model.Bmv2PipelineModelParser;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040027import org.onosproject.drivers.bmv2.Bmv2DefaultInterpreter;
Carmelo Casconec8e84982017-07-26 15:34:42 -040028import org.onosproject.grpc.ctl.GrpcControllerImpl;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.pi.model.DefaultPiPipeconf;
31import org.onosproject.net.pi.model.PiPipeconf;
32import org.onosproject.net.pi.model.PiPipeconfId;
33import org.onosproject.net.pi.model.PiPipelineInterpreter;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020034import org.onosproject.net.pi.runtime.PiAction;
35import org.onosproject.net.pi.runtime.PiActionId;
36import org.onosproject.net.pi.runtime.PiActionParam;
37import org.onosproject.net.pi.runtime.PiActionParamId;
38import org.onosproject.net.pi.runtime.PiHeaderFieldId;
39import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040040import org.onosproject.net.pi.runtime.PiPacketMetadata;
41import org.onosproject.net.pi.runtime.PiPacketMetadataId;
42import org.onosproject.net.pi.runtime.PiPacketOperation;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020043import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040044import org.onosproject.net.pi.runtime.PiTableId;
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020045import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
46import org.onosproject.p4runtime.api.P4RuntimeClient;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040047import org.onosproject.p4runtime.ctl.P4RuntimeClientImpl;
Carmelo Casconec8e84982017-07-26 15:34:42 -040048import org.onosproject.p4runtime.ctl.P4RuntimeControllerImpl;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040049import p4.P4RuntimeGrpc;
50import p4.P4RuntimeOuterClass;
Carmelo Casconec8e84982017-07-26 15:34:42 -040051
52import java.net.URL;
53import java.util.concurrent.ExecutionException;
54
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020055import static org.onlab.util.ImmutableByteSequence.*;
Carmelo Casconec8e84982017-07-26 15:34:42 -040056import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
57import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040058import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
59import static p4.P4RuntimeOuterClass.ActionProfileGroup.Type.SELECT;
60import static p4.P4RuntimeOuterClass.Update.Type.INSERT;
Carmelo Casconec8e84982017-07-26 15:34:42 -040061
62/**
63 * Class used for quick testing of P4Runtime with real devices. To be removed before release.
64 */
65public class P4RuntimeTest {
66
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040067 private static final String GRPC_SERVER_ADDR = "192.168.56.102";
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020068 private static final int GRPC_SERVER_PORT = 55044;
69
70 private static final String TABLE_0 = "table0";
71 private static final String SET_EGRESS_PORT = "set_egress_port";
72 private static final String PORT = "port";
73 private static final String ETHERNET = "ethernet";
74 private static final String DST_ADDR = "dstAddr";
75 private static final String SRC_ADDR = "srcAddr";
76 private static final String STANDARD_METADATA = "standard_metadata";
77 private static final String INGRESS_PORT = "ingress_port";
78 private static final String ETHER_TYPE = "etherType";
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040079
Andrea Campanella0288c872017-08-07 18:32:51 +020080
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040081 private final URL p4InfoUrl = this.getClass().getResource("/bmv2/default.p4info");
82 private final URL jsonUrl = this.getClass().getResource("/bmv2/default.json");
Carmelo Casconec8e84982017-07-26 15:34:42 -040083
84 private final PiPipeconf bmv2DefaultPipeconf = DefaultPiPipeconf.builder()
Andrea Campanella0288c872017-08-07 18:32:51 +020085 .withId(new PiPipeconfId("mock-p4runtime"))
Carmelo Casconec8e84982017-07-26 15:34:42 -040086 .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -040087 .addBehaviour(PiPipelineInterpreter.class, Bmv2DefaultInterpreter.class)
Carmelo Casconec8e84982017-07-26 15:34:42 -040088 .addExtension(P4_INFO_TEXT, p4InfoUrl)
89 .addExtension(BMV2_JSON, jsonUrl)
90 .build();
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
245 public void testTofino() throws Exception {
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200246 createClient();
247 setPipelineConfig(bmv2DefaultPipeconf, null);
Carmelo Casconeb2e3dba2017-07-27 12:07:09 -0400248 }
249
250// OLD STUFF
Carmelo Casconec8e84982017-07-26 15:34:42 -0400251// log.info("++++++++++++++++++++++++++++");
252//
253// PiPipelineInterpreter interpreter = (PiPipelineInterpreter) defaultPipeconf
254// .implementation(PiPipelineInterpreter.class)
255// .orElse(null)
256// .newInstance();
257//
258// TrafficTreatment t = DefaultTrafficTreatment.builder()
259// .setOutput(PortNumber.portNumber(830L)).build();
260// byte[] payload = new byte[1000];
261//// payload[0] = 1;
262// Arrays.fill( payload, (byte) 1 );
263//
264// OutboundPacket packet = new DefaultOutboundPacket(
265// deviceId, t, ByteBuffer.wrap(payload));
266//
267//
268// Collection<PiPacketOperation> operations = interpreter.mapOutboundPacket(packet,defaultPipeconf);
269// log.info("{}", operations);
270// operations.forEach(piPacketOperation -> {
271// try {
272// client.packetOut(piPacketOperation, defaultPipeconf).get();
273// } catch (InterruptedException | ExecutionException e) {
274// log.error("{}",e);
275// }
276// });
277
278// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 0);
279
280// assert(client.writeTableEntries(Lists.newArrayList(piTableEntry), INSERT, defaultPipeconf).get());
281
282// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 1);
Carmelo Casconec8e84982017-07-26 15:34:42 -0400283}