Charles Chan
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
......@@ -762,6 +762,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
//log.trace("processLinkAdded: re-starting route population process");
//defaultRoutingHandler.startPopulationProcess();
mcastHandler.init();
}
private void processLinkRemoved(Link link) {
......@@ -775,6 +777,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
//log.trace("processLinkRemoved: re-starting route population process");
//defaultRoutingHandler.startPopulationProcess();
mcastHandler.processLinkDown(link);
}
private void processDeviceAdded(Device device) {
......@@ -784,17 +788,22 @@ public class SegmentRoutingManager implements SegmentRoutingService {
+ "processed after config completes.", device.id());
return;
}
processDeviceAddedInternal(device.id());
}
private void processDeviceAddedInternal(DeviceId deviceId) {
// Irrespective of whether the local is a MASTER or not for this device,
// we need to create a SR-group-handler instance. This is because in a
// multi-instance setup, any instance can initiate forwarding/next-objectives
// for any switch (even if this instance is a SLAVE or not even connected
// to the switch). To handle this, a default-group-handler instance is necessary
// per switch.
if (groupHandlerMap.get(device.id()) == null) {
log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
if (groupHandlerMap.get(deviceId) == null) {
DefaultGroupHandler groupHandler;
try {
groupHandler = DefaultGroupHandler.
createGroupHandler(device.id(),
createGroupHandler(deviceId,
appId,
deviceConfiguration,
linkService,
......@@ -804,23 +813,25 @@ public class SegmentRoutingManager implements SegmentRoutingService {
log.warn(e.getMessage() + " Aborting processDeviceAdded.");
return;
}
groupHandlerMap.put(device.id(), groupHandler);
log.debug("updating groupHandlerMap with new config for device: {}",
deviceId);
groupHandlerMap.put(deviceId, groupHandler);
// Also, in some cases, drivers may need extra
// information to process rules (eg. Router IP/MAC); and so, we send
// port addressing rules to the driver as well irrespective of whether
// this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
defaultRoutingHandler.populatePortAddressingRules(deviceId);
}
if (mastershipService.isLocalMaster(device.id())) {
hostHandler.readInitialHosts(device.id());
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
if (mastershipService.isLocalMaster(deviceId)) {
hostHandler.readInitialHosts(deviceId);
DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
groupHandler.createGroupsFromSubnetConfig();
routingRulePopulator.populateSubnetBroadcastRule(device.id());
groupHandler.createGroupsForXConnect(device.id());
routingRulePopulator.populateXConnectBroadcastRule(device.id());
routingRulePopulator.populateSubnetBroadcastRule(deviceId);
groupHandler.createGroupsForXConnect(deviceId);
routingRulePopulator.populateXConnectBroadcastRule(deviceId);
}
netcfgHandler.initVRouters(device.id());
netcfgHandler.initVRouters(deviceId);
}
private void processDeviceRemoved(Device device) {
......@@ -829,34 +840,29 @@ public class SegmentRoutingManager implements SegmentRoutingService {
.forEach(entry -> {
nsNextObjStore.remove(entry.getKey());
});
subnetNextObjStore.entrySet().stream()
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
.forEach(entry -> {
subnetNextObjStore.remove(entry.getKey());
});
portNextObjStore.entrySet().stream()
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
.forEach(entry -> {
portNextObjStore.remove(entry.getKey());
});
xConnectNextObjStore.entrySet().stream()
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
.forEach(entry -> {
xConnectNextObjStore.remove(entry.getKey());
});
subnetVidStore.entrySet().stream()
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
.forEach(entry -> {
subnetVidStore.remove(entry.getKey());
});
groupHandlerMap.remove(device.id());
defaultRoutingHandler.purgeEcmpGraph(device.id());
mcastHandler.removeDevice(device.id());
}
private void processPortRemoved(Device device, Port port) {
......@@ -900,48 +906,11 @@ public class SegmentRoutingManager implements SegmentRoutingService {
tunnelHandler, policyStore);
for (Device device : deviceService.getDevices()) {
// Irrespective of whether the local is a MASTER or not for this device,
// we need to create a SR-group-handler instance. This is because in a
// multi-instance setup, any instance can initiate forwarding/next-objectives
// for any switch (even if this instance is a SLAVE or not even connected
// to the switch). To handle this, a default-group-handler instance is necessary
// per switch.
log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
if (groupHandlerMap.get(device.id()) == null) {
DefaultGroupHandler groupHandler;
try {
groupHandler = DefaultGroupHandler.
createGroupHandler(device.id(),
appId,
deviceConfiguration,
linkService,
flowObjectiveService,
segmentRoutingManager);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting configureNetwork.");
return;
}
log.debug("updating groupHandlerMap with new config for "
+ "device: {}", device.id());
groupHandlerMap.put(device.id(), groupHandler);
// Also, in some cases, drivers may need extra
// information to process rules (eg. Router IP/MAC); and so, we send
// port addressing rules to the driver as well, irrespective of whether
// this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
}
if (mastershipService.isLocalMaster(device.id())) {
hostHandler.readInitialHosts(device.id());
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
groupHandler.createGroupsFromSubnetConfig();
routingRulePopulator.populateSubnetBroadcastRule(device.id());
groupHandler.createGroupsForXConnect(device.id());
routingRulePopulator.populateXConnectBroadcastRule(device.id());
}
processDeviceAddedInternal(device.id());
}
defaultRoutingHandler.startPopulationProcess();
mcastHandler.init();
}
@Override
......
......@@ -26,7 +26,7 @@ import java.util.Objects;
/**
* Key of multicast next objective store.
*/
public class McastNextObjectiveStoreKey {
public class McastStoreKey {
private final IpAddress mcastIp;
private final DeviceId deviceId;
......@@ -36,7 +36,7 @@ public class McastNextObjectiveStoreKey {
* @param mcastIp multicast group IP address
* @param deviceId device ID
*/
public McastNextObjectiveStoreKey(IpAddress mcastIp, DeviceId deviceId) {
public McastStoreKey(IpAddress mcastIp, DeviceId deviceId) {
checkNotNull(mcastIp, "mcastIp cannot be null");
checkNotNull(deviceId, "deviceId cannot be null");
checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address");
......@@ -67,11 +67,11 @@ public class McastNextObjectiveStoreKey {
if (this == o) {
return true;
}
if (!(o instanceof McastNextObjectiveStoreKey)) {
if (!(o instanceof McastStoreKey)) {
return false;
}
McastNextObjectiveStoreKey that =
(McastNextObjectiveStoreKey) o;
McastStoreKey that =
(McastStoreKey) o;
return (Objects.equals(this.mcastIp, that.mcastIp) &&
Objects.equals(this.deviceId, that.deviceId));
}
......
......@@ -5,7 +5,7 @@
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<meta name="CocoaVersion" content="1404.34">
<meta name="CocoaVersion" content="1404.46">
<style type="text/css">
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}
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 @@
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}
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}
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}
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}
span.s1 {font-kerning: none}
span.s2 {font-kerning: none; color: #0433ff; -webkit-text-stroke: 0px #0433ff}
span.s3 {font-kerning: none; color: #000000; -webkit-text-stroke: 0px #000000}
......@@ -22,7 +23,8 @@
span.s6 {font-kerning: none; color: #77bb41; -webkit-text-stroke: 0px #77bb41}
span.s7 {font-kerning: none; color: #00c7fc; -webkit-text-stroke: 0px #00c7fc}
span.s8 {font-kerning: none; color: #ff2600; -webkit-text-stroke: 0px #ff2600}
span.s9 {font-kerning: none; color: #669c35; -webkit-text-stroke: 0px #669c35}
span.s9 {font-kerning: none; color: #000000}
span.s10 {font-kerning: none; color: #669c35; -webkit-text-stroke: 0px #669c35}
span.Apple-tab-span {white-space:pre}
</style>
</head>
......@@ -31,7 +33,7 @@
<p class="p2"><span class="s1">Orange: vSG LAN connectivity (cross-connect)</span></p>
<p class="p3"><span class="s1">Magenta: vSG WAN connectivity (default route)</span></p>
<p class="p4"><span class="s1">Green: vRouter integration</span></p>
<p class="p5"><span class="s1">Light Blue: PIM integration</span></p>
<p class="p5"><span class="s1">Light Blue: Multicast</span></p>
<p class="p6"><span class="s1">Red: Link validation</span></p>
<p class="p7"><span class="s1"><br>
</span></p>
......@@ -221,7 +223,11 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"org.onosproject.core" : {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"core" : {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"linkDiscoveryMode" : "STRICT" </span><span class="s8">// enable strict link validation</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>} <span class="Apple-converted-space">   </span></span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>},</span></p>
<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>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ingressVlan": "None",</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"egressVlan": "None"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}<span class="Apple-converted-space"> </span></span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"org.onosproject.segmentrouting" : {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"segmentrouting" : {</span></p>
......@@ -243,7 +249,7 @@
<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>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ospfEnabled" : "true", </span><span class="s6">// enable OSPF</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"pimEnabled" : "true", </span><span class="s7">// enable PIM</span></p>
<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>
<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>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>}</span></p>
......
......@@ -228,6 +228,10 @@
"org.onosproject.core" : {
"core" : {
"linkDiscoveryMode" : "STRICT"
},
"multicast": {
"ingressVlan": "None",
"egressVlan": "None"
}
},
"org.onosproject.segmentrouting" : {
......