blob: c334218f916d7d6fc19416f54984364d5a45c529 [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.drivers.p4runtime;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Lists;
22import org.easymock.Capture;
23import org.easymock.EasyMock;
24import org.junit.Assert;
25import org.junit.Before;
26import org.junit.Test;
27import org.onlab.util.ImmutableByteSequence;
28import org.onosproject.TestApplicationId;
29import org.onosproject.core.ApplicationId;
30import org.onosproject.core.GroupId;
31import org.onosproject.drivers.p4runtime.P4RuntimeGroupProgrammable.DefaultP4RuntimeGroupCookie;
32import org.onosproject.net.Device;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.driver.DriverData;
36import org.onosproject.net.driver.DriverHandler;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.flow.instructions.Instructions;
40import org.onosproject.net.group.DefaultGroup;
41import org.onosproject.net.group.DefaultGroupBucket;
42import org.onosproject.net.group.DefaultGroupDescription;
43import org.onosproject.net.group.DefaultGroupKey;
44import org.onosproject.net.group.Group;
45import org.onosproject.net.group.GroupBucket;
46import org.onosproject.net.group.GroupBuckets;
47import org.onosproject.net.group.GroupDescription;
48import org.onosproject.net.group.GroupKey;
49import org.onosproject.net.group.GroupOperation;
50import org.onosproject.net.group.GroupOperations;
51import org.onosproject.net.group.GroupStore;
52import org.onosproject.net.pi.model.DefaultPiPipeconf;
53import org.onosproject.net.pi.model.PiPipeconf;
54import org.onosproject.net.pi.model.PiPipeconfId;
55import org.onosproject.net.pi.model.PiPipelineInterpreter;
56import org.onosproject.net.pi.model.PiPipelineModel;
57import org.onosproject.net.pi.runtime.PiActionProfileId;
58import org.onosproject.net.pi.runtime.PiAction;
59import org.onosproject.net.pi.runtime.PiActionGroup;
60import org.onosproject.net.pi.runtime.PiActionGroupMember;
61import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
62import org.onosproject.net.pi.runtime.PiActionId;
63import org.onosproject.net.pi.runtime.PiActionParam;
64import org.onosproject.net.pi.runtime.PiActionParamId;
65import org.onosproject.net.pi.runtime.PiPipeconfService;
66import org.onosproject.net.pi.runtime.PiTableAction;
67import org.onosproject.net.pi.runtime.PiTableId;
68import org.onosproject.p4runtime.api.P4RuntimeClient;
69import org.onosproject.p4runtime.api.P4RuntimeController;
70
71import java.net.URL;
72import java.util.Collection;
73import java.util.List;
74import java.util.Optional;
75import java.util.concurrent.CompletableFuture;
76
77import static org.easymock.EasyMock.*;
78import static org.junit.Assert.assertEquals;
79import static org.onosproject.net.group.GroupDescription.Type.SELECT;
80import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
81import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
82import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
83
84public class P4runtimeGroupProgrammableTest {
85 private static final String P4INFO_PATH = "/default.p4info";
86 private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
87 private static final PiPipeconfId PIPECONF_ID = new PiPipeconfId("p4runtime-mock-pipeconf");
88 private static final PiPipeconf PIPECONF = buildPipeconf();
89 private static final PiTableId ECMP_TABLE_ID = PiTableId.of("ecmp");
90 private static final PiActionProfileId ACT_PROF_ID = PiActionProfileId.of("ecmp_selector");
91 private static final ApplicationId APP_ID = TestApplicationId.create("P4runtimeGroupProgrammableTest");
92 private static final GroupId GROUP_ID = GroupId.valueOf(1);
93 private static final PiActionId EGRESS_PORT_ACTION_ID = PiActionId.of("set_egress_port");
94 private static final PiActionParamId PORT_PARAM_ID = PiActionParamId.of("port");
95 private static final List<GroupBucket> BUCKET_LIST = ImmutableList.of(
96 outputBucket(1),
97 outputBucket(2),
98 outputBucket(3)
99 );
100 private static final DefaultP4RuntimeGroupCookie COOKIE =
101 new DefaultP4RuntimeGroupCookie(ECMP_TABLE_ID, ACT_PROF_ID, GROUP_ID.id());
102 private static final GroupKey GROUP_KEY =
103 new DefaultGroupKey(P4RuntimeGroupProgrammable.KRYO.serialize(COOKIE));
104 private static final GroupBuckets BUCKETS = new GroupBuckets(BUCKET_LIST);
105 private static final GroupDescription GROUP_DESC =
106 new DefaultGroupDescription(DEVICE_ID,
107 SELECT,
108 BUCKETS,
109 GROUP_KEY,
110 GROUP_ID.id(),
111 APP_ID);
112 private static final Group GROUP = new DefaultGroup(GROUP_ID, GROUP_DESC);
113 private static final int DEFAULT_MEMBER_WEIGHT = 1;
114 private static final int BASE_MEM_ID = 65535;
115 private static final Collection<PiActionGroupMember> EXPECTED_MEMBERS =
116 ImmutableSet.of(
117 outputMember(1),
118 outputMember(2),
119 outputMember(3)
120 );
121
122 private P4RuntimeGroupProgrammable programmable;
123 private DriverHandler driverHandler;
124 private DriverData driverData;
125 private P4RuntimeController controller;
126 private P4RuntimeClient client;
127 private PiPipeconfService piPipeconfService;
128 private DeviceService deviceService;
129 private Device device;
130 private GroupStore groupStore;
131
132 private static PiPipeconf buildPipeconf() {
133 final URL p4InfoUrl = P4runtimeGroupProgrammableTest.class.getResource(P4INFO_PATH);
134 return DefaultPiPipeconf.builder()
135 .withId(PIPECONF_ID)
136 .withPipelineModel(niceMock(PiPipelineModel.class))
137 .addExtension(P4_INFO_TEXT, p4InfoUrl)
138 .build();
139 }
140
141 private static GroupBucket outputBucket(int portNum) {
142 ImmutableByteSequence paramVal = ImmutableByteSequence.copyFrom(portNum);
143 PiActionParam param = new PiActionParam(PiActionParamId.of(PORT_PARAM_ID.name()), paramVal);
144 PiTableAction action = PiAction.builder().withId(EGRESS_PORT_ACTION_ID).withParameter(param).build();
145
146 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
147 .add(Instructions.piTableAction(action))
148 .build();
149
150 return DefaultGroupBucket.createSelectGroupBucket(treatment);
151 }
152
153 private static PiActionGroupMember outputMember(int portNum) {
154 PiActionParam param = new PiActionParam(PORT_PARAM_ID,
155 ImmutableByteSequence.copyFrom(portNum));
156 PiAction piAction = PiAction.builder()
157 .withId(EGRESS_PORT_ACTION_ID)
158 .withParameter(param).build();
159
160 return PiActionGroupMember.builder()
161 .withAction(piAction)
162 .withId(PiActionGroupMemberId.of(BASE_MEM_ID + portNum))
163 .withWeight(DEFAULT_MEMBER_WEIGHT)
164 .build();
165 }
166
167 @Before
168 public void setup() {
169 driverHandler = EasyMock.niceMock(DriverHandler.class);
170 driverData = EasyMock.niceMock(DriverData.class);
171 controller = EasyMock.niceMock(P4RuntimeController.class);
172 client = EasyMock.niceMock(P4RuntimeClient.class);
173 piPipeconfService = EasyMock.niceMock(PiPipeconfService.class);
174 deviceService = EasyMock.niceMock(DeviceService.class);
175 device = EasyMock.niceMock(Device.class);
176 groupStore = EasyMock.niceMock(GroupStore.class);
177
178 expect(controller.hasClient(DEVICE_ID)).andReturn(true).anyTimes();
179 expect(controller.getClient(DEVICE_ID)).andReturn(client).anyTimes();
180 expect(device.is(PiPipelineInterpreter.class)).andReturn(true).anyTimes();
181 expect(device.id()).andReturn(DEVICE_ID).anyTimes();
182 expect(deviceService.getDevice(DEVICE_ID)).andReturn(device).anyTimes();
183 expect(driverData.deviceId()).andReturn(DEVICE_ID).anyTimes();
184 expect(groupStore.getGroup(DEVICE_ID, GROUP_ID)).andReturn(GROUP).anyTimes();
185 expect(piPipeconfService.ofDevice(DEVICE_ID)).andReturn(Optional.of(PIPECONF_ID)).anyTimes();
186 expect(piPipeconfService.getPipeconf(PIPECONF_ID)).andReturn(Optional.of(PIPECONF)).anyTimes();
187 expect(driverHandler.data()).andReturn(driverData).anyTimes();
188 expect(driverHandler.get(P4RuntimeController.class)).andReturn(controller).anyTimes();
189 expect(driverHandler.get(PiPipeconfService.class)).andReturn(piPipeconfService).anyTimes();
190 expect(driverHandler.get(DeviceService.class)).andReturn(deviceService).anyTimes();
191 expect(driverHandler.get(GroupStore.class)).andReturn(groupStore).anyTimes();
192
193 programmable = new P4RuntimeGroupProgrammable();
194 programmable.setHandler(driverHandler);
195 programmable.setData(driverData);
196 EasyMock.replay(driverHandler, driverData, controller, piPipeconfService,
197 deviceService, device, groupStore);
198 }
199
200 /**
201 * Test init function.
202 */
203 @Test
204 public void testInit() {
205 programmable.init();
206 }
207
208 /**
209 * Test add group with buckets.
210 */
211 @Test
212 public void testAddGroup() {
213 List<GroupOperation> ops = Lists.newArrayList();
214 ops.add(GroupOperation.createAddGroupOperation(GROUP_ID, SELECT, BUCKETS));
215 GroupOperations groupOps = new GroupOperations(ops);
216 CompletableFuture<Boolean> completeTrue = new CompletableFuture<>();
217 completeTrue.complete(true);
218
219 Capture<PiActionGroup> groupCapture1 = EasyMock.newCapture();
220 expect(client.writeActionGroup(EasyMock.capture(groupCapture1), EasyMock.eq(INSERT), EasyMock.eq(PIPECONF)))
221 .andReturn(completeTrue).anyTimes();
222
223 Capture<PiActionGroup> groupCapture2 = EasyMock.newCapture();
224 Capture<Collection<PiActionGroupMember>> membersCapture = EasyMock.newCapture();
225 expect(client.writeActionGroupMembers(EasyMock.capture(groupCapture2),
226 EasyMock.capture(membersCapture),
227 EasyMock.eq(INSERT),
228 EasyMock.eq(PIPECONF)))
229 .andReturn(completeTrue).anyTimes();
230
231 EasyMock.replay(client);
232 programmable.performGroupOperation(DEVICE_ID, groupOps);
233
234 // verify group installed by group programmable
235 PiActionGroup group1 = groupCapture1.getValue();
236 PiActionGroup group2 = groupCapture2.getValue();
237 assertEquals("Groups should be equal", group1, group2);
238 assertEquals(GROUP_ID.id(), group1.id().id());
239 assertEquals(PiActionGroup.Type.SELECT, group1.type());
240 assertEquals(ACT_PROF_ID, group1.actionProfileId());
241
242 // members installed
243 Collection<PiActionGroupMember> members = group1.members();
244 assertEquals(3, members.size());
245
246 Assert.assertTrue(EXPECTED_MEMBERS.containsAll(members));
247 Assert.assertTrue(members.containsAll(EXPECTED_MEMBERS));
248 }
249
250 /**
251 * Test remove group with buckets.
252 */
253 @Test
254 public void testDelGroup() {
255 List<GroupOperation> ops = Lists.newArrayList();
256 ops.add(GroupOperation.createDeleteGroupOperation(GROUP_ID, SELECT));
257 GroupOperations groupOps = new GroupOperations(ops);
258 CompletableFuture<Boolean> completeTrue = new CompletableFuture<>();
259 completeTrue.complete(true);
260
261 Capture<PiActionGroup> groupCapture1 = EasyMock.newCapture();
262 expect(client.writeActionGroup(EasyMock.capture(groupCapture1), EasyMock.eq(DELETE), EasyMock.eq(PIPECONF)))
263 .andReturn(completeTrue).anyTimes();
264
265 Capture<PiActionGroup> groupCapture2 = EasyMock.newCapture();
266 Capture<Collection<PiActionGroupMember>> membersCapture = EasyMock.newCapture();
267 expect(client.writeActionGroupMembers(EasyMock.capture(groupCapture2),
268 EasyMock.capture(membersCapture),
269 EasyMock.eq(DELETE),
270 EasyMock.eq(PIPECONF)))
271 .andReturn(completeTrue).anyTimes();
272
273 EasyMock.replay(client);
274 programmable.performGroupOperation(DEVICE_ID, groupOps);
275
276 // verify group installed by group programmable
277 PiActionGroup group1 = groupCapture1.getValue();
278 PiActionGroup group2 = groupCapture2.getValue();
279 assertEquals("Groups should be equal", group1, group2);
280 assertEquals(GROUP_ID.id(), group1.id().id());
281 assertEquals(PiActionGroup.Type.SELECT, group1.type());
282 assertEquals(ACT_PROF_ID, group1.actionProfileId());
283
284 // members installed
285 Collection<PiActionGroupMember> members = group1.members();
286 assertEquals(3, members.size());
287
288 Assert.assertTrue(EXPECTED_MEMBERS.containsAll(members));
289 Assert.assertTrue(members.containsAll(EXPECTED_MEMBERS));
290 }
291}