Committed by
Gerrit Code Review
CORD-348 Fabric multicast support - error handling
Automatically failover to backup spine if - ingress - transit link down - transit - egress link down - transit device down Can recover from fatal error with human involved - ingress switch down - egress switch down - all links to spine down Scan through McastRouteStore when - SR activate - link up Also include following features - Use flow objective context in McastHandler - Update Mcast VLAN config sample Change-Id: I75007d9efd7646e7c4e57fa6d3fc6943543153cf
Showing
5 changed files
with
339 additions
and
108 deletions
... | @@ -42,25 +42,33 @@ import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; | ... | @@ -42,25 +42,33 @@ import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; |
42 | import org.onosproject.net.flowobjective.DefaultFilteringObjective; | 42 | import org.onosproject.net.flowobjective.DefaultFilteringObjective; |
43 | import org.onosproject.net.flowobjective.DefaultForwardingObjective; | 43 | import org.onosproject.net.flowobjective.DefaultForwardingObjective; |
44 | import org.onosproject.net.flowobjective.DefaultNextObjective; | 44 | import org.onosproject.net.flowobjective.DefaultNextObjective; |
45 | +import org.onosproject.net.flowobjective.DefaultObjectiveContext; | ||
45 | import org.onosproject.net.flowobjective.FilteringObjective; | 46 | import org.onosproject.net.flowobjective.FilteringObjective; |
46 | import org.onosproject.net.flowobjective.ForwardingObjective; | 47 | import org.onosproject.net.flowobjective.ForwardingObjective; |
47 | import org.onosproject.net.flowobjective.NextObjective; | 48 | import org.onosproject.net.flowobjective.NextObjective; |
49 | +import org.onosproject.net.flowobjective.ObjectiveContext; | ||
48 | import org.onosproject.net.mcast.McastEvent; | 50 | import org.onosproject.net.mcast.McastEvent; |
49 | import org.onosproject.net.mcast.McastRouteInfo; | 51 | import org.onosproject.net.mcast.McastRouteInfo; |
50 | import org.onosproject.net.topology.TopologyService; | 52 | import org.onosproject.net.topology.TopologyService; |
51 | -import org.onosproject.segmentrouting.storekey.McastNextObjectiveStoreKey; | 53 | +import org.onosproject.segmentrouting.storekey.McastStoreKey; |
52 | import org.onosproject.store.serializers.KryoNamespaces; | 54 | import org.onosproject.store.serializers.KryoNamespaces; |
53 | import org.onosproject.store.service.ConsistentMap; | 55 | import org.onosproject.store.service.ConsistentMap; |
54 | import org.onosproject.store.service.Serializer; | 56 | import org.onosproject.store.service.Serializer; |
55 | import org.onosproject.store.service.StorageService; | 57 | import org.onosproject.store.service.StorageService; |
58 | +import org.onosproject.store.service.Versioned; | ||
56 | import org.slf4j.Logger; | 59 | import org.slf4j.Logger; |
57 | import org.slf4j.LoggerFactory; | 60 | import org.slf4j.LoggerFactory; |
58 | 61 | ||
59 | import java.util.Collection; | 62 | import java.util.Collection; |
60 | import java.util.Collections; | 63 | import java.util.Collections; |
64 | +import java.util.Iterator; | ||
61 | import java.util.List; | 65 | import java.util.List; |
66 | +import java.util.Map; | ||
62 | import java.util.Optional; | 67 | import java.util.Optional; |
63 | import java.util.Set; | 68 | import java.util.Set; |
69 | +import java.util.stream.Collectors; | ||
70 | + | ||
71 | +import static com.google.common.base.Preconditions.checkState; | ||
64 | 72 | ||
65 | /** | 73 | /** |
66 | * Handles multicast-related events. | 74 | * Handles multicast-related events. |
... | @@ -71,8 +79,27 @@ public class McastHandler { | ... | @@ -71,8 +79,27 @@ public class McastHandler { |
71 | private final ApplicationId coreAppId; | 79 | private final ApplicationId coreAppId; |
72 | private StorageService storageService; | 80 | private StorageService storageService; |
73 | private TopologyService topologyService; | 81 | private TopologyService topologyService; |
74 | - private final KryoNamespace.Builder kryoBuilder; | 82 | + private final ConsistentMap<McastStoreKey, NextObjective> mcastNextObjStore; |
75 | - private final ConsistentMap<McastNextObjectiveStoreKey, NextObjective> mcastNextObjStore; | 83 | + private final KryoNamespace.Builder mcastKryo; |
84 | + private final ConsistentMap<McastStoreKey, McastRole> mcastRoleStore; | ||
85 | + | ||
86 | + /** | ||
87 | + * Role in the multicast tree. | ||
88 | + */ | ||
89 | + public enum McastRole { | ||
90 | + /** | ||
91 | + * The device is the ingress device of this group. | ||
92 | + */ | ||
93 | + INGRESS, | ||
94 | + /** | ||
95 | + * The device is the transit device of this group. | ||
96 | + */ | ||
97 | + TRANSIT, | ||
98 | + /** | ||
99 | + * The device is the egress device of this group. | ||
100 | + */ | ||
101 | + EGRESS | ||
102 | + } | ||
76 | 103 | ||
77 | /** | 104 | /** |
78 | * Constructs the McastEventHandler. | 105 | * Constructs the McastEventHandler. |
... | @@ -81,19 +108,36 @@ public class McastHandler { | ... | @@ -81,19 +108,36 @@ public class McastHandler { |
81 | */ | 108 | */ |
82 | public McastHandler(SegmentRoutingManager srManager) { | 109 | public McastHandler(SegmentRoutingManager srManager) { |
83 | coreAppId = srManager.coreService.getAppId(CoreService.CORE_APP_NAME); | 110 | coreAppId = srManager.coreService.getAppId(CoreService.CORE_APP_NAME); |
84 | - | ||
85 | this.srManager = srManager; | 111 | this.srManager = srManager; |
86 | this.storageService = srManager.storageService; | 112 | this.storageService = srManager.storageService; |
87 | this.topologyService = srManager.topologyService; | 113 | this.topologyService = srManager.topologyService; |
88 | - | 114 | + mcastKryo = new KryoNamespace.Builder() |
89 | - kryoBuilder = new KryoNamespace.Builder() | ||
90 | .register(KryoNamespaces.API) | 115 | .register(KryoNamespaces.API) |
91 | - .register(McastNextObjectiveStoreKey.class); | 116 | + .register(McastStoreKey.class) |
117 | + .register(McastRole.class); | ||
92 | mcastNextObjStore = storageService | 118 | mcastNextObjStore = storageService |
93 | - .<McastNextObjectiveStoreKey, NextObjective>consistentMapBuilder() | 119 | + .<McastStoreKey, NextObjective>consistentMapBuilder() |
94 | .withName("onos-mcast-nextobj-store") | 120 | .withName("onos-mcast-nextobj-store") |
95 | - .withSerializer(Serializer.using(kryoBuilder.build())) | 121 | + .withSerializer(Serializer.using(mcastKryo.build())) |
96 | .build(); | 122 | .build(); |
123 | + mcastRoleStore = storageService | ||
124 | + .<McastStoreKey, McastRole>consistentMapBuilder() | ||
125 | + .withName("onos-mcast-role-store") | ||
126 | + .withSerializer(Serializer.using(mcastKryo.build())) | ||
127 | + .build(); | ||
128 | + } | ||
129 | + | ||
130 | + /** | ||
131 | + * Read initial multicast from mcast store. | ||
132 | + */ | ||
133 | + public void init() { | ||
134 | + srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> { | ||
135 | + ConnectPoint source = srManager.multicastRouteService.fetchSource(mcastRoute); | ||
136 | + Set<ConnectPoint> sinks = srManager.multicastRouteService.fetchSinks(mcastRoute); | ||
137 | + sinks.forEach(sink -> { | ||
138 | + processSinkAddedInternal(source, sink, mcastRoute.group()); | ||
139 | + }); | ||
140 | + }); | ||
97 | } | 141 | } |
98 | 142 | ||
99 | /** | 143 | /** |
... | @@ -166,6 +210,9 @@ public class McastHandler { | ... | @@ -166,6 +210,9 @@ public class McastHandler { |
166 | 210 | ||
167 | // Process the egress device | 211 | // Process the egress device |
168 | boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); | 212 | boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); |
213 | + if (isLast) { | ||
214 | + mcastRoleStore.remove(new McastStoreKey(mcastIp, sink.deviceId())); | ||
215 | + } | ||
169 | 216 | ||
170 | // If this is the last sink on the device, also update upstream | 217 | // If this is the last sink on the device, also update upstream |
171 | Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp); | 218 | Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp); |
... | @@ -176,6 +223,7 @@ public class McastHandler { | ... | @@ -176,6 +223,7 @@ public class McastHandler { |
176 | if (isLast) { | 223 | if (isLast) { |
177 | isLast = removePortFromDevice(link.src().deviceId(), link.src().port(), | 224 | isLast = removePortFromDevice(link.src().deviceId(), link.src().port(), |
178 | mcastIp, assignedVlan); | 225 | mcastIp, assignedVlan); |
226 | + mcastRoleStore.remove(new McastStoreKey(mcastIp, link.src().deviceId())); | ||
179 | } | 227 | } |
180 | } | 228 | } |
181 | } | 229 | } |
... | @@ -192,6 +240,9 @@ public class McastHandler { | ... | @@ -192,6 +240,9 @@ public class McastHandler { |
192 | IpAddress mcastIp) { | 240 | IpAddress mcastIp) { |
193 | VlanId assignedVlan = assignedVlan(); | 241 | VlanId assignedVlan = assignedVlan(); |
194 | 242 | ||
243 | + // Process the ingress device | ||
244 | + addFilterToDevice(source.deviceId(), source.port(), assignedVlan); | ||
245 | + | ||
195 | // When source and sink are on the same device | 246 | // When source and sink are on the same device |
196 | if (source.deviceId().equals(sink.deviceId())) { | 247 | if (source.deviceId().equals(sink.deviceId())) { |
197 | // Source and sink are on even the same port. There must be something wrong. | 248 | // Source and sink are on even the same port. There must be something wrong. |
... | @@ -200,22 +251,88 @@ public class McastHandler { | ... | @@ -200,22 +251,88 @@ public class McastHandler { |
200 | return; | 251 | return; |
201 | } | 252 | } |
202 | addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); | 253 | addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); |
254 | + mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), McastRole.INGRESS); | ||
203 | return; | 255 | return; |
204 | } | 256 | } |
205 | 257 | ||
206 | - // Process the ingress device | ||
207 | - addFilterToDevice(source.deviceId(), source.port(), assignedVlan); | ||
208 | - | ||
209 | // Find a path. If present, create/update groups and flows for each hop | 258 | // Find a path. If present, create/update groups and flows for each hop |
210 | Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp); | 259 | Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp); |
211 | if (mcastPath.isPresent()) { | 260 | if (mcastPath.isPresent()) { |
212 | - mcastPath.get().links().forEach(link -> { | 261 | + List<Link> links = mcastPath.get().links(); |
262 | + checkState(links.size() == 2, | ||
263 | + "Path in leaf-spine topology should always be two hops: ", links); | ||
264 | + | ||
265 | + links.forEach(link -> { | ||
213 | addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan); | 266 | addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan); |
214 | addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp, assignedVlan); | 267 | addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp, assignedVlan); |
215 | }); | 268 | }); |
269 | + | ||
216 | // Process the egress device | 270 | // Process the egress device |
217 | addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); | 271 | addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); |
272 | + | ||
273 | + // Setup mcast roles | ||
274 | + mcastRoleStore.put(new McastStoreKey(mcastIp, source.deviceId()), | ||
275 | + McastRole.INGRESS); | ||
276 | + mcastRoleStore.put(new McastStoreKey(mcastIp, links.get(0).dst().deviceId()), | ||
277 | + McastRole.TRANSIT); | ||
278 | + mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), | ||
279 | + McastRole.EGRESS); | ||
280 | + } else { | ||
281 | + log.warn("Unable to find a path from {} to {}. Abort sinkAdded", | ||
282 | + source.deviceId(), sink.deviceId()); | ||
283 | + } | ||
284 | + } | ||
285 | + | ||
286 | + /** | ||
287 | + * Processes the LINK_DOWN event. | ||
288 | + * | ||
289 | + * @param affectedLink Link that is going down | ||
290 | + */ | ||
291 | + protected void processLinkDown(Link affectedLink) { | ||
292 | + VlanId assignedVlan = assignedVlan(); | ||
293 | + | ||
294 | + getAffectedGroups(affectedLink).forEach(mcastIp -> { | ||
295 | + // Find out the ingress, transit and egress device of affected group | ||
296 | + DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS) | ||
297 | + .stream().findAny().orElse(null); | ||
298 | + DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT) | ||
299 | + .stream().findAny().orElse(null); | ||
300 | + Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS); | ||
301 | + if (ingressDevice == null || transitDevice == null || egressDevices == null) { | ||
302 | + log.warn("Missing ingress {}, transit {}, or egress {} devices", | ||
303 | + ingressDevice, transitDevice, egressDevices); | ||
304 | + return; | ||
305 | + } | ||
306 | + | ||
307 | + // Remove entire transit | ||
308 | + removeGroupFromDevice(transitDevice, mcastIp, assignedVlan); | ||
309 | + | ||
310 | + // Remove transit-facing port on ingress device | ||
311 | + PortNumber ingressTransitPort = ingressTransitPort(mcastIp); | ||
312 | + if (ingressTransitPort != null) { | ||
313 | + removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan); | ||
314 | + mcastRoleStore.remove(new McastStoreKey(mcastIp, transitDevice)); | ||
315 | + } | ||
316 | + | ||
317 | + // Construct a new path for each egress device | ||
318 | + egressDevices.forEach(egressDevice -> { | ||
319 | + Optional<Path> mcastPath = getPath(ingressDevice, egressDevice, mcastIp); | ||
320 | + if (mcastPath.isPresent()) { | ||
321 | + List<Link> links = mcastPath.get().links(); | ||
322 | + links.forEach(link -> { | ||
323 | + addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp, assignedVlan); | ||
324 | + addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan); | ||
325 | + }); | ||
326 | + // Setup new transit mcast role | ||
327 | + mcastRoleStore.put(new McastStoreKey(mcastIp, | ||
328 | + links.get(0).dst().deviceId()), McastRole.TRANSIT); | ||
329 | + } else { | ||
330 | + log.warn("Fail to recover egress device {} from link failure {}", | ||
331 | + egressDevice, affectedLink); | ||
332 | + removeGroupFromDevice(egressDevice, mcastIp, assignedVlan); | ||
218 | } | 333 | } |
334 | + }); | ||
335 | + }); | ||
219 | } | 336 | } |
220 | 337 | ||
221 | /** | 338 | /** |
... | @@ -228,7 +345,8 @@ public class McastHandler { | ... | @@ -228,7 +345,8 @@ public class McastHandler { |
228 | private void addFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan) { | 345 | private void addFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan) { |
229 | // Do nothing if the port is configured as suppressed | 346 | // Do nothing if the port is configured as suppressed |
230 | ConnectPoint connectPt = new ConnectPoint(deviceId, port); | 347 | ConnectPoint connectPt = new ConnectPoint(deviceId, port); |
231 | - if (srManager.deviceConfiguration.suppressSubnet().contains(connectPt) || | 348 | + if (srManager.deviceConfiguration == null || |
349 | + srManager.deviceConfiguration.suppressSubnet().contains(connectPt) || | ||
232 | srManager.deviceConfiguration.suppressHost().contains(connectPt)) { | 350 | srManager.deviceConfiguration.suppressHost().contains(connectPt)) { |
233 | log.info("Ignore suppressed port {}", connectPt); | 351 | log.info("Ignore suppressed port {}", connectPt); |
234 | return; | 352 | return; |
... | @@ -236,8 +354,13 @@ public class McastHandler { | ... | @@ -236,8 +354,13 @@ public class McastHandler { |
236 | 354 | ||
237 | FilteringObjective.Builder filtObjBuilder = | 355 | FilteringObjective.Builder filtObjBuilder = |
238 | filterObjBuilder(deviceId, port, assignedVlan); | 356 | filterObjBuilder(deviceId, port, assignedVlan); |
239 | - srManager.flowObjectiveService.filter(deviceId, filtObjBuilder.add()); | 357 | + ObjectiveContext context = new DefaultObjectiveContext( |
240 | - // TODO add objective context | 358 | + (objective) -> log.debug("Successfully add filter on {}/{}, vlan {}", |
359 | + deviceId, port.toLong(), assignedVlan), | ||
360 | + (objective, error) -> | ||
361 | + log.warn("Failed to add filter on {}/{}, vlan {}: {}", | ||
362 | + deviceId, port.toLong(), assignedVlan, error)); | ||
363 | + srManager.flowObjectiveService.filter(deviceId, filtObjBuilder.add(context)); | ||
241 | } | 364 | } |
242 | 365 | ||
243 | /** | 366 | /** |
... | @@ -251,17 +374,14 @@ public class McastHandler { | ... | @@ -251,17 +374,14 @@ public class McastHandler { |
251 | */ | 374 | */ |
252 | private void addPortToDevice(DeviceId deviceId, PortNumber port, | 375 | private void addPortToDevice(DeviceId deviceId, PortNumber port, |
253 | IpAddress mcastIp, VlanId assignedVlan) { | 376 | IpAddress mcastIp, VlanId assignedVlan) { |
254 | - log.info("Add port {} to {}. mcastIp={}, assignedVlan={}", | 377 | + McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId); |
255 | - port, deviceId, mcastIp, assignedVlan); | ||
256 | - McastNextObjectiveStoreKey mcastNextObjectiveStoreKey = | ||
257 | - new McastNextObjectiveStoreKey(mcastIp, deviceId); | ||
258 | ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder(); | 378 | ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder(); |
259 | - if (!mcastNextObjStore.containsKey(mcastNextObjectiveStoreKey)) { | 379 | + if (!mcastNextObjStore.containsKey(mcastStoreKey)) { |
260 | // First time someone request this mcast group via this device | 380 | // First time someone request this mcast group via this device |
261 | portBuilder.add(port); | 381 | portBuilder.add(port); |
262 | } else { | 382 | } else { |
263 | // This device already serves some subscribers of this mcast group | 383 | // This device already serves some subscribers of this mcast group |
264 | - NextObjective nextObj = mcastNextObjStore.get(mcastNextObjectiveStoreKey).value(); | 384 | + NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value(); |
265 | // Stop if the port is already in the nextobj | 385 | // Stop if the port is already in the nextobj |
266 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); | 386 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); |
267 | if (existingPorts.contains(port)) { | 387 | if (existingPorts.contains(port)) { |
... | @@ -271,14 +391,19 @@ public class McastHandler { | ... | @@ -271,14 +391,19 @@ public class McastHandler { |
271 | portBuilder.addAll(existingPorts).add(port).build(); | 391 | portBuilder.addAll(existingPorts).add(port).build(); |
272 | } | 392 | } |
273 | // Create, store and apply the new nextObj and fwdObj | 393 | // Create, store and apply the new nextObj and fwdObj |
394 | + ObjectiveContext context = new DefaultObjectiveContext( | ||
395 | + (objective) -> log.debug("Successfully add {} on {}/{}, vlan {}", | ||
396 | + mcastIp, deviceId, port.toLong(), assignedVlan), | ||
397 | + (objective, error) -> | ||
398 | + log.warn("Failed to add {} on {}/{}, vlan {}: {}", | ||
399 | + mcastIp, deviceId, port.toLong(), assignedVlan, error)); | ||
274 | NextObjective newNextObj = | 400 | NextObjective newNextObj = |
275 | nextObjBuilder(mcastIp, assignedVlan, portBuilder.build()).add(); | 401 | nextObjBuilder(mcastIp, assignedVlan, portBuilder.build()).add(); |
276 | ForwardingObjective fwdObj = | 402 | ForwardingObjective fwdObj = |
277 | - fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(); | 403 | + fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context); |
278 | - mcastNextObjStore.put(mcastNextObjectiveStoreKey, newNextObj); | 404 | + mcastNextObjStore.put(mcastStoreKey, newNextObj); |
279 | srManager.flowObjectiveService.next(deviceId, newNextObj); | 405 | srManager.flowObjectiveService.next(deviceId, newNextObj); |
280 | srManager.flowObjectiveService.forward(deviceId, fwdObj); | 406 | srManager.flowObjectiveService.forward(deviceId, fwdObj); |
281 | - // TODO add objective callback | ||
282 | } | 407 | } |
283 | 408 | ||
284 | /** | 409 | /** |
... | @@ -294,19 +419,17 @@ public class McastHandler { | ... | @@ -294,19 +419,17 @@ public class McastHandler { |
294 | */ | 419 | */ |
295 | private boolean removePortFromDevice(DeviceId deviceId, PortNumber port, | 420 | private boolean removePortFromDevice(DeviceId deviceId, PortNumber port, |
296 | IpAddress mcastIp, VlanId assignedVlan) { | 421 | IpAddress mcastIp, VlanId assignedVlan) { |
297 | - log.info("Remove port {} from {}. mcastIp={}, assignedVlan={}", | 422 | + McastStoreKey mcastStoreKey = |
298 | - port, deviceId, mcastIp, assignedVlan); | 423 | + new McastStoreKey(mcastIp, deviceId); |
299 | - McastNextObjectiveStoreKey mcastNextObjectiveStoreKey = | ||
300 | - new McastNextObjectiveStoreKey(mcastIp, deviceId); | ||
301 | // This device is not serving this multicast group | 424 | // This device is not serving this multicast group |
302 | - if (!mcastNextObjStore.containsKey(mcastNextObjectiveStoreKey)) { | 425 | + if (!mcastNextObjStore.containsKey(mcastStoreKey)) { |
303 | log.warn("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port); | 426 | log.warn("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port); |
304 | return false; | 427 | return false; |
305 | } | 428 | } |
306 | - NextObjective nextObj = mcastNextObjStore.get(mcastNextObjectiveStoreKey).value(); | 429 | + NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value(); |
307 | 430 | ||
308 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); | 431 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); |
309 | - // This device does not serve this multicast group | 432 | + // This port does not serve this multicast group |
310 | if (!existingPorts.contains(port)) { | 433 | if (!existingPorts.contains(port)) { |
311 | log.warn("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port); | 434 | log.warn("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port); |
312 | return false; | 435 | return false; |
... | @@ -322,22 +445,91 @@ public class McastHandler { | ... | @@ -322,22 +445,91 @@ public class McastHandler { |
322 | // NOTE: Rely on GroupStore garbage collection rather than explicitly | 445 | // NOTE: Rely on GroupStore garbage collection rather than explicitly |
323 | // remove L3MG since there might be other flows/groups refer to | 446 | // remove L3MG since there might be other flows/groups refer to |
324 | // the same L2IG | 447 | // the same L2IG |
325 | - fwdObj = fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(); | 448 | + ObjectiveContext context = new DefaultObjectiveContext( |
326 | - mcastNextObjStore.remove(mcastNextObjectiveStoreKey); | 449 | + (objective) -> log.debug("Successfully remove {} on {}/{}, vlan {}", |
450 | + mcastIp, deviceId, port.toLong(), assignedVlan), | ||
451 | + (objective, error) -> | ||
452 | + log.warn("Failed to remove {} on {}/{}, vlan {}: {}", | ||
453 | + mcastIp, deviceId, port.toLong(), assignedVlan, error)); | ||
454 | + fwdObj = fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context); | ||
455 | + mcastNextObjStore.remove(mcastStoreKey); | ||
327 | srManager.flowObjectiveService.forward(deviceId, fwdObj); | 456 | srManager.flowObjectiveService.forward(deviceId, fwdObj); |
328 | } else { | 457 | } else { |
329 | // If this is not the last sink, update flows and groups | 458 | // If this is not the last sink, update flows and groups |
459 | + ObjectiveContext context = new DefaultObjectiveContext( | ||
460 | + (objective) -> log.debug("Successfully update {} on {}/{}, vlan {}", | ||
461 | + mcastIp, deviceId, port.toLong(), assignedVlan), | ||
462 | + (objective, error) -> | ||
463 | + log.warn("Failed to update {} on {}/{}, vlan {}: {}", | ||
464 | + mcastIp, deviceId, port.toLong(), assignedVlan, error)); | ||
330 | newNextObj = nextObjBuilder(mcastIp, assignedVlan, existingPorts).add(); | 465 | newNextObj = nextObjBuilder(mcastIp, assignedVlan, existingPorts).add(); |
331 | fwdObj = fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(); | 466 | fwdObj = fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(); |
332 | - mcastNextObjStore.put(mcastNextObjectiveStoreKey, newNextObj); | 467 | + mcastNextObjStore.put(mcastStoreKey, newNextObj); |
333 | srManager.flowObjectiveService.next(deviceId, newNextObj); | 468 | srManager.flowObjectiveService.next(deviceId, newNextObj); |
334 | srManager.flowObjectiveService.forward(deviceId, fwdObj); | 469 | srManager.flowObjectiveService.forward(deviceId, fwdObj); |
335 | } | 470 | } |
336 | - // TODO add objective callback | ||
337 | - | ||
338 | return existingPorts.isEmpty(); | 471 | return existingPorts.isEmpty(); |
339 | } | 472 | } |
340 | 473 | ||
474 | + | ||
475 | + /** | ||
476 | + * Removes entire group on given device. | ||
477 | + * | ||
478 | + * @param deviceId device ID | ||
479 | + * @param mcastIp multicast group to be removed | ||
480 | + * @param assignedVlan assigned VLAN ID | ||
481 | + */ | ||
482 | + private void removeGroupFromDevice(DeviceId deviceId, IpAddress mcastIp, | ||
483 | + VlanId assignedVlan) { | ||
484 | + McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId); | ||
485 | + // This device is not serving this multicast group | ||
486 | + if (!mcastNextObjStore.containsKey(mcastStoreKey)) { | ||
487 | + log.warn("{} is not serving {}. Abort.", deviceId, mcastIp); | ||
488 | + return; | ||
489 | + } | ||
490 | + NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value(); | ||
491 | + // NOTE: Rely on GroupStore garbage collection rather than explicitly | ||
492 | + // remove L3MG since there might be other flows/groups refer to | ||
493 | + // the same L2IG | ||
494 | + ObjectiveContext context = new DefaultObjectiveContext( | ||
495 | + (objective) -> log.debug("Successfully remove {} on {}, vlan {}", | ||
496 | + mcastIp, deviceId, assignedVlan), | ||
497 | + (objective, error) -> | ||
498 | + log.warn("Failed to remove {} on {}, vlan {}: {}", | ||
499 | + mcastIp, deviceId, assignedVlan, error)); | ||
500 | + ForwardingObjective fwdObj = fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context); | ||
501 | + srManager.flowObjectiveService.forward(deviceId, fwdObj); | ||
502 | + mcastNextObjStore.remove(mcastStoreKey); | ||
503 | + mcastRoleStore.remove(mcastStoreKey); | ||
504 | + } | ||
505 | + | ||
506 | + /** | ||
507 | + * Remove all groups on given device. | ||
508 | + * | ||
509 | + * @param deviceId device ID | ||
510 | + */ | ||
511 | + public void removeDevice(DeviceId deviceId) { | ||
512 | + Iterator<Map.Entry<McastStoreKey, Versioned<NextObjective>>> itNextObj = | ||
513 | + mcastNextObjStore.entrySet().iterator(); | ||
514 | + while (itNextObj.hasNext()) { | ||
515 | + Map.Entry<McastStoreKey, Versioned<NextObjective>> entry = itNextObj.next(); | ||
516 | + if (entry.getKey().deviceId().equals(deviceId)) { | ||
517 | + removeGroupFromDevice(entry.getKey().deviceId(), entry.getKey().mcastIp(), assignedVlan()); | ||
518 | + itNextObj.remove(); | ||
519 | + } | ||
520 | + } | ||
521 | + | ||
522 | + Iterator<Map.Entry<McastStoreKey, Versioned<McastRole>>> itRole = | ||
523 | + mcastRoleStore.entrySet().iterator(); | ||
524 | + while (itRole.hasNext()) { | ||
525 | + Map.Entry<McastStoreKey, Versioned<McastRole>> entry = itRole.next(); | ||
526 | + if (entry.getKey().deviceId().equals(deviceId)) { | ||
527 | + itRole.remove(); | ||
528 | + } | ||
529 | + } | ||
530 | + | ||
531 | + } | ||
532 | + | ||
341 | /** | 533 | /** |
342 | * Creates a next objective builder for multicast. | 534 | * Creates a next objective builder for multicast. |
343 | * | 535 | * |
... | @@ -456,16 +648,15 @@ public class McastHandler { | ... | @@ -456,16 +648,15 @@ public class McastHandler { |
456 | private Optional<Path> getPath(DeviceId src, DeviceId dst, IpAddress mcastIp) { | 648 | private Optional<Path> getPath(DeviceId src, DeviceId dst, IpAddress mcastIp) { |
457 | List<Path> allPaths = Lists.newArrayList( | 649 | List<Path> allPaths = Lists.newArrayList( |
458 | topologyService.getPaths(topologyService.currentTopology(), src, dst)); | 650 | topologyService.getPaths(topologyService.currentTopology(), src, dst)); |
651 | + log.debug("{} path(s) found from {} to {}", allPaths.size(), src, dst); | ||
459 | if (allPaths.isEmpty()) { | 652 | if (allPaths.isEmpty()) { |
460 | - log.warn("Fail to find a path from {} to {}. Abort.", src, dst); | ||
461 | return Optional.empty(); | 653 | return Optional.empty(); |
462 | } | 654 | } |
463 | 655 | ||
464 | // If one of the available path is used before, use the same path | 656 | // If one of the available path is used before, use the same path |
465 | - McastNextObjectiveStoreKey mcastNextObjectiveStoreKey = | 657 | + McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, src); |
466 | - new McastNextObjectiveStoreKey(mcastIp, src); | 658 | + if (mcastNextObjStore.containsKey(mcastStoreKey)) { |
467 | - if (mcastNextObjStore.containsKey(mcastNextObjectiveStoreKey)) { | 659 | + NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value(); |
468 | - NextObjective nextObj = mcastNextObjStore.get(mcastNextObjectiveStoreKey).value(); | ||
469 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); | 660 | Set<PortNumber> existingPorts = getPorts(nextObj.next()); |
470 | for (Path path : allPaths) { | 661 | for (Path path : allPaths) { |
471 | PortNumber srcPort = path.links().get(0).src().port(); | 662 | PortNumber srcPort = path.links().get(0).src().port(); |
... | @@ -480,6 +671,37 @@ public class McastHandler { | ... | @@ -480,6 +671,37 @@ public class McastHandler { |
480 | } | 671 | } |
481 | 672 | ||
482 | /** | 673 | /** |
674 | + * Gets device(s) of given role in given multicast group. | ||
675 | + * | ||
676 | + * @param mcastIp multicast IP | ||
677 | + * @param role multicast role | ||
678 | + * @return set of device ID or empty set if not found | ||
679 | + */ | ||
680 | + private Set<DeviceId> getDevice(IpAddress mcastIp, McastRole role) { | ||
681 | + return mcastRoleStore.entrySet().stream() | ||
682 | + .filter(entry -> entry.getKey().mcastIp().equals(mcastIp) && | ||
683 | + entry.getValue().value() == role) | ||
684 | + .map(Map.Entry::getKey).map(McastStoreKey::deviceId) | ||
685 | + .collect(Collectors.toSet()); | ||
686 | + } | ||
687 | + | ||
688 | + /** | ||
689 | + * Gets groups which is affected by the link down event. | ||
690 | + * | ||
691 | + * @param link link going down | ||
692 | + * @return a set of multicast IpAddress | ||
693 | + */ | ||
694 | + private Set<IpAddress> getAffectedGroups(Link link) { | ||
695 | + DeviceId deviceId = link.src().deviceId(); | ||
696 | + PortNumber port = link.src().port(); | ||
697 | + return mcastNextObjStore.entrySet().stream() | ||
698 | + .filter(entry -> entry.getKey().deviceId().equals(deviceId) && | ||
699 | + getPorts(entry.getValue().value().next()).contains(port)) | ||
700 | + .map(Map.Entry::getKey).map(McastStoreKey::mcastIp) | ||
701 | + .collect(Collectors.toSet()); | ||
702 | + } | ||
703 | + | ||
704 | + /** | ||
483 | * Gets egress VLAN from McastConfig. | 705 | * Gets egress VLAN from McastConfig. |
484 | * | 706 | * |
485 | * @return egress VLAN or VlanId.NONE if not configured | 707 | * @return egress VLAN or VlanId.NONE if not configured |
... | @@ -500,4 +722,34 @@ public class McastHandler { | ... | @@ -500,4 +722,34 @@ public class McastHandler { |
500 | VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) : | 722 | VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) : |
501 | egressVlan(); | 723 | egressVlan(); |
502 | } | 724 | } |
725 | + | ||
726 | + /** | ||
727 | + * Gets the spine-facing port on ingress device of given multicast group. | ||
728 | + * | ||
729 | + * @param mcastIp multicast IP | ||
730 | + * @return spine-facing port on ingress device | ||
731 | + */ | ||
732 | + private PortNumber ingressTransitPort(IpAddress mcastIp) { | ||
733 | + DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS) | ||
734 | + .stream().findAny().orElse(null); | ||
735 | + if (ingressDevice != null) { | ||
736 | + NextObjective nextObj = mcastNextObjStore | ||
737 | + .get(new McastStoreKey(mcastIp, ingressDevice)).value(); | ||
738 | + Set<PortNumber> ports = getPorts(nextObj.next()); | ||
739 | + | ||
740 | + for (PortNumber port : ports) { | ||
741 | + // Spine-facing port should have no subnet and no xconnect | ||
742 | + if (srManager.deviceConfiguration != null && | ||
743 | + srManager.deviceConfiguration.getPortSubnet(ingressDevice, port) == null && | ||
744 | + srManager.deviceConfiguration.getXConnects().values().stream() | ||
745 | + .allMatch(connectPoints -> | ||
746 | + connectPoints.stream().noneMatch(connectPoint -> | ||
747 | + connectPoint.port().equals(port)) | ||
748 | + )) { | ||
749 | + return port; | ||
750 | + } | ||
751 | + } | ||
752 | + } | ||
753 | + return null; | ||
754 | + } | ||
503 | } | 755 | } | ... | ... |
... | @@ -762,6 +762,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -762,6 +762,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
762 | defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null); | 762 | defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null); |
763 | //log.trace("processLinkAdded: re-starting route population process"); | 763 | //log.trace("processLinkAdded: re-starting route population process"); |
764 | //defaultRoutingHandler.startPopulationProcess(); | 764 | //defaultRoutingHandler.startPopulationProcess(); |
765 | + | ||
766 | + mcastHandler.init(); | ||
765 | } | 767 | } |
766 | 768 | ||
767 | private void processLinkRemoved(Link link) { | 769 | private void processLinkRemoved(Link link) { |
... | @@ -775,6 +777,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -775,6 +777,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
775 | defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link); | 777 | defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link); |
776 | //log.trace("processLinkRemoved: re-starting route population process"); | 778 | //log.trace("processLinkRemoved: re-starting route population process"); |
777 | //defaultRoutingHandler.startPopulationProcess(); | 779 | //defaultRoutingHandler.startPopulationProcess(); |
780 | + | ||
781 | + mcastHandler.processLinkDown(link); | ||
778 | } | 782 | } |
779 | 783 | ||
780 | private void processDeviceAdded(Device device) { | 784 | private void processDeviceAdded(Device device) { |
... | @@ -784,17 +788,22 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -784,17 +788,22 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
784 | + "processed after config completes.", device.id()); | 788 | + "processed after config completes.", device.id()); |
785 | return; | 789 | return; |
786 | } | 790 | } |
791 | + processDeviceAddedInternal(device.id()); | ||
792 | + } | ||
793 | + | ||
794 | + private void processDeviceAddedInternal(DeviceId deviceId) { | ||
787 | // Irrespective of whether the local is a MASTER or not for this device, | 795 | // Irrespective of whether the local is a MASTER or not for this device, |
788 | // we need to create a SR-group-handler instance. This is because in a | 796 | // we need to create a SR-group-handler instance. This is because in a |
789 | // multi-instance setup, any instance can initiate forwarding/next-objectives | 797 | // multi-instance setup, any instance can initiate forwarding/next-objectives |
790 | // for any switch (even if this instance is a SLAVE or not even connected | 798 | // for any switch (even if this instance is a SLAVE or not even connected |
791 | // to the switch). To handle this, a default-group-handler instance is necessary | 799 | // to the switch). To handle this, a default-group-handler instance is necessary |
792 | // per switch. | 800 | // per switch. |
793 | - if (groupHandlerMap.get(device.id()) == null) { | 801 | + log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet()); |
802 | + if (groupHandlerMap.get(deviceId) == null) { | ||
794 | DefaultGroupHandler groupHandler; | 803 | DefaultGroupHandler groupHandler; |
795 | try { | 804 | try { |
796 | groupHandler = DefaultGroupHandler. | 805 | groupHandler = DefaultGroupHandler. |
797 | - createGroupHandler(device.id(), | 806 | + createGroupHandler(deviceId, |
798 | appId, | 807 | appId, |
799 | deviceConfiguration, | 808 | deviceConfiguration, |
800 | linkService, | 809 | linkService, |
... | @@ -804,23 +813,25 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -804,23 +813,25 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
804 | log.warn(e.getMessage() + " Aborting processDeviceAdded."); | 813 | log.warn(e.getMessage() + " Aborting processDeviceAdded."); |
805 | return; | 814 | return; |
806 | } | 815 | } |
807 | - groupHandlerMap.put(device.id(), groupHandler); | 816 | + log.debug("updating groupHandlerMap with new config for device: {}", |
817 | + deviceId); | ||
818 | + groupHandlerMap.put(deviceId, groupHandler); | ||
808 | // Also, in some cases, drivers may need extra | 819 | // Also, in some cases, drivers may need extra |
809 | // information to process rules (eg. Router IP/MAC); and so, we send | 820 | // information to process rules (eg. Router IP/MAC); and so, we send |
810 | // port addressing rules to the driver as well irrespective of whether | 821 | // port addressing rules to the driver as well irrespective of whether |
811 | // this instance is the master or not. | 822 | // this instance is the master or not. |
812 | - defaultRoutingHandler.populatePortAddressingRules(device.id()); | 823 | + defaultRoutingHandler.populatePortAddressingRules(deviceId); |
813 | } | 824 | } |
814 | - if (mastershipService.isLocalMaster(device.id())) { | 825 | + if (mastershipService.isLocalMaster(deviceId)) { |
815 | - hostHandler.readInitialHosts(device.id()); | 826 | + hostHandler.readInitialHosts(deviceId); |
816 | - DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); | 827 | + DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId); |
817 | groupHandler.createGroupsFromSubnetConfig(); | 828 | groupHandler.createGroupsFromSubnetConfig(); |
818 | - routingRulePopulator.populateSubnetBroadcastRule(device.id()); | 829 | + routingRulePopulator.populateSubnetBroadcastRule(deviceId); |
819 | - groupHandler.createGroupsForXConnect(device.id()); | 830 | + groupHandler.createGroupsForXConnect(deviceId); |
820 | - routingRulePopulator.populateXConnectBroadcastRule(device.id()); | 831 | + routingRulePopulator.populateXConnectBroadcastRule(deviceId); |
821 | } | 832 | } |
822 | 833 | ||
823 | - netcfgHandler.initVRouters(device.id()); | 834 | + netcfgHandler.initVRouters(deviceId); |
824 | } | 835 | } |
825 | 836 | ||
826 | private void processDeviceRemoved(Device device) { | 837 | private void processDeviceRemoved(Device device) { |
... | @@ -829,34 +840,29 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -829,34 +840,29 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
829 | .forEach(entry -> { | 840 | .forEach(entry -> { |
830 | nsNextObjStore.remove(entry.getKey()); | 841 | nsNextObjStore.remove(entry.getKey()); |
831 | }); | 842 | }); |
832 | - | ||
833 | subnetNextObjStore.entrySet().stream() | 843 | subnetNextObjStore.entrySet().stream() |
834 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) | 844 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) |
835 | .forEach(entry -> { | 845 | .forEach(entry -> { |
836 | subnetNextObjStore.remove(entry.getKey()); | 846 | subnetNextObjStore.remove(entry.getKey()); |
837 | }); | 847 | }); |
838 | - | ||
839 | portNextObjStore.entrySet().stream() | 848 | portNextObjStore.entrySet().stream() |
840 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) | 849 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) |
841 | .forEach(entry -> { | 850 | .forEach(entry -> { |
842 | portNextObjStore.remove(entry.getKey()); | 851 | portNextObjStore.remove(entry.getKey()); |
843 | }); | 852 | }); |
844 | - | ||
845 | xConnectNextObjStore.entrySet().stream() | 853 | xConnectNextObjStore.entrySet().stream() |
846 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) | 854 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) |
847 | .forEach(entry -> { | 855 | .forEach(entry -> { |
848 | xConnectNextObjStore.remove(entry.getKey()); | 856 | xConnectNextObjStore.remove(entry.getKey()); |
849 | }); | 857 | }); |
850 | - | ||
851 | subnetVidStore.entrySet().stream() | 858 | subnetVidStore.entrySet().stream() |
852 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) | 859 | .filter(entry -> entry.getKey().deviceId().equals(device.id())) |
853 | .forEach(entry -> { | 860 | .forEach(entry -> { |
854 | subnetVidStore.remove(entry.getKey()); | 861 | subnetVidStore.remove(entry.getKey()); |
855 | }); | 862 | }); |
856 | - | ||
857 | groupHandlerMap.remove(device.id()); | 863 | groupHandlerMap.remove(device.id()); |
858 | - | ||
859 | defaultRoutingHandler.purgeEcmpGraph(device.id()); | 864 | defaultRoutingHandler.purgeEcmpGraph(device.id()); |
865 | + mcastHandler.removeDevice(device.id()); | ||
860 | } | 866 | } |
861 | 867 | ||
862 | private void processPortRemoved(Device device, Port port) { | 868 | private void processPortRemoved(Device device, Port port) { |
... | @@ -900,48 +906,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -900,48 +906,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
900 | tunnelHandler, policyStore); | 906 | tunnelHandler, policyStore); |
901 | 907 | ||
902 | for (Device device : deviceService.getDevices()) { | 908 | for (Device device : deviceService.getDevices()) { |
903 | - // Irrespective of whether the local is a MASTER or not for this device, | 909 | + processDeviceAddedInternal(device.id()); |
904 | - // we need to create a SR-group-handler instance. This is because in a | ||
905 | - // multi-instance setup, any instance can initiate forwarding/next-objectives | ||
906 | - // for any switch (even if this instance is a SLAVE or not even connected | ||
907 | - // to the switch). To handle this, a default-group-handler instance is necessary | ||
908 | - // per switch. | ||
909 | - log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet()); | ||
910 | - if (groupHandlerMap.get(device.id()) == null) { | ||
911 | - DefaultGroupHandler groupHandler; | ||
912 | - try { | ||
913 | - groupHandler = DefaultGroupHandler. | ||
914 | - createGroupHandler(device.id(), | ||
915 | - appId, | ||
916 | - deviceConfiguration, | ||
917 | - linkService, | ||
918 | - flowObjectiveService, | ||
919 | - segmentRoutingManager); | ||
920 | - } catch (DeviceConfigNotFoundException e) { | ||
921 | - log.warn(e.getMessage() + " Aborting configureNetwork."); | ||
922 | - return; | ||
923 | - } | ||
924 | - log.debug("updating groupHandlerMap with new config for " | ||
925 | - + "device: {}", device.id()); | ||
926 | - groupHandlerMap.put(device.id(), groupHandler); | ||
927 | - | ||
928 | - // Also, in some cases, drivers may need extra | ||
929 | - // information to process rules (eg. Router IP/MAC); and so, we send | ||
930 | - // port addressing rules to the driver as well, irrespective of whether | ||
931 | - // this instance is the master or not. | ||
932 | - defaultRoutingHandler.populatePortAddressingRules(device.id()); | ||
933 | - } | ||
934 | - if (mastershipService.isLocalMaster(device.id())) { | ||
935 | - hostHandler.readInitialHosts(device.id()); | ||
936 | - DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); | ||
937 | - groupHandler.createGroupsFromSubnetConfig(); | ||
938 | - routingRulePopulator.populateSubnetBroadcastRule(device.id()); | ||
939 | - groupHandler.createGroupsForXConnect(device.id()); | ||
940 | - routingRulePopulator.populateXConnectBroadcastRule(device.id()); | ||
941 | - } | ||
942 | } | 910 | } |
943 | 911 | ||
944 | defaultRoutingHandler.startPopulationProcess(); | 912 | defaultRoutingHandler.startPopulationProcess(); |
913 | + mcastHandler.init(); | ||
945 | } | 914 | } |
946 | 915 | ||
947 | @Override | 916 | @Override | ... | ... |
... | @@ -26,7 +26,7 @@ import java.util.Objects; | ... | @@ -26,7 +26,7 @@ import java.util.Objects; |
26 | /** | 26 | /** |
27 | * Key of multicast next objective store. | 27 | * Key of multicast next objective store. |
28 | */ | 28 | */ |
29 | -public class McastNextObjectiveStoreKey { | 29 | +public class McastStoreKey { |
30 | private final IpAddress mcastIp; | 30 | private final IpAddress mcastIp; |
31 | private final DeviceId deviceId; | 31 | private final DeviceId deviceId; |
32 | 32 | ||
... | @@ -36,7 +36,7 @@ public class McastNextObjectiveStoreKey { | ... | @@ -36,7 +36,7 @@ public class McastNextObjectiveStoreKey { |
36 | * @param mcastIp multicast group IP address | 36 | * @param mcastIp multicast group IP address |
37 | * @param deviceId device ID | 37 | * @param deviceId device ID |
38 | */ | 38 | */ |
39 | - public McastNextObjectiveStoreKey(IpAddress mcastIp, DeviceId deviceId) { | 39 | + public McastStoreKey(IpAddress mcastIp, DeviceId deviceId) { |
40 | checkNotNull(mcastIp, "mcastIp cannot be null"); | 40 | checkNotNull(mcastIp, "mcastIp cannot be null"); |
41 | checkNotNull(deviceId, "deviceId cannot be null"); | 41 | checkNotNull(deviceId, "deviceId cannot be null"); |
42 | checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address"); | 42 | checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address"); |
... | @@ -67,11 +67,11 @@ public class McastNextObjectiveStoreKey { | ... | @@ -67,11 +67,11 @@ public class McastNextObjectiveStoreKey { |
67 | if (this == o) { | 67 | if (this == o) { |
68 | return true; | 68 | return true; |
69 | } | 69 | } |
70 | - if (!(o instanceof McastNextObjectiveStoreKey)) { | 70 | + if (!(o instanceof McastStoreKey)) { |
71 | return false; | 71 | return false; |
72 | } | 72 | } |
73 | - McastNextObjectiveStoreKey that = | 73 | + McastStoreKey that = |
74 | - (McastNextObjectiveStoreKey) o; | 74 | + (McastStoreKey) o; |
75 | return (Objects.equals(this.mcastIp, that.mcastIp) && | 75 | return (Objects.equals(this.mcastIp, that.mcastIp) && |
76 | Objects.equals(this.deviceId, that.deviceId)); | 76 | Objects.equals(this.deviceId, that.deviceId)); |
77 | } | 77 | } | ... | ... |
... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
5 | <meta http-equiv="Content-Style-Type" content="text/css"> | 5 | <meta http-equiv="Content-Style-Type" content="text/css"> |
6 | <title></title> | 6 | <title></title> |
7 | <meta name="Generator" content="Cocoa HTML Writer"> | 7 | <meta name="Generator" content="Cocoa HTML Writer"> |
8 | - <meta name="CocoaVersion" content="1404.34"> | 8 | + <meta name="CocoaVersion" content="1404.46"> |
9 | <style type="text/css"> | 9 | <style type="text/css"> |
10 | p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #0433ff; -webkit-text-stroke: #0433ff} | 10 | p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #0433ff; -webkit-text-stroke: #0433ff} |
11 | p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #ff9300; -webkit-text-stroke: #ff9300} | 11 | p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #ff9300; -webkit-text-stroke: #ff9300} |
... | @@ -14,6 +14,7 @@ | ... | @@ -14,6 +14,7 @@ |
14 | p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #00c7fc; -webkit-text-stroke: #00c7fc} | 14 | p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #00c7fc; -webkit-text-stroke: #00c7fc} |
15 | p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #ff2600; -webkit-text-stroke: #ff2600} | 15 | p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #ff2600; -webkit-text-stroke: #ff2600} |
16 | p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #000000; -webkit-text-stroke: #000000} | 16 | p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #000000; -webkit-text-stroke: #000000} |
17 | + p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Menlo; color: #00c7fc; -webkit-text-stroke: #000000} | ||
17 | span.s1 {font-kerning: none} | 18 | span.s1 {font-kerning: none} |
18 | span.s2 {font-kerning: none; color: #0433ff; -webkit-text-stroke: 0px #0433ff} | 19 | span.s2 {font-kerning: none; color: #0433ff; -webkit-text-stroke: 0px #0433ff} |
19 | span.s3 {font-kerning: none; color: #000000; -webkit-text-stroke: 0px #000000} | 20 | span.s3 {font-kerning: none; color: #000000; -webkit-text-stroke: 0px #000000} |
... | @@ -22,7 +23,8 @@ | ... | @@ -22,7 +23,8 @@ |
22 | span.s6 {font-kerning: none; color: #77bb41; -webkit-text-stroke: 0px #77bb41} | 23 | span.s6 {font-kerning: none; color: #77bb41; -webkit-text-stroke: 0px #77bb41} |
23 | span.s7 {font-kerning: none; color: #00c7fc; -webkit-text-stroke: 0px #00c7fc} | 24 | span.s7 {font-kerning: none; color: #00c7fc; -webkit-text-stroke: 0px #00c7fc} |
24 | span.s8 {font-kerning: none; color: #ff2600; -webkit-text-stroke: 0px #ff2600} | 25 | span.s8 {font-kerning: none; color: #ff2600; -webkit-text-stroke: 0px #ff2600} |
25 | - span.s9 {font-kerning: none; color: #669c35; -webkit-text-stroke: 0px #669c35} | 26 | + span.s9 {font-kerning: none; color: #000000} |
27 | + span.s10 {font-kerning: none; color: #669c35; -webkit-text-stroke: 0px #669c35} | ||
26 | span.Apple-tab-span {white-space:pre} | 28 | span.Apple-tab-span {white-space:pre} |
27 | </style> | 29 | </style> |
28 | </head> | 30 | </head> |
... | @@ -31,7 +33,7 @@ | ... | @@ -31,7 +33,7 @@ |
31 | <p class="p2"><span class="s1">Orange: vSG LAN connectivity (cross-connect)</span></p> | 33 | <p class="p2"><span class="s1">Orange: vSG LAN connectivity (cross-connect)</span></p> |
32 | <p class="p3"><span class="s1">Magenta: vSG WAN connectivity (default route)</span></p> | 34 | <p class="p3"><span class="s1">Magenta: vSG WAN connectivity (default route)</span></p> |
33 | <p class="p4"><span class="s1">Green: vRouter integration</span></p> | 35 | <p class="p4"><span class="s1">Green: vRouter integration</span></p> |
34 | -<p class="p5"><span class="s1">Light Blue: PIM integration</span></p> | 36 | +<p class="p5"><span class="s1">Light Blue: Multicast</span></p> |
35 | <p class="p6"><span class="s1">Red: Link validation</span></p> | 37 | <p class="p6"><span class="s1">Red: Link validation</span></p> |
36 | <p class="p7"><span class="s1"><br> | 38 | <p class="p7"><span class="s1"><br> |
37 | </span></p> | 39 | </span></p> |
... | @@ -221,7 +223,11 @@ | ... | @@ -221,7 +223,11 @@ |
221 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"org.onosproject.core" : {</span></p> | 223 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"org.onosproject.core" : {</span></p> |
222 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"core" : {</span></p> | 224 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"core" : {</span></p> |
223 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"linkDiscoveryMode" : "STRICT" </span><span class="s8">// enable strict link validation</span></p> | 225 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"linkDiscoveryMode" : "STRICT" </span><span class="s8">// enable strict link validation</span></p> |
224 | -<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>} <span class="Apple-converted-space"> </span></span></p> | 226 | +<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>},</span></p> |
227 | +<p class="p8"><span class="s9"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-converted-space"> </span>"multicast": { </span><span class="s1">// The VLAN we expect to see on the multicast ingress and egress</span></p> | ||
228 | +<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"ingressVlan": "None",</span></p> | ||
229 | +<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"egressVlan": "None"</span></p> | ||
230 | +<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}<span class="Apple-converted-space"> </span></span></p> | ||
225 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>},</span></p> | 231 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>},</span></p> |
226 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"org.onosproject.segmentrouting" : {</span></p> | 232 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"org.onosproject.segmentrouting" : {</span></p> |
227 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"segmentrouting" : {</span></p> | 233 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"segmentrouting" : {</span></p> |
... | @@ -243,7 +249,7 @@ | ... | @@ -243,7 +249,7 @@ |
243 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"controlPlaneConnectPoint" : "of:0000000000000002/31", </span><span class="s6">// location of Quagga</span></p> | 249 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"controlPlaneConnectPoint" : "of:0000000000000002/31", </span><span class="s6">// location of Quagga</span></p> |
244 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"ospfEnabled" : "true", </span><span class="s6">// enable OSPF</span></p> | 250 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"ospfEnabled" : "true", </span><span class="s6">// enable OSPF</span></p> |
245 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"pimEnabled" : "true", </span><span class="s7">// enable PIM</span></p> | 251 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"pimEnabled" : "true", </span><span class="s7">// enable PIM</span></p> |
246 | -<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"interfaces" : [ "external-quagga" ] </span><span class="s9">// </span><span class="s6">VR only handles peers on these ports</span></p> | 252 | +<p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>"interfaces" : [ "external-quagga" ] </span><span class="s10">// </span><span class="s6">VR only handles peers on these ports</span></p> |
247 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> | 253 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> |
248 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> | 254 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> |
249 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> | 255 | <p class="p7"><span class="s1"><span class="Apple-converted-space"> </span>}</span></p> | ... | ... |
... | @@ -228,6 +228,10 @@ | ... | @@ -228,6 +228,10 @@ |
228 | "org.onosproject.core" : { | 228 | "org.onosproject.core" : { |
229 | "core" : { | 229 | "core" : { |
230 | "linkDiscoveryMode" : "STRICT" | 230 | "linkDiscoveryMode" : "STRICT" |
231 | + }, | ||
232 | + "multicast": { | ||
233 | + "ingressVlan": "None", | ||
234 | + "egressVlan": "None" | ||
231 | } | 235 | } |
232 | }, | 236 | }, |
233 | "org.onosproject.segmentrouting" : { | 237 | "org.onosproject.segmentrouting" : { | ... | ... |
-
Please register or login to post a comment