blob: 92ad3cac4faac97b08a59d86c4043e2498bf2951 [file] [log] [blame]
Carmelo Cascone8d99b172017-07-18 17:26:31 -04001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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.ctl;
18
19import com.google.common.collect.Lists;
20import com.google.common.testing.EqualsTester;
21import org.junit.Test;
22import org.onlab.util.ImmutableByteSequence;
23import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
24import org.onosproject.net.pi.model.DefaultPiPipeconf;
25import org.onosproject.net.pi.model.PiPipeconf;
26import org.onosproject.net.pi.model.PiPipeconfId;
27import org.onosproject.net.pi.runtime.PiAction;
28import org.onosproject.net.pi.runtime.PiActionId;
29import org.onosproject.net.pi.runtime.PiActionParam;
30import org.onosproject.net.pi.runtime.PiActionParamId;
31import org.onosproject.net.pi.runtime.PiHeaderFieldId;
32import org.onosproject.net.pi.runtime.PiTableEntry;
33import org.onosproject.net.pi.runtime.PiTableId;
34import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020035import org.slf4j.Logger;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040036import p4.P4RuntimeOuterClass.Action;
37import p4.P4RuntimeOuterClass.TableEntry;
38
39import java.net.URL;
40import java.util.Collection;
41import java.util.Random;
42
43import static org.hamcrest.MatcherAssert.assertThat;
44import static org.hamcrest.Matchers.hasSize;
45import static org.hamcrest.Matchers.is;
46import static org.onlab.util.ImmutableByteSequence.copyFrom;
47import static org.onlab.util.ImmutableByteSequence.fit;
48import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
49import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
50import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
51import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020052import static org.slf4j.LoggerFactory.getLogger;
53
54//import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
55//import org.onosproject.drivers.bmv2.Bmv2DefaultInterpreter;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040056
57public class TableEntryEncoderTest {
58
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020059 private final Logger log = getLogger(getClass());
60
Carmelo Cascone8d99b172017-07-18 17:26:31 -040061 private static final String TABLE_0 = "table0";
62 private static final String SET_EGRESS_PORT = "set_egress_port";
63 private static final String PORT = "port";
64 private static final String ETHERNET = "ethernet";
65 private static final String DST_ADDR = "dstAddr";
66 private static final String SRC_ADDR = "srcAddr";
67 private static final String STANDARD_METADATA = "standard_metadata";
68 private static final String INGRESS_PORT = "ingress_port";
69 private static final String ETHER_TYPE = "etherType";
70
71 private final Random rand = new Random();
72 private final URL p4InfoUrl = this.getClass().getResource("/default.p4info");
73 private final URL jsonUrl = this.getClass().getResource("/default.json");
74
75 private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
76 .withId(new PiPipeconfId("mock"))
77 .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020078// .addBehaviour(PiPipelineInterpreter.class, Bmv2DefaultInterpreter.class)
Carmelo Cascone8d99b172017-07-18 17:26:31 -040079 .addExtension(P4_INFO_TEXT, p4InfoUrl)
80 .addExtension(BMV2_JSON, jsonUrl)
81 .build();
82
83 private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
84 private final ImmutableByteSequence ethAddr = fit(copyFrom(rand.nextInt()), 48);
85 private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
86 private final PiHeaderFieldId ethDstAddrFieldId = PiHeaderFieldId.of(ETHERNET, DST_ADDR);
87 private final PiHeaderFieldId ethSrcAddrFieldId = PiHeaderFieldId.of(ETHERNET, SRC_ADDR);
88 private final PiHeaderFieldId inPortFieldId = PiHeaderFieldId.of(STANDARD_METADATA, INGRESS_PORT);
89 private final PiHeaderFieldId ethTypeFieldId = PiHeaderFieldId.of(ETHERNET, ETHER_TYPE);
90 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
91 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
92 private final PiTableId tableId = PiTableId.of(TABLE_0);
93
94 private final PiTableEntry piTableEntry = PiTableEntry
95 .builder()
96 .forTable(tableId)
97 .withFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ImmutableByteSequence.ofOnes(6)))
98 .withFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ImmutableByteSequence.ofOnes(6)))
99 .withFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ImmutableByteSequence.ofOnes(2)))
100 .withFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ImmutableByteSequence.ofOnes(2)))
101 .withAction(PiAction
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200102 .builder()
103 .withId(outActionId)
104 .withParameter(new PiActionParam(portParamId, portValue))
105 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400106 .withPriority(1)
107 .withCookie(2)
108 .build();
109
110 public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException {
111 }
112
113 @Test
114 public void testP4InfoBrowser() throws Exception {
115
116 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
117
118 assertThat(browser.tables().hasName(TABLE_0), is(true));
119 assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
120
121 int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
122 int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
123
124 assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + "." + INGRESS_PORT), is(true));
125 assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
126
127 // TODO: improve, assert browsing other entities (counters, meters, etc.)
128 }
129
130 @Test
131 public void testTableEntryEncoder()
132 throws P4InfoBrowser.NotFoundException, ImmutableByteSequence.ByteSequenceTrimException {
133
134 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntry), defaultPipeconf);
135 assertThat(result, hasSize(1));
136
137 TableEntry tableEntryMsg = result.iterator().next();
138
139 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
140 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
141
142 // Test equality for decoded entry.
143 new EqualsTester()
144 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
145 .testEquals();
146
147 // Table ID.
148 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
149 int encodedTableId = tableEntryMsg.getTableId();
150 assertThat(encodedTableId, is(p4InfoTableId));
151
152 // Ternary match.
153 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
154 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
155
156 Action actionMsg = tableEntryMsg.getAction().getAction();
157
158 // Action ID.
159 int p4InfoActionId = browser.actions().getByName(outActionId.name()).getPreamble().getId();
160 int encodedActionId = actionMsg.getActionId();
161 assertThat(encodedActionId, is(p4InfoActionId));
162
163 // Action param ID.
164 int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.name()).getId();
165 int encodedActionParamId = actionMsg.getParams(0).getParamId();
166 assertThat(encodedActionParamId, is(p4InfoActionParamId));
167
168 // Action param value.
169 byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray();
170 assertThat(encodedActionParam, is(portValue.asArray()));
171
172 // TODO: improve, assert other field match types (ternary, LPM)
173 }
174
175// @Test
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200176// public void testRuntime() throws ExecutionException, InterruptedException,
177// PiPipelineInterpreter.PiInterpreterException, IllegalAccessException, InstantiationException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400178//
179// // FIXME: remove me.
180//
181// P4RuntimeControllerImpl controller = new P4RuntimeControllerImpl();
182// GrpcControllerImpl grpcController = new GrpcControllerImpl();
183// controller.grpcController = grpcController;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200184// GrpcControllerImpl.enableMessageLog = true;
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400185// grpcController.activate();
186// DeviceId deviceId = DeviceId.deviceId("dummy:1");
187//
188// ManagedChannelBuilder channelBuilder = NettyChannelBuilder
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200189// .forAddress("192.168.56.102", 59975)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400190// .usePlaintext(true);
191//
192// assert (controller.createClient(deviceId, 1, channelBuilder));
193//
194// P4RuntimeClient client = controller.getClient(deviceId);
195//
196// assert(client.setPipelineConfig(defaultPipeconf, PiPipeconf.ExtensionType.BMV2_JSON).get());
197//
198// assert(client.initStreamChannel().get());
199//
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200200// log.info("++++++++++++++++++++++++++++");
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400201//
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200202// PiPipelineInterpreter interpreter = (PiPipelineInterpreter) defaultPipeconf
203// .implementation(PiPipelineInterpreter.class)
204// .orElse(null)
205// .newInstance();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400206//
Andrea Campanellafc1d34c2017-07-18 17:01:41 +0200207// TrafficTreatment t = DefaultTrafficTreatment.builder()
208// .setOutput(PortNumber.portNumber(830L)).build();
209// byte[] payload = new byte[1000];
210//// payload[0] = 1;
211// Arrays.fill( payload, (byte) 1 );
212//
213// OutboundPacket packet = new DefaultOutboundPacket(
214// deviceId, t, ByteBuffer.wrap(payload));
215//
216//
217// Collection<PiPacketOperation> operations = interpreter.mapOutboundPacket(packet,defaultPipeconf);
218// log.info("{}", operations);
219// operations.forEach(piPacketOperation -> {
220// try {
221// client.packetOut(piPacketOperation, defaultPipeconf).get();
222// } catch (InterruptedException | ExecutionException e) {
223// log.error("{}",e);
224// }
225// });
226//
227//// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 0);
228//
229//// assert(client.writeTableEntries(Lists.newArrayList(piTableEntry), INSERT, defaultPipeconf).get());
230//
231//// assert(client.dumpTable(PiTableId.of(TABLE_0), defaultPipeconf).get().size() == 1);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400232// }
233}