Saurav Das
Committed by Gerrit Code Review

CORD-354 OF-DPA support for link-failures.

Bug fix in flowObjectives store. Adding a removeNextGroup API to the store.

Change-Id: I5890411e5b4eabdc057402687ada26e539500f8f
...@@ -597,11 +597,20 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -597,11 +597,20 @@ public class SegmentRoutingManager implements SegmentRoutingService {
597 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED || 597 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
598 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || 598 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
599 event.type() == DeviceEvent.Type.DEVICE_UPDATED) { 599 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
600 - if (deviceService.isAvailable(((Device) event.subject()).id())) { 600 + DeviceId deviceId = ((Device) event.subject()).id();
601 + if (deviceService.isAvailable(deviceId)) {
601 log.info("Processing device event {} for available device {}", 602 log.info("Processing device event {} for available device {}",
602 event.type(), ((Device) event.subject()).id()); 603 event.type(), ((Device) event.subject()).id());
603 processDeviceAdded((Device) event.subject()); 604 processDeviceAdded((Device) event.subject());
605 + } /* else {
606 + if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
607 + // availability changed and not available - dev gone
608 + DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
609 + if (groupHandler != null) {
610 + groupHandler.removeAllGroups();
611 + }
604 } 612 }
613 + }*/
605 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { 614 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
606 processPortRemoved((Device) event.subject(), 615 processPortRemoved((Device) event.subject(),
607 ((DeviceEvent) event).port()); 616 ((DeviceEvent) event).port());
...@@ -655,7 +664,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -655,7 +664,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
655 log.debug("A link {} was removed", link.toString()); 664 log.debug("A link {} was removed", link.toString());
656 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId()); 665 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
657 if (groupHandler != null) { 666 if (groupHandler != null) {
658 - groupHandler.portDown(link.src().port()); 667 + groupHandler.portDown(link.src().port(),
668 + mastershipService.isLocalMaster(link.src().deviceId()));
659 } 669 }
660 log.trace("Starting optimized route population process"); 670 log.trace("Starting optimized route population process");
661 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link); 671 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
...@@ -711,7 +721,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -711,7 +721,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
711 log.debug("Port {} was removed", port.toString()); 721 log.debug("Port {} was removed", port.toString());
712 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); 722 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
713 if (groupHandler != null) { 723 if (groupHandler != null) {
714 - groupHandler.portDown(port.number()); 724 + groupHandler.portDown(port.number(),
725 + mastershipService.isLocalMaster(device.id()));
715 } 726 }
716 } 727 }
717 728
......
...@@ -32,11 +32,13 @@ import org.onlab.packet.Ip4Prefix; ...@@ -32,11 +32,13 @@ import org.onlab.packet.Ip4Prefix;
32 import org.onlab.packet.IpPrefix; 32 import org.onlab.packet.IpPrefix;
33 import org.onlab.packet.MacAddress; 33 import org.onlab.packet.MacAddress;
34 import org.onlab.packet.MplsLabel; 34 import org.onlab.packet.MplsLabel;
35 +import org.onlab.packet.VlanId;
35 import org.onlab.util.KryoNamespace; 36 import org.onlab.util.KryoNamespace;
36 import org.onosproject.core.ApplicationId; 37 import org.onosproject.core.ApplicationId;
37 import org.onosproject.net.DeviceId; 38 import org.onosproject.net.DeviceId;
38 import org.onosproject.net.Link; 39 import org.onosproject.net.Link;
39 import org.onosproject.net.PortNumber; 40 import org.onosproject.net.PortNumber;
41 +import org.onosproject.net.flow.DefaultTrafficSelector;
40 import org.onosproject.net.flow.DefaultTrafficTreatment; 42 import org.onosproject.net.flow.DefaultTrafficTreatment;
41 import org.onosproject.net.flow.TrafficSelector; 43 import org.onosproject.net.flow.TrafficSelector;
42 import org.onosproject.net.flow.TrafficTreatment; 44 import org.onosproject.net.flow.TrafficTreatment;
...@@ -49,6 +51,7 @@ import org.onosproject.net.flowobjective.ObjectiveError; ...@@ -49,6 +51,7 @@ import org.onosproject.net.flowobjective.ObjectiveError;
49 import org.onosproject.net.group.DefaultGroupKey; 51 import org.onosproject.net.group.DefaultGroupKey;
50 import org.onosproject.net.group.GroupKey; 52 import org.onosproject.net.group.GroupKey;
51 import org.onosproject.net.link.LinkService; 53 import org.onosproject.net.link.LinkService;
54 +import org.onosproject.segmentrouting.SegmentRoutingManager;
52 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; 55 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
53 import org.onosproject.segmentrouting.config.DeviceProperties; 56 import org.onosproject.segmentrouting.config.DeviceProperties;
54 import org.onosproject.store.service.EventuallyConsistentMap; 57 import org.onosproject.store.service.EventuallyConsistentMap;
...@@ -71,9 +74,11 @@ public class DefaultGroupHandler { ...@@ -71,9 +74,11 @@ public class DefaultGroupHandler {
71 protected MacAddress nodeMacAddr = null; 74 protected MacAddress nodeMacAddr = null;
72 protected LinkService linkService; 75 protected LinkService linkService;
73 protected FlowObjectiveService flowObjectiveService; 76 protected FlowObjectiveService flowObjectiveService;
74 - 77 + // local store for neighbor-device-ids and the set of ports on this device
78 + // that connect to the same neighbor
75 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap = 79 protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
76 new ConcurrentHashMap<>(); 80 new ConcurrentHashMap<>();
81 + //local store for ports on this device connected to neighbor-device-id
77 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap = 82 protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
78 new ConcurrentHashMap<>(); 83 new ConcurrentHashMap<>();
79 protected EventuallyConsistentMap< 84 protected EventuallyConsistentMap<
...@@ -225,6 +230,9 @@ public class DefaultGroupHandler { ...@@ -225,6 +230,9 @@ public class DefaultGroupHandler {
225 deviceId, 230 deviceId,
226 nsSet); 231 nsSet);
227 for (NeighborSet ns : nsSet) { 232 for (NeighborSet ns : nsSet) {
233 + Integer nextId = nsNextObjStore.
234 + get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
235 + if (nextId != null && isMaster) {
228 // Create the new bucket to be updated 236 // Create the new bucket to be updated
229 TrafficTreatment.Builder tBuilder = 237 TrafficTreatment.Builder tBuilder =
230 DefaultTrafficTreatment.builder(); 238 DefaultTrafficTreatment.builder();
...@@ -236,15 +244,19 @@ public class DefaultGroupHandler { ...@@ -236,15 +244,19 @@ public class DefaultGroupHandler {
236 .copyTtlOut() 244 .copyTtlOut()
237 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 245 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
238 } 246 }
239 - 247 + // setup metadata to pass to nextObjective - indicate the vlan on egress
240 - Integer nextId = nsNextObjStore. 248 + // if needed by the switch pipeline. Since hashed next-hops are always to
241 - get(new NeighborSetNextObjectiveStoreKey(deviceId, ns)); 249 + // other neighboring routers, there is no subnet assigned on those ports.
242 - if (nextId != null && isMaster) { 250 + TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
243 - NextObjective.Builder nextObjBuilder = DefaultNextObjective 251 + metabuilder.matchVlanId(
244 - .builder().withId(nextId) 252 + VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
245 - .withType(NextObjective.Type.HASHED).fromApp(appId); 253 +
246 - 254 + NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
247 - nextObjBuilder.addTreatment(tBuilder.build()); 255 + .withId(nextId)
256 + .withType(NextObjective.Type.HASHED)
257 + .addTreatment(tBuilder.build())
258 + .withMeta(metabuilder.build())
259 + .fromApp(appId);
248 log.info("**linkUp in device {}: Adding Bucket " 260 log.info("**linkUp in device {}: Adding Bucket "
249 + "with Port {} to next object id {}", 261 + "with Port {} to next object id {}",
250 deviceId, 262 deviceId,
...@@ -253,6 +265,18 @@ public class DefaultGroupHandler { ...@@ -253,6 +265,18 @@ public class DefaultGroupHandler {
253 NextObjective nextObjective = nextObjBuilder. 265 NextObjective nextObjective = nextObjBuilder.
254 addToExisting(new SRNextObjectiveContext(deviceId)); 266 addToExisting(new SRNextObjectiveContext(deviceId));
255 flowObjectiveService.next(deviceId, nextObjective); 267 flowObjectiveService.next(deviceId, nextObjective);
268 +
269 + // the addition of a bucket may actually change the neighborset
270 + // update the global store
271 + /*
272 + Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
273 + boolean newadd = neighbors.add(newLink.dst().deviceId());
274 + if (newadd) {
275 + NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
276 + nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
277 + nextId);
278 + nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
279 + }*/
256 } else if (isMaster) { 280 } else if (isMaster) {
257 log.warn("linkUp in device {}, but global store has no record " 281 log.warn("linkUp in device {}, but global store has no record "
258 + "for neighbor-set {}", deviceId, ns); 282 + "for neighbor-set {}", deviceId, ns);
...@@ -265,7 +289,7 @@ public class DefaultGroupHandler { ...@@ -265,7 +289,7 @@ public class DefaultGroupHandler {
265 * 289 *
266 * @param port port number that has gone down 290 * @param port port number that has gone down
267 */ 291 */
268 - public void portDown(PortNumber port) { 292 + public void portDown(PortNumber port, boolean isMaster) {
269 if (portDeviceMap.get(port) == null) { 293 if (portDeviceMap.get(port) == null) {
270 log.warn("portDown: unknown port"); 294 log.warn("portDown: unknown port");
271 return; 295 return;
...@@ -292,10 +316,17 @@ public class DefaultGroupHandler { ...@@ -292,10 +316,17 @@ public class DefaultGroupHandler {
292 .filter((ns) -> (ns.getDeviceIds() 316 .filter((ns) -> (ns.getDeviceIds()
293 .contains(portDeviceMap.get(port)))) 317 .contains(portDeviceMap.get(port))))
294 .collect(Collectors.toSet()); 318 .collect(Collectors.toSet());
295 - log.trace("portDown: nsNextObjStore contents for device {}:", 319 + log.debug("portDown: nsNextObjStore contents for device {}:{}",
296 - deviceId, 320 + deviceId, nsSet);
297 - nsSet);
298 for (NeighborSet ns : nsSet) { 321 for (NeighborSet ns : nsSet) {
322 + Integer nextId = nsNextObjStore.
323 + get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
324 + if (nextId != null && isMaster) {
325 + log.info("**portDown in device {}: Removing Bucket "
326 + + "with Port {} to next object id {}",
327 + deviceId,
328 + port,
329 + nextId);
299 // Create the bucket to be removed 330 // Create the bucket to be removed
300 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment 331 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
301 .builder(); 332 .builder();
...@@ -307,25 +338,28 @@ public class DefaultGroupHandler { ...@@ -307,25 +338,28 @@ public class DefaultGroupHandler {
307 .copyTtlOut() 338 .copyTtlOut()
308 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 339 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
309 } 340 }
310 -
311 - Integer nextId = nsNextObjStore.
312 - get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
313 - if (nextId != null) {
314 NextObjective.Builder nextObjBuilder = DefaultNextObjective 341 NextObjective.Builder nextObjBuilder = DefaultNextObjective
315 - .builder().withType(NextObjective.Type.SIMPLE).withId(nextId).fromApp(appId); 342 + .builder()
343 + .withType(NextObjective.Type.HASHED) //same as original
344 + .withId(nextId)
345 + .fromApp(appId)
346 + .addTreatment(tBuilder.build());
347 + NextObjective nextObjective = nextObjBuilder.
348 + removeFromExisting(new SRNextObjectiveContext(deviceId));
316 349
317 - nextObjBuilder.addTreatment(tBuilder.build()); 350 + flowObjectiveService.next(deviceId, nextObjective);
318 351
319 - log.info("**portDown in device {}: Removing Bucket " 352 + // the removal of a bucket may actually change the neighborset
320 - + "with Port {} to next object id {}", 353 + // update the global store
321 - deviceId, 354 + /*
322 - port, 355 + Set<DeviceId> neighbors = new HashSet<DeviceId>(ns.getDeviceIds());
356 + boolean removed = neighbors.remove(portDeviceMap.get(port));
357 + if (removed) {
358 + NeighborSet nsnew = new NeighborSet(neighbors, ns.getEdgeLabel());
359 + nsNextObjStore.put(new NeighborSetNextObjectiveStoreKey(deviceId, nsnew),
323 nextId); 360 nextId);
324 - // should do removefromexisting and only if master 361 + nsNextObjStore.remove(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
325 - /*NextObjective nextObjective = nextObjBuilder. 362 + }*/
326 - remove(new SRNextObjectiveContext(deviceId));
327 -
328 - flowObjectiveService.next(deviceId, nextObjective);*/
329 } 363 }
330 364
331 } 365 }
...@@ -718,6 +752,22 @@ public class DefaultGroupHandler { ...@@ -718,6 +752,22 @@ public class DefaultGroupHandler {
718 return false; 752 return false;
719 } 753 }
720 754
755 + public void removeAllGroups() {
756 + for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
757 + nsNextObjStore.entrySet()) {
758 + removeGroup(entry.getValue());
759 + }
760 + for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
761 + portNextObjStore.entrySet()) {
762 + removeGroup(entry.getValue());
763 + }
764 + for (Map.Entry<SubnetNextObjectiveStoreKey, Integer> entry:
765 + subnetNextObjStore.entrySet()) {
766 + removeGroup(entry.getValue());
767 + }
768 + // should probably clean local stores port-neighbor
769 + }
770 +
721 protected static class SRNextObjectiveContext implements ObjectiveContext { 771 protected static class SRNextObjectiveContext implements ObjectiveContext {
722 final DeviceId deviceId; 772 final DeviceId deviceId;
723 773
......
...@@ -27,7 +27,8 @@ public interface FlowObjectiveStore ...@@ -27,7 +27,8 @@ public interface FlowObjectiveStore
27 extends Store<ObjectiveEvent, FlowObjectiveStoreDelegate> { 27 extends Store<ObjectiveEvent, FlowObjectiveStoreDelegate> {
28 28
29 /** 29 /**
30 - * Adds a NextGroup to the store. 30 + * Adds a NextGroup to the store, by mapping it to the nextId as key,
31 + * and replacing any previous mapping.
31 * 32 *
32 * @param nextId an integer 33 * @param nextId an integer
33 * @param group a next group opaque object 34 * @param group a next group opaque object
...@@ -36,12 +37,22 @@ public interface FlowObjectiveStore ...@@ -36,12 +37,22 @@ public interface FlowObjectiveStore
36 37
37 /** 38 /**
38 * Fetch a next group from the store. 39 * Fetch a next group from the store.
39 - * @param nextId an integer 40 + *
40 - * @return a next group 41 + * @param nextId an integer used as key
42 + * @return a next group, or null if group was not found
41 */ 43 */
42 NextGroup getNextGroup(Integer nextId); 44 NextGroup getNextGroup(Integer nextId);
43 45
44 /** 46 /**
47 + * Remove a next group mapping from the store.
48 + *
49 + * @param nextId the key to remove from the store.
50 + * @return the next group which mapped to the nextId and is now removed, or
51 + * null if no group mapping existed in the store
52 + */
53 + NextGroup removeNextGroup(Integer nextId);
54 +
55 + /**
45 * Allocates a next objective id. This id is globally unique 56 * Allocates a next objective id. This id is globally unique
46 * 57 *
47 * @return an integer 58 * @return an integer
......
...@@ -48,6 +48,7 @@ import org.onosproject.net.flowobjective.NextObjective; ...@@ -48,6 +48,7 @@ import org.onosproject.net.flowobjective.NextObjective;
48 import org.onosproject.net.flowobjective.Objective; 48 import org.onosproject.net.flowobjective.Objective;
49 import org.onosproject.net.flowobjective.ObjectiveError; 49 import org.onosproject.net.flowobjective.ObjectiveError;
50 import org.onosproject.net.flowobjective.ObjectiveEvent; 50 import org.onosproject.net.flowobjective.ObjectiveEvent;
51 +import org.onosproject.net.flowobjective.ObjectiveEvent.Type;
51 import org.onosproject.net.group.GroupService; 52 import org.onosproject.net.group.GroupService;
52 import org.slf4j.Logger; 53 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory; 54 import org.slf4j.LoggerFactory;
...@@ -381,6 +382,7 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -381,6 +382,7 @@ public class FlowObjectiveManager implements FlowObjectiveService {
381 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate { 382 private class InternalStoreDelegate implements FlowObjectiveStoreDelegate {
382 @Override 383 @Override
383 public void notify(ObjectiveEvent event) { 384 public void notify(ObjectiveEvent event) {
385 + if (event.type() == Type.ADD) {
384 log.debug("Received notification of obj event {}", event); 386 log.debug("Received notification of obj event {}", event);
385 Set<PendingNext> pending = pendingForwards.remove(event.subject()); 387 Set<PendingNext> pending = pendingForwards.remove(event.subject());
386 388
...@@ -390,10 +392,9 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -390,10 +392,9 @@ public class FlowObjectiveManager implements FlowObjectiveService {
390 } 392 }
391 393
392 log.debug("Processing pending forwarding objectives {}", pending.size()); 394 log.debug("Processing pending forwarding objectives {}", pending.size());
393 -
394 pending.forEach(p -> getDevicePipeliner(p.deviceId()) 395 pending.forEach(p -> getDevicePipeliner(p.deviceId())
395 .forward(p.forwardingObjective())); 396 .forward(p.forwardingObjective()));
396 - 397 + }
397 } 398 }
398 } 399 }
399 400
......
...@@ -79,10 +79,9 @@ public class DistributedFlowObjectiveStore ...@@ -79,10 +79,9 @@ public class DistributedFlowObjectiveStore
79 log.info("Stopped"); 79 log.info("Stopped");
80 } 80 }
81 81
82 -
83 @Override 82 @Override
84 public void putNextGroup(Integer nextId, NextGroup group) { 83 public void putNextGroup(Integer nextId, NextGroup group) {
85 - nextGroups.putIfAbsent(nextId, group.data()); 84 + nextGroups.put(nextId, group.data());
86 notifyDelegate(new ObjectiveEvent(ObjectiveEvent.Type.ADD, nextId)); 85 notifyDelegate(new ObjectiveEvent(ObjectiveEvent.Type.ADD, nextId));
87 } 86 }
88 87
...@@ -96,6 +95,16 @@ public class DistributedFlowObjectiveStore ...@@ -96,6 +95,16 @@ public class DistributedFlowObjectiveStore
96 } 95 }
97 96
98 @Override 97 @Override
98 + public NextGroup removeNextGroup(Integer nextId) {
99 + Versioned<byte[]> versionGroup = nextGroups.remove(nextId);
100 + if (versionGroup != null) {
101 + notifyDelegate(new ObjectiveEvent(ObjectiveEvent.Type.REMOVE, nextId));
102 + return new DefaultNextGroup(versionGroup.value());
103 + }
104 + return null;
105 + }
106 +
107 + @Override
99 public int allocateNextId() { 108 public int allocateNextId() {
100 return (int) nextIds.incrementAndGet(); 109 return (int) nextIds.incrementAndGet();
101 } 110 }
......
...@@ -71,7 +71,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -71,7 +71,6 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
71 * (non-Javadoc) 71 * (non-Javadoc)
72 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter 72 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
73 */ 73 */
74 -
75 @Override 74 @Override
76 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion, 75 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
77 VlanIdCriterion vidCriterion, 76 VlanIdCriterion vidCriterion,
...@@ -267,7 +266,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -267,7 +266,8 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
267 } 266 }
268 267
269 if (fwd.nextId() != null) { 268 if (fwd.nextId() != null) {
270 - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); 269 + NextGroup next = getGroupForNextObjective(fwd.nextId());
270 + if (next != null) {
271 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); 271 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
272 // we only need the top level group's key to point the flow to it 272 // we only need the top level group's key to point the flow to it
273 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); 273 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
...@@ -278,6 +278,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -278,6 +278,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
278 } 278 }
279 tb.deferred().group(group.id()); 279 tb.deferred().group(group.id());
280 } 280 }
281 + }
281 tb.transition(ACL_TABLE); 282 tb.transition(ACL_TABLE);
282 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() 283 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
283 .fromApp(fwd.appId()) 284 .fromApp(fwd.appId())
......