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
Showing
7 changed files
with
433 additions
and
167 deletions
... | @@ -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()) | ... | ... |
... | @@ -94,7 +94,6 @@ import org.onosproject.net.group.GroupEvent; | ... | @@ -94,7 +94,6 @@ import org.onosproject.net.group.GroupEvent; |
94 | import org.onosproject.net.group.GroupKey; | 94 | import org.onosproject.net.group.GroupKey; |
95 | import org.onosproject.net.group.GroupListener; | 95 | import org.onosproject.net.group.GroupListener; |
96 | import org.onosproject.net.group.GroupService; | 96 | import org.onosproject.net.group.GroupService; |
97 | -import org.onosproject.net.packet.PacketService; | ||
98 | import org.onosproject.store.serializers.KryoNamespaces; | 97 | import org.onosproject.store.serializers.KryoNamespaces; |
99 | import org.slf4j.Logger; | 98 | import org.slf4j.Logger; |
100 | 99 | ||
... | @@ -149,7 +148,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -149,7 +148,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
149 | protected FlowObjectiveStore flowObjectiveStore; | 148 | protected FlowObjectiveStore flowObjectiveStore; |
150 | protected DeviceId deviceId; | 149 | protected DeviceId deviceId; |
151 | protected ApplicationId driverId; | 150 | protected ApplicationId driverId; |
152 | - protected PacketService packetService; | ||
153 | protected DeviceService deviceService; | 151 | protected DeviceService deviceService; |
154 | protected KryoNamespace appKryo = new KryoNamespace.Builder() | 152 | protected KryoNamespace appKryo = new KryoNamespace.Builder() |
155 | .register(KryoNamespaces.API) | 153 | .register(KryoNamespaces.API) |
... | @@ -174,6 +172,10 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -174,6 +172,10 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
174 | Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<VlanId, | 172 | Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<VlanId, |
175 | Set<PortNumber>>(); | 173 | Set<PortNumber>>(); |
176 | 174 | ||
175 | + // local store for pending bucketAdds - by design there can only be one | ||
176 | + // pending bucket for a group | ||
177 | + ConcurrentHashMap<Integer, NextObjective> pendingBuckets = new ConcurrentHashMap<>(); | ||
178 | + | ||
177 | // index number for group creation | 179 | // index number for group creation |
178 | AtomicInteger l3vpnindex = new AtomicInteger(0); | 180 | AtomicInteger l3vpnindex = new AtomicInteger(0); |
179 | 181 | ||
... | @@ -202,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -202,7 +204,6 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
202 | flowRuleService = serviceDirectory.get(FlowRuleService.class); | 204 | flowRuleService = serviceDirectory.get(FlowRuleService.class); |
203 | groupService = serviceDirectory.get(GroupService.class); | 205 | groupService = serviceDirectory.get(GroupService.class); |
204 | flowObjectiveStore = context.store(); | 206 | flowObjectiveStore = context.store(); |
205 | - packetService = serviceDirectory.get(PacketService.class); | ||
206 | deviceService = serviceDirectory.get(DeviceService.class); | 207 | deviceService = serviceDirectory.get(DeviceService.class); |
207 | groupService.addListener(new InnerGroupListener()); | 208 | groupService.addListener(new InnerGroupListener()); |
208 | 209 | ||
... | @@ -293,10 +294,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -293,10 +294,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
293 | if (nextGroup != null) { | 294 | if (nextGroup != null) { |
294 | log.debug("Processing NextObjective id{} in dev{} - add bucket", | 295 | log.debug("Processing NextObjective id{} in dev{} - add bucket", |
295 | nextObjective.id(), deviceId); | 296 | nextObjective.id(), deviceId); |
296 | - addBucketToGroup(nextObjective); | 297 | + addBucketToGroup(nextObjective, nextGroup); |
297 | } else { | 298 | } else { |
298 | // it is possible that group-chain has not been fully created yet | 299 | // it is possible that group-chain has not been fully created yet |
299 | - waitToAddBucketToGroup(nextObjective); | 300 | + log.debug("Waiting to add bucket to group for next-id:{} in dev:{}", |
301 | + nextObjective.id(), deviceId); | ||
302 | + // by design only one pending bucket is allowed for the group | ||
303 | + pendingBuckets.put(nextObjective.id(), nextObjective); | ||
300 | } | 304 | } |
301 | break; | 305 | break; |
302 | case REMOVE: | 306 | case REMOVE: |
... | @@ -307,7 +311,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -307,7 +311,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
307 | } | 311 | } |
308 | log.debug("Processing NextObjective id{} in dev{} - remove group", | 312 | log.debug("Processing NextObjective id{} in dev{} - remove group", |
309 | nextObjective.id(), deviceId); | 313 | nextObjective.id(), deviceId); |
310 | - removeGroup(nextObjective); | 314 | + removeGroup(nextObjective, nextGroup); |
311 | break; | 315 | break; |
312 | case REMOVE_FROM_EXISTING: | 316 | case REMOVE_FROM_EXISTING: |
313 | if (nextGroup == null) { | 317 | if (nextGroup == null) { |
... | @@ -317,7 +321,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -317,7 +321,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
317 | } | 321 | } |
318 | log.debug("Processing NextObjective id{} in dev{} - remove bucket", | 322 | log.debug("Processing NextObjective id{} in dev{} - remove bucket", |
319 | nextObjective.id(), deviceId); | 323 | nextObjective.id(), deviceId); |
320 | - removeBucketFromGroup(nextObjective); | 324 | + removeBucketFromGroup(nextObjective, nextGroup); |
321 | break; | 325 | break; |
322 | default: | 326 | default: |
323 | log.warn("Unsupported operation {}", nextObjective.op()); | 327 | log.warn("Unsupported operation {}", nextObjective.op()); |
... | @@ -791,7 +795,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -791,7 +795,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
791 | return Collections.emptySet(); | 795 | return Collections.emptySet(); |
792 | } | 796 | } |
793 | 797 | ||
794 | - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); | 798 | + NextGroup next = getGroupForNextObjective(fwd.nextId()); |
799 | + if (next != null) { | ||
795 | List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); | 800 | List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); |
796 | // we only need the top level group's key to point the flow to it | 801 | // we only need the top level group's key to point the flow to it |
797 | Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); | 802 | Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst()); |
... | @@ -803,6 +808,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -803,6 +808,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
803 | } | 808 | } |
804 | tb.deferred().group(group.id()); | 809 | tb.deferred().group(group.id()); |
805 | } | 810 | } |
811 | + } | ||
806 | tb.transition(ACL_TABLE); | 812 | tb.transition(ACL_TABLE); |
807 | FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() | 813 | FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() |
808 | .fromApp(fwd.appId()) | 814 | .fromApp(fwd.appId()) |
... | @@ -868,7 +874,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -868,7 +874,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
868 | 874 | ||
869 | TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); | 875 | TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); |
870 | if (fwd.nextId() != null) { | 876 | if (fwd.nextId() != null) { |
871 | - NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); | 877 | + NextGroup next = getGroupForNextObjective(fwd.nextId()); |
872 | if (next != null) { | 878 | if (next != null) { |
873 | List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); | 879 | List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); |
874 | // we only need the top level group's key to point the flow to it | 880 | // we only need the top level group's key to point the flow to it |
... | @@ -903,6 +909,23 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -903,6 +909,23 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
903 | return rules; | 909 | return rules; |
904 | } | 910 | } |
905 | 911 | ||
912 | + protected NextGroup getGroupForNextObjective(Integer nextId) { | ||
913 | + NextGroup next = flowObjectiveStore.getNextGroup(nextId); | ||
914 | + if (next != null) { | ||
915 | + List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); | ||
916 | + if (gkeys != null && !gkeys.isEmpty()) { | ||
917 | + return next; | ||
918 | + } else { | ||
919 | + log.warn("Empty next group found in FlowObjective store for " | ||
920 | + + "next-id:{} in dev:{}", nextId, deviceId); | ||
921 | + } | ||
922 | + } else { | ||
923 | + log.warn("next-id {} not found in Flow objective store for dev:{}", | ||
924 | + nextId, deviceId); | ||
925 | + } | ||
926 | + return null; | ||
927 | + } | ||
928 | + | ||
906 | private void pass(Objective obj) { | 929 | private void pass(Objective obj) { |
907 | if (obj.context().isPresent()) { | 930 | if (obj.context().isPresent()) { |
908 | obj.context().get().onSuccess(obj); | 931 | obj.context().get().onSuccess(obj); |
... | @@ -1013,6 +1036,16 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1013,6 +1036,16 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1013 | } | 1036 | } |
1014 | } | 1037 | } |
1015 | 1038 | ||
1039 | + private void updatePendingGroups(GroupKey gkey, GroupChainElem gce) { | ||
1040 | + Set<GroupChainElem> gceSet = Collections.newSetFromMap( | ||
1041 | + new ConcurrentHashMap<GroupChainElem, Boolean>()); | ||
1042 | + gceSet.add(gce); | ||
1043 | + Set<GroupChainElem> retval = pendingGroups.putIfAbsent(gkey, gceSet); | ||
1044 | + if (retval != null) { | ||
1045 | + retval.add(gce); | ||
1046 | + } | ||
1047 | + } | ||
1048 | + | ||
1016 | /** | 1049 | /** |
1017 | * Creates a simple L2 Interface Group. | 1050 | * Creates a simple L2 Interface Group. |
1018 | * | 1051 | * |
... | @@ -1242,14 +1275,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1242,14 +1275,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1242 | } | 1275 | } |
1243 | 1276 | ||
1244 | // store l2groupkey with the groupChainElem for the outer-group that depends on it | 1277 | // store l2groupkey with the groupChainElem for the outer-group that depends on it |
1245 | - GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1); | 1278 | + GroupChainElem gce = new GroupChainElem(outerGrpDesc, 1, false); |
1246 | - Set<GroupChainElem> gceSet = Collections.newSetFromMap( | 1279 | + updatePendingGroups(l2groupkey, gce); |
1247 | - new ConcurrentHashMap<GroupChainElem, Boolean>()); | ||
1248 | - gceSet.add(gce); | ||
1249 | - Set<GroupChainElem> retval = pendingGroups.putIfAbsent(l2groupkey, gceSet); | ||
1250 | - if (retval != null) { | ||
1251 | - retval.add(gce); | ||
1252 | - } | ||
1253 | 1280 | ||
1254 | // create group description for the inner l2interfacegroup | 1281 | // create group description for the inner l2interfacegroup |
1255 | GroupBucket l2interfaceGroupBucket = | 1282 | GroupBucket l2interfaceGroupBucket = |
... | @@ -1376,7 +1403,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1376,7 +1403,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1376 | l2floodgroupId, | 1403 | l2floodgroupId, |
1377 | nextObj.appId()); | 1404 | nextObj.appId()); |
1378 | GroupChainElem gce = new GroupChainElem(l2floodGroupDescription, | 1405 | GroupChainElem gce = new GroupChainElem(l2floodGroupDescription, |
1379 | - l2interfaceGroupDescs.size()); | 1406 | + l2interfaceGroupDescs.size(), |
1407 | + false); | ||
1380 | log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}", | 1408 | log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}", |
1381 | deviceId, Integer.toHexString(l2floodgroupId), | 1409 | deviceId, Integer.toHexString(l2floodgroupId), |
1382 | l2floodgroupkey, nextObj.id()); | 1410 | l2floodgroupkey, nextObj.id()); |
... | @@ -1392,16 +1420,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1392,16 +1420,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1392 | for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { | 1420 | for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { |
1393 | // store all l2groupkeys with the groupChainElem for the l2floodgroup | 1421 | // store all l2groupkeys with the groupChainElem for the l2floodgroup |
1394 | // that depends on it | 1422 | // that depends on it |
1395 | - Set<GroupChainElem> gceSet = Collections.newSetFromMap( | 1423 | + updatePendingGroups(l2intGrpDesc.appCookie(), gce); |
1396 | - new ConcurrentHashMap<GroupChainElem, Boolean>()); | 1424 | + // send groups for all l2 interface groups |
1397 | - gceSet.add(gce); | ||
1398 | - Set<GroupChainElem> retval = pendingGroups.putIfAbsent( | ||
1399 | - l2intGrpDesc.appCookie(), gceSet); | ||
1400 | - if (retval != null) { | ||
1401 | - retval.add(gce); | ||
1402 | - } | ||
1403 | - | ||
1404 | - // create and send groups for all l2 interface groups | ||
1405 | groupService.addGroup(l2intGrpDesc); | 1425 | groupService.addGroup(l2intGrpDesc); |
1406 | } | 1426 | } |
1407 | } | 1427 | } |
... | @@ -1430,17 +1450,81 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1430,17 +1450,81 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1430 | * <p> | 1450 | * <p> |
1431 | * NOTE: We do not create MPLS ECMP groups as they are unimplemented in | 1451 | * NOTE: We do not create MPLS ECMP groups as they are unimplemented in |
1432 | * OF-DPA 2.0 (even though it is in the spec). Therefore we do not | 1452 | * OF-DPA 2.0 (even though it is in the spec). Therefore we do not |
1433 | - * check the nextObjective meta. | 1453 | + * check the nextObjective meta to see what is matching before being |
1454 | + * sent to this nextObjective. | ||
1434 | * | 1455 | * |
1435 | * @param nextObj the nextObjective of type HASHED | 1456 | * @param nextObj the nextObjective of type HASHED |
1436 | */ | 1457 | */ |
1437 | private void processHashedNextObjective(NextObjective nextObj) { | 1458 | private void processHashedNextObjective(NextObjective nextObj) { |
1438 | - // break up hashed next objective to multiple groups | ||
1439 | - Collection<TrafficTreatment> buckets = nextObj.next(); | ||
1440 | - | ||
1441 | // storage for all group keys in the chain of groups created | 1459 | // storage for all group keys in the chain of groups created |
1442 | List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); | 1460 | List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); |
1443 | List<GroupInfo> unsentGroups = new ArrayList<>(); | 1461 | List<GroupInfo> unsentGroups = new ArrayList<>(); |
1462 | + createHashBucketChains(nextObj, allGroupKeys, unsentGroups); | ||
1463 | + | ||
1464 | + // now we can create the outermost L3 ECMP group | ||
1465 | + List<GroupBucket> l3ecmpGroupBuckets = new ArrayList<>(); | ||
1466 | + for (GroupInfo gi : unsentGroups) { | ||
1467 | + // create ECMP bucket to point to the outer group | ||
1468 | + TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | ||
1469 | + ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); | ||
1470 | + GroupBucket sbucket = DefaultGroupBucket | ||
1471 | + .createSelectGroupBucket(ttb.build()); | ||
1472 | + l3ecmpGroupBuckets.add(sbucket); | ||
1473 | + } | ||
1474 | + int l3ecmpGroupId = L3ECMPMASK | nextObj.id() << 12; | ||
1475 | + GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpGroupId)); | ||
1476 | + GroupDescription l3ecmpGroupDesc = | ||
1477 | + new DefaultGroupDescription( | ||
1478 | + deviceId, | ||
1479 | + GroupDescription.Type.SELECT, | ||
1480 | + new GroupBuckets(l3ecmpGroupBuckets), | ||
1481 | + l3ecmpGroupKey, | ||
1482 | + l3ecmpGroupId, | ||
1483 | + nextObj.appId()); | ||
1484 | + GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, | ||
1485 | + l3ecmpGroupBuckets.size(), | ||
1486 | + false); | ||
1487 | + | ||
1488 | + // create objects for local and distributed storage | ||
1489 | + allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l3ecmpGroupKey)); | ||
1490 | + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); | ||
1491 | + | ||
1492 | + // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective | ||
1493 | + // that depends on it | ||
1494 | + updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp); | ||
1495 | + | ||
1496 | + log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", | ||
1497 | + deviceId, Integer.toHexString(l3ecmpGroupId), | ||
1498 | + l3ecmpGroupKey, nextObj.id()); | ||
1499 | + // finally we are ready to send the innermost groups | ||
1500 | + for (GroupInfo gi : unsentGroups) { | ||
1501 | + log.debug("Sending innermost group {} in group chain on device {} ", | ||
1502 | + Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); | ||
1503 | + updatePendingGroups(gi.outerGrpDesc.appCookie(), l3ecmpGce); | ||
1504 | + groupService.addGroup(gi.innerGrpDesc); | ||
1505 | + } | ||
1506 | + | ||
1507 | + } | ||
1508 | + | ||
1509 | + /** | ||
1510 | + * Creates group chains for all buckets in a hashed group, and stores the | ||
1511 | + * GroupInfos and GroupKeys for all the groups in the lists passed in, which | ||
1512 | + * should be empty. | ||
1513 | + * <p> | ||
1514 | + * Does not create the top level ECMP group. Does not actually send the | ||
1515 | + * groups to the groupService. | ||
1516 | + * | ||
1517 | + * @param nextObj the Next Objective with buckets that need to be converted | ||
1518 | + * to group chains | ||
1519 | + * @param allGroupKeys a list to store groupKey for each bucket-group-chain | ||
1520 | + * @param unsentGroups a list to store GroupInfo for each bucket-group-chain | ||
1521 | + */ | ||
1522 | + private void createHashBucketChains(NextObjective nextObj, | ||
1523 | + List<Deque<GroupKey>> allGroupKeys, | ||
1524 | + List<GroupInfo> unsentGroups) { | ||
1525 | + // break up hashed next objective to multiple groups | ||
1526 | + Collection<TrafficTreatment> buckets = nextObj.next(); | ||
1527 | + | ||
1444 | for (TrafficTreatment bucket : buckets) { | 1528 | for (TrafficTreatment bucket : buckets) { |
1445 | //figure out how many labels are pushed in each bucket | 1529 | //figure out how many labels are pushed in each bucket |
1446 | int labelsPushed = 0; | 1530 | int labelsPushed = 0; |
... | @@ -1508,15 +1592,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1508,15 +1592,8 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1508 | l3vpngroupkey, | 1592 | l3vpngroupkey, |
1509 | l3vpngroupId, | 1593 | l3vpngroupId, |
1510 | nextObj.appId()); | 1594 | nextObj.appId()); |
1511 | - GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1); | 1595 | + GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1, false); |
1512 | - Set<GroupChainElem> gceSet = Collections.newSetFromMap( | 1596 | + updatePendingGroups(onelabelGroupInfo.outerGrpDesc.appCookie(), l3vpnGce); |
1513 | - new ConcurrentHashMap<GroupChainElem, Boolean>()); | ||
1514 | - gceSet.add(l3vpnGce); | ||
1515 | - Set<GroupChainElem> retval = pendingGroups | ||
1516 | - .putIfAbsent(onelabelGroupInfo.outerGrpDesc.appCookie(), gceSet); | ||
1517 | - if (retval != null) { | ||
1518 | - retval.add(l3vpnGce); | ||
1519 | - } | ||
1520 | 1597 | ||
1521 | gkeyChain.addFirst(onelabelGroupInfo.innerGrpDesc.appCookie()); | 1598 | gkeyChain.addFirst(onelabelGroupInfo.innerGrpDesc.appCookie()); |
1522 | gkeyChain.addFirst(onelabelGroupInfo.outerGrpDesc.appCookie()); | 1599 | gkeyChain.addFirst(onelabelGroupInfo.outerGrpDesc.appCookie()); |
... | @@ -1535,80 +1612,186 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1535,80 +1612,186 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1535 | 1612 | ||
1536 | } else { | 1613 | } else { |
1537 | log.warn("Driver currently does not handle more than 1 MPLS " | 1614 | log.warn("Driver currently does not handle more than 1 MPLS " |
1538 | - + "labels. Not processing nextObjective {}", nextObj); | 1615 | + + "labels. Not processing nextObjective {}", nextObj.id()); |
1539 | return; | 1616 | return; |
1540 | } | 1617 | } |
1541 | 1618 | ||
1542 | // all groups in this chain | 1619 | // all groups in this chain |
1543 | allGroupKeys.add(gkeyChain); | 1620 | allGroupKeys.add(gkeyChain); |
1544 | } | 1621 | } |
1622 | + } | ||
1545 | 1623 | ||
1546 | - // now we can create the outermost L3 ECMP group | 1624 | + /** |
1547 | - List<GroupBucket> l3ecmpGroupBuckets = new ArrayList<>(); | 1625 | + * Adds a bucket to the top level group of a group-chain, and creates the chain. |
1548 | - for (GroupInfo gi : unsentGroups) { | 1626 | + * |
1549 | - // create ECMP bucket to point to the outer group | 1627 | + * @param nextObjective the next group to add a bucket to |
1628 | + * @param next the representation of the existing group-chain for this next objective | ||
1629 | + */ | ||
1630 | + private void addBucketToGroup(NextObjective nextObjective, NextGroup next) { | ||
1631 | + if (nextObjective.type() != NextObjective.Type.HASHED) { | ||
1632 | + log.warn("AddBuckets not applied to nextType:{} in dev:{} for next:{}", | ||
1633 | + nextObjective.type(), deviceId, nextObjective.id()); | ||
1634 | + return; | ||
1635 | + } | ||
1636 | + if (nextObjective.next().size() > 1) { | ||
1637 | + log.warn("Only one bucket can be added at a time"); | ||
1638 | + return; | ||
1639 | + } | ||
1640 | + // storage for all group keys in the chain of groups created | ||
1641 | + List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); | ||
1642 | + List<GroupInfo> unsentGroups = new ArrayList<>(); | ||
1643 | + createHashBucketChains(nextObjective, allGroupKeys, unsentGroups); | ||
1644 | + | ||
1645 | + // now we can create the outermost L3 ECMP group bucket to add | ||
1646 | + GroupInfo gi = unsentGroups.get(0); // only one bucket, so only one group-chain | ||
1550 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | 1647 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); |
1551 | ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); | 1648 | ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); |
1552 | - GroupBucket sbucket = DefaultGroupBucket | 1649 | + GroupBucket sbucket = DefaultGroupBucket.createSelectGroupBucket(ttb.build()); |
1553 | - .createSelectGroupBucket(ttb.build()); | 1650 | + |
1554 | - l3ecmpGroupBuckets.add(sbucket); | 1651 | + // recreate the original L3 ECMP group id and description |
1555 | - } | 1652 | + int l3ecmpGroupId = L3ECMPMASK | nextObjective.id() << 12; |
1556 | - int l3ecmpGroupId = L3ECMPMASK | nextObj.id() << 12; | ||
1557 | GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpGroupId)); | 1653 | GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpGroupId)); |
1654 | + | ||
1655 | + // Although GroupDescriptions are not necessary for adding buckets to | ||
1656 | + // existing groups, we use one in the GroupChainElem. When the latter is | ||
1657 | + // processed, the info will be extracted for the bucketAdd call to groupService | ||
1558 | GroupDescription l3ecmpGroupDesc = | 1658 | GroupDescription l3ecmpGroupDesc = |
1559 | new DefaultGroupDescription( | 1659 | new DefaultGroupDescription( |
1560 | deviceId, | 1660 | deviceId, |
1561 | GroupDescription.Type.SELECT, | 1661 | GroupDescription.Type.SELECT, |
1562 | - new GroupBuckets(l3ecmpGroupBuckets), | 1662 | + new GroupBuckets(Collections.singletonList(sbucket)), |
1563 | l3ecmpGroupKey, | 1663 | l3ecmpGroupKey, |
1564 | l3ecmpGroupId, | 1664 | l3ecmpGroupId, |
1565 | - nextObj.appId()); | 1665 | + nextObjective.appId()); |
1566 | - GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, | 1666 | + GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, 1, true); |
1567 | - l3ecmpGroupBuckets.size()); | 1667 | + |
1568 | - | 1668 | + // update original NextGroup with new bucket-chain |
1569 | - // create objects for local and distributed storage | 1669 | + // don't need to update pendingNextObjectives -- group already exists |
1570 | - allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l3ecmpGroupKey)); | 1670 | + Deque<GroupKey> newBucketChain = allGroupKeys.get(0); |
1571 | - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); | 1671 | + newBucketChain.addFirst(l3ecmpGroupKey); |
1572 | - | 1672 | + List<Deque<GroupKey>> allOriginalKeys = appKryo.deserialize(next.data()); |
1573 | - // store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective | 1673 | + allOriginalKeys.add(newBucketChain); |
1574 | - // that depends on it | 1674 | + flowObjectiveStore.putNextGroup(nextObjective.id(), |
1575 | - updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp); | 1675 | + new OfdpaNextGroup(allOriginalKeys, nextObjective)); |
1576 | - | 1676 | + |
1577 | - log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", | 1677 | + log.debug("Adding to L3ECMP: device:{} gid:{} gkey:{} nextId:{}", |
1578 | deviceId, Integer.toHexString(l3ecmpGroupId), | 1678 | deviceId, Integer.toHexString(l3ecmpGroupId), |
1579 | - l3ecmpGroupKey, nextObj.id()); | 1679 | + l3ecmpGroupKey, nextObjective.id()); |
1580 | - // finally we are ready to send the innermost groups | 1680 | + // send the innermost group |
1581 | - for (GroupInfo gi : unsentGroups) { | ||
1582 | log.debug("Sending innermost group {} in group chain on device {} ", | 1681 | log.debug("Sending innermost group {} in group chain on device {} ", |
1583 | Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); | 1682 | Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); |
1584 | - Set<GroupChainElem> gceSet = Collections.newSetFromMap( | 1683 | + updatePendingGroups(gi.outerGrpDesc.appCookie(), l3ecmpGce); |
1585 | - new ConcurrentHashMap<GroupChainElem, Boolean>()); | ||
1586 | - gceSet.add(l3ecmpGce); | ||
1587 | - Set<GroupChainElem> retval = pendingGroups | ||
1588 | - .putIfAbsent(gi.outerGrpDesc.appCookie(), gceSet); | ||
1589 | - if (retval != null) { | ||
1590 | - retval.add(l3ecmpGce); | ||
1591 | - } | ||
1592 | - | ||
1593 | groupService.addGroup(gi.innerGrpDesc); | 1684 | groupService.addGroup(gi.innerGrpDesc); |
1594 | - } | ||
1595 | 1685 | ||
1596 | } | 1686 | } |
1597 | 1687 | ||
1598 | - private void addBucketToGroup(NextObjective nextObjective) { | 1688 | + /** |
1599 | - // TODO Auto-generated method stub | 1689 | + * Removes the bucket in the top level group of a possible group-chain. Does |
1690 | + * not remove the groups in a group-chain pointed to by this bucket, as they | ||
1691 | + * may be in use (referenced by other groups) elsewhere. | ||
1692 | + * | ||
1693 | + * @param nextObjective the next group to remove a bucket from | ||
1694 | + * @param next the representation of the existing group-chain for this next objective | ||
1695 | + */ | ||
1696 | + private void removeBucketFromGroup(NextObjective nextObjective, NextGroup next) { | ||
1697 | + if (nextObjective.type() != NextObjective.Type.HASHED) { | ||
1698 | + log.warn("RemoveBuckets not applied to nextType:{} in dev:{} for next:{}", | ||
1699 | + nextObjective.type(), deviceId, nextObjective.id()); | ||
1700 | + return; | ||
1600 | } | 1701 | } |
1601 | - | 1702 | + Collection<TrafficTreatment> treatments = nextObjective.next(); |
1602 | - private void waitToAddBucketToGroup(NextObjective nextObjective) { | 1703 | + TrafficTreatment treatment = treatments.iterator().next(); |
1603 | - // TODO Auto-generated method stub | 1704 | + // find the bucket to remove by noting the outport, and figuring out the |
1705 | + // top-level group in the group-chain that indirectly references the port | ||
1706 | + PortNumber outport = null; | ||
1707 | + for (Instruction ins : treatment.allInstructions()) { | ||
1708 | + if (ins instanceof OutputInstruction) { | ||
1709 | + outport = ((OutputInstruction) ins).port(); | ||
1710 | + break; | ||
1711 | + } | ||
1712 | + } | ||
1713 | + if (outport == null) { | ||
1714 | + log.error("next objective {} has no outport", nextObjective.id()); | ||
1715 | + return; | ||
1604 | } | 1716 | } |
1605 | 1717 | ||
1606 | - private void removeBucketFromGroup(NextObjective nextObjective) { | 1718 | + List<Deque<GroupKey>> allgkeys = appKryo.deserialize(next.data()); |
1607 | - // TODO Auto-generated method stub | 1719 | + Deque<GroupKey> foundChain = null; |
1720 | + int index = 0; | ||
1721 | + for (Deque<GroupKey> gkeys : allgkeys) { | ||
1722 | + GroupKey groupWithPort = gkeys.peekLast(); | ||
1723 | + Group group = groupService.getGroup(deviceId, groupWithPort); | ||
1724 | + if (group == null) { | ||
1725 | + log.warn("Inconsistent group chain"); | ||
1726 | + continue; | ||
1727 | + } | ||
1728 | + // last group in group chain should have a single bucket pointing to port | ||
1729 | + List<Instruction> lastIns = group.buckets().buckets().iterator() | ||
1730 | + .next().treatment().allInstructions(); | ||
1731 | + for (Instruction i : lastIns) { | ||
1732 | + if (i instanceof OutputInstruction) { | ||
1733 | + PortNumber lastport = ((OutputInstruction) i).port(); | ||
1734 | + if (lastport.equals(outport)) { | ||
1735 | + foundChain = gkeys; | ||
1736 | + break; | ||
1737 | + } | ||
1738 | + } | ||
1739 | + } | ||
1740 | + if (foundChain != null) { | ||
1741 | + break; | ||
1742 | + } | ||
1743 | + index++; | ||
1744 | + } | ||
1745 | + if (foundChain != null) { | ||
1746 | + //first groupkey is the one we want to modify | ||
1747 | + GroupKey modGroupKey = foundChain.peekFirst(); | ||
1748 | + Group modGroup = groupService.getGroup(deviceId, modGroupKey); | ||
1749 | + //second groupkey is the one we wish to remove the reference to | ||
1750 | + GroupKey pointedGroupKey = null; | ||
1751 | + int i = 0; | ||
1752 | + for (GroupKey gk : foundChain) { | ||
1753 | + if (i++ == 1) { | ||
1754 | + pointedGroupKey = gk; | ||
1755 | + break; | ||
1756 | + } | ||
1757 | + } | ||
1758 | + Group pointedGroup = groupService.getGroup(deviceId, pointedGroupKey); | ||
1759 | + GroupBucket bucket = DefaultGroupBucket.createSelectGroupBucket( | ||
1760 | + DefaultTrafficTreatment.builder() | ||
1761 | + .group(pointedGroup.id()) | ||
1762 | + .build()); | ||
1763 | + GroupBuckets removeBuckets = new GroupBuckets(Collections | ||
1764 | + .singletonList(bucket)); | ||
1765 | + log.debug("Removing buckets from group id {} for next id {} in device {}", | ||
1766 | + modGroup.id(), nextObjective.id(), deviceId); | ||
1767 | + groupService.removeBucketsFromGroup(deviceId, modGroupKey, | ||
1768 | + removeBuckets, modGroupKey, | ||
1769 | + nextObjective.appId()); | ||
1770 | + //update store | ||
1771 | + allgkeys.remove(index); | ||
1772 | + flowObjectiveStore.putNextGroup(nextObjective.id(), | ||
1773 | + new OfdpaNextGroup(allgkeys, nextObjective)); | ||
1774 | + } else { | ||
1775 | + log.warn("Could not find appropriate group-chain for removing bucket" | ||
1776 | + + " for next id {} in dev:{}", nextObjective.id(), deviceId); | ||
1777 | + } | ||
1608 | } | 1778 | } |
1609 | 1779 | ||
1610 | - private void removeGroup(NextObjective nextObjective) { | 1780 | + /** |
1611 | - // TODO Auto-generated method stub | 1781 | + * Removes all groups in multiple possible group-chains that represent the next |
1782 | + * objective. | ||
1783 | + * | ||
1784 | + * @param nextObjective the next objective to remove | ||
1785 | + * @param next the NextGroup that represents the existing group-chain for | ||
1786 | + * this next objective | ||
1787 | + */ | ||
1788 | + private void removeGroup(NextObjective nextObjective, NextGroup next) { | ||
1789 | + List<Deque<GroupKey>> allgkeys = appKryo.deserialize(next.data()); | ||
1790 | + allgkeys.forEach(groupChain -> { | ||
1791 | + groupChain.forEach(groupKey -> | ||
1792 | + groupService.removeGroup(deviceId, groupKey, nextObjective.appId())); | ||
1793 | + }); | ||
1794 | + flowObjectiveStore.removeNextGroup(nextObjective.id()); | ||
1612 | } | 1795 | } |
1613 | 1796 | ||
1614 | /** | 1797 | /** |
... | @@ -1617,7 +1800,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1617,7 +1800,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1617 | * and this driver has received notification for it. A second assumption is | 1800 | * and this driver has received notification for it. A second assumption is |
1618 | * that if there is another group waiting for this group then the appropriate | 1801 | * that if there is another group waiting for this group then the appropriate |
1619 | * stores already have the information to act upon the notification for the | 1802 | * stores already have the information to act upon the notification for the |
1620 | - * creating of this group. | 1803 | + * creation of this group. |
1621 | * <p> | 1804 | * <p> |
1622 | * The processing of the GroupChainElement depends on the number of groups | 1805 | * The processing of the GroupChainElement depends on the number of groups |
1623 | * this element is waiting on. For all group types other than SIMPLE, a | 1806 | * this element is waiting on. For all group types other than SIMPLE, a |
... | @@ -1632,8 +1815,16 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1632,8 +1815,16 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1632 | return; | 1815 | return; |
1633 | } | 1816 | } |
1634 | log.debug("GCE: {} ready to be processed", gce); | 1817 | log.debug("GCE: {} ready to be processed", gce); |
1818 | + if (gce.addBucketToGroup) { | ||
1819 | + groupService.addBucketsToGroup(gce.groupDescription.deviceId(), | ||
1820 | + gce.groupDescription.appCookie(), | ||
1821 | + gce.groupDescription.buckets(), | ||
1822 | + gce.groupDescription.appCookie(), | ||
1823 | + gce.groupDescription.appId()); | ||
1824 | + } else { | ||
1635 | groupService.addGroup(gce.groupDescription); | 1825 | groupService.addGroup(gce.groupDescription); |
1636 | } | 1826 | } |
1827 | + } | ||
1637 | 1828 | ||
1638 | private class GroupChecker implements Runnable { | 1829 | private class GroupChecker implements Runnable { |
1639 | @Override | 1830 | @Override |
... | @@ -1646,35 +1837,47 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1646,35 +1837,47 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1646 | .collect(Collectors.toSet()); | 1837 | .collect(Collectors.toSet()); |
1647 | keys.addAll(otherkeys); | 1838 | keys.addAll(otherkeys); |
1648 | 1839 | ||
1649 | - keys.stream().forEach(key -> { | 1840 | + keys.stream().forEach(key -> |
1841 | + processPendingGroupsOrNextObjectives(key, false)); | ||
1842 | + } | ||
1843 | + } | ||
1844 | + | ||
1845 | + private void processPendingGroupsOrNextObjectives(GroupKey key, boolean added) { | ||
1650 | //first check for group chain | 1846 | //first check for group chain |
1651 | Set<GroupChainElem> gceSet = pendingGroups.remove(key); | 1847 | Set<GroupChainElem> gceSet = pendingGroups.remove(key); |
1652 | if (gceSet != null) { | 1848 | if (gceSet != null) { |
1653 | for (GroupChainElem gce : gceSet) { | 1849 | for (GroupChainElem gce : gceSet) { |
1654 | - log.info("Group service processed group key {} in device {}. " | 1850 | + log.info("Group service {} group key {} in device {}. " |
1655 | + "Processing next group in group chain with group id {}", | 1851 | + "Processing next group in group chain with group id {}", |
1852 | + (added) ? "ADDED" : "processed", | ||
1656 | key, deviceId, | 1853 | key, deviceId, |
1657 | Integer.toHexString(gce.groupDescription.givenGroupId())); | 1854 | Integer.toHexString(gce.groupDescription.givenGroupId())); |
1658 | processGroupChain(gce); | 1855 | processGroupChain(gce); |
1659 | } | 1856 | } |
1660 | } else { | 1857 | } else { |
1661 | - List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); | 1858 | + // otherwise chain complete - check for waiting nextObjectives |
1662 | - if (objList != null) { | 1859 | + List<OfdpaNextGroup> nextGrpList = pendingNextObjectives.getIfPresent(key); |
1860 | + if (nextGrpList != null) { | ||
1663 | pendingNextObjectives.invalidate(key); | 1861 | pendingNextObjectives.invalidate(key); |
1664 | - objList.forEach(obj -> { | 1862 | + nextGrpList.forEach(nextGrp -> { |
1665 | - log.info("Group service processed group key {} in device:{}. " | 1863 | + log.info("Group service {} group key {} in device:{}. " |
1666 | + "Done implementing next objective: {} <<-->> gid:{}", | 1864 | + "Done implementing next objective: {} <<-->> gid:{}", |
1667 | - key, deviceId, obj.nextObjective().id(), | 1865 | + (added) ? "ADDED" : "processed", |
1866 | + key, deviceId, nextGrp.nextObjective().id(), | ||
1668 | Integer.toHexString(groupService.getGroup(deviceId, key) | 1867 | Integer.toHexString(groupService.getGroup(deviceId, key) |
1669 | .givenGroupId())); | 1868 | .givenGroupId())); |
1670 | - pass(obj.nextObjective()); | 1869 | + pass(nextGrp.nextObjective()); |
1671 | - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); | 1870 | + flowObjectiveStore.putNextGroup(nextGrp.nextObjective().id(), nextGrp); |
1672 | - }); | 1871 | + // check if addBuckets waiting for this completion |
1673 | - } | 1872 | + NextObjective pendBkt = pendingBuckets |
1873 | + .remove(nextGrp.nextObjective().id()); | ||
1874 | + if (pendBkt != null) { | ||
1875 | + addBucketToGroup(pendBkt, nextGrp); | ||
1674 | } | 1876 | } |
1675 | }); | 1877 | }); |
1676 | } | 1878 | } |
1677 | } | 1879 | } |
1880 | + } | ||
1678 | 1881 | ||
1679 | private class InnerGroupListener implements GroupListener { | 1882 | private class InnerGroupListener implements GroupListener { |
1680 | @Override | 1883 | @Override |
... | @@ -1682,31 +1885,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1682,31 +1885,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1682 | log.trace("received group event of type {}", event.type()); | 1885 | log.trace("received group event of type {}", event.type()); |
1683 | if (event.type() == GroupEvent.Type.GROUP_ADDED) { | 1886 | if (event.type() == GroupEvent.Type.GROUP_ADDED) { |
1684 | GroupKey key = event.subject().appCookie(); | 1887 | GroupKey key = event.subject().appCookie(); |
1685 | - // first check for group chain | 1888 | + processPendingGroupsOrNextObjectives(key, true); |
1686 | - Set<GroupChainElem> gceSet = pendingGroups.remove(key); | ||
1687 | - if (gceSet != null) { | ||
1688 | - for (GroupChainElem gce : gceSet) { | ||
1689 | - log.info("group ADDED with group key {} .. " | ||
1690 | - + "Processing next group in group chain with group key {}", | ||
1691 | - key, | ||
1692 | - gce.groupDescription.appCookie()); | ||
1693 | - processGroupChain(gce); | ||
1694 | - } | ||
1695 | - } else { | ||
1696 | - List<OfdpaNextGroup> objList = pendingNextObjectives.getIfPresent(key); | ||
1697 | - if (objList != null) { | ||
1698 | - pendingNextObjectives.invalidate(key); | ||
1699 | - objList.forEach(obj -> { | ||
1700 | - log.info("group ADDED with key {} in dev {}.. Done implementing next " | ||
1701 | - + "objective: {} <<-->> gid:{}", | ||
1702 | - key, deviceId, obj.nextObjective().id(), | ||
1703 | - Integer.toHexString(groupService.getGroup(deviceId, key) | ||
1704 | - .givenGroupId())); | ||
1705 | - pass(obj.nextObjective()); | ||
1706 | - flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj); | ||
1707 | - }); | ||
1708 | - } | ||
1709 | - } | ||
1710 | } | 1889 | } |
1711 | } | 1890 | } |
1712 | } | 1891 | } |
... | @@ -1714,7 +1893,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1714,7 +1893,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1714 | /** | 1893 | /** |
1715 | * Represents an entire group-chain that implements a Next-Objective from | 1894 | * Represents an entire group-chain that implements a Next-Objective from |
1716 | * the application. The objective is represented as a list of deques, where | 1895 | * the application. The objective is represented as a list of deques, where |
1717 | - * each deque can is a separate chain of groups. | 1896 | + * each deque is a separate chain of groups. |
1718 | * <p> | 1897 | * <p> |
1719 | * For example, an ECMP group with 3 buckets, where each bucket points to | 1898 | * For example, an ECMP group with 3 buckets, where each bucket points to |
1720 | * a group chain of L3 Unicast and L2 interface groups will look like this: | 1899 | * a group chain of L3 Unicast and L2 interface groups will look like this: |
... | @@ -1765,10 +1944,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1765,10 +1944,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1765 | private class GroupChainElem { | 1944 | private class GroupChainElem { |
1766 | private GroupDescription groupDescription; | 1945 | private GroupDescription groupDescription; |
1767 | private AtomicInteger waitOnGroups; | 1946 | private AtomicInteger waitOnGroups; |
1947 | + private boolean addBucketToGroup; | ||
1768 | 1948 | ||
1769 | - GroupChainElem(GroupDescription groupDescription, int waitOnGroups) { | 1949 | + GroupChainElem(GroupDescription groupDescription, int waitOnGroups, |
1950 | + boolean addBucketToGroup) { | ||
1770 | this.groupDescription = groupDescription; | 1951 | this.groupDescription = groupDescription; |
1771 | this.waitOnGroups = new AtomicInteger(waitOnGroups); | 1952 | this.waitOnGroups = new AtomicInteger(waitOnGroups); |
1953 | + this.addBucketToGroup = addBucketToGroup; | ||
1772 | } | 1954 | } |
1773 | 1955 | ||
1774 | /** | 1956 | /** |
... | @@ -1788,6 +1970,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1788,6 +1970,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1788 | return (Integer.toHexString(groupDescription.givenGroupId()) + | 1970 | return (Integer.toHexString(groupDescription.givenGroupId()) + |
1789 | " groupKey: " + groupDescription.appCookie() + | 1971 | " groupKey: " + groupDescription.appCookie() + |
1790 | " waiting-on-groups: " + waitOnGroups.get() + | 1972 | " waiting-on-groups: " + waitOnGroups.get() + |
1973 | + " addBucketToGroup: " + addBucketToGroup + | ||
1791 | " device: " + deviceId); | 1974 | " device: " + deviceId); |
1792 | } | 1975 | } |
1793 | } | 1976 | } | ... | ... |
-
Please register or login to post a comment