blob: 8932a169e87b5b4bbe794e709c60df2379709cb9 [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;
20import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Lists;
22import com.google.protobuf.ByteString;
23import io.grpc.ManagedChannel;
24import io.grpc.Server;
25import io.grpc.inprocess.InProcessChannelBuilder;
26import io.grpc.inprocess.InProcessServerBuilder;
27import io.grpc.internal.AbstractServerImplBuilder;
28import org.easymock.EasyMock;
29import org.junit.AfterClass;
30import org.junit.Before;
31import org.junit.BeforeClass;
32import org.junit.Test;
33import org.onlab.util.ImmutableByteSequence;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.pi.model.DefaultPiPipeconf;
36import org.onosproject.net.pi.model.PiPipeconf;
37import org.onosproject.net.pi.model.PiPipeconfId;
38import org.onosproject.net.pi.model.PiPipelineModel;
39import org.onosproject.net.pi.runtime.PiActionProfileId;
40import org.onosproject.net.pi.runtime.PiAction;
41import org.onosproject.net.pi.runtime.PiActionGroup;
42import org.onosproject.net.pi.runtime.PiActionGroupId;
43import org.onosproject.net.pi.runtime.PiActionGroupMember;
44import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
45import org.onosproject.net.pi.runtime.PiActionId;
46import org.onosproject.net.pi.runtime.PiActionParam;
47import org.onosproject.net.pi.runtime.PiActionParamId;
48import p4.P4RuntimeOuterClass.ActionProfileGroup;
49import p4.P4RuntimeOuterClass.ActionProfileMember;
50import p4.P4RuntimeOuterClass.Entity;
51import p4.P4RuntimeOuterClass.Update;
52import p4.P4RuntimeOuterClass.WriteRequest;
53
54import java.io.IOException;
55import java.net.URL;
56import java.util.Collection;
57import java.util.List;
58import java.util.concurrent.CompletableFuture;
59import java.util.concurrent.TimeUnit;
60
61import static org.easymock.EasyMock.*;
62import static org.junit.Assert.assertEquals;
63import static org.junit.Assert.assertNotNull;
64import static org.junit.Assert.assertTrue;
65import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
66import static org.onosproject.net.pi.runtime.PiActionGroup.Type.SELECT;
67import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
68import static p4.P4RuntimeOuterClass.*;
69
70/**
71 * Tests for P4 Runtime Action Profile Group support.
72 */
73public class P4RuntimeGroupTest {
74 private static final String PIPECONF_ID = "p4runtime-mock-pipeconf";
75 private static final String P4INFO_PATH = "/default.p4info";
76 private static final PiPipeconf PIPECONF = buildPipeconf();
77 private static final int P4_INFO_ACT_PROF_ID = 285227860;
78 private static final PiActionProfileId ACT_PROF_ID = PiActionProfileId.of("ecmp_selector");
79 private static final PiActionGroupId GROUP_ID = PiActionGroupId.of(1);
80 private static final int DEFAULT_MEMBER_WEIGHT = 1;
81 private static final PiActionId EGRESS_PORT_ACTION_ID = PiActionId.of("set_egress_port");
82 private static final PiActionParamId PORT_PARAM_ID = PiActionParamId.of("port");
83 private static final int BASE_MEM_ID = 65535;
84 private static final List<Integer> MEMBER_IDS = ImmutableList.of(65536, 65537, 65538);
85 private static final Collection<PiActionGroupMember> GROUP_MEMBERS =
86 ImmutableSet.of(
87 outputMember((short) 1),
88 outputMember((short) 2),
89 outputMember((short) 3)
90 );
91 private static final PiActionGroup GROUP = PiActionGroup.builder()
92 .withId(GROUP_ID)
93 .addMembers(GROUP_MEMBERS)
94 .withActionProfileId(ACT_PROF_ID)
95 .withType(SELECT)
96 .build();
97 private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
98 private static final int P4_DEVICE_ID = 1;
99 private static final int SET_EGRESS_PORT_ID = 16794308;
100 private static final String GRPC_SERVER_NAME = "P4RuntimeGroupTest";
101 private static final long DEFAULT_TIMEOUT_TIME = 5;
102
103 private P4RuntimeClientImpl client;
104 private P4RuntimeControllerImpl controller;
105 private static MockP4RuntimeServer p4RuntimeServerImpl = new MockP4RuntimeServer();
106 private static Server grpcServer;
107 private static ManagedChannel grpcChannel;
108
109 private static PiActionGroupMember outputMember(short portNum) {
110 PiActionParam param = new PiActionParam(PORT_PARAM_ID,
111 ImmutableByteSequence.copyFrom(portNum));
112 PiAction piAction = PiAction.builder()
113 .withId(EGRESS_PORT_ACTION_ID)
114 .withParameter(param).build();
115
116 return PiActionGroupMember.builder()
117 .withAction(piAction)
118 .withId(PiActionGroupMemberId.of(BASE_MEM_ID + portNum))
119 .withWeight(DEFAULT_MEMBER_WEIGHT)
120 .build();
121 }
122
123 private static PiPipeconf buildPipeconf() {
124 final URL p4InfoUrl = P4RuntimeGroupTest.class.getResource(P4INFO_PATH);
125 return DefaultPiPipeconf.builder()
126 .withId(new PiPipeconfId(PIPECONF_ID))
127 .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
128 .addExtension(P4_INFO_TEXT, p4InfoUrl)
129 .build();
130 }
131
132 @BeforeClass
133 public static void globalSetup() throws IOException {
134 AbstractServerImplBuilder builder = InProcessServerBuilder
135 .forName(GRPC_SERVER_NAME).directExecutor();
136 builder.addService(p4RuntimeServerImpl);
137 grpcServer = builder.build().start();
138 grpcChannel = InProcessChannelBuilder.forName(GRPC_SERVER_NAME)
139 .directExecutor()
140 .usePlaintext(true)
141 .build();
142 }
143
144 @AfterClass
145 public static void globalTeerDown() {
146 grpcServer.shutdown();
147 grpcChannel.shutdown();
148 }
149
150
151 @Before
152 public void setup() {
153 controller = niceMock(P4RuntimeControllerImpl.class);
154 client = new P4RuntimeClientImpl(DEVICE_ID, P4_DEVICE_ID,
155 grpcChannel,
156 controller);
157 }
158
159 @Test
160 public void testInsertPiActionGroup() throws Exception {
161 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
162 client.writeActionGroup(GROUP, INSERT, PIPECONF);
163 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
164 WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
165 assertEquals(1, result.getDeviceId());
166 assertEquals(1, result.getUpdatesCount());
167
168 Update update = result.getUpdatesList().get(0);
169 assertEquals(Update.Type.INSERT, update.getType());
170
171 Entity entity = update.getEntity();
172 ActionProfileGroup actionProfileGroup = entity.getActionProfileGroup();
173 assertNotNull(actionProfileGroup);
174
175 assertEquals(P4_INFO_ACT_PROF_ID, actionProfileGroup.getActionProfileId());
176 assertEquals(3, actionProfileGroup.getMembersCount());
177 List<ActionProfileGroup.Member> members = actionProfileGroup.getMembersList();
178
179 for (ActionProfileGroup.Member member : members) {
180 // XXX: We can't guarantee the order of member, just make sure we
181 // have these member ids
182 assertTrue(MEMBER_IDS.contains(member.getMemberId()));
183 assertEquals(DEFAULT_MEMBER_WEIGHT, member.getWeight());
184 }
185 }
186
187 @Test
188 public void testInsertPiActionMembers() throws Exception {
189 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
190 client.writeActionGroupMembers(GROUP, GROUP_MEMBERS, INSERT, PIPECONF);
191 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
192 WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
193 assertEquals(1, result.getDeviceId());
194 assertEquals(3, result.getUpdatesCount());
195
196 List<Update> updates = result.getUpdatesList();
197 for (Update update : updates) {
198 assertEquals(Update.Type.INSERT, update.getType());
199 Entity entity = update.getEntity();
200 ActionProfileMember member = entity.getActionProfileMember();
201 assertNotNull(member);
202 assertEquals(P4_INFO_ACT_PROF_ID, member.getActionProfileId());
203 assertTrue(MEMBER_IDS.contains(member.getMemberId()));
204 Action action = member.getAction();
205 assertEquals(SET_EGRESS_PORT_ID, action.getActionId());
206 assertEquals(1, action.getParamsCount());
207 Action.Param param = action.getParamsList().get(0);
208 assertEquals(1, param.getParamId());
209 byte outPort = (byte) (member.getMemberId() - BASE_MEM_ID);
210 ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
211 assertEquals(bs, param.getValue());
212 }
213 }
214
215 @Test
216 public void testReadGroups() throws Exception {
217 ActionProfileGroup.Builder group = ActionProfileGroup.newBuilder()
218 .setGroupId(GROUP_ID.id())
219 .setType(ActionProfileGroup.Type.SELECT)
220 .setActionProfileId(P4_INFO_ACT_PROF_ID);
221
222 List<ActionProfileMember> members = Lists.newArrayList();
223
224 MEMBER_IDS.forEach(id -> {
225 ActionProfileGroup.Member member = ActionProfileGroup.Member.newBuilder()
226 .setMemberId(id)
227 .setWeight(DEFAULT_MEMBER_WEIGHT)
228 .build();
229 group.addMembers(member);
230
231 byte outPort = (byte) (id - BASE_MEM_ID);
232 ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
233 Action.Param param = Action.Param.newBuilder()
234 .setParamId(1)
235 .setValue(bs)
236 .build();
237
238 Action action = Action.newBuilder()
239 .setActionId(SET_EGRESS_PORT_ID)
240 .addParams(param)
241 .build();
242
243
244 ActionProfileMember actProfMember =
245 ActionProfileMember.newBuilder()
246 .setMemberId(id)
247 .setAction(action)
248 .build();
249 members.add(actProfMember);
250 });
251
252 List<ReadResponse> responses = Lists.newArrayList();
253 responses.add(ReadResponse.newBuilder()
254 .addEntities(Entity.newBuilder().setActionProfileGroup(group))
255 .build()
256 );
257
258 members.forEach(m -> {
259 responses.add(ReadResponse.newBuilder()
260 .addEntities(Entity.newBuilder().setActionProfileMember(m))
261 .build());
262 });
263
264 p4RuntimeServerImpl.willReturnReadResult(responses);
265 CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(4);
266 CompletableFuture<Collection<PiActionGroup>> groupsComplete = client.dumpGroups(ACT_PROF_ID, PIPECONF);
267 complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
268
269 Collection<PiActionGroup> groups = groupsComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
270 assertEquals(1, groups.size());
271 PiActionGroup piActionGroup = groups.iterator().next();
272 assertEquals(ACT_PROF_ID, piActionGroup.actionProfileId());
273 assertEquals(GROUP_ID, piActionGroup.id());
274 assertEquals(SELECT, piActionGroup.type());
275 assertEquals(3, piActionGroup.members().size());
276 assertTrue(GROUP_MEMBERS.containsAll(piActionGroup.members()));
277 assertTrue(piActionGroup.members().containsAll(GROUP_MEMBERS));
278 }
279}