X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=vpnservice%2Fvpnmanager%2Fvpnmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Fvpnmanager%2FVpnSubnetRouteHandler.java;h=e538de71cf24cb5a3c06889f9b4569caee281c54;hb=4e71b898eaea5b547dd51100d52671624a9e3e6d;hp=83e74632c212be010484148b647838cdc9225e15;hpb=f60b2b35594f7cb0bc3aeba1a48f9ef9610649d5;p=netvirt.git diff --git a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java index 83e74632c2..e538de71cf 100644 --- a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java +++ b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java @@ -11,20 +11,24 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.math.BigInteger; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.netvirt.bgpmanager.api.IBgpManager; +import org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer.VpnOpDataType; import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.TaskState; @@ -55,28 +59,32 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VpnSubnetRouteHandler implements NeutronvpnListener { - private static final Logger logger = LoggerFactory.getLogger(VpnSubnetRouteHandler.class); + private static final Logger LOG = LoggerFactory.getLogger(VpnSubnetRouteHandler.class); private final DataBroker dataBroker; private final SubnetOpDpnManager subOpDpnManager; private final IBgpManager bgpManager; private final VpnInterfaceManager vpnInterfaceManager; private final IdManagerService idManager; private LockManagerService lockManager; + private final VpnOpDataSyncer vpnOpDataSyncer; public VpnSubnetRouteHandler(final DataBroker dataBroker, final SubnetOpDpnManager subnetOpDpnManager, - final IBgpManager bgpManager, final VpnInterfaceManager vpnIntfManager, - final IdManagerService idManager, LockManagerService lockManagerService) { + final IBgpManager bgpManager, final VpnInterfaceManager vpnIntfManager, final IdManagerService idManager, + LockManagerService lockManagerService, final VpnOpDataSyncer vpnOpDataSyncer) { this.dataBroker = dataBroker; this.subOpDpnManager = subnetOpDpnManager; this.bgpManager = bgpManager; this.vpnInterfaceManager = vpnIntfManager; this.idManager = idManager; this.lockManager = lockManagerService; + this.vpnOpDataSyncer = vpnOpDataSyncer; } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") @Override public void onSubnetAddedToVpn(SubnetAddedToVpn notification) { - if (!notification.isExternalVpn()) { + if (!notification.isBgpVpn()) { return; } @@ -84,13 +92,26 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { String vpnName = notification.getVpnName(); String subnetIp = notification.getSubnetIp(); Long elanTag = notification.getElanTag(); + boolean isRouteAdvertised = false; Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!"); Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!"); Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!"); Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!"); - logger.info("onSubnetAddedToVpn: Subnet " + subnetId.getValue() + " being added to vpn"); + LOG.info("onSubnetAddedToVpn: Subnet {} being added to vpn", subnetId.getValue()); + long vpnId = VpnUtil.getVpnId(dataBroker, vpnName); + if (vpnId == VpnConstants.INVALID_ID) { + vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataType.vpnInstanceToId, vpnName, + VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS); + vpnId = VpnUtil.getVpnId(dataBroker, vpnName); + if (vpnId == VpnConstants.INVALID_ID) { + LOG.error( + "onSubnetAddedToVpn: VpnInstance to VPNId mapping not yet available for VpnName {} processing " + + "subnet {} with IP {}, bailing out now.", vpnName, subnetId, subnetIp); + return; + } + } //TODO(vivek): Change this to use more granularized lock at subnetId level try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); @@ -98,51 +119,57 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { Subnetmap subMap = null; // Please check if subnetId belongs to an External Network - InstanceIdentifier subMapid = InstanceIdentifier.builder(Subnetmaps.class). - child(Subnetmap.class, new SubnetmapKey(subnetId)).build(); + InstanceIdentifier subMapid = + InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, + new SubnetmapKey(subnetId)).build(); Optional sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid); if (!sm.isPresent()) { - logger.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId); + LOG.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId); return; } subMap = sm.get(); - InstanceIdentifier netsIdentifier = InstanceIdentifier.builder(ExternalNetworks.class). - child(Networks.class, new NetworksKey(subMap.getNetworkId())).build(); - Optional optionalNets = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, netsIdentifier); + InstanceIdentifier netsIdentifier = + InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class, + new NetworksKey(subMap.getNetworkId())).build(); + Optional optionalNets = + VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, netsIdentifier); if (optionalNets.isPresent()) { - logger.info("onSubnetAddedToVpn: subnet {} is an external subnet on external network {}, so ignoring this for SubnetRoute", - subnetId.getValue(), subMap.getNetworkId().getValue()); + LOG.info( + "onSubnetAddedToVpn: subnet {} is an external subnet on external network {}, so ignoring this" + + " for SubnetRoute", subnetId.getValue(), subMap.getNetworkId().getValue()); return; } //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); Optional optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier); if (optionalSubs.isPresent()) { - logger.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() + - " already detected to be present"); + LOG.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet {} already detected to be present", + subnetId.getValue()); return; } - logger.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue()); - Map subDpnMap = new HashMap(); - SubnetOpDataEntry subOpEntry = null; + LOG.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + Map subDpnMap = new HashMap<>(); BigInteger dpnId = null; BigInteger nhDpnId = null; SubnetToDpn subDpn = null; - SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId)); + SubnetOpDataEntryBuilder subOpBuilder = + new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId)); subOpBuilder.setSubnetId(subnetId); subOpBuilder.setSubnetCidr(subnetIp); - String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpnName); - if (rd == null) { - logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD "); + String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName); + if (!VpnUtil.isBgpVpn(vpnName, primaryRd)) { + LOG.error("onSubnetAddedToVpn: The VPN Instance name " + + notification.getVpnName() + " does not have RD "); return; } - subOpBuilder.setVrfId(rd); + subOpBuilder.setVrfId(primaryRd); subOpBuilder.setVpnName(vpnName); - subOpBuilder.setSubnetToDpn(new ArrayList()); + subOpBuilder.setSubnetToDpn(new ArrayList<>()); subOpBuilder.setRouteAdvState(TaskState.Na); subOpBuilder.setElanTag(elanTag); @@ -155,18 +182,19 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { try { dpnId = InterfaceUtils.getDpIdFromInterface(intfState); } catch (Exception e) { - logger.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},", + LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},", " subnetroute inclusion for this interface failed with exception {}", port.getValue(), e); continue; } if (dpnId.equals(BigInteger.ZERO)) { - logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not assigned DPN yet, ignoring "); + LOG.info("onSubnetAddedToVpn: Port " + port.getValue() + + " is not assigned DPN yet, ignoring "); continue; } subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId); if (intfState.getOperStatus() != OperStatus.Up) { - logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring "); + LOG.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring "); continue; } subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue()); @@ -182,72 +210,84 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { } } if (subDpnMap.size() > 0) { - subOpBuilder.setSubnetToDpn(new ArrayList(subDpnMap.values())); + subOpBuilder.setSubnetToDpn(new ArrayList<>(subDpnMap.values())); } } if (nhDpnId != null) { - logger.info("Next-Hop dpn {} is available for rd {} subnetIp {} vpn {}", nhDpnId, rd, subnetIp, vpnName); + LOG.info("Next-Hop dpn {} is available for rd {} subnetIp {} vpn {}", nhDpnId, primaryRd, + subnetIp, vpnName); subOpBuilder.setNhDpnId(nhDpnId); try { /* Write the subnet route entry to the FIB. And also advertise the subnet route entry via BGP. */ - int label = getLabel(rd, subnetIp); + int label = getLabel(primaryRd, subnetIp); if (label == 0) { - logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {} to vpn {}", subnetIp, vpnName); + LOG.error( + "Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {}" + + " to vpn {}", + subnetIp, vpnName); return; } - addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - subOpBuilder.setRouteAdvState(TaskState.Done); + isRouteAdvertised = + addSubnetRouteToFib(primaryRd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } } catch (Exception ex) { - logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId + - " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex); + LOG.error( + "onSubnetAddedToVpn: FIB rules and Advertising nhDpnId {} information for subnet {} to " + + "BGP failed", + nhDpnId, subnetId.getValue(), ex); subOpBuilder.setRouteAdvState(TaskState.Pending); } - }else{ - logger.info("Next-Hop dpn is unavailable for rd {} subnetIp {} vpn {}", rd, subnetIp, vpnName); + } else { + LOG.info("Next-Hop dpn is unavailable for rd {} subnetIp {} vpn {}", primaryRd, subnetIp, vpnName); } - subOpEntry = subOpBuilder.build(); + SubnetOpDataEntry subOpEntry = subOpBuilder.build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); - logger.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}", + LOG.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}", subnetId.getValue()); } catch (Exception ex) { - logger.error("Creation of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}", ex); + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle subnet {} added to vpn {} {}", subnetIp, vpnName, e); + LOG.error("Unable to handle subnet {} added to vpn {} {}", subnetIp, vpnName, e); } - } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") @Override public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) { Uuid subnetId = notification.getSubnetId(); - if (!notification.isExternalVpn()) { + if (!notification.isBgpVpn()) { return; } - logger.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn"); + LOG.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn"); //TODO(vivek): Change this to use more granularized lock at subnetId level try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); try { - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); - logger.trace(" Removing the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); + LOG.trace(" Removing the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); Optional optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier); if (!optionalSubs.isPresent()) { - logger.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() + - " not available in datastore"); + LOG.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet {} not available in datastore", + subnetId.getValue()); return; } @@ -256,19 +296,21 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { * contain only ports that are UP. So here we explicitly cleanup the ports of the subnet by * going through the list of ports on the subnet */ - InstanceIdentifier subMapid = InstanceIdentifier.builder(Subnetmaps.class). - child(Subnetmap.class, new SubnetmapKey(subnetId)).build(); + InstanceIdentifier subMapid = + InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, + new SubnetmapKey(subnetId)).build(); Optional sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid); if (!sm.isPresent()) { - logger.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId); + LOG.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId); } else { Subnetmap subMap = sm.get(); List portList = subMap.getPortList(); if (portList != null) { for (Uuid port : portList) { - InstanceIdentifier portOpIdentifier = InstanceIdentifier.builder(PortOpData.class). - child(PortOpDataEntry.class, new PortOpDataEntryKey(port.getValue())).build(); - logger.trace("Deleting portOpData entry for port " + port.getValue()); + InstanceIdentifier portOpIdentifier = + InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class, + new PortOpDataEntryKey(port.getValue())).build(); + LOG.trace("Deleting portOpData entry for port " + port.getValue()); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier); } } @@ -278,25 +320,26 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { String rd = subOpBuilder.getVrfId(); String subnetIp = subOpBuilder.getSubnetCidr(); String vpnName = subOpBuilder.getVpnName(); + BigInteger nhDpnId = subOpBuilder.getNhDpnId(); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier); - logger.info("onSubnetDeletedFromVpn: Removed subnetopdataentry for subnet {} successfully from Datastore", subnetId.getValue()); + LOG.info("onSubnetDeletedFromVpn: Removed subnetopdataentry for subnet {} successfully from Datastore", + subnetId.getValue()); try { //Withdraw the routes for all the interfaces on this subnet //Remove subnet route entry from FIB deleteSubnetRouteFromFib(rd, subnetIp, vpnName); - withdrawSubnetRoutefromBgp(rd, subnetIp); } catch (Exception ex) { - logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " + - subnetId.getValue() + " failed {}" + ex); + LOG.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet {} failed", + subnetId.getValue(), ex); } } catch (Exception ex) { - logger.error("Removal of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}" + ex); + LOG.error("Removal of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle subnet {} removed to vpn {} {}", notification.getSubnetIp(), notification.getVpnName(), e); + LOG.error("Unable to handle subnet {} removed to vpn {}", notification.getSubnetIp(), + notification.getVpnName(), e); } } @@ -312,46 +355,50 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!"); Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!"); - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); - Optional optionalSubs = VpnUtil.read(dataBroker, - LogicalDatastoreType.OPERATIONAL, - subOpIdentifier); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); + Optional optionalSubs = + VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier); if (optionalSubs.isPresent()) { - if (!notification.isExternalVpn()) { + if (!notification.isBgpVpn()) { SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName); - bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId); + bldr.setElanTag(elanTag).setBgpVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId); onSubnetDeletedFromVpn(bldr.build()); } // TODO(vivek): Something got updated, but we donot know what ? } else { - if (notification.isExternalVpn()) { + if (notification.isBgpVpn()) { SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag); - bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);; + bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setBgpVpn(true); onSubnetAddedToVpn(bldr.build()); } // TODO(vivek): Something got updated, but we donot know what ? } } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") @Override public void onPortAddedToSubnet(PortAddedToSubnet notification) { Uuid subnetId = notification.getSubnetId(); Uuid portId = notification.getPortId(); + boolean isRouteAdvertised = false; - logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue()); + LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue()); //TODO(vivek): Change this to use more granularized lock at subnetId level try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); try { - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); Optional optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier); if (!optionalSubs.isPresent()) { - logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() + - " that is not in VPN, ignoring"); + LOG.info("onPortAddedToSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring", + portId.getValue(), subnetId.getValue()); return; } Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,portId.getValue()); @@ -364,21 +411,22 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { try { dpnId = InterfaceUtils.getDpIdFromInterface(intfState); } catch (Exception e) { - logger.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},", + LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},", " subnetroute inclusion for this interface failed with exception {}", portId.getValue(), e); return; } if (dpnId.equals(BigInteger.ZERO)) { - logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring "); + LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring "); return; } subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId); if (intfState.getOperStatus() != OperStatus.Up) { - logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring "); + LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring "); return; } - logger.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + LOG.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet {}", + subnetId.getValue()); SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue()); if (subDpn == null) { return; @@ -395,45 +443,58 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { String subnetIp = subOpBuilder.getSubnetCidr(); String vpnName = subOpBuilder.getVpnName(); Long elanTag = subOpBuilder.getElanTag(); - if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || - (subOpBuilder.getRouteAdvState() == TaskState.Na)) { + if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) + || (subOpBuilder.getRouteAdvState() == TaskState.Na)) { try { // Write the Subnet Route Entry to FIB // Advertise BGP Route here and set route_adv_state to DONE int label = getLabel(rd, subnetIp); if (label == 0) { - logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of port {} to subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName); + LOG.error( + "Unable to fetch label from Id Manager. Bailing out of handling addition of port {} " + + "to subnet {} in vpn {}", + portId.getValue(), subnetIp, vpnName); return; } - addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - subOpBuilder.setRouteAdvState(TaskState.Done); + isRouteAdvertised = + addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } } catch (Exception ex) { - logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId + - " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex); + LOG.error( + "onPortAddedToSubnet: Advertising NextHopDPN {} information for subnet {} to BGP failed", + nhDpnId, subnetId.getValue(), ex); } } SubnetOpDataEntry subOpEntry = subOpBuilder.build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); - logger.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port " + portId.getValue()); + LOG.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port {}", + portId.getValue()); } catch (Exception ex) { - logger.error("Creation of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}", ex); + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle port {} added to subnet {} {}", portId.getValue(), subnetId.getValue(), e); + LOG.error("Unable to handle port {} added to subnet {} {}", portId.getValue(), subnetId.getValue(), e); } } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") @Override public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) { Uuid subnetId = notification.getSubnetId(); Uuid portId = notification.getPortId(); + boolean isRouteAdvertised = false; - logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue()); + LOG.info( + "onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue()); //TODO(vivek): Change this to use more granularized lock at subnetId level try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); @@ -444,18 +505,21 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { } BigInteger dpnId = portOpEntry.getDpnId(); if (dpnId == null) { - logger.debug("onPortRemovedFromSubnet: Port {} does not have a DPNId associated, ignoring", portId.getValue()); + LOG.debug("onPortRemovedFromSubnet: Port {} does not have a DPNId associated, ignoring", + portId.getValue()); return; } - logger.debug("onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + LOG.debug( + "onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue()); - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); Optional optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, - subOpIdentifier); + subOpIdentifier); if (!optionalSubs.isPresent()) { - logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() + - " that is not in VPN, ignoring"); + LOG.info("onPortRemovedFromSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring", + portId.getValue(), subnetId.getValue()); return; } SubnetOpDataEntry subOpEntry = null; @@ -469,7 +533,8 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) { // select another NhDpnId if (last) { - logger.debug("onPortRemovedFromSubnet: Last port " + portId + " on the subnet: " + subnetId.getValue()); + LOG.debug("onPortRemovedFromSubnet: Last port {} on the subnet {}", portId, + subnetId.getValue()); // last port on this DPN, so we need to swap the NHDpnId subDpnList = subOpBuilder.getSubnetToDpn(); if (subDpnList.isEmpty()) { @@ -477,33 +542,44 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { try { // withdraw route from BGP deleteSubnetRouteFromFib(rd, subnetIp, vpnName); - withdrawSubnetRoutefromBgp(rd, subnetIp); subOpBuilder.setRouteAdvState(TaskState.Na); } catch (Exception ex) { - logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " + - subnetId.getValue() + " from BGP failed ", ex); + LOG.error( + "onPortRemovedFromSubnet: Withdrawing NextHopDPN {} information for subnet {} " + + "from BGP failed ", + dpnId, subnetId.getValue(), ex); subOpBuilder.setRouteAdvState(TaskState.Pending); } } else { nhDpnId = subDpnList.get(0).getDpnId(); subOpBuilder.setNhDpnId(nhDpnId); - logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue()); + LOG.debug("onInterfaceDown: Swapping the Designated DPN to {} for subnet {}", nhDpnId, + subnetId.getValue()); try { // Best effort Withdrawal of route from BGP for this subnet // Advertise the new NexthopIP to BGP for this subnet //withdrawSubnetRoutefromBgp(rd, subnetIp); int label = getLabel(rd, subnetIp); if (label == 0) { - logger.error("Unable to fetch label from Id Manager. Bailing out of handling removal of port {} from subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName); + LOG.error( + "Unable to fetch label from Id Manager. Bailing out of handling removal of " + + "port {} from subnet {} in vpn {}", + portId.getValue(), subnetIp, vpnName); return; } - addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - subOpBuilder.setRouteAdvState(TaskState.Done); + isRouteAdvertised = + addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } } catch (Exception ex) { - logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId + - " information for subnet " + subnetId.getValue() + - " to BGP failed {}" + ex); + LOG.error( + "onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN {} information for " + + "subnet {} to BGP failed", + dpnId, subnetId.getValue(), ex); subOpBuilder.setRouteAdvState(TaskState.Pending); } } @@ -511,59 +587,64 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { } subOpEntry = subOpBuilder.build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); - logger.info("onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId.getValue()); + LOG.info( + "onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId + .getValue()); } catch (Exception ex) { - logger.error("Creation of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}" + ex); + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle port {} removed from subnet {} {}", portId.getValue(), subnetId.getValue(), e); + LOG.error("Unable to handle port {} removed from subnet {} {}", portId.getValue(), subnetId.getValue(), + e); } } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") public void onInterfaceUp(BigInteger dpnId, String intfName) { - logger.info("onInterfaceUp: Port " + intfName); + LOG.info("onInterfaceUp: Port " + intfName); //TODO(vivek): Change this to use more granularized lock at subnetId level SubnetToDpn subDpn = null; + boolean isRouteAdvertised = false; PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName); if (portOpEntry == null) { - logger.info("onInterfaceUp: Port " + intfName + "is part of a subnet not in VPN, ignoring"); + LOG.info("onInterfaceUp: Port " + intfName + "is part of a subnet not in VPN, ignoring"); return; } - if ((dpnId == null) || (dpnId == BigInteger.ZERO)) { + if ((dpnId == null) || (Objects.equals(dpnId, BigInteger.ZERO))) { dpnId = portOpEntry.getDpnId(); if (dpnId == null) { - logger.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName); - return; + LOG.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName); + return; } } Uuid subnetId = portOpEntry.getSubnetId(); try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); try { - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); Optional optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, - subOpIdentifier); + subOpIdentifier); if (!optionalSubs.isPresent()) { - logger.error("onInterfaceUp: SubnetOpDataEntry for subnet " + subnetId.getValue() + - " is not available"); + LOG.error("onInterfaceUp: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue()); return; } - SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get()); - logger.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + LOG.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId); subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName); if (subDpn == null) { return; } + SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get()); List subDpnList = subOpBuilder.getSubnetToDpn(); subDpnList.add(subDpn); subOpBuilder.setSubnetToDpn(subDpnList); - if (subOpBuilder.getNhDpnId() == null) { + if (subOpBuilder.getNhDpnId() == null) { subOpBuilder.setNhDpnId(dpnId); } BigInteger nhDpnId = subOpBuilder.getNhDpnId(); @@ -571,63 +652,75 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { String subnetIp = subOpBuilder.getSubnetCidr(); String vpnName = subOpBuilder.getVpnName(); Long elanTag = subOpBuilder.getElanTag(); - if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || (subOpBuilder.getRouteAdvState() == TaskState.Na)) { + if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) + || (subOpBuilder.getRouteAdvState() == TaskState.Na)) { try { // Write the Subnet Route Entry to FIB // Advertise BGP Route here and set route_adv_state to DONE int label = getLabel(rd, subnetIp); if (label == 0) { - logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface up event for port {} for subnet {} in vpn {}", intfName, subnetIp, vpnName); + LOG.error( + "Unable to fetch label from Id Manager. Bailing out of handling interface up event " + + "for port {} for subnet {} in vpn {}", + intfName, subnetIp, vpnName); return; } - addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - subOpBuilder.setRouteAdvState(TaskState.Done); + isRouteAdvertised = + addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } } catch (Exception ex) { - logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " + - subnetId.getValue() + " to BGP failed {}" + ex); + LOG.error("onInterfaceUp: Advertising NextHopDPN {} information for subnet {} to BGP failed", + nhDpnId, subnetId.getValue(), ex); } } SubnetOpDataEntry subOpEntry = subOpBuilder.build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); - logger.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName); + LOG.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName); } catch (Exception ex) { - logger.error("Creation of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}" + ex); + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle interface up event for port {} in subnet {} {}", portOpEntry.getPortId(), subnetId.getValue(), e); + LOG.error("Unable to handle interface up event for port {} in subnet {} {}", portOpEntry.getPortId(), + subnetId.getValue(), e); } } + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") public void onInterfaceDown(final BigInteger dpnId, final String interfaceName) { - logger.info("onInterfaceDown: Port " + interfaceName); + boolean isRouteAdvertised = false; + LOG.info("onInterfaceDown: Port " + interfaceName); //TODO(vivek): Change this to use more granularized lock at subnetId level PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(interfaceName); if (portOpEntry == null) { - logger.info("onInterfaceDown: Port " + interfaceName + "is part of a subnet not in VPN, ignoring"); + LOG.info("onInterfaceDown: Port " + interfaceName + "is part of a subnet not in VPN, ignoring"); return; } - if ((dpnId == null) ||(dpnId == BigInteger.ZERO)) { - logger.error("onInterfaceDown: Unable to determine the DPNID for port " + interfaceName); + if ((dpnId == null) || (Objects.equals(dpnId, BigInteger.ZERO))) { + LOG.error("onInterfaceDown: Unable to determine the DPNID for port " + interfaceName); return; } Uuid subnetId = portOpEntry.getSubnetId(); try { VpnUtil.lockSubnet(lockManager, subnetId.getValue()); try { - logger.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); + LOG.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue()); boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, interfaceName); - InstanceIdentifier subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class). - child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build(); + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); Optional optionalSubs = VpnUtil.read(dataBroker, - LogicalDatastoreType.OPERATIONAL, - subOpIdentifier); + LogicalDatastoreType.OPERATIONAL, + subOpIdentifier); if (!optionalSubs.isPresent()) { - logger.error("onInterfaceDown: SubnetOpDataEntry for subnet " + subnetId.getValue() + - " is not available"); + LOG.error("onInterfaceDown: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue()); return; } SubnetOpDataEntry subOpEntry = null; @@ -641,7 +734,9 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) { // select another NhDpnId if (last) { - logger.debug("onInterfaceDown: Last active port " + interfaceName + " on the subnet: " + subnetId.getValue()); + LOG.debug( + "onInterfaceDown: Last active port " + interfaceName + " on the subnet: " + subnetId + .getValue()); // last port on this DPN, so we need to swap the NHDpnId subDpnList = subOpBuilder.getSubnetToDpn(); if (subDpnList.isEmpty()) { @@ -649,31 +744,43 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { try { // Withdraw route from BGP for this subnet deleteSubnetRouteFromFib(rd, subnetIp, vpnName); - withdrawSubnetRoutefromBgp(rd, subnetIp); subOpBuilder.setRouteAdvState(TaskState.Na); } catch (Exception ex) { - logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " + - subnetId.getValue() + " from BGP failed {}" + ex); + LOG.error( + "onInterfaceDown: Withdrawing NextHopDPN {} information for subnet {} from BGP " + + "failed", + dpnId, subnetId.getValue(), ex); subOpBuilder.setRouteAdvState(TaskState.Pending); } } else { nhDpnId = subDpnList.get(0).getDpnId(); subOpBuilder.setNhDpnId(nhDpnId); - logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue()); + LOG.debug( + "onInterfaceDown: Swapping the Designated DPN to {} for subnet {}" , nhDpnId, + subnetId.getValue()); try { // Best effort Withdrawal of route from BGP for this subnet //withdrawSubnetRoutefromBgp(rd, subnetIp); int label = getLabel(rd, subnetIp); if (label == 0) { - logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface down event for port {} in subnet {} for vpn {}", interfaceName, subnetIp, vpnName); + LOG.error( + "Unable to fetch label from Id Manager. Bailing out of handling interface " + + "down event for port {} in subnet {} for vpn {}", + interfaceName, subnetIp, vpnName); return; } - addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label); - subOpBuilder.setRouteAdvState(TaskState.Done); + isRouteAdvertised = + addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } } catch (Exception ex) { - logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " + - subnetId.getValue() + " to BGP failed {}" + ex); + LOG.error( + "onInterfaceDown: Swapping Withdrawing NextHopDPN {} information for " + + "subnet {} to BGP failed", dpnId, subnetId.getValue(), ex); subOpBuilder.setRouteAdvState(TaskState.Pending); } } @@ -681,15 +788,15 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { } subOpEntry = subOpBuilder.build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); - logger.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + interfaceName); + LOG.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + interfaceName); } catch (Exception ex) { - logger.error("Creation of SubnetOpDataEntry for subnet " + - subnetId.getValue() + " failed {}" + ex); + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); } finally { VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); } } catch (Exception e) { - logger.error("Unable to handle interface down event for port {} in subnet {} {}", portOpEntry.getPortId(), subnetId.getValue(), e); + LOG.error("Unable to handle interface down event for port {} in subnet {} {}", portOpEntry.getPortId(), + subnetId.getValue(), e); } } @@ -701,64 +808,227 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener { public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) { } - private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName, - Long elanTag, int label) { + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + public void updateSubnetRouteOnTunnelUpEvent(Uuid subnetId, BigInteger dpnId) { + boolean isRouteAdvertised = false; + LOG.info("updateSubnetRouteOnTunnelUpEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString()); + try { + VpnUtil.lockSubnet(lockManager, subnetId.getValue()); + try { + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); + Optional optionalSubs = VpnUtil.read(dataBroker, + LogicalDatastoreType.OPERATIONAL, + subOpIdentifier); + if (!optionalSubs.isPresent()) { + LOG.error("updateSubnetRouteOnTunnelUpEvent: SubnetOpDataEntry for subnet {} is not available", + subnetId.getValue()); + return; + } + SubnetOpDataEntry subOpEntry = null; + SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get()); + String rd = subOpBuilder.getVrfId(); + String subnetIp = subOpBuilder.getSubnetCidr(); + String vpnName = subOpBuilder.getVpnName(); + List subDpnList = subOpBuilder.getSubnetToDpn(); + long elanTag = subOpBuilder.getElanTag(); + if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) + || (subOpBuilder.getRouteAdvState() == TaskState.Na)) { + for (SubnetToDpn subDpn : subDpnList) { + if (subDpn.getDpnId().equals(dpnId)) { + if (subOpBuilder.getNhDpnId() == null) { + try { + subOpBuilder.setNhDpnId(dpnId); + int label = getLabel(rd, subnetIp); + isRouteAdvertised = + addSubnetRouteToFib(rd, subnetIp, dpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + } else { + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } + } catch (Exception ex) { + LOG.error( + "updateSubnetRouteOnTunnelUpEvent: Advertising NextHopDPN {} information for " + + "subnet {} to BGP failed", + dpnId, subnetId.getValue(), ex); + } + } + } + } + subOpEntry = subOpBuilder.build(); + MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); + LOG.info( + "updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up on dpn" + + " {} for subnet {}", + dpnId.toString(), subnetId.getValue()); + } + } catch (Exception ex) { + LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); + } finally { + VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); + } + } catch (Exception e) { + LOG.error("Unable to handle tunnel up event for subnetId {} dpnId {}", subnetId.getValue(), + dpnId.toString()); + } + } + + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + public void updateSubnetRouteOnTunnelDownEvent(Uuid subnetId, BigInteger dpnId) { + LOG.info("updateSubnetRouteOnTunnelDownEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString()); + //TODO(vivek): Change this to use more granularized lock at subnetId level + try { + VpnUtil.lockSubnet(lockManager, subnetId.getValue()); + try { + InstanceIdentifier subOpIdentifier = + InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class, + new SubnetOpDataEntryKey(subnetId)).build(); + Optional optionalSubs = VpnUtil.read(dataBroker, + LogicalDatastoreType.OPERATIONAL, + subOpIdentifier); + if (!optionalSubs.isPresent()) { + LOG.error("updateSubnetRouteOnTunnelDownEvent: SubnetOpDataEntry for subnet {} is not available", + subnetId.getValue()); + return; + } + SubnetOpDataEntry subOpEntry = null; + SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get()); + BigInteger nhDpnId = subOpBuilder.getNhDpnId(); + if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) { + electNewDPNForSubNetRoute(subOpBuilder, dpnId, subnetId); + subOpEntry = subOpBuilder.build(); + MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry); + LOG.info( + "updateSubnetRouteOnTunnelDownEvent: Updated subnetopdataentry to OP Datastore tunnnel down " + + "on dpn {} for subnet {}", + dpnId.toString(), subnetId.getValue()); + } + } catch (Exception ex) { + LOG.error("Updation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex); + } finally { + VpnUtil.unlockSubnet(lockManager, subnetId.getValue()); + } + } catch (Exception e) { + LOG.error("Unable to handle tunnel down event for subnetId {} dpnId {}", subnetId.getValue(), + dpnId.toString()); + } + } + + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName, + Long elanTag, int label, Uuid subnetId) throws Exception { Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!"); Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!"); Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!"); Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!"); - String nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId); - if(nexthopIp != null) - vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId , null); - else - logger.info("Unable to get nextHop ip address for nextHop DPN {}. Abort adding subnet route to FIB table.", nhDpnId); + String nexthopIp = null; + try { + nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId); + } catch (Exception e) { + LOG.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp); + return false; + } + if (nexthopIp != null) { + VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp), + VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp, subnetId, true /* isNatPrefix*/)); + vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId, + null); + try { + //BGP manager will handle withdraw and advertise internally if prefix + //already exist + bgpManager.advertisePrefix(rd, null /*macAddress*/, subnetIp, Collections.singletonList(nexthopIp), + VrfEntry.EncapType.Mplsgre, label, 0 /*l3vni*/, 0 /*l2vni*/, null /*gatewayMacAddress*/); + } catch (Exception e) { + LOG.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e); + throw e; + } + } else { + LOG.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp); + return false; + } + return true; } private int getLabel(String rd, String subnetIp) { int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, - VpnUtil.getNextHopLabelKey(rd, subnetIp)); - logger.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp); + VpnUtil.getNextHopLabelKey(rd, subnetIp)); + LOG.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp); return label; } - private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName) { + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName) throws Exception { Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!"); Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!"); vpnInterfaceManager.deleteSubnetRouteFibEntryFromDS(rd, subnetIp, vpnName); - } - - private void advertiseSubnetRouteToBgp(String rd, String subnetIp, BigInteger nhDpnId, String vpnName, - Long elanTag, int label) throws Exception { - Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!"); - Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!"); - Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!"); - Preconditions.checkNotNull(nhDpnId, "nhDpnId cannot be null or empty!"); - Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!"); - String nexthopIp = null; - nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId); - if (nexthopIp == null) { - logger.error("createSubnetRouteInVpn: Unable to obtain endpointIp address for DPNId " + nhDpnId); - throw new Exception("Unable to obtain endpointIp address for DPNId " + nhDpnId); - } try { - // BGPManager (inside ODL) requires a withdraw followed by advertise - // due to bugs with ClusterDataChangeListener used by BGPManager. - //bgpManager.withdrawPrefix(rd, subnetIp); - bgpManager.advertisePrefix(rd, subnetIp, Arrays.asList(nexthopIp), label); + bgpManager.withdrawPrefix(rd, subnetIp); } catch (Exception e) { - logger.error("Subnet route not advertised for rd " + rd + " failed ", e); + LOG.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e); throw e; } } - private void withdrawSubnetRoutefromBgp(String rd, String subnetIp) throws Exception { - Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!"); - Preconditions.checkNotNull(subnetIp, "SubnetIp cannot be null or empty!"); - try { - bgpManager.withdrawPrefix(rd, subnetIp); - } catch (Exception e) { - logger.error("Subnet route not advertised for rd " + rd + " failed ", e); - throw e; + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private void electNewDPNForSubNetRoute(SubnetOpDataEntryBuilder subOpBuilder, BigInteger dpnId, Uuid subnetId) { + List subDpnList = null; + boolean isRouteAdvertised = false; + subDpnList = subOpBuilder.getSubnetToDpn(); + String rd = subOpBuilder.getVrfId(); + String subnetIp = subOpBuilder.getSubnetCidr(); + String vpnName = subOpBuilder.getVpnName(); + long elanTag = subOpBuilder.getElanTag(); + BigInteger nhDpnId = null; + boolean isAlternateDpnSelected = false; + Iterator subNetIt = subDpnList.iterator(); + int label = getLabel(rd, subnetIp); + while (subNetIt.hasNext()) { + SubnetToDpn subnetToDpn = subNetIt.next(); + nhDpnId = subnetToDpn.getDpnId(); + if (!nhDpnId.equals(dpnId)) { + try { + //update the VRF entry for the subnetroute. + isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId); + if (isRouteAdvertised) { + subOpBuilder.setRouteAdvState(TaskState.Done); + subOpBuilder.setNhDpnId(nhDpnId); + isAlternateDpnSelected = true; + break; + } + } catch (Exception ex) { + LOG.error( + "electNewDPNForSubNetRoute: Swapping and trying to configure NextHopDPN {} for subnet {} " + + "failed ex {}", + dpnId.toString(), subnetId.getValue(), ex); + subOpBuilder.setRouteAdvState(TaskState.Na); + } + } + } + + //If no alternate Dpn is selected as nextHopDpn ,withdraw the subnetroute. + if (!isAlternateDpnSelected) { + LOG.info("No alternate DPN available for subnet {}.Prefix withdrawn from BGP", subnetIp); + try { + // Withdraw route from BGP for this subnet + deleteSubnetRouteFromFib(rd, subnetIp, vpnName); + subOpBuilder.setNhDpnId(null); + subOpBuilder.setRouteAdvState(TaskState.Na); + } catch (Exception ex) { + LOG.error( + "electNewDPNForSubNetRoute: Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet " + + + subnetId.getValue() + " from BGP failed {}" + ex); + subOpBuilder.setRouteAdvState(TaskState.Pending); + } } } }