blob: 0619f6a74870d49db3a3724182fde9f8b43325af [file] [log] [blame]
Carmelo Cascone8d99b172017-07-18 17:26:31 -04001/*
Carmelo Cascone4c289b72019-01-22 15:30:45 -08002 * Copyright 2019-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
Carmelo Cascone4c289b72019-01-22 15:30:45 -080017package org.onosproject.p4runtime.ctl.codec;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040018
Carmelo Cascone8d99b172017-07-18 17:26:31 -040019import com.google.common.testing.EqualsTester;
Yi Tseng82512da2017-08-16 19:46:36 -070020import org.easymock.EasyMock;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040021import org.junit.Test;
22import org.onlab.util.ImmutableByteSequence;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040023import org.onosproject.net.pi.model.DefaultPiPipeconf;
Carmelo Cascone87892e22017-11-13 16:01:29 -080024import org.onosproject.net.pi.model.PiActionId;
25import org.onosproject.net.pi.model.PiActionParamId;
26import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040027import org.onosproject.net.pi.model.PiPipeconf;
28import org.onosproject.net.pi.model.PiPipeconfId;
Yi Tseng82512da2017-08-16 19:46:36 -070029import org.onosproject.net.pi.model.PiPipelineModel;
Carmelo Cascone87892e22017-11-13 16:01:29 -080030import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040031import org.onosproject.net.pi.runtime.PiAction;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040032import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070033import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
steven308017632e152018-10-20 00:51:08 +080034import org.onosproject.net.pi.runtime.PiCounterCellData;
Yi Tseng95390822018-01-22 17:57:22 -080035import org.onosproject.net.pi.runtime.PiExactFieldMatch;
Carmelo Cascone0e896a02017-07-31 07:22:27 +020036import org.onosproject.net.pi.runtime.PiMatchKey;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040037import org.onosproject.net.pi.runtime.PiTableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040038import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080039import org.onosproject.p4runtime.ctl.utils.P4InfoBrowser;
40import org.onosproject.p4runtime.ctl.utils.PipeconfHelper;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020041import p4.v1.P4RuntimeOuterClass.Action;
steven308017632e152018-10-20 00:51:08 +080042import p4.v1.P4RuntimeOuterClass.CounterData;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020043import p4.v1.P4RuntimeOuterClass.TableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040044
45import java.net.URL;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040046import java.util.Random;
47
48import static org.hamcrest.MatcherAssert.assertThat;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040049import static org.hamcrest.Matchers.is;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070050import static org.onlab.util.ImmutableByteSequence.copyFrom;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070051import static org.onlab.util.ImmutableByteSequence.ofOnes;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040052import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020053
Yi Tseng82512da2017-08-16 19:46:36 -070054/**
55 * Test for P4 runtime table entry encoder.
56 */
Carmelo Cascone8d99b172017-07-18 17:26:31 -040057public class TableEntryEncoderTest {
Carmelo Cascone87892e22017-11-13 16:01:29 -080058 private static final String DOT = ".";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040059 private static final String TABLE_0 = "table0";
Yi Tseng95390822018-01-22 17:57:22 -080060 private static final String TABLE_ECMP = "ecmp";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040061 private static final String SET_EGRESS_PORT = "set_egress_port";
62 private static final String PORT = "port";
Carmelo Cascone87892e22017-11-13 16:01:29 -080063 private static final String HDR = "hdr";
Yi Tseng95390822018-01-22 17:57:22 -080064 private static final String META = "meta";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040065 private static final String ETHERNET = "ethernet";
66 private static final String DST_ADDR = "dstAddr";
67 private static final String SRC_ADDR = "srcAddr";
68 private static final String STANDARD_METADATA = "standard_metadata";
Yi Tseng95390822018-01-22 17:57:22 -080069 private static final String ECMP_METADATA = "ecmp_metadata";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040070 private static final String INGRESS_PORT = "ingress_port";
71 private static final String ETHER_TYPE = "etherType";
Yi Tseng95390822018-01-22 17:57:22 -080072 private static final String ECMP_GROUP_ID = "ecmp_group_id";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040073
steven308017632e152018-10-20 00:51:08 +080074 private static final long PACKETS = 10;
75 private static final long BYTES = 100;
76
Carmelo Cascone8d99b172017-07-18 17:26:31 -040077 private final Random rand = new Random();
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070078 private final URL p4InfoUrl = this.getClass().getResource("/test.p4info");
Carmelo Cascone8d99b172017-07-18 17:26:31 -040079
80 private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
81 .withId(new PiPipeconfId("mock"))
Yi Tseng82512da2017-08-16 19:46:36 -070082 .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
Carmelo Cascone8d99b172017-07-18 17:26:31 -040083 .addExtension(P4_INFO_TEXT, p4InfoUrl)
Carmelo Cascone8d99b172017-07-18 17:26:31 -040084 .build();
85
86 private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
Carmelo Cascone8a571af2018-04-06 23:17:04 -070087 private final ImmutableByteSequence ethAddr = copyFrom(rand.nextInt()).fit(48);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040088 private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
Carmelo Cascone87892e22017-11-13 16:01:29 -080089 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + DST_ADDR);
90 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + SRC_ADDR);
91 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
92 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + ETHER_TYPE);
Yi Tseng95390822018-01-22 17:57:22 -080093 private final PiMatchFieldId ecmpGroupFieldId =
94 PiMatchFieldId.of(META + DOT + ECMP_METADATA + DOT + ECMP_GROUP_ID);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040095 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
96 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
97 private final PiTableId tableId = PiTableId.of(TABLE_0);
Yi Tseng95390822018-01-22 17:57:22 -080098 private final PiTableId ecmpTableId = PiTableId.of(TABLE_ECMP);
steven308017632e152018-10-20 00:51:08 +080099 private final PiCounterCellData counterCellData = new PiCounterCellData(PACKETS, BYTES);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400100
101 private final PiTableEntry piTableEntry = PiTableEntry
102 .builder()
103 .forTable(tableId)
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200104 .withMatchKey(PiMatchKey.builder()
105 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
106 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
107 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
108 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
109 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400110 .withAction(PiAction
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200111 .builder()
112 .withId(outActionId)
113 .withParameter(new PiActionParam(portParamId, portValue))
114 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400115 .withPriority(1)
116 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800117 .withCounterCellData(counterCellData)
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400118 .build();
119
Yi Tsengd28936e2018-02-23 22:11:11 +0100120 private final PiTableEntry piTableEntryWithoutAction = PiTableEntry
121 .builder()
122 .forTable(tableId)
123 .withMatchKey(PiMatchKey.builder()
124 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
125 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
126 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
127 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
128 .build())
129 .withPriority(1)
130 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800131 .withCounterCellData(counterCellData)
Yi Tsengd28936e2018-02-23 22:11:11 +0100132 .build();
133
Yi Tseng95390822018-01-22 17:57:22 -0800134 private final PiTableEntry piTableEntryWithGroupAction = PiTableEntry
135 .builder()
136 .forTable(ecmpTableId)
137 .withMatchKey(PiMatchKey.builder()
138 .addFieldMatch(new PiExactFieldMatch(ecmpGroupFieldId, ofOnes(1)))
139 .build())
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700140 .withAction(PiActionProfileGroupId.of(1))
Yi Tseng95390822018-01-22 17:57:22 -0800141 .withPriority(1)
142 .withCookie(2)
steven308017632e152018-10-20 00:51:08 +0800143 .withCounterCellData(counterCellData)
Yi Tseng95390822018-01-22 17:57:22 -0800144 .build();
145
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400146 public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException {
147 }
148
149 @Test
150 public void testP4InfoBrowser() throws Exception {
151
152 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
153
154 assertThat(browser.tables().hasName(TABLE_0), is(true));
155 assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
156
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200157 int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
158 int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400159
Carmelo Cascone87892e22017-11-13 16:01:29 -0800160 assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + DOT + INGRESS_PORT), is(true));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400161 assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
162
163 // TODO: improve, assert browsing other entities (counters, meters, etc.)
164 }
165
166 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800167 public void testTableEntryEncoder() throws Exception {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400168
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800169 TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
170 piTableEntry, null, defaultPipeconf);
171 PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
172 tableEntryMsg, null, defaultPipeconf);
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400173
174 // Test equality for decoded entry.
175 new EqualsTester()
176 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
177 .testEquals();
178
179 // Table ID.
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200180 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400181 int encodedTableId = tableEntryMsg.getTableId();
182 assertThat(encodedTableId, is(p4InfoTableId));
183
184 // Ternary match.
185 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
186 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
187
188 Action actionMsg = tableEntryMsg.getAction().getAction();
189
190 // Action ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800191 int p4InfoActionId = browser.actions().getByName(outActionId.toString()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400192 int encodedActionId = actionMsg.getActionId();
193 assertThat(encodedActionId, is(p4InfoActionId));
194
195 // Action param ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800196 int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.toString()).getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400197 int encodedActionParamId = actionMsg.getParams(0).getParamId();
198 assertThat(encodedActionParamId, is(p4InfoActionParamId));
199
200 // Action param value.
201 byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray();
202 assertThat(encodedActionParam, is(portValue.asArray()));
203
steven308017632e152018-10-20 00:51:08 +0800204 // Counter
205 CounterData counterData = tableEntryMsg.getCounterData();
206 PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(),
207 counterData.getByteCount());
208 assertThat(encodedCounterData, is(counterCellData));
209
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400210 // TODO: improve, assert other field match types (ternary, LPM)
211 }
Yi Tseng95390822018-01-22 17:57:22 -0800212
213 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800214 public void testActopProfileGroup() throws Exception {
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800215 TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
216 piTableEntryWithGroupAction, null, defaultPipeconf);
217 PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
218 tableEntryMsg, null, defaultPipeconf);
Yi Tseng95390822018-01-22 17:57:22 -0800219
220 // Test equality for decoded entry.
221 new EqualsTester()
222 .addEqualityGroup(piTableEntryWithGroupAction, decodedPiTableEntry)
223 .testEquals();
224
225 // Table ID.
226 int p4InfoTableId = browser.tables().getByName(ecmpTableId.id()).getPreamble().getId();
227 int encodedTableId = tableEntryMsg.getTableId();
228 assertThat(encodedTableId, is(p4InfoTableId));
229
230 // Exact match.
231 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getExact().getValue().toByteArray();
232 assertThat(encodedTernaryMatchValue, is(new byte[]{(byte) 0xff}));
233
234 // Action profile group id
235 int actionProfileGroupId = tableEntryMsg.getAction().getActionProfileGroupId();
236 assertThat(actionProfileGroupId, is(1));
237 }
Yi Tsengd28936e2018-02-23 22:11:11 +0100238
239 @Test
240 public void testEncodeWithNoAction() throws Exception {
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800241 TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
242 piTableEntryWithoutAction, null, defaultPipeconf);
243 PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
244 tableEntryMsg, null, defaultPipeconf);
Yi Tsengd28936e2018-02-23 22:11:11 +0100245
246 // Test equality for decoded entry.
247 new EqualsTester()
248 .addEqualityGroup(piTableEntryWithoutAction, decodedPiTableEntry)
249 .testEquals();
250
251 // Table ID.
252 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
253 int encodedTableId = tableEntryMsg.getTableId();
254 assertThat(encodedTableId, is(p4InfoTableId));
255
256 // Ternary match.
257 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
258 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
259
260 // no action
261 assertThat(tableEntryMsg.hasAction(), is(false));
262
steven308017632e152018-10-20 00:51:08 +0800263 // Counter
264 CounterData counterData = tableEntryMsg.getCounterData();
265 PiCounterCellData encodedCounterData = new PiCounterCellData(counterData.getPacketCount(),
266 counterData.getByteCount());
267 assertThat(encodedCounterData, is(counterCellData));
268
Yi Tsengd28936e2018-02-23 22:11:11 +0100269 // TODO: improve, assert other field match types (ternary, LPM)
270 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400271}