blob: 07991087a31a62a384937319021f24d6c7551320 [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;
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 Cascone6af4e172018-06-15 16:01:30 +020039import p4.v1.P4RuntimeOuterClass.Action;
40import p4.v1.P4RuntimeOuterClass.TableEntry;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040041
42import java.net.URL;
43import java.util.Collection;
44import java.util.Random;
45
46import static org.hamcrest.MatcherAssert.assertThat;
47import static org.hamcrest.Matchers.hasSize;
48import static org.hamcrest.Matchers.is;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070049import static org.onlab.util.ImmutableByteSequence.copyFrom;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070050import static org.onlab.util.ImmutableByteSequence.ofOnes;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040051import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
52import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
53import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020054
Yi Tseng82512da2017-08-16 19:46:36 -070055/**
56 * Test for P4 runtime table entry encoder.
57 */
Carmelo Cascone8d99b172017-07-18 17:26:31 -040058public class TableEntryEncoderTest {
Carmelo Cascone87892e22017-11-13 16:01:29 -080059 private static final String DOT = ".";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040060 private static final String TABLE_0 = "table0";
Yi Tseng95390822018-01-22 17:57:22 -080061 private static final String TABLE_ECMP = "ecmp";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040062 private static final String SET_EGRESS_PORT = "set_egress_port";
63 private static final String PORT = "port";
Carmelo Cascone87892e22017-11-13 16:01:29 -080064 private static final String HDR = "hdr";
Yi Tseng95390822018-01-22 17:57:22 -080065 private static final String META = "meta";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040066 private static final String ETHERNET = "ethernet";
67 private static final String DST_ADDR = "dstAddr";
68 private static final String SRC_ADDR = "srcAddr";
69 private static final String STANDARD_METADATA = "standard_metadata";
Yi Tseng95390822018-01-22 17:57:22 -080070 private static final String ECMP_METADATA = "ecmp_metadata";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040071 private static final String INGRESS_PORT = "ingress_port";
72 private static final String ETHER_TYPE = "etherType";
Yi Tseng95390822018-01-22 17:57:22 -080073 private static final String ECMP_GROUP_ID = "ecmp_group_id";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040074
75 private final Random rand = new Random();
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070076 private final URL p4InfoUrl = this.getClass().getResource("/test.p4info");
Carmelo Cascone8d99b172017-07-18 17:26:31 -040077
78 private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
79 .withId(new PiPipeconfId("mock"))
Yi Tseng82512da2017-08-16 19:46:36 -070080 .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
Carmelo Cascone8d99b172017-07-18 17:26:31 -040081 .addExtension(P4_INFO_TEXT, p4InfoUrl)
Carmelo Cascone8d99b172017-07-18 17:26:31 -040082 .build();
83
84 private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
Carmelo Cascone8a571af2018-04-06 23:17:04 -070085 private final ImmutableByteSequence ethAddr = copyFrom(rand.nextInt()).fit(48);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040086 private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
Carmelo Cascone87892e22017-11-13 16:01:29 -080087 private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + DST_ADDR);
88 private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + SRC_ADDR);
89 private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
90 private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + ETHER_TYPE);
Yi Tseng95390822018-01-22 17:57:22 -080091 private final PiMatchFieldId ecmpGroupFieldId =
92 PiMatchFieldId.of(META + DOT + ECMP_METADATA + DOT + ECMP_GROUP_ID);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040093 private final PiActionParamId portParamId = PiActionParamId.of(PORT);
94 private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
95 private final PiTableId tableId = PiTableId.of(TABLE_0);
Yi Tseng95390822018-01-22 17:57:22 -080096 private final PiTableId ecmpTableId = PiTableId.of(TABLE_ECMP);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040097
98 private final PiTableEntry piTableEntry = PiTableEntry
99 .builder()
100 .forTable(tableId)
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200101 .withMatchKey(PiMatchKey.builder()
102 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
103 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
104 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
105 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
106 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400107 .withAction(PiAction
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200108 .builder()
109 .withId(outActionId)
110 .withParameter(new PiActionParam(portParamId, portValue))
111 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400112 .withPriority(1)
113 .withCookie(2)
114 .build();
115
Yi Tsengd28936e2018-02-23 22:11:11 +0100116 private final PiTableEntry piTableEntryWithoutAction = PiTableEntry
117 .builder()
118 .forTable(tableId)
119 .withMatchKey(PiMatchKey.builder()
120 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
121 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
122 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
123 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
124 .build())
125 .withPriority(1)
126 .withCookie(2)
127 .build();
128
Yi Tseng95390822018-01-22 17:57:22 -0800129 private final PiTableEntry piTableEntryWithGroupAction = PiTableEntry
130 .builder()
131 .forTable(ecmpTableId)
132 .withMatchKey(PiMatchKey.builder()
133 .addFieldMatch(new PiExactFieldMatch(ecmpGroupFieldId, ofOnes(1)))
134 .build())
135 .withAction(PiActionGroupId.of(1))
136 .withPriority(1)
137 .withCookie(2)
138 .build();
139
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400140 public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException {
141 }
142
143 @Test
144 public void testP4InfoBrowser() throws Exception {
145
146 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
147
148 assertThat(browser.tables().hasName(TABLE_0), is(true));
149 assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
150
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200151 int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
152 int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400153
Carmelo Cascone87892e22017-11-13 16:01:29 -0800154 assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + DOT + INGRESS_PORT), is(true));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400155 assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
156
157 // TODO: improve, assert browsing other entities (counters, meters, etc.)
158 }
159
160 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800161 public void testTableEntryEncoder() throws Exception {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400162
163 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntry), defaultPipeconf);
164 assertThat(result, hasSize(1));
165
166 TableEntry tableEntryMsg = result.iterator().next();
167
168 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
169 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
170
171 // Test equality for decoded entry.
172 new EqualsTester()
173 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
174 .testEquals();
175
176 // Table ID.
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200177 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400178 int encodedTableId = tableEntryMsg.getTableId();
179 assertThat(encodedTableId, is(p4InfoTableId));
180
181 // Ternary match.
182 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
183 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
184
185 Action actionMsg = tableEntryMsg.getAction().getAction();
186
187 // Action ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800188 int p4InfoActionId = browser.actions().getByName(outActionId.toString()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400189 int encodedActionId = actionMsg.getActionId();
190 assertThat(encodedActionId, is(p4InfoActionId));
191
192 // Action param ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800193 int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.toString()).getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400194 int encodedActionParamId = actionMsg.getParams(0).getParamId();
195 assertThat(encodedActionParamId, is(p4InfoActionParamId));
196
197 // Action param value.
198 byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray();
199 assertThat(encodedActionParam, is(portValue.asArray()));
200
201 // TODO: improve, assert other field match types (ternary, LPM)
202 }
Yi Tseng95390822018-01-22 17:57:22 -0800203
204 @Test
Carmelo Cascone5bc7e102018-02-18 18:27:55 -0800205 public void testActopProfileGroup() throws Exception {
Yi Tseng95390822018-01-22 17:57:22 -0800206 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithGroupAction), defaultPipeconf);
207 assertThat(result, hasSize(1));
208
209 TableEntry tableEntryMsg = result.iterator().next();
210
211 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
212 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
213
214 // Test equality for decoded entry.
215 new EqualsTester()
216 .addEqualityGroup(piTableEntryWithGroupAction, decodedPiTableEntry)
217 .testEquals();
218
219 // Table ID.
220 int p4InfoTableId = browser.tables().getByName(ecmpTableId.id()).getPreamble().getId();
221 int encodedTableId = tableEntryMsg.getTableId();
222 assertThat(encodedTableId, is(p4InfoTableId));
223
224 // Exact match.
225 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getExact().getValue().toByteArray();
226 assertThat(encodedTernaryMatchValue, is(new byte[]{(byte) 0xff}));
227
228 // Action profile group id
229 int actionProfileGroupId = tableEntryMsg.getAction().getActionProfileGroupId();
230 assertThat(actionProfileGroupId, is(1));
231 }
Yi Tsengd28936e2018-02-23 22:11:11 +0100232
233 @Test
234 public void testEncodeWithNoAction() throws Exception {
235 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithoutAction), defaultPipeconf);
236 assertThat(result, hasSize(1));
237
238 TableEntry tableEntryMsg = result.iterator().next();
239
240 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
241 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
242
243 // Test equality for decoded entry.
244 new EqualsTester()
245 .addEqualityGroup(piTableEntryWithoutAction, decodedPiTableEntry)
246 .testEquals();
247
248 // Table ID.
249 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
250 int encodedTableId = tableEntryMsg.getTableId();
251 assertThat(encodedTableId, is(p4InfoTableId));
252
253 // Ternary match.
254 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
255 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
256
257 // no action
258 assertThat(tableEntryMsg.hasAction(), is(false));
259
260 // TODO: improve, assert other field match types (ternary, LPM)
261 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400262}