blob: e230550af96da73d927d230a90d39734c348d45e [file] [log] [blame]
Charles Chana7903c82018-03-15 20:14:16 -07001/*
2 * Copyright 2018-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.net.flowobjective.impl;
18
19import com.google.common.collect.Lists;
20import com.google.common.collect.Sets;
21import org.junit.Before;
22import org.junit.Ignore;
23import org.junit.Test;
24import org.onlab.packet.Ethernet;
25import org.onlab.packet.IpPrefix;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.MplsLabel;
28import org.onlab.packet.VlanId;
Charles Chan45c19d72018-04-19 21:38:40 -070029import org.onosproject.cfg.ComponentConfigService;
Charles Chana7903c82018-03-15 20:14:16 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.DefaultApplicationId;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.behaviour.NextGroup;
35import org.onosproject.net.behaviour.Pipeliner;
36import org.onosproject.net.behaviour.PipelinerAdapter;
Charles Chan45c19d72018-04-19 21:38:40 -070037import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.driver.DriverService;
Charles Chana7903c82018-03-15 20:14:16 -070039import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.flow.criteria.Criteria;
44import org.onosproject.net.flowobjective.DefaultFilteringObjective;
45import org.onosproject.net.flowobjective.DefaultForwardingObjective;
46import org.onosproject.net.flowobjective.DefaultNextObjective;
47import org.onosproject.net.flowobjective.FilteringObjective;
48import org.onosproject.net.flowobjective.FlowObjectiveStore;
49import org.onosproject.net.flowobjective.ForwardingObjective;
50import org.onosproject.net.flowobjective.NextObjective;
51import org.onosproject.net.flowobjective.Objective;
Charles Chan45c19d72018-04-19 21:38:40 -070052import org.onosproject.net.flowobjective.ObjectiveContext;
Charles Chana7903c82018-03-15 20:14:16 -070053import org.onosproject.net.flowobjective.ObjectiveError;
54import org.onosproject.net.flowobjective.ObjectiveEvent;
55
56import static java.util.concurrent.Executors.newFixedThreadPool;
57import static org.easymock.EasyMock.createMock;
58import static org.easymock.EasyMock.expect;
59import static org.easymock.EasyMock.replay;
Charles Chan45c19d72018-04-19 21:38:40 -070060import static org.easymock.EasyMock.reset;
Charles Chana7903c82018-03-15 20:14:16 -070061import static org.easymock.EasyMock.verify;
62import static org.junit.Assert.assertTrue;
63import static org.junit.Assert.assertEquals;
64import static org.onlab.junit.TestTools.assertAfter;
65import static org.onlab.util.Tools.groupedThreads;
pierventre13a72352020-10-27 16:08:48 +010066import static org.onosproject.net.OsgiPropertyConstants.IFOM_OBJ_TIMEOUT_MS_DEFAULT;
Charles Chana7903c82018-03-15 20:14:16 -070067
68import java.util.Collection;
69import java.util.List;
Charles Chan1491b9b2018-11-27 21:33:33 +080070import java.util.Objects;
Charles Chana7903c82018-03-15 20:14:16 -070071import java.util.Random;
Charles Chan1491b9b2018-11-27 21:33:33 +080072import java.util.concurrent.atomic.AtomicInteger;
Charles Chana7903c82018-03-15 20:14:16 -070073
74public class InOrderFlowObjectiveManagerTest {
75 private InOrderFlowObjectiveManager mgr;
76
77 private static final int PRIORITY = 1000;
78 private static final ApplicationId APP_ID = new DefaultApplicationId(1, "org.onosproject.test");
79 private static final DeviceId DEV1 = DeviceId.deviceId("of:1");
80 private static final PortNumber P1 = PortNumber.portNumber(1);
81 private static final PortNumber P2 = PortNumber.portNumber(2);
82 private static final PortNumber P3 = PortNumber.portNumber(3);
83 private static final PortNumber P4 = PortNumber.portNumber(4);
84 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
85 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
86 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
87 private static final VlanId V1 = VlanId.vlanId((short) 10);
88 private static final VlanId V2 = VlanId.vlanId((short) 20);
89 private static final VlanId V3 = VlanId.vlanId((short) 30);
90 private static final TrafficSelector S1 = DefaultTrafficSelector.builder()
91 .matchEthType(Ethernet.TYPE_IPV4).matchIPDst(IpPrefix.valueOf("10.0.0.1/32")).build();
92 private static final TrafficSelector S2 = DefaultTrafficSelector.builder()
93 .matchEthType(Ethernet.TYPE_IPV4).matchIPDst(IpPrefix.valueOf("10.0.0.2/32")).build();
94 private static final int NID1 = 1;
95 private static final int NID2 = 2;
96 private static final NextGroup NGRP1 = () -> new byte[] {0x00, 0x01};
97 private static final NextGroup NGRP2 = () -> new byte[] {0x02, 0x03};
98
99 // Delay flow objectives OFFSET + rand(0, BOUND) millis
Charles Chan45c19d72018-04-19 21:38:40 -0700100 private static final int DEFAULT_OFFSET = 10; // ms
101 private static final int DEFAULT_BOUND = 40; // ms
Charles Chanb4f4fdb2018-12-21 13:55:29 -0800102 private static final int TIMEOUT_THRESH = 500; // ms
Charles Chan45c19d72018-04-19 21:38:40 -0700103 private static int offset = DEFAULT_OFFSET;
104 private static int bound = DEFAULT_BOUND;
Charles Chana7903c82018-03-15 20:14:16 -0700105
106 private static final FilteringObjective FILT1 = buildFilteringObjective(P2, V3, M3, 1).add();
107 private static final FilteringObjective FILT2 = buildFilteringObjective(P2, V2, M2, 2).add();
108 private static final FilteringObjective FILT3 = buildFilteringObjective(P2, V3, M3, 3).remove();
109 private static final FilteringObjective FILT4 = buildFilteringObjective(P1, V1, M1, 4).add();
110 private static final FilteringObjective FILT5 = buildFilteringObjective(P2, V2, M2, 5).remove();
111 private static final FilteringObjective FILT6 = buildFilteringObjective(P1, V1, M1, 6).remove();
112 private static final FilteringObjective FILT7 = buildFilteringObjective(P2, V3, M3, 7).add();
113 private List<FilteringObjective> expectFiltObjs = Lists.newCopyOnWriteArrayList(
114 Lists.newArrayList(FILT1, FILT2, FILT3, FILT4, FILT5, FILT6, FILT7));
115
116 private static final NextObjective NEXT1 = buildNextObjective(NID1, V1, Sets.newHashSet(P1)).add();
117 private static final NextObjective NEXT2 = buildNextObjective(NID2, V2, Sets.newHashSet(P3)).add();
118 private static final NextObjective NEXT3 = buildNextObjective(NID1, V1, Sets.newHashSet(P1, P2)).addToExisting();
119 private static final NextObjective NEXT4 = buildNextObjective(NID2, V2, Sets.newHashSet(P3, P4)).addToExisting();
120 private static final NextObjective NEXT5 = buildNextObjective(NID1, V1, Sets.newHashSet(P1)).removeFromExisting();
121 private static final NextObjective NEXT6 = buildNextObjective(NID2, V2, Sets.newHashSet(P3)).removeFromExisting();
122 private static final NextObjective NEXT7 = buildNextObjective(NID1, V1, Sets.newHashSet()).remove();
123 private static final NextObjective NEXT8 = buildNextObjective(NID2, V2, Sets.newHashSet()).remove();
124 private List<NextObjective> expectNextObjs = Lists.newCopyOnWriteArrayList(
125 Lists.newArrayList(NEXT1, NEXT2, NEXT3, NEXT4, NEXT5, NEXT6, NEXT7, NEXT8));
126 private List<NextObjective> expectNextObjsPending = Lists.newCopyOnWriteArrayList(
127 Lists.newArrayList(NEXT5, NEXT6, NEXT1, NEXT2, NEXT3, NEXT4, NEXT7, NEXT8));
128
129 private static final ForwardingObjective FWD1 = buildFwdObjective(S1, NID1).add();
130 private static final ForwardingObjective FWD2 = buildFwdObjective(S2, NID2).add();
131 private static final ForwardingObjective FWD3 = buildFwdObjective(S1, NID2).add();
132 private static final ForwardingObjective FWD4 = buildFwdObjective(S2, NID1).add();
133 private static final ForwardingObjective FWD5 = buildFwdObjective(S1, NID2).remove();
134 private static final ForwardingObjective FWD6 = buildFwdObjective(S2, NID1).remove();
135 private List<ForwardingObjective> expectFwdObjs = Lists.newCopyOnWriteArrayList(
136 Lists.newArrayList(FWD1, FWD2, FWD3, FWD4, FWD5, FWD6));
137
138 private List<Objective> actualObjs = Lists.newCopyOnWriteArrayList();
139
140 private Pipeliner pipeliner = new PipelinerAdapter() {
141 @Override
142 public void filter(FilteringObjective filterObjective) {
143 recordObjective(filterObjective);
144 }
145
146 @Override
147 public void forward(ForwardingObjective forwardObjective) {
148 recordObjective(forwardObjective);
149 }
150
151 @Override
152 public void next(NextObjective nextObjective) {
153 recordObjective(nextObjective);
154
155 // Notify delegate when the next obj is completed
156 ObjectiveEvent.Type type;
157 if (nextObjective.op() == Objective.Operation.ADD ||
158 nextObjective.op() == Objective.Operation.ADD_TO_EXISTING) {
159 type = ObjectiveEvent.Type.ADD;
160 } else if (nextObjective.op() == Objective.Operation.REMOVE ||
161 nextObjective.op() == Objective.Operation.REMOVE_FROM_EXISTING) {
162 type = ObjectiveEvent.Type.REMOVE;
163 } else {
164 return;
165 }
166 mgr.delegate.notify(new ObjectiveEvent(type, nextObjective.id()));
167 }
168
169 /**
170 * Record the objectives.
171 * The random delay is introduced in order to mimic pipeline and flow operation behavior.
172 *
173 * @param obj Flow objective
174 */
175 private void recordObjective(Objective obj) {
176 try {
Charles Chan45c19d72018-04-19 21:38:40 -0700177 Thread.sleep(new Random().nextInt(bound) + offset);
Ray Milkey95c9e0f2018-05-30 14:16:37 -0700178 if (!actualObjs.contains(obj)) {
179 actualObjs.add(obj);
180 }
Charles Chana7903c82018-03-15 20:14:16 -0700181 obj.context().ifPresent(c -> c.onSuccess(obj));
182 } catch (Exception e) {
183 obj.context().ifPresent(c -> c.onError(obj, ObjectiveError.UNKNOWN));
184 }
185 }
186 };
187
188 @Before
189 public void setUp() {
pierventre13a72352020-10-27 16:08:48 +0100190 internalSetup(IFOM_OBJ_TIMEOUT_MS_DEFAULT);
Charles Chanb4f4fdb2018-12-21 13:55:29 -0800191 }
192
193 private void internalSetup(int objTimeoutMs) {
Charles Chana7903c82018-03-15 20:14:16 -0700194 mgr = new InOrderFlowObjectiveManager();
pierventre13a72352020-10-27 16:08:48 +0100195 mgr.objectiveTimeoutMs = objTimeoutMs;
Charles Chana7903c82018-03-15 20:14:16 -0700196 mgr.pipeliners.put(DEV1, pipeliner);
piera6b11992020-01-27 17:45:03 +0100197 mgr.installerExecutor = newFixedThreadPool(4, groupedThreads("foo", "bar"));
Charles Chan45c19d72018-04-19 21:38:40 -0700198 mgr.cfgService = createMock(ComponentConfigService.class);
199 mgr.deviceService = createMock(DeviceService.class);
200 mgr.driverService = createMock(DriverService.class);
Charles Chana7903c82018-03-15 20:14:16 -0700201 mgr.flowObjectiveStore = createMock(FlowObjectiveStore.class);
pier8b3aef42019-03-11 15:14:02 -0700202 mgr.activate(null);
Charles Chana7903c82018-03-15 20:14:16 -0700203
Charles Chan45c19d72018-04-19 21:38:40 -0700204 reset(mgr.flowObjectiveStore);
Charles Chan45c19d72018-04-19 21:38:40 -0700205 offset = DEFAULT_OFFSET;
206 bound = DEFAULT_BOUND;
Charles Chana7903c82018-03-15 20:14:16 -0700207 actualObjs.clear();
208 }
209
210 @Test
Charles Chan45c19d72018-04-19 21:38:40 -0700211 public void filter() {
Charles Chana7903c82018-03-15 20:14:16 -0700212 expectFiltObjs.forEach(filtObj -> mgr.filter(DEV1, filtObj));
213
214 // Wait for the pipeline operation to complete
Charles Chan45c19d72018-04-19 21:38:40 -0700215 int expectedTime = (bound + offset) * 7;
Charles Chana7903c82018-03-15 20:14:16 -0700216 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectFiltObjs.size(), actualObjs.size()));
217
218 assertTrue(actualObjs.indexOf(FILT1) < actualObjs.indexOf(FILT2));
219 assertTrue(actualObjs.indexOf(FILT2) < actualObjs.indexOf(FILT3));
220 assertTrue(actualObjs.indexOf(FILT3) < actualObjs.indexOf(FILT5));
221 assertTrue(actualObjs.indexOf(FILT5) < actualObjs.indexOf(FILT7));
222 assertTrue(actualObjs.indexOf(FILT4) < actualObjs.indexOf(FILT6));
223 }
224
225 @Test
Charles Chan45c19d72018-04-19 21:38:40 -0700226 public void forward() {
Charles Chana7903c82018-03-15 20:14:16 -0700227 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(NGRP1).times(3);
228 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(NGRP2).times(3);
229 replay(mgr.flowObjectiveStore);
230
231 expectFwdObjs.forEach(fwdObj -> mgr.forward(DEV1, fwdObj));
232
233 // Wait for the pipeline operation to complete
Charles Chan45c19d72018-04-19 21:38:40 -0700234 int expectedTime = (bound + offset) * 6;
Charles Chana7903c82018-03-15 20:14:16 -0700235 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectFwdObjs.size(), actualObjs.size()));
236
237 assertTrue(actualObjs.indexOf(FWD1) < actualObjs.indexOf(FWD3));
238 assertTrue(actualObjs.indexOf(FWD3) < actualObjs.indexOf(FWD5));
239 assertTrue(actualObjs.indexOf(FWD2) < actualObjs.indexOf(FWD4));
240 assertTrue(actualObjs.indexOf(FWD4) < actualObjs.indexOf(FWD6));
241
242 verify(mgr.flowObjectiveStore);
243 }
244
245 @Test
Charles Chan45c19d72018-04-19 21:38:40 -0700246 public void forwardTimeout() {
Charles Chan1491b9b2018-11-27 21:33:33 +0800247 final AtomicInteger counter = new AtomicInteger(0);
248 ForwardingObjective fwdTimeout = buildFwdObjective(S1, NID2).add(new ObjectiveContext() {
249 @Override
250 public void onError(Objective objective, ObjectiveError error) {
251 if (Objects.equals(ObjectiveError.INSTALLATIONTIMEOUT, error)) {
252 counter.incrementAndGet();
253 }
254 }
255 });
256 List<ForwardingObjective> expectFwdObjsTimeout = Lists.newCopyOnWriteArrayList(
257 Lists.newArrayList(fwdTimeout, FWD1, FWD2));
258
259 // Reduce timeout so the unit test doesn't have to wait many seconds
Charles Chanb4f4fdb2018-12-21 13:55:29 -0800260 internalSetup(TIMEOUT_THRESH);
Charles Chan1491b9b2018-11-27 21:33:33 +0800261
Charles Chanc51852e2019-01-07 19:59:10 -0800262 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(NGRP1).times(1);
Charles Chan45c19d72018-04-19 21:38:40 -0700263 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(NGRP2).times(2);
264 replay(mgr.flowObjectiveStore);
265
266 // Force this objective to time out
pierventre13a72352020-10-27 16:08:48 +0100267 offset = mgr.objectiveTimeoutMs * 3;
Charles Chan45c19d72018-04-19 21:38:40 -0700268
269 expectFwdObjsTimeout.forEach(fwdObj -> mgr.forward(DEV1, fwdObj));
270
271 // Wait for the pipeline operation to complete
272 int expectedTime = (bound + offset) * 3;
273 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectFwdObjsTimeout.size(), actualObjs.size()));
274
Charles Chanb4f4fdb2018-12-21 13:55:29 -0800275 assertAfter(expectedTime, expectedTime * 5, () -> assertTrue(counter.get() != 0));
Charles Chan1491b9b2018-11-27 21:33:33 +0800276 assertTrue(actualObjs.indexOf(fwdTimeout) < actualObjs.indexOf(FWD1));
Charles Chan45c19d72018-04-19 21:38:40 -0700277
278 verify(mgr.flowObjectiveStore);
279 }
280
281 @Test
282 public void forwardPending() {
Charles Chana7903c82018-03-15 20:14:16 -0700283 // Note: current logic will double check if the next obj need to be queued
284 // it does not check when resubmitting pending next back to the queue
285 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(null).times(2);
286 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(null).times(2);
287 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(NGRP1).times(3);
288 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(NGRP2).times(3);
289 replay(mgr.flowObjectiveStore);
290
291 expectFwdObjs.forEach(fwdObj -> mgr.forward(DEV1, fwdObj));
292
293 // Trigger the next objectives
294 mgr.next(DEV1, NEXT1);
295 mgr.next(DEV1, NEXT2);
296
297 // Wait for the pipeline operation to complete
Charles Chan45c19d72018-04-19 21:38:40 -0700298 int expectedTime = (bound + offset) * 8;
Charles Chana7903c82018-03-15 20:14:16 -0700299 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectFwdObjs.size() + 2, actualObjs.size()));
300
301 assertTrue(actualObjs.indexOf(NEXT1) < actualObjs.indexOf(FWD1));
302 assertTrue(actualObjs.indexOf(FWD1) < actualObjs.indexOf(FWD3));
303 assertTrue(actualObjs.indexOf(FWD3) < actualObjs.indexOf(FWD5));
304 assertTrue(actualObjs.indexOf(NEXT2) < actualObjs.indexOf(FWD2));
305 assertTrue(actualObjs.indexOf(FWD2) < actualObjs.indexOf(FWD4));
306 assertTrue(actualObjs.indexOf(FWD4) < actualObjs.indexOf(FWD6));
307
308 verify(mgr.flowObjectiveStore);
309 }
310
311 @Test
Charles Chan45c19d72018-04-19 21:38:40 -0700312 public void next() {
Charles Chana7903c82018-03-15 20:14:16 -0700313 // Note: ADD operation won't query this
314 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(NGRP1).times(3);
315 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(NGRP2).times(3);
316 replay(mgr.flowObjectiveStore);
317
318 expectNextObjs.forEach(nextObj -> mgr.next(DEV1, nextObj));
319
320 // Wait for the pipeline operation to complete
Charles Chan45c19d72018-04-19 21:38:40 -0700321 int expectedTime = (bound + offset) * 8;
Charles Chana7903c82018-03-15 20:14:16 -0700322 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectNextObjs.size(), actualObjs.size()));
323
324 assertTrue(actualObjs.indexOf(NEXT1) < actualObjs.indexOf(NEXT3));
325 assertTrue(actualObjs.indexOf(NEXT3) < actualObjs.indexOf(NEXT5));
326 assertTrue(actualObjs.indexOf(NEXT5) < actualObjs.indexOf(NEXT7));
327 assertTrue(actualObjs.indexOf(NEXT2) < actualObjs.indexOf(NEXT4));
328 assertTrue(actualObjs.indexOf(NEXT4) < actualObjs.indexOf(NEXT6));
329 assertTrue(actualObjs.indexOf(NEXT6) < actualObjs.indexOf(NEXT8));
330
331 verify(mgr.flowObjectiveStore);
332 }
333
334 // FIXME We currently do not handle the case when an app sends edit/remove of a next id before add.
335 // The edit/remove operation will be queued by pendingNext, and the add operation will be
336 // queued by the ordering queue forever due to the deadlock. This can be improved by making
337 // pendingForwards, pendingNexts and ordering queue caches.
338 @Test
339 @Ignore("Not supported")
Charles Chan45c19d72018-04-19 21:38:40 -0700340 public void nextPending() {
Charles Chana7903c82018-03-15 20:14:16 -0700341 // Note: current logic will double check if the next obj need to be queued
342 // it does not check when resubmitting pending next back to the queue
343 expect(mgr.flowObjectiveStore.getNextGroup(NID1)).andReturn(null).times(6);
344 expect(mgr.flowObjectiveStore.getNextGroup(NID2)).andReturn(null).times(6);
345 replay(mgr.flowObjectiveStore);
346
347 expectNextObjsPending.forEach(nextObj -> mgr.next(DEV1, nextObj));
348
349 // Wait for the pipeline operation to complete
Charles Chan45c19d72018-04-19 21:38:40 -0700350 int expectedTime = (bound + offset) * 8;
Charles Chana7903c82018-03-15 20:14:16 -0700351 assertAfter(expectedTime, expectedTime * 5, () -> assertEquals(expectNextObjs.size(), actualObjs.size()));
352
353 assertTrue(actualObjs.indexOf(NEXT1) < actualObjs.indexOf(NEXT5));
354 assertTrue(actualObjs.indexOf(NEXT5) < actualObjs.indexOf(NEXT3));
355 assertTrue(actualObjs.indexOf(NEXT3) < actualObjs.indexOf(NEXT7));
356 assertTrue(actualObjs.indexOf(NEXT2) < actualObjs.indexOf(NEXT6));
357 assertTrue(actualObjs.indexOf(NEXT6) < actualObjs.indexOf(NEXT4));
358 assertTrue(actualObjs.indexOf(NEXT4) < actualObjs.indexOf(NEXT8));
359
360 verify(mgr.flowObjectiveStore);
361 }
362
363 /**
364 * Creates filtering objective builder with a serial number encoded in MPLS label.
365 * The serial number is used to identify same objective that occurs multiple times.
366 *
367 * @param portnum Port number
368 * @param vlanId VLAN Id
369 * @param mac MAC address
370 * @param serial Serial number
371 * @return Filtering objective builder
372 */
373 private static FilteringObjective.Builder buildFilteringObjective(PortNumber portnum, VlanId vlanId,
374 MacAddress mac, int serial) {
375 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
376 fob.withKey(Criteria.matchInPort(portnum))
377 .addCondition(Criteria.matchEthDst(mac))
378 .addCondition(Criteria.matchVlanId(VlanId.NONE))
379 .addCondition(Criteria.matchMplsLabel(MplsLabel.mplsLabel(serial)))
380 .withPriority(PRIORITY);
381
382 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
383 tBuilder.pushVlan().setVlanId(vlanId);
384 fob.withMeta(tBuilder.build());
385
386 fob.permit().fromApp(APP_ID);
387 return fob;
388 }
389
390 /**
391 * Creates next objective builder.
392 *
393 * @param nextId next ID
394 * @param vlanId VLAN ID
395 * @param ports Set of ports that is in the given VLAN ID
396 *
397 * @return Next objective builder
398 */
399 private static NextObjective.Builder buildNextObjective(int nextId, VlanId vlanId, Collection<PortNumber> ports) {
400 TrafficSelector metadata =
401 DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
402
403 NextObjective.Builder nextObjBuilder = DefaultNextObjective
404 .builder().withId(nextId)
405 .withType(NextObjective.Type.BROADCAST).fromApp(APP_ID)
406 .withMeta(metadata);
407
408 ports.forEach(port -> {
409 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
410 tBuilder.popVlan();
411 tBuilder.setOutput(port);
412 nextObjBuilder.addTreatment(tBuilder.build());
413 });
414
415 return nextObjBuilder;
416 }
417
418 /**
419 * Creates forwarding objective builder.
420 *
421 * @param selector Traffic selector
422 * @param nextId next ID
423 * @return Forwarding objective builder
424 */
425 private static ForwardingObjective.Builder buildFwdObjective(TrafficSelector selector, int nextId) {
426 return DefaultForwardingObjective.builder()
427 .makePermanent()
428 .withSelector(selector)
429 .nextStep(nextId)
430 .fromApp(APP_ID)
431 .withPriority(PRIORITY)
432 .withFlag(ForwardingObjective.Flag.SPECIFIC);
433 }
434}