Charles Chan

CORD-135 Support Multicast Source on a Configured Port

Missing part of gerrit #9230
Forwarding objective need to check the existing VLAN as well

Change-Id: I8e9cadc57c332a20567eaeaa2030901fc2dbf5b8
...@@ -197,7 +197,6 @@ public class McastHandler { ...@@ -197,7 +197,6 @@ public class McastHandler {
197 ConnectPoint source = mcastRouteInfo.source().orElse(null); 197 ConnectPoint source = mcastRouteInfo.source().orElse(null);
198 ConnectPoint sink = mcastRouteInfo.sink().orElse(null); 198 ConnectPoint sink = mcastRouteInfo.sink().orElse(null);
199 IpAddress mcastIp = mcastRouteInfo.route().group(); 199 IpAddress mcastIp = mcastRouteInfo.route().group();
200 - VlanId assignedVlan = assignedVlan();
201 200
202 // When source and sink are on the same device 201 // When source and sink are on the same device
203 if (source.deviceId().equals(sink.deviceId())) { 202 if (source.deviceId().equals(sink.deviceId())) {
...@@ -206,12 +205,12 @@ public class McastHandler { ...@@ -206,12 +205,12 @@ public class McastHandler {
206 log.warn("Sink is on the same port of source. Abort"); 205 log.warn("Sink is on the same port of source. Abort");
207 return; 206 return;
208 } 207 }
209 - removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); 208 + removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
210 return; 209 return;
211 } 210 }
212 211
213 // Process the egress device 212 // Process the egress device
214 - boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); 213 + boolean isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
215 if (isLast) { 214 if (isLast) {
216 mcastRoleStore.remove(new McastStoreKey(mcastIp, sink.deviceId())); 215 mcastRoleStore.remove(new McastStoreKey(mcastIp, sink.deviceId()));
217 } 216 }
...@@ -224,7 +223,8 @@ public class McastHandler { ...@@ -224,7 +223,8 @@ public class McastHandler {
224 for (Link link : links) { 223 for (Link link : links) {
225 if (isLast) { 224 if (isLast) {
226 isLast = removePortFromDevice(link.src().deviceId(), link.src().port(), 225 isLast = removePortFromDevice(link.src().deviceId(), link.src().port(),
227 - mcastIp, assignedVlan); 226 + mcastIp,
227 + assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
228 mcastRoleStore.remove(new McastStoreKey(mcastIp, link.src().deviceId())); 228 mcastRoleStore.remove(new McastStoreKey(mcastIp, link.src().deviceId()));
229 } 229 }
230 } 230 }
...@@ -240,10 +240,8 @@ public class McastHandler { ...@@ -240,10 +240,8 @@ public class McastHandler {
240 */ 240 */
241 private void processSinkAddedInternal(ConnectPoint source, ConnectPoint sink, 241 private void processSinkAddedInternal(ConnectPoint source, ConnectPoint sink,
242 IpAddress mcastIp) { 242 IpAddress mcastIp) {
243 - VlanId assignedVlan = assignedVlan();
244 -
245 // Process the ingress device 243 // Process the ingress device
246 - addFilterToDevice(source.deviceId(), source.port(), assignedVlan); 244 + addFilterToDevice(source.deviceId(), source.port(), assignedVlan(source));
247 245
248 // When source and sink are on the same device 246 // When source and sink are on the same device
249 if (source.deviceId().equals(sink.deviceId())) { 247 if (source.deviceId().equals(sink.deviceId())) {
...@@ -252,7 +250,7 @@ public class McastHandler { ...@@ -252,7 +250,7 @@ public class McastHandler {
252 log.warn("Sink is on the same port of source. Abort"); 250 log.warn("Sink is on the same port of source. Abort");
253 return; 251 return;
254 } 252 }
255 - addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); 253 + addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(source));
256 mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), McastRole.INGRESS); 254 mcastRoleStore.put(new McastStoreKey(mcastIp, sink.deviceId()), McastRole.INGRESS);
257 return; 255 return;
258 } 256 }
...@@ -265,12 +263,13 @@ public class McastHandler { ...@@ -265,12 +263,13 @@ public class McastHandler {
265 "Path in leaf-spine topology should always be two hops: ", links); 263 "Path in leaf-spine topology should always be two hops: ", links);
266 264
267 links.forEach(link -> { 265 links.forEach(link -> {
268 - addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan); 266 + addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
269 - addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp, assignedVlan); 267 + assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
268 + addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null));
270 }); 269 });
271 270
272 // Process the egress device 271 // Process the egress device
273 - addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan); 272 + addPortToDevice(sink.deviceId(), sink.port(), mcastIp, assignedVlan(null));
274 273
275 // Setup mcast roles 274 // Setup mcast roles
276 mcastRoleStore.put(new McastStoreKey(mcastIp, source.deviceId()), 275 mcastRoleStore.put(new McastStoreKey(mcastIp, source.deviceId()),
...@@ -291,8 +290,6 @@ public class McastHandler { ...@@ -291,8 +290,6 @@ public class McastHandler {
291 * @param affectedLink Link that is going down 290 * @param affectedLink Link that is going down
292 */ 291 */
293 protected void processLinkDown(Link affectedLink) { 292 protected void processLinkDown(Link affectedLink) {
294 - VlanId assignedVlan = assignedVlan();
295 -
296 getAffectedGroups(affectedLink).forEach(mcastIp -> { 293 getAffectedGroups(affectedLink).forEach(mcastIp -> {
297 // Find out the ingress, transit and egress device of affected group 294 // Find out the ingress, transit and egress device of affected group
298 DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS) 295 DeviceId ingressDevice = getDevice(mcastIp, McastRole.INGRESS)
...@@ -300,19 +297,23 @@ public class McastHandler { ...@@ -300,19 +297,23 @@ public class McastHandler {
300 DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT) 297 DeviceId transitDevice = getDevice(mcastIp, McastRole.TRANSIT)
301 .stream().findAny().orElse(null); 298 .stream().findAny().orElse(null);
302 Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS); 299 Set<DeviceId> egressDevices = getDevice(mcastIp, McastRole.EGRESS);
303 - if (ingressDevice == null || transitDevice == null || egressDevices == null) { 300 + ConnectPoint source = getSource(mcastIp);
304 - log.warn("Missing ingress {}, transit {}, or egress {} devices", 301 +
305 - ingressDevice, transitDevice, egressDevices); 302 + // Do not proceed if any of these info is missing
303 + if (ingressDevice == null || transitDevice == null
304 + || egressDevices == null || source == null) {
305 + log.warn("Missing ingress {}, transit {}, egress {} devices or source {}",
306 + ingressDevice, transitDevice, egressDevices, source);
306 return; 307 return;
307 } 308 }
308 309
309 // Remove entire transit 310 // Remove entire transit
310 - removeGroupFromDevice(transitDevice, mcastIp, assignedVlan); 311 + removeGroupFromDevice(transitDevice, mcastIp, assignedVlan(null));
311 312
312 // Remove transit-facing port on ingress device 313 // Remove transit-facing port on ingress device
313 PortNumber ingressTransitPort = ingressTransitPort(mcastIp); 314 PortNumber ingressTransitPort = ingressTransitPort(mcastIp);
314 if (ingressTransitPort != null) { 315 if (ingressTransitPort != null) {
315 - removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan); 316 + removePortFromDevice(ingressDevice, ingressTransitPort, mcastIp, assignedVlan(source));
316 mcastRoleStore.remove(new McastStoreKey(mcastIp, transitDevice)); 317 mcastRoleStore.remove(new McastStoreKey(mcastIp, transitDevice));
317 } 318 }
318 319
...@@ -322,8 +323,9 @@ public class McastHandler { ...@@ -322,8 +323,9 @@ public class McastHandler {
322 if (mcastPath.isPresent()) { 323 if (mcastPath.isPresent()) {
323 List<Link> links = mcastPath.get().links(); 324 List<Link> links = mcastPath.get().links();
324 links.forEach(link -> { 325 links.forEach(link -> {
325 - addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp, assignedVlan); 326 + addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
326 - addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan); 327 + assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
328 + addFilterToDevice(link.dst().deviceId(), link.dst().port(), assignedVlan(null));
327 }); 329 });
328 // Setup new transit mcast role 330 // Setup new transit mcast role
329 mcastRoleStore.put(new McastStoreKey(mcastIp, 331 mcastRoleStore.put(new McastStoreKey(mcastIp,
...@@ -331,7 +333,7 @@ public class McastHandler { ...@@ -331,7 +333,7 @@ public class McastHandler {
331 } else { 333 } else {
332 log.warn("Fail to recover egress device {} from link failure {}", 334 log.warn("Fail to recover egress device {} from link failure {}",
333 egressDevice, affectedLink); 335 egressDevice, affectedLink);
334 - removeGroupFromDevice(egressDevice, mcastIp, assignedVlan); 336 + removeGroupFromDevice(egressDevice, mcastIp, assignedVlan(null));
335 } 337 }
336 }); 338 });
337 }); 339 });
...@@ -521,7 +523,9 @@ public class McastHandler { ...@@ -521,7 +523,9 @@ public class McastHandler {
521 while (itNextObj.hasNext()) { 523 while (itNextObj.hasNext()) {
522 Map.Entry<McastStoreKey, Versioned<NextObjective>> entry = itNextObj.next(); 524 Map.Entry<McastStoreKey, Versioned<NextObjective>> entry = itNextObj.next();
523 if (entry.getKey().deviceId().equals(deviceId)) { 525 if (entry.getKey().deviceId().equals(deviceId)) {
524 - removeGroupFromDevice(entry.getKey().deviceId(), entry.getKey().mcastIp(), assignedVlan()); 526 + ConnectPoint source = getSource(entry.getKey().mcastIp());
527 + removeGroupFromDevice(entry.getKey().deviceId(), entry.getKey().mcastIp(),
528 + assignedVlan(deviceId.equals(source.deviceId()) ? source : null));
525 itNextObj.remove(); 529 itNextObj.remove();
526 } 530 }
527 } 531 }
...@@ -693,6 +697,19 @@ public class McastHandler { ...@@ -693,6 +697,19 @@ public class McastHandler {
693 } 697 }
694 698
695 /** 699 /**
700 + * Gets source connect point of given multicast group.
701 + *
702 + * @param mcastIp multicast IP
703 + * @return source connect point or null if not found
704 + */
705 + private ConnectPoint getSource(IpAddress mcastIp) {
706 + return srManager.multicastRouteService.getRoutes().stream()
707 + .filter(mcastRoute -> mcastRoute.group().equals(mcastIp))
708 + .map(mcastRoute -> srManager.multicastRouteService.fetchSource(mcastRoute))
709 + .findAny().orElse(null);
710 + }
711 +
712 + /**
696 * Gets groups which is affected by the link down event. 713 * Gets groups which is affected by the link down event.
697 * 714 *
698 * @param link link going down 715 * @param link link going down
...@@ -721,13 +738,27 @@ public class McastHandler { ...@@ -721,13 +738,27 @@ public class McastHandler {
721 738
722 /** 739 /**
723 * Gets assigned VLAN according to the value of egress VLAN. 740 * Gets assigned VLAN according to the value of egress VLAN.
741 + * If connect point is specified, try to reuse the assigned VLAN on the connect point.
724 * 742 *
725 - * @return assigned VLAN 743 + * @param cp connect point; Can be null if not specified
744 + * @return assigned VLAN ID
726 */ 745 */
727 - private VlanId assignedVlan() { 746 + private VlanId assignedVlan(ConnectPoint cp) {
728 - return (egressVlan().equals(VlanId.NONE)) ? 747 + // Use the egressVlan if it is tagged
729 - VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) : 748 + if (!egressVlan().equals(VlanId.NONE)) {
730 - egressVlan(); 749 + return egressVlan();
750 + }
751 + // Reuse unicast VLAN if the port has subnet configured
752 + if (cp != null) {
753 + Ip4Prefix portSubnet = srManager.deviceConfiguration
754 + .getPortSubnet(cp.deviceId(), cp.port());
755 + VlanId unicastVlan = srManager.getSubnetAssignedVlanId(cp.deviceId(), portSubnet);
756 + if (unicastVlan != null) {
757 + return unicastVlan;
758 + }
759 + }
760 + // By default, use VLAN_NO_SUBNET
761 + return VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
731 } 762 }
732 763
733 /** 764 /**
......