From 4ed33ac63f597a999af34b95f20ce483a40ae0b6 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 24 Mar 2017 12:34:05 +0530 Subject: [PATCH] Bug 7939, 7938, 7968, 7997: Potential fix for the four L3VPN bugs While creating LocalFibEntry, localDpnId list is being returned empty leading to local FIB entry not getting installed. The fix ensures we log an error statement in case it happens Change-Id: I95589523079f9d990b5e61d96b71b2c6d1c133e1 Signed-off-by: Abhinav Gupta --- .../netvirt/fibmanager/VrfEntryListener.java | 268 +++++++++++------- 1 file changed, 168 insertions(+), 100 deletions(-) diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java index 958605139f..16cc0c9c23 100755 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java @@ -123,7 +123,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class VrfEntryListener extends AsyncDataTreeChangeListenerBase implements AutoCloseable, ResourceHandler { +public class VrfEntryListener extends AsyncDataTreeChangeListenerBase implements + AutoCloseable, ResourceHandler { private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class); private static final String FLOWID_PREFIX = "L3."; private static final int BATCH_SIZE = 1000; @@ -257,7 +258,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase transactionObjects) { + public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, + Object vrfEntry, List transactionObjects) { this.transactionObjects = transactionObjects; if (vrfEntry instanceof VrfEntry) { createFibEntries(tx, identifier, (VrfEntry)vrfEntry); @@ -290,7 +294,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase transactionObjects) { + public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, + Object vrfEntry, List transactionObjects) { this.transactionObjects = transactionObjects; if (vrfEntry instanceof VrfEntry) { deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry); @@ -298,7 +303,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase transactionObjects) { this.transactionObjects = transactionObjects; if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) { @@ -326,7 +332,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnToDpnList = vpnInstance.getVpnToDpnList(); final Long vpnId = vpnInstance.getVpnId(); @@ -345,7 +352,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> futures = new ArrayList<>(); @@ -363,30 +371,30 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry); - if (vpnToDpnList != null) { - DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); - dataStoreCoordinator.enqueueJob("FIB-"+ rd.toString() + "-" + vrfEntry.getDestPrefix(), - new Callable>>() { - @Override - public List> call() throws Exception { - WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); - for (VpnToDpnList vpnDpn : vpnToDpnList) { - if ( !localDpnIdList.contains(vpnDpn.getDpnId())) { - if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) { - createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx); - } - } + if (!localDpnIdList.isEmpty()) { + if (vpnToDpnList != null) { + DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); + dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(), () -> { + WriteTransaction tx = dataBroker.newWriteOnlyTransaction(); + for (VpnToDpnList vpnDpn : vpnToDpnList) { + if (!localDpnIdList.contains(vpnDpn.getDpnId())) { + if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) { + createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, + vrfEntry, tx); } - List> futures = new ArrayList<>(); - futures.add(tx.submit()); - return futures; } - }); + } + List> futures = new ArrayList<>(); + futures.add(tx.submit()); + return futures; + }); + } } Optional optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd); if ( optVpnUuid.isPresent() ) { - Optional optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get()); + Optional optInterVpnLink = + InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get()); LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent()); if ( optInterVpnLink.isPresent() ) { InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get(); @@ -408,12 +416,14 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vrfEntryIid, final VrfEntry vrfEntry) { + private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier vrfEntryIid, + final VrfEntry vrfEntry) { final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class); final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!"); + Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has " + + "null vpnId!"); final Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); if (vpnToDpnList != null) { @@ -470,7 +480,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceNames = lri.getVpnInstanceList(); vpnInstanceNames.add(vpnInstanceName); builder.setVpnInstanceList(vpnInstanceNames); - FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK); + FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), + FibUtil.DEFAULT_CALLBACK); } else { LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel()); } @@ -490,7 +501,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd); + Optional vpnInstanceOpDataEntryOptional = + FibUtil.getVpnInstanceOpData(dataBroker, rd); if (vpnInstanceOpDataEntryOptional.isPresent()) { String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName(); if (!lri.getVpnInstanceList().contains(vpnInstanceName)) { @@ -503,9 +515,12 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase instructions = new ArrayList(); - BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1))); - instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE })); - instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE })); + BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)). + or((BigInteger.valueOf(vpnId).shiftLeft(1))); + instructions.add(new InstructionInfo(InstructionType.write_metadata, + new BigInteger[]{subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE})); + instructions.add(new InstructionInfo(InstructionType.goto_table, + new long[]{NwConstants.L3_SUBNET_ROUTE_TABLE})); makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx); if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { @@ -515,10 +530,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName()); + Optional vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, + interVpnLink.getName()); if ( !vpnLinkState.isPresent() || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) { LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state", @@ -568,9 +587,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{})); - BigInteger[] metadata = new BigInteger[] { - MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)), - MetaDataUtil.getMetaDataMaskForLPortDispatcher() + BigInteger[] metadata = new BigInteger[]{MetaDataUtil.getMetaDataForLPortDispatcher( + lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, + NwConstants.L3VPN_SERVICE_INDEX)), MetaDataUtil.getMetaDataMaskForLPortDispatcher() }; List instructions = Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos), @@ -578,7 +597,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd); + Optional vpnInstanceOpDataEntryOptional = + FibUtil.getVpnInstanceOpData(dataBroker, rd); if (vpnInstanceOpDataEntryOptional.isPresent()) { String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName(); if (lri.getVpnInstanceList().contains(vpnInstanceName)) { @@ -754,13 +777,17 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); + final List lfibinstructions = Arrays.asList(new InstructionInfo( + InstructionType.apply_actions, actionsInfos)); if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel()); } else { - LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. LFib and Terminating table entries will not be created.", rd, vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpnId); + LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. LFib and " + + "Terminating table entries will not be created.", rd, vrfEntry.getDestPrefix(), + vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpnId); } DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); dataStoreCoordinator.enqueueJob(jobKey, @@ -814,7 +844,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> futures = new ArrayList<>(); @@ -853,7 +884,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstancesList = lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList(); + List vpnInstancesList = + lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList(); if (vpnInstancesList.contains(vpnInstanceName)) { LOG.debug("vpninstance {} name is present", vpnInstanceName); vpnInstancesList.remove(vpnInstanceName); @@ -869,7 +901,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase mkMatches = new ArrayList<>(); - LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos); + LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId, + label, actionsInfos); // Matching metadata // FIXME vxlan vni bit set is not working properly with OVS.need to revisit @@ -899,9 +933,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase mkInstructions = new ArrayList<>(); mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos)); - FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, - getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label), - 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); + FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, + NwConstants.INTERNAL_TUNNEL_TABLE, getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, + label), 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0, + COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) ); @@ -910,7 +945,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase flowInstanceId = InstanceIdentifier.builder(Nodes.class) .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build(); + .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())) + .child(Flow.class,flowKey).build(); tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true ); } @@ -998,7 +1034,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase>>() { @Override public List> call() throws Exception { @@ -1083,10 +1120,12 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase egressActions = nextHopManager.getEgressActionsForInterface(egressInterface, actionInfos.size()); + List egressActions = nextHopManager.getEgressActionsForInterface(egressInterface, + actionInfos.size()); if (egressActions.isEmpty()) { LOG.error( - "Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", + "Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB " + + "entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), egressInterface); return; } @@ -1261,7 +1300,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd); + Optional vpnInstanceOpDataEntryOptional = + FibUtil.getVpnInstanceOpData(dataBroker, rd); String vpnInstanceName = ""; if (vpnInstanceOpDataEntryOptional.isPresent()) { vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName(); @@ -1346,7 +1386,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd); + if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && + vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) { + Optional vpnInstanceOpDataEntryOptional = + FibUtil.getVpnInstanceOpData(dataBroker, rd); String vpnInstanceName = ""; if (vpnInstanceOpDataEntryOptional.isPresent()) { vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName(); @@ -1371,14 +1414,14 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase identifier, final VrfEntry vrfEntry) { + private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier identifier, + final VrfEntry vrfEntry) { final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class); final String rd = vrfTableKey.getRouteDistinguisher(); @@ -1478,7 +1526,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase