blob: b51a2c33a8dfac5bab4cc4641dabef475efbd3c7 [file] [log] [blame]
Yi Tseng82512da2017-08-16 19:46:36 -07001/*
2 * Copyright 2017-present Open Networking Foundation
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.ImmutableList;
Yi Tseng82512da2017-08-16 19:46:36 -070020import com.google.common.collect.Lists;
21import com.google.protobuf.ByteString;
22import io.grpc.ManagedChannel;
23import io.grpc.Server;
24import io.grpc.inprocess.InProcessChannelBuilder;
25import io.grpc.inprocess.InProcessServerBuilder;
26import io.grpc.internal.AbstractServerImplBuilder;
27import org.easymock.EasyMock;
28import org.junit.AfterClass;
29import org.junit.Before;
30import org.junit.BeforeClass;
31import org.junit.Test;
32import org.onlab.util.ImmutableByteSequence;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.pi.model.DefaultPiPipeconf;
Carmelo Cascone87892e22017-11-13 16:01:29 -080035import org.onosproject.net.pi.model.PiActionId;
36import org.onosproject.net.pi.model.PiActionParamId;
37import org.onosproject.net.pi.model.PiActionProfileId;
Yi Tseng82512da2017-08-16 19:46:36 -070038import org.onosproject.net.pi.model.PiPipeconf;
39import org.onosproject.net.pi.model.PiPipeconfId;
40import org.onosproject.net.pi.model.PiPipelineModel;
Yi Tseng82512da2017-08-16 19:46:36 -070041import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng82512da2017-08-16 19:46:36 -070042import org.onosproject.net.pi.runtime.PiActionParam;
Carmelo Casconecb4327a2018-09-11 15:17:23 -070043import org.onosproject.net.pi.runtime.PiActionProfileGroup;
44import org.onosproject.net.pi.runtime.PiActionProfileGroupId;
45import org.onosproject.net.pi.runtime.PiActionProfileMember;
46import org.onosproject.net.pi.runtime.PiActionProfileMemberId;
Yi Tseng2a340f72018-11-02 16:52:47 -070047import org.onosproject.p4runtime.api.P4RuntimeClientKey;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020048import p4.v1.P4RuntimeOuterClass.ActionProfileGroup;
49import p4.v1.P4RuntimeOuterClass.ActionProfileMember;
50import p4.v1.P4RuntimeOuterClass.Entity;
51import p4.v1.P4RuntimeOuterClass.Uint128;
52import p4.v1.P4RuntimeOuterClass.Update;
53import p4.v1.P4RuntimeOuterClass.WriteRequest;
Yi Tseng82512da2017-08-16 19:46:36 -070054
55import java.io.IOException;
56import java.net.URL;
57import java.util.Collection;
58import java.util.List;
59import java.util.concurrent.CompletableFuture;
60import java.util.concurrent.TimeUnit;
Carmelo Cascone87b9b392017-10-02 18:33:20 +020061import java.util.stream.Collectors;
Yi Tseng82512da2017-08-16 19:46:36 -070062
Carmelo Cascone87b9b392017-10-02 18:33:20 +020063import static org.easymock.EasyMock.niceMock;
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070064import static org.junit.Assert.assertEquals;
65import static org.junit.Assert.assertNotNull;
66import static org.junit.Assert.assertTrue;
Yi Tseng82512da2017-08-16 19:46:36 -070067import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
Yi Tseng82512da2017-08-16 19:46:36 -070068import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
Carmelo Cascone6af4e172018-06-15 16:01:30 +020069import static p4.v1.P4RuntimeOuterClass.Action;
70import static p4.v1.P4RuntimeOuterClass.ReadResponse;
Yi Tseng82512da2017-08-16 19:46:36 -070071
72/**
73 * Tests for P4 Runtime Action Profile Group support.
74 */
75public class P4RuntimeGroupTest {
76 private static final String PIPECONF_ID = "p4runtime-mock-pipeconf";
Carmelo Casconeca94bcf2017-10-27 14:16:59 -070077 private static final String P4INFO_PATH = "/test.p4info";
Yi Tseng82512da2017-08-16 19:46:36 -070078 private static final PiPipeconf PIPECONF = buildPipeconf();
79 private static final int P4_INFO_ACT_PROF_ID = 285227860;
80 private static final PiActionProfileId ACT_PROF_ID = PiActionProfileId.of("ecmp_selector");
Carmelo Casconecb4327a2018-09-11 15:17:23 -070081 private static final PiActionProfileGroupId GROUP_ID = PiActionProfileGroupId.of(1);
Yi Tseng82512da2017-08-16 19:46:36 -070082 private static final int DEFAULT_MEMBER_WEIGHT = 1;
83 private static final PiActionId EGRESS_PORT_ACTION_ID = PiActionId.of("set_egress_port");
84 private static final PiActionParamId PORT_PARAM_ID = PiActionParamId.of("port");
85 private static final int BASE_MEM_ID = 65535;
86 private static final List<Integer> MEMBER_IDS = ImmutableList.of(65536, 65537, 65538);
Carmelo Casconecb4327a2018-09-11 15:17:23 -070087 private static final List<PiActionProfileMember> GROUP_MEMBERS =
Carmelo Casconee44592f2018-09-12 02:24:47 -070088 Lists.newArrayList(
Yi Tseng82512da2017-08-16 19:46:36 -070089 outputMember((short) 1),
90 outputMember((short) 2),
91 outputMember((short) 3)
92 );
Carmelo Casconecb4327a2018-09-11 15:17:23 -070093 private static final PiActionProfileGroup GROUP = PiActionProfileGroup.builder()
Yi Tseng82512da2017-08-16 19:46:36 -070094 .withId(GROUP_ID)
95 .addMembers(GROUP_MEMBERS)
96 .withActionProfileId(ACT_PROF_ID)
Yi Tseng82512da2017-08-16 19:46:36 -070097 .build();
98 private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
99 private static final int P4_DEVICE_ID = 1;
100 private static final int SET_EGRESS_PORT_ID = 16794308;
101 private static final String GRPC_SERVER_NAME = "P4RuntimeGroupTest";
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200102 private static final long DEFAULT_TIMEOUT_TIME = 10;
Yi Tseng3e7f1452017-10-20 10:31:53 -0700103 private static final Uint128 DEFAULT_ELECTION_ID = Uint128.newBuilder().setLow(1).build();
Yi Tseng2a340f72018-11-02 16:52:47 -0700104 private static final String P4R_IP = "127.0.0.1";
105 private static final int P4R_PORT = 50010;
Yi Tseng82512da2017-08-16 19:46:36 -0700106
107 private P4RuntimeClientImpl client;
108 private P4RuntimeControllerImpl controller;
109 private static MockP4RuntimeServer p4RuntimeServerImpl = new MockP4RuntimeServer();
110 private static Server grpcServer;
111 private static ManagedChannel grpcChannel;
112
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700113 private static PiActionProfileMember outputMember(short portNum) {
Yi Tseng82512da2017-08-16 19:46:36 -0700114 PiActionParam param = new PiActionParam(PORT_PARAM_ID,
115 ImmutableByteSequence.copyFrom(portNum));
116 PiAction piAction = PiAction.builder()
117 .withId(EGRESS_PORT_ACTION_ID)
118 .withParameter(param).build();
119
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700120 return PiActionProfileMember.builder()
Carmelo Casconee44592f2018-09-12 02:24:47 -0700121 .forActionProfile(ACT_PROF_ID)
Yi Tseng82512da2017-08-16 19:46:36 -0700122 .withAction(piAction)
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700123 .withId(PiActionProfileMemberId.of(BASE_MEM_ID + portNum))
Yi Tseng82512da2017-08-16 19:46:36 -0700124 .withWeight(DEFAULT_MEMBER_WEIGHT)
125 .build();
126 }
127
128 private static PiPipeconf buildPipeconf() {
129 final URL p4InfoUrl = P4RuntimeGroupTest.class.getResource(P4INFO_PATH);
130 return DefaultPiPipeconf.builder()
131 .withId(new PiPipeconfId(PIPECONF_ID))
132 .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
133 .addExtension(P4_INFO_TEXT, p4InfoUrl)
134 .build();
135 }
136
137 @BeforeClass
138 public static void globalSetup() throws IOException {
139 AbstractServerImplBuilder builder = InProcessServerBuilder
140 .forName(GRPC_SERVER_NAME).directExecutor();
141 builder.addService(p4RuntimeServerImpl);
142 grpcServer = builder.build().start();
143 grpcChannel = InProcessChannelBuilder.forName(GRPC_SERVER_NAME)
144 .directExecutor()
Yi Tseng82512da2017-08-16 19:46:36 -0700145 .build();
146 }
147
148 @AfterClass
Carmelo Casconee5b28722018-06-22 17:28:28 +0200149 public static void globalTearDown() {
Yi Tseng82512da2017-08-16 19:46:36 -0700150 grpcServer.shutdown();
151 grpcChannel.shutdown();
152 }
153
154
155 @Before
156 public void setup() {
157 controller = niceMock(P4RuntimeControllerImpl.class);
Yi Tseng2a340f72018-11-02 16:52:47 -0700158 P4RuntimeClientKey clientKey = new P4RuntimeClientKey(DEVICE_ID, P4R_IP, P4R_PORT, P4_DEVICE_ID);
159 client = new P4RuntimeClientImpl(clientKey, grpcChannel, controller);
Carmelo Casconee5b28722018-06-22 17:28:28 +0200160 client.becomeMaster();
Yi Tseng82512da2017-08-16 19:46:36 -0700161 }
162
163 @Test
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700164 public void testInsertPiActionProfileGroup() throws Exception {
Yi Tseng82512da2017-08-16 19:46:36 -0700165 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700166 client.writeActionProfileGroup(GROUP, INSERT, PIPECONF, 3);
Yi Tseng82512da2017-08-16 19:46:36 -0700167 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
168 WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
169 assertEquals(1, result.getDeviceId());
170 assertEquals(1, result.getUpdatesCount());
Yi Tseng3e7f1452017-10-20 10:31:53 -0700171 assertEquals(DEFAULT_ELECTION_ID, result.getElectionId());
Yi Tseng82512da2017-08-16 19:46:36 -0700172
173 Update update = result.getUpdatesList().get(0);
174 assertEquals(Update.Type.INSERT, update.getType());
175
176 Entity entity = update.getEntity();
177 ActionProfileGroup actionProfileGroup = entity.getActionProfileGroup();
178 assertNotNull(actionProfileGroup);
179
180 assertEquals(P4_INFO_ACT_PROF_ID, actionProfileGroup.getActionProfileId());
181 assertEquals(3, actionProfileGroup.getMembersCount());
182 List<ActionProfileGroup.Member> members = actionProfileGroup.getMembersList();
183
184 for (ActionProfileGroup.Member member : members) {
185 // XXX: We can't guarantee the order of member, just make sure we
186 // have these member ids
187 assertTrue(MEMBER_IDS.contains(member.getMemberId()));
188 assertEquals(DEFAULT_MEMBER_WEIGHT, member.getWeight());
189 }
190 }
191
192 @Test
193 public void testInsertPiActionMembers() throws Exception {
194 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700195 client.writeActionProfileMembers(GROUP_MEMBERS, INSERT, PIPECONF);
Yi Tseng82512da2017-08-16 19:46:36 -0700196 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
197 WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
198 assertEquals(1, result.getDeviceId());
199 assertEquals(3, result.getUpdatesCount());
Yi Tseng3e7f1452017-10-20 10:31:53 -0700200 assertEquals(DEFAULT_ELECTION_ID, result.getElectionId());
Yi Tseng82512da2017-08-16 19:46:36 -0700201
202 List<Update> updates = result.getUpdatesList();
203 for (Update update : updates) {
204 assertEquals(Update.Type.INSERT, update.getType());
205 Entity entity = update.getEntity();
206 ActionProfileMember member = entity.getActionProfileMember();
207 assertNotNull(member);
208 assertEquals(P4_INFO_ACT_PROF_ID, member.getActionProfileId());
209 assertTrue(MEMBER_IDS.contains(member.getMemberId()));
210 Action action = member.getAction();
211 assertEquals(SET_EGRESS_PORT_ID, action.getActionId());
212 assertEquals(1, action.getParamsCount());
213 Action.Param param = action.getParamsList().get(0);
214 assertEquals(1, param.getParamId());
215 byte outPort = (byte) (member.getMemberId() - BASE_MEM_ID);
216 ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
217 assertEquals(bs, param.getValue());
218 }
219 }
220
221 @Test
222 public void testReadGroups() throws Exception {
223 ActionProfileGroup.Builder group = ActionProfileGroup.newBuilder()
224 .setGroupId(GROUP_ID.id())
Yi Tseng82512da2017-08-16 19:46:36 -0700225 .setActionProfileId(P4_INFO_ACT_PROF_ID);
226
227 List<ActionProfileMember> members = Lists.newArrayList();
228
229 MEMBER_IDS.forEach(id -> {
230 ActionProfileGroup.Member member = ActionProfileGroup.Member.newBuilder()
231 .setMemberId(id)
232 .setWeight(DEFAULT_MEMBER_WEIGHT)
233 .build();
234 group.addMembers(member);
235
236 byte outPort = (byte) (id - BASE_MEM_ID);
237 ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
238 Action.Param param = Action.Param.newBuilder()
239 .setParamId(1)
240 .setValue(bs)
241 .build();
242
243 Action action = Action.newBuilder()
244 .setActionId(SET_EGRESS_PORT_ID)
245 .addParams(param)
246 .build();
247
Yi Tseng82512da2017-08-16 19:46:36 -0700248 ActionProfileMember actProfMember =
249 ActionProfileMember.newBuilder()
Carmelo Casconee44592f2018-09-12 02:24:47 -0700250 .setActionProfileId(P4_INFO_ACT_PROF_ID)
Yi Tseng82512da2017-08-16 19:46:36 -0700251 .setMemberId(id)
252 .setAction(action)
253 .build();
254 members.add(actProfMember);
255 });
256
257 List<ReadResponse> responses = Lists.newArrayList();
258 responses.add(ReadResponse.newBuilder()
259 .addEntities(Entity.newBuilder().setActionProfileGroup(group))
260 .build()
261 );
262
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200263 responses.add(ReadResponse.newBuilder()
264 .addAllEntities(members.stream()
Carmelo Casconee44592f2018-09-12 02:24:47 -0700265 .map(m -> Entity.newBuilder()
266 .setActionProfileMember(m).build())
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200267 .collect(Collectors.toList()))
268 .build());
Yi Tseng82512da2017-08-16 19:46:36 -0700269
270 p4RuntimeServerImpl.willReturnReadResult(responses);
Carmelo Cascone87b9b392017-10-02 18:33:20 +0200271 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(2);
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700272 CompletableFuture<List<PiActionProfileGroup>> groupsComplete = client.dumpActionProfileGroups(
273 ACT_PROF_ID, PIPECONF);
Yi Tseng82512da2017-08-16 19:46:36 -0700274 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
275
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700276 Collection<PiActionProfileGroup> groups = groupsComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
Yi Tseng82512da2017-08-16 19:46:36 -0700277 assertEquals(1, groups.size());
Carmelo Casconecb4327a2018-09-11 15:17:23 -0700278 PiActionProfileGroup piActionGroup = groups.iterator().next();
Yi Tseng82512da2017-08-16 19:46:36 -0700279 assertEquals(ACT_PROF_ID, piActionGroup.actionProfileId());
280 assertEquals(GROUP_ID, piActionGroup.id());
Yi Tseng82512da2017-08-16 19:46:36 -0700281 assertEquals(3, piActionGroup.members().size());
282 assertTrue(GROUP_MEMBERS.containsAll(piActionGroup.members()));
283 assertTrue(piActionGroup.members().containsAll(GROUP_MEMBERS));
284 }
285}