blob: 149eae0c1e2dcb62663fbd76f1395405fac4c7e8 [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;
39import p4.P4RuntimeOuterClass.Action;
40import p4.P4RuntimeOuterClass.TableEntry;
41
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;
50import static org.onlab.util.ImmutableByteSequence.fit;
51import 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;
53import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
54import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
Andrea Campanellafc1d34c2017-07-18 17:01:41 +020055
Yi Tseng82512da2017-08-16 19:46:36 -070056/**
57 * Test for P4 runtime table entry encoder.
58 */
Carmelo Cascone8d99b172017-07-18 17:26:31 -040059public class TableEntryEncoderTest {
Carmelo Cascone87892e22017-11-13 16:01:29 -080060 private static final String DOT = ".";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040061 private static final String TABLE_0 = "table0";
Yi Tseng95390822018-01-22 17:57:22 -080062 private static final String TABLE_ECMP = "ecmp";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040063 private static final String SET_EGRESS_PORT = "set_egress_port";
64 private static final String PORT = "port";
Carmelo Cascone87892e22017-11-13 16:01:29 -080065 private static final String HDR = "hdr";
Yi Tseng95390822018-01-22 17:57:22 -080066 private static final String META = "meta";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040067 private static final String ETHERNET = "ethernet";
68 private static final String DST_ADDR = "dstAddr";
69 private static final String SRC_ADDR = "srcAddr";
70 private static final String STANDARD_METADATA = "standard_metadata";
Yi Tseng95390822018-01-22 17:57:22 -080071 private static final String ECMP_METADATA = "ecmp_metadata";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040072 private static final String INGRESS_PORT = "ingress_port";
73 private static final String ETHER_TYPE = "etherType";
Yi Tseng95390822018-01-22 17:57:22 -080074 private static final String ECMP_GROUP_ID = "ecmp_group_id";
75 private static final String ECMP_ACT_PROFILE = "ecmp_selector";
Carmelo Cascone8d99b172017-07-18 17:26:31 -040076
77 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);
87 private final ImmutableByteSequence ethAddr = fit(copyFrom(rand.nextInt()), 48);
88 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);
Carmelo Cascone8d99b172017-07-18 17:26:31 -040099
100 private final PiTableEntry piTableEntry = PiTableEntry
101 .builder()
102 .forTable(tableId)
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200103 .withMatchKey(PiMatchKey.builder()
104 .addFieldMatch(new PiTernaryFieldMatch(ethDstAddrFieldId, ethAddr, ofOnes(6)))
105 .addFieldMatch(new PiTernaryFieldMatch(ethSrcAddrFieldId, ethAddr, ofOnes(6)))
106 .addFieldMatch(new PiTernaryFieldMatch(inPortFieldId, portValue, ofOnes(2)))
107 .addFieldMatch(new PiTernaryFieldMatch(ethTypeFieldId, portValue, ofOnes(2)))
108 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400109 .withAction(PiAction
Carmelo Cascone0e896a02017-07-31 07:22:27 +0200110 .builder()
111 .withId(outActionId)
112 .withParameter(new PiActionParam(portParamId, portValue))
113 .build())
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400114 .withPriority(1)
115 .withCookie(2)
116 .build();
117
Yi Tseng95390822018-01-22 17:57:22 -0800118 private final PiTableEntry piTableEntryWithGroupAction = PiTableEntry
119 .builder()
120 .forTable(ecmpTableId)
121 .withMatchKey(PiMatchKey.builder()
122 .addFieldMatch(new PiExactFieldMatch(ecmpGroupFieldId, ofOnes(1)))
123 .build())
124 .withAction(PiActionGroupId.of(1))
125 .withPriority(1)
126 .withCookie(2)
127 .build();
128
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400129 public TableEntryEncoderTest() throws ImmutableByteSequence.ByteSequenceTrimException {
130 }
131
132 @Test
133 public void testP4InfoBrowser() throws Exception {
134
135 P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
136
137 assertThat(browser.tables().hasName(TABLE_0), is(true));
138 assertThat(browser.actions().hasName(SET_EGRESS_PORT), is(true));
139
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200140 int tableId = browser.tables().getByName(TABLE_0).getPreamble().getId();
141 int actionId = browser.actions().getByName(SET_EGRESS_PORT).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400142
Carmelo Cascone87892e22017-11-13 16:01:29 -0800143 assertThat(browser.matchFields(tableId).hasName(STANDARD_METADATA + DOT + INGRESS_PORT), is(true));
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400144 assertThat(browser.actionParams(actionId).hasName(PORT), is(true));
145
146 // TODO: improve, assert browsing other entities (counters, meters, etc.)
147 }
148
149 @Test
Yi Tseng95390822018-01-22 17:57:22 -0800150 public void testTableEntryEncoder() throws P4InfoBrowser.NotFoundException {
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400151
152 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntry), defaultPipeconf);
153 assertThat(result, hasSize(1));
154
155 TableEntry tableEntryMsg = result.iterator().next();
156
157 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
158 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
159
160 // Test equality for decoded entry.
161 new EqualsTester()
162 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
163 .testEquals();
164
165 // Table ID.
Carmelo Casconecb0a49c2017-10-03 14:32:23 +0200166 int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400167 int encodedTableId = tableEntryMsg.getTableId();
168 assertThat(encodedTableId, is(p4InfoTableId));
169
170 // Ternary match.
171 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getTernary().getValue().toByteArray();
172 assertThat(encodedTernaryMatchValue, is(ethAddr.asArray()));
173
174 Action actionMsg = tableEntryMsg.getAction().getAction();
175
176 // Action ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800177 int p4InfoActionId = browser.actions().getByName(outActionId.toString()).getPreamble().getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400178 int encodedActionId = actionMsg.getActionId();
179 assertThat(encodedActionId, is(p4InfoActionId));
180
181 // Action param ID.
Carmelo Cascone87892e22017-11-13 16:01:29 -0800182 int p4InfoActionParamId = browser.actionParams(p4InfoActionId).getByName(portParamId.toString()).getId();
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400183 int encodedActionParamId = actionMsg.getParams(0).getParamId();
184 assertThat(encodedActionParamId, is(p4InfoActionParamId));
185
186 // Action param value.
187 byte[] encodedActionParam = actionMsg.getParams(0).getValue().toByteArray();
188 assertThat(encodedActionParam, is(portValue.asArray()));
189
190 // TODO: improve, assert other field match types (ternary, LPM)
191 }
Yi Tseng95390822018-01-22 17:57:22 -0800192
193 @Test
194 public void testActopProfileGroup() throws P4InfoBrowser.NotFoundException {
195 Collection<TableEntry> result = encode(Lists.newArrayList(piTableEntryWithGroupAction), defaultPipeconf);
196 assertThat(result, hasSize(1));
197
198 TableEntry tableEntryMsg = result.iterator().next();
199
200 Collection<PiTableEntry> decodedResults = decode(Lists.newArrayList(tableEntryMsg), defaultPipeconf);
201 PiTableEntry decodedPiTableEntry = decodedResults.iterator().next();
202
203 // Test equality for decoded entry.
204 new EqualsTester()
205 .addEqualityGroup(piTableEntryWithGroupAction, decodedPiTableEntry)
206 .testEquals();
207
208 // Table ID.
209 int p4InfoTableId = browser.tables().getByName(ecmpTableId.id()).getPreamble().getId();
210 int encodedTableId = tableEntryMsg.getTableId();
211 assertThat(encodedTableId, is(p4InfoTableId));
212
213 // Exact match.
214 byte[] encodedTernaryMatchValue = tableEntryMsg.getMatch(0).getExact().getValue().toByteArray();
215 assertThat(encodedTernaryMatchValue, is(new byte[]{(byte) 0xff}));
216
217 // Action profile group id
218 int actionProfileGroupId = tableEntryMsg.getAction().getActionProfileGroupId();
219 assertThat(actionProfileGroupId, is(1));
220 }
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400221}