blob: d9e5f9a75f3fdc179e1c89d8a55bc9479cd5df27 [file] [log] [blame]
Carmelo Cascone8d99b172017-07-18 17:26:31 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Carmelo Cascone8d99b172017-07-18 17:26:31 -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.ctl;
18
19import com.google.common.collect.Lists;
20import com.google.common.testing.EqualsTester;
Yi Tseng82512da2017-08-16 19:46:36 -070021import org.easymock.EasyMock;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040022import org.junit.Test;
23import org.onlab.util.ImmutableByteSequence;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040024import org.onosproject.net.pi.model.DefaultPiPipeconf;
Carmelo Cascone87892e22017-11-13 16:01:29 -080025import org.onosproject.net.pi.model.PiActionId;
26import org.onosproject.net.pi.model.PiActionParamId;
27import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040028import org.onosproject.net.pi.model.PiPipeconf;
29import org.onosproject.net.pi.model.PiPipeconfId;
Yi Tseng82512da2017-08-16 19:46:36 -070030import org.onosproject.net.pi.model.PiPipelineModel;
Carmelo Cascone87892e22017-11-13 16:01:29 -080031import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040032import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng95390822018-01-22 17:57:22 -080033import org.onosproject.net.pi.runtime.PiActionGroupId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040034import org.onosproject.net.pi.runtime.PiActionParam;
steven308017632e152018-10-20 00:51:08 +080035import org.onosproject.net.pi.runtime.PiCounterCellData;
Yi Tseng95390822018-01-22 17:57:22 -080036import org.onosproject.net.pi.runtime.PiExactFieldMatch;
Carmelo Cascone0e896a02017-07-31 07:22:27 +020037import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040038import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040039import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020040import p4.v1.P4RuntimeOuterClass.Action;
steven308017632e152018-10-20 00:51:08 +080041import p4.v1.P4RuntimeOuterClass.CounterData;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020042import p4.v1.P4RuntimeOuterClass.TableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040043
44import java.net.URL;
45import java.util.Collection;
46import java.util.Random;
47
48import static org.hamcrest.MatcherAssert.assertThat;
49import static org.hamcrest.Matchers.hasSize;
50import static org.hamcrest.Matchers.is;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070051import static org.onlab.util.ImmutableByteSequence.copyFrom;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070052import static org.onlab.util.ImmutableByteSequence.ofOnes;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040053import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
54import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
55import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020056
Yi Tseng82512da2017-08-16 19:46:36 -070057/**
58 * Test for P4 runtime table entry encoder.
59 */
Carmelo Cascone8d99b172017-07-18 17:26:31 -040060public class TableEntryEncoderTest {
Carmelo Cascone87892e22017-11-13 16:01:29 -080061 private static final String DOT = ".";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040062 private static final String TABLE_0 = "table0";
Yi Tseng95390822018-01-22 17:57:22 -080063 private static final String TABLE_ECMP = "ecmp";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040064 private static final String SET_EGRESS_PORT = "set_egress_port";
65 private static final String PORT = "port";
Carmelo Cascone87892e22017-11-13 16:01:29 -080066 private static final String HDR = "hdr";
Yi Tseng95390822018-01-22 17:57:22 -080067 private static final String META = "meta";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040068 private static final String ETHERNET = "ethernet";
69 private static final String DST_ADDR = "dstAddr";
70 private static final String SRC_ADDR = "srcAddr";
71 private static final String STANDARD_METADATA = "standard_metadata";
Yi Tseng95390822018-01-22 17:57:22 -080072 private static final String ECMP_METADATA = "ecmp_metadata";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040073 private static final String INGRESS_PORT = "ingress_port";
74 private static final String ETHER_TYPE = "etherType";
Yi Tseng95390822018-01-22 17:57:22 -080075 private static final String ECMP_GROUP_ID = "ecmp_group_id";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040076
steven308017632e152018-10-20 00:51:08 +080077 private static final long PACKETS = 10;
78 private static final long BYTES = 100;
79
Carmelo Cascone8d99b172017-07-18 17:26:31 -040080 private final Random rand = new Random();
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070081 private final URL p4InfoUrl = this.getClass().getResource("/test.p4info");
Carmelo Cascone8d99b172017-07-18 17:26:31 -040082
83 private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
84 .withId(new PiPipeconfId("mock"))
Yi Tseng82512da2017-08-16 19:46:36 -070085 .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
Carmelo Cascone8d99b172017-07-18 17:26:31 -040086 .addExtension(P4_INFO_TEXT, p4InfoUrl)
Carmelo Cascone8d99b172017-07-18 17:26:31 -040087 .build();
88
89 private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
Carmelo Cascone8a571af2018-04-06 23:17:04 -070090 private final ImmutableByteSequence ethAddr = copyFrom(rand.nextInt()).fit(48);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040091 private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
Carmelo Cascone87892e22017-11-13 16:01:29 -080092 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + DST_ADDR);
93 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + SRC_ADDR);
94 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
95 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + ETHER_TYPE);
Yi Tseng95390822018-01-22 17:57:22 -080096 private final PiMatchFieldId ecmpGroupFieldId =
97 PiMatchFieldId.of(META + DOT + ECMP_METADATA + DOT + ECMP_GROUP_ID);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040098 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
99 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
100 private final PiTableId tableId = PiTableId.of(TABLE_0);
Yi Tseng95390822018-01-22 17:57:22 -0800101 private final PiTableId ecmpTableId = PiTableId.of(TABLE_ECMP);
steven308017632e152018-10-20 00:51:08 +0800102 private final PiCounterCellData counterCellData = new PiCounterCellData(PACKETS, BYTES);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400103
104 private final PiTableEntry piTableEntry = PiTableEntry
105 .builder()
106 .forTable(tableId)
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200107 .withMatchKey(PiMatchKey.builder()
108 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
109 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
110 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
111 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
112 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400113 .withAction(PiAction
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200114 .builder()
115 .withId(outActionId)
116 .withParameter(new PiActionParam(portParamId, portValue))
117 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400118 .withPriority(1)
119 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800120 .withCounterCellData(counterCellData)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400121 .build();
122
Yi Tsengd28936e2018-02-23 22:11:11 +0100123 private final PiTableEntry piTableEntryWithoutAction = PiTableEntry
124 .builder()
125 .forTable(tableId)
126 .withMatchKey(PiMatchKey.builder()
127 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
128 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
129 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
130 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
131 .build())
132 .withPriority(1)
133 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800134 .withCounterCellData(counterCellData)
Yi Tsengd28936e2018-02-23 22:11:11 +0100135 .build();
136
Yi Tseng95390822018-01-22 17:57:22 -0800137 private final PiTableEntry piTableEntryWithGroupAction = PiTableEntry
138 .builder()
139 .forTable(ecmpTableId)
140 .withMatchKey(PiMatchKey.builder()
141 .addFieldMatch(new PiExactFieldMatch(ecmpGroupFieldId, ofOnes(1)))
142 .build())
143 .withAction(PiActionGroupId.of(1))
144 .withPriority(1)
145 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800146 .withCounterCellData(counterCellData)
Yi Tseng95390822018-01-22 17:57:22 -0800147 .build();
148
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400149 public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException {
150 }
151
152 @Test
153 public void testP4InfoBrowser() throws Exception {
154
155 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
156
157 assertThat(browser.tables().hasName(TABLE_0), is(true));
158 assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
159
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200160 int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
161 int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400162
Carmelo Cascone87892e22017-11-13 16:01:29 -0800163 assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + DOT + INGRESS_PORT), is(true));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400164 assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
165
166 // TODO: improve, assert browsing other entities (counters, meters, etc.)
167 }
168
169 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800170 public void testTableEntryEncoder() throws Exception {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400171
172 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntry), defaultPipeconf);
173 assertThat(result, hasSize(1));
174
175 TableEntry tableEntryMsg = result.iterator().next();
176
177 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
178 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
179
180 // Test equality for decoded entry.
181 new EqualsTester()
182 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
183 .testEquals();
184
185 // Table ID.
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200186 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400187 int encodedTableId = tableEntryMsg.getTableId();
188 assertThat(encodedTableId, is(p4InfoTableId));
189
190 // Ternary match.
191 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
192 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
193
194 Action actionMsg = tableEntryMsg.getAction().getAction();
195
196 // Action ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800197 int p4InfoActionId = browser.actions().getByName(outActionId.toString()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400198 int encodedActionId = actionMsg.getActionId();
199 assertThat(encodedActionId, is(p4InfoActionId));
200
201 // Action param ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800202 int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.toString()).getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400203 int encodedActionParamId = actionMsg.getParams(0).getParamId();
204 assertThat(encodedActionParamId, is(p4InfoActionParamId));
205
206 // Action param value.
207 byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray();
208 assertThat(encodedActionParam, is(portValue.asArray()));
209
steven308017632e152018-10-20 00:51:08 +0800210 // Counter
211 CounterData counterData = tableEntryMsg.getCounterData();
212 PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(),
213 counterData.getByteCount());
214 assertThat(encodedCounterData, is(counterCellData));
215
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400216 // TODO: improve, assert other field match types (ternary, LPM)
217 }
Yi Tseng95390822018-01-22 17:57:22 -0800218
219 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800220 public void testActopProfileGroup() throws Exception {
Yi Tseng95390822018-01-22 17:57:22 -0800221 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithGroupAction), defaultPipeconf);
222 assertThat(result, hasSize(1));
223
224 TableEntry tableEntryMsg = result.iterator().next();
225
226 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
227 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
228
229 // Test equality for decoded entry.
230 new EqualsTester()
231 .addEqualityGroup(piTableEntryWithGroupAction, decodedPiTableEntry)
232 .testEquals();
233
234 // Table ID.
235 int p4InfoTableId = browser.tables().getByName(ecmpTableId.id()).getPreamble().getId();
236 int encodedTableId = tableEntryMsg.getTableId();
237 assertThat(encodedTableId, is(p4InfoTableId));
238
239 // Exact match.
240 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getExact().getValue().toByteArray();
241 assertThat(encodedTernaryMatchValue, is(new byte[]{(byte) 0xff}));
242
243 // Action profile group id
244 int actionProfileGroupId = tableEntryMsg.getAction().getActionProfileGroupId();
245 assertThat(actionProfileGroupId, is(1));
246 }
Yi Tsengd28936e2018-02-23 22:11:11 +0100247
248 @Test
249 public void testEncodeWithNoAction() throws Exception {
250 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithoutAction), defaultPipeconf);
251 assertThat(result, hasSize(1));
252
253 TableEntry tableEntryMsg = result.iterator().next();
254
255 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
256 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
257
258 // Test equality for decoded entry.
259 new EqualsTester()
260 .addEqualityGroup(piTableEntryWithoutAction, decodedPiTableEntry)
261 .testEquals();
262
263 // Table ID.
264 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
265 int encodedTableId = tableEntryMsg.getTableId();
266 assertThat(encodedTableId, is(p4InfoTableId));
267
268 // Ternary match.
269 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
270 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
271
272 // no action
273 assertThat(tableEntryMsg.hasAction(), is(false));
274
steven308017632e152018-10-20 00:51:08 +0800275 // Counter
276 CounterData counterData = tableEntryMsg.getCounterData();
277 PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(),
278 counterData.getByteCount());
279 assertThat(encodedCounterData, is(counterCellData));
280
Yi Tsengd28936e2018-02-23 22:11:11 +0100281 // TODO: improve, assert other field match types (ternary, LPM)
282 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400283}