Bug 6786: L3VPN is not honoring VTEP add or delete in operational cloud 52/47452/10
authorHANAMANTAGOUD V Kandagal <hanamantagoud.v.kandagal@ericsson.com>
Mon, 24 Oct 2016 14:34:19 +0000 (20:04 +0530)
committerSam Hague <shague@redhat.com>
Fri, 11 Nov 2016 20:15:06 +0000 (20:15 +0000)
As part of making L3VPN honor VTEP add-delete operation , this is a first
set of change where VpnInterface can be configured and VRF entry created
even if VTEP IP on a DPN is not available.

Change-Id: If07f297be3894fe1cd5de5b614565055fa16f09e
Signed-off-by: HANAMANTAGOUD V Kandagal <hanamantagoud.v.kandagal@ericsson.com>
Signed-off-by: ehvkand <hanamantagoud.v.kandagal@ericsson.com>
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java

index 210777f735691bc8ac382d8e21c41c2c37a2045b..b6d192f2247232a14394b5adbc6f6349b401032e 100644 (file)
@@ -484,13 +484,6 @@ public class FibUtil {
 
         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
 
-        for ( String nextHop: nextHopList){
-            if (nextHop == null || nextHop.isEmpty()){
-                LOG.error("nextHop list contains null element");
-                return;
-            }
-        }
-
         LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
         try{
             InstanceIdentifier<VrfEntry> vrfEntryId =
index e84235daf27035e66fd954034cb2771d399a6132..e30c66e1ce7427d38b13f73bcfd36c0130412b9c 100755 (executable)
@@ -623,11 +623,17 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
             // Get the rd of the vpn instance
             String rd = getRouteDistinguisher(vpnName);
-
-            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
-            if (nextHopIp == null){
-                LOG.error("NextHop for interface {} is null", interfaceName);
-                return;
+            String nextHopIp = null;
+            try {
+                nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
+            } catch (Exception e) {
+                LOG.warn("Unable to retrieve enpoint ip address for dpnId {} for vpnInterface {} vpnName {}",
+                        dpnId, interfaceName, vpnName);
+            }
+            List<java.lang.String> nhList = new ArrayList<>();
+            if (nextHopIp != null){
+                nhList.add(nextHopIp);
+                LOG.trace("NextHop for interface {} is {}", interfaceName, nhList);
             }
 
             List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
@@ -644,7 +650,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 }
                 List<String> adjNextHop = nextHop.getNextHopIpList();
                 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
-                        (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
+                        (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nhList)
                         .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
 
                 if (nextHop.isPrimaryAdjacency()) {
@@ -675,15 +681,15 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             for (Adjacency nextHop : aug.getAdjacency()) {
                 long label = nextHop.getLabel();
                 if (rd != null) {
-                    addToLabelMapper(label, dpnId, nextHop.getIpAddress(), Arrays.asList(nextHopIp), vpnId,
+                    addToLabelMapper(label, dpnId, nextHop.getIpAddress(), nhList, vpnId,
                             interfaceName, null,false, rd, writeOperTxn);
-                    addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label, RouteOrigin.LOCAL, writeConfigTxn);
+                    addPrefixToBGP(rd, nextHop.getIpAddress(), nhList, label, RouteOrigin.LOCAL, writeConfigTxn);
                     //TODO: ERT - check for VPNs importing my route
                     for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
                         String vpnRd = vpn.getVrfId();
                         if (vpnRd != null) {
                             LOG.debug("Exporting route with rd {} prefix {} nexthop {} label {} to VPN {}", vpnRd, nextHop.getIpAddress(), nextHopIp, label, vpn);
-                            fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), Arrays.asList(nextHopIp), (int) label,
+                            fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), nhList, (int) label,
                                     RouteOrigin.SELF_IMPORTED, writeConfigTxn);
                         }
                     }
@@ -1045,14 +1051,18 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         }
     }
 
-    private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label, RouteOrigin origin,
+    private void addPrefixToBGP(String rd, String prefix, List<String> nextHopList, long label, RouteOrigin origin,
                                 WriteTransaction writeConfigTxn) {
         try {
-            LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
-            fibManager.addOrUpdateFibEntry(dataBroker, rd, prefix, Arrays.asList(nextHopIp), (int)label, origin,
-                                           writeConfigTxn);
-            bgpManager.advertisePrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label);
-            LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
+            LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopList, label);
+            fibManager.addOrUpdateFibEntry(dataBroker, rd, prefix, nextHopList, (int)label, origin, writeConfigTxn);
+            LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopList, label);
+            // Advertize the prefix to BGP only if nexthop ip is available
+            if (nextHopList!= null && !nextHopList.isEmpty()) {
+                bgpManager.advertisePrefix(rd, prefix, nextHopList, (int)label);
+            } else {
+                LOG.warn("NextHopList is null/empty. Hence rd {} prefix {} is not advertised to BGP", rd, prefix);
+            }
         } catch(Exception e) {
             LOG.error("Add prefix failed", e);
         }
@@ -1206,35 +1216,41 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         // This is either an extra-route (or) a learned IP via subnet-route
                         String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
                         if (nextHopIp == null || nextHopIp.isEmpty()) {
-                            LOG.error("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
+                            LOG.warn("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
                                     rd, nextHop.getIpAddress());
-                            continue;
+                        } else {
+                            nhList = Arrays.asList(nextHopIp);
                         }
-                        nhList = Arrays.asList(nextHopIp);
                     } else {
                         // This is a primary adjacency
                         nhList = nextHop.getNextHopIpList();
                     }
-                    if (rd.equals(vpnName)) {
-                        //this is an internal vpn - the rd is assigned to the vpn instance name;
-                        //remove from FIB directly
-                        for(String nh : nhList) {
-                            fibManager.removeOrUpdateFibEntry(dataBroker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
-                        }
-                    } else {
-                        List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
-                        for (String nh : nhList) {
-                            //IRT: remove routes from other vpns importing it
-                            removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
-                            for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
-                                String vpnRd = vpn.getVrfId();
-                                if (vpnRd != null) {
-                                    LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
-                                    fibManager.removeOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
+
+                    if (!nhList.isEmpty()) {
+                        if (rd.equals(vpnName)) {
+                            //this is an internal vpn - the rd is assigned to the vpn instance name;
+                            //remove from FIB directly
+                            for (String nh : nhList) {
+                                fibManager.removeOrUpdateFibEntry(dataBroker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
+                            }
+                        } else {
+                            List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+                            for (String nh : nhList) {
+                                //IRT: remove routes from other vpns importing it
+                                removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
+                                for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
+                                    String vpnRd = vpn.getVrfId();
+                                    if (vpnRd != null) {
+                                        LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
+                                        fibManager.removeOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
+                                    }
                                 }
                             }
                         }
+                    } else {
+                        fibManager.removeFibEntry(dataBroker, rd , nextHop.getIpAddress(), writeConfigTxn);
                     }
+
                     String ip = nextHop.getIpAddress().split("/")[0];
                     VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker,
                             vpnName, ip);
@@ -1631,8 +1647,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
             String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
             if (nextHopIp == null || nextHopIp.isEmpty()) {
-                LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
-                        intfName, destination);
+                LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for rd {} prefix {}",
+                        intfName, rd, destination);
                 return;
             }
             nextHop = nextHopIp;
@@ -1669,11 +1685,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             InterVpnLinkUtil.leakRoute(dataBroker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
         } else {
             if (rd != null) {
-                addPrefixToBGP(rd, destination, nextHop, label, origin, writeConfigTxn);
+                addPrefixToBGP(rd, destination, nextHopIpList, label, origin, writeConfigTxn);
             } else {
                 // ### add FIB route directly
-                fibManager.addOrUpdateFibEntry(dataBroker, routerID, destination, Arrays.asList(nextHop), label,
-                                               origin, writeConfigTxn);
+                fibManager.addOrUpdateFibEntry(dataBroker, routerID, destination, nextHopIpList, label, origin, writeConfigTxn);
             }
         }
         if (!writeOperTxnPresent) {
index 73f871644e1bc062eb16d44f0ad5d7b7d006c51f..438b33ec85ecbf53b484fa7c1b5cedcf0b36fef5 100644 (file)
@@ -209,8 +209,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             logger.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);
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
                         subOpBuilder.setRouteAdvState(TaskState.Done);
                     } catch (Exception ex) {
                         logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
@@ -294,8 +293,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 try {
                     //Withdraw the routes for all the interfaces on this subnet
                     //Remove subnet route entry from FIB
-                    deleteSubnetRouteFromFib(rd, subnetIp, vpnName, nhDpnId);
-                    withdrawSubnetRoutefromBgp(rd, subnetIp);
+                    deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
                 } catch (Exception ex) {
                     logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " +
                             subnetId.getValue() + " failed {}" + ex);
@@ -416,8 +414,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             logger.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);
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
                         subOpBuilder.setRouteAdvState(TaskState.Done);
                     } catch (Exception ex) {
                         logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
@@ -487,8 +484,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             subOpBuilder.setNhDpnId(null);
                             try {
                                 // withdraw route from BGP
-                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, nhDpnId);
-                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
                                 subOpBuilder.setRouteAdvState(TaskState.Na);
                             } catch (Exception ex) {
                                 logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
@@ -508,8 +504,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                                     logger.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);
+                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
                                 subOpBuilder.setRouteAdvState(TaskState.Done);
                             } catch (Exception ex) {
                                 logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
@@ -591,8 +586,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             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);
                             return;
                         }
-                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
-                        advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
+                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
                         subOpBuilder.setRouteAdvState(TaskState.Done);
                     } catch (Exception ex) {
                         logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
@@ -659,8 +653,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             subOpBuilder.setNhDpnId(null);
                             try {
                                 // Withdraw route from BGP for this subnet
-                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, nhDpnId);
-                                withdrawSubnetRoutefromBgp(rd, subnetIp);
+                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
                                 subOpBuilder.setRouteAdvState(TaskState.Na);
                             } catch (Exception ex) {
                                 logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
@@ -679,8 +672,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                                     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);
                                     return;
                                 }
-                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
-                                advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
+                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
                                 subOpBuilder.setRouteAdvState(TaskState.Done);
                             } catch (Exception ex) {
                                 logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
@@ -713,16 +705,33 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     }
 
     private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
-                                     Long elanTag, int label) {
+                                     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) {
+            logger.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
+            return;
+        }
+        if (nexthopIp != null) {
+            VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp), VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp));
+            vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId, null);
+            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);
+            } catch (Exception e) {
+                logger.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e);
+                throw e;
+            }
+        } else {
+            logger.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
+        }
     }
 
     private int getLabel(String rd, String subnetIp) {
@@ -732,44 +741,14 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         return label;
     }
 
-    private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName,
-                                          BigInteger nhDpnId) {
+    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);
-        } catch (Exception e) {
-            logger.error("Subnet route not advertised for rd " + rd + " failed ", 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);
+            logger.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e);
             throw e;
         }
     }