VPNv6 external network support for multiple router 00/76600/21
authorKarthikeyan Krishnan <karthikeyangceb007@gmail.com>
Wed, 3 Oct 2018 09:41:24 +0000 (15:11 +0530)
committerSam Hague <shague@redhat.com>
Wed, 17 Oct 2018 20:03:27 +0000 (20:03 +0000)
Issue:
=======
1) Single external network/internet(public) is
sharing to more than one router is not
working as expected for IPv6 internet data traffic.

2) Before spawning the VM on the compute, internet
access was set/enabled with router already. In this
case if boot the VM on the new DPN, default V6 internet
fallback rule is not getting programmed.

Solution:
=========
RCA for issue (1):
------------------
 IPv6 internet default fall back rule(21->21) is
 not getting programmed for if external network is
 associated with more than one router due to flow-id
 is not proper for each router.

RCA for issue (2):
------------------
 When first/last VM is booted/removed from the DPN,
 there is no check for whether router is already
 been set with external/internet connectivity via
 router-gw set as a result V6 internet default
 fallback rule is missing for newly added DPN.

As part of this fix, internet default fall back rule
flow-id is constrcted based on the router-id always.
Since we can not go with either external-vpn(router)
or internet bgp-vpn.

Also addressed the issue (2) problem as well.

NAT Module Dependency:
=======================
+ RouterDpnChangeListener --> Program and un-program
the V6 internet default fallback flows on when first
VM is booted on the compute or last VM is removed from
the compute for router VPN

Issue: NETVIRT-1440

Change-Id: I2e20158368984172117597e32a5310477ad57d16
Signed-off-by: Karthikeyan Krishnan <karthikeyangceb007@gmail.com>
natservice/impl/src/main/java/org/opendaylight/netvirt/natservice/internal/RouterDpnChangeListener.java
neutronvpn/api/src/main/java/org/opendaylight/netvirt/neutronvpn/interfaces/INeutronVpnManager.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/IPV6InternetDefaultRouteProgrammer.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronPortChangeListener.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnManager.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnManagerImpl.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnNatManager.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnUtils.java

index 11401b3efda7a3018ad796a4cb85fc820a07b6b5..1e21c71ee83c2f8150ba9035791328d53719f3da 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.GroupEntity;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -199,6 +200,11 @@ public class RouterDpnChangeListener
                                         + "vpnId {}...", dpnId, routerUuid, vpnId);
                                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
                                 }
+                                /* install V6 internet default fallback rule in FIB_TABLE if router
+                                 * is having V6 subnet
+                                 */
+                                nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
+                                        NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.ADD_FLOW);
                                 if (router.isEnableSnat()) {
                                     LOG.info("add : SNAT enabled for router {}", routerUuid);
                                     if (extNwProvType == null) {
@@ -290,7 +296,11 @@ public class RouterDpnChangeListener
                                         vpnName);
                                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
                                 }
-
+                                /* remove V6 internet default fallback rule in FIB_TABLE if router
+                                 * is having V6 subnet
+                                 */
+                                nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
+                                        NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.DEL_FLOW);
                                 if (router.isEnableSnat()) {
                                     LOG.info("remove : SNAT enabled for router {}", routerUuid);
                                     removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, confTx);
index 8fc193767073add1e1965eb42bb26fb5406b2085..c7a3af896c1dcd749b0768398a411ba6576581bb 100644 (file)
@@ -46,5 +46,7 @@ public interface INeutronVpnManager {
 
     String getOpenDaylightVniRangesConfig();
 
+    void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove);
+
 }
 
index 516fbbb22132213f6b84837305d9ed4871dbb8b5..6cf49d923c3fbe58570392636292474bd7dcdb5d 100644 (file)
@@ -41,7 +41,8 @@ public class IPV6InternetDefaultRouteProgrammer {
         this.mdsalManager = mdsalManager;
     }
 
-    private FlowEntity buildIPv6FallbacktoExternalVpn(BigInteger dpId, long internetBgpVpnId, long vpnId, boolean add) {
+    private FlowEntity buildIPv6FallbacktoExternalVpn(BigInteger dpId, String routerId, long internetBgpVpnId,
+                                                      long vpnId, boolean add) {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV6);
 
@@ -58,7 +59,10 @@ public class IPV6InternetDefaultRouteProgrammer {
             instructionInfo.add(new InstructionApplyActions(listActionInfo));
         }
         String defaultIPv6 = "0:0:0:0:0:0:0:0";
-        String flowRef = getIPv6FlowRefL3(dpId, NwConstants.L3_FIB_TABLE, defaultIPv6, internetBgpVpnId);
+        /* For each router it needs to have unique flow-id. Hence router-id is being used to generate the
+         * flow-id for each DPN instead of internet vpnId.
+         */
+        String flowRef = getIPv6FlowRefL3(dpId, NwConstants.L3_FIB_TABLE, defaultIPv6, routerId);
 
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
                 NwConstants.TABLE_MISS_PRIORITY, flowRef/* "L3 ipv6 internet default route",*/, 0, 0,
@@ -74,20 +78,20 @@ public class IPV6InternetDefaultRouteProgrammer {
      * @param internetBgpVpnId internetVpn id as long
      * @param vpnId id of router associated to internet bgpvpn as long
      */
-    public void installDefaultRoute(BigInteger dpnId, long internetBgpVpnId, long vpnId) {
-        FlowEntity flowEntity = buildIPv6FallbacktoExternalVpn(dpnId, internetBgpVpnId, vpnId, true);
+    public void installDefaultRoute(BigInteger dpnId, String routerId, long internetBgpVpnId, long vpnId) {
+        FlowEntity flowEntity = buildIPv6FallbacktoExternalVpn(dpnId, routerId, internetBgpVpnId, vpnId, true);
         LOG.trace("installDefaultRoute: flowEntity: {} ", flowEntity);
         mdsalManager.installFlow(flowEntity);
     }
 
-    public void removeDefaultRoute(BigInteger dpnId, long internetBgpVpnId, long vpnId) {
-        FlowEntity flowEntity = buildIPv6FallbacktoExternalVpn(dpnId, internetBgpVpnId, vpnId, false);
+    public void removeDefaultRoute(BigInteger dpnId, String routerId, long internetBgpVpnId, long vpnId) {
+        FlowEntity flowEntity = buildIPv6FallbacktoExternalVpn(dpnId, routerId, internetBgpVpnId, vpnId, false);
         LOG.trace("removeDefaultRoute: flowEntity: {} ", flowEntity);
         mdsalManager.removeFlow(flowEntity);
     }
 
-    public String getIPv6FlowRefL3(BigInteger dpnId, short tableId, String destPrefix, long vpnId) {
+    public String getIPv6FlowRefL3(BigInteger dpnId, short tableId, String destPrefix, String routerId) {
         return "L3." + dpnId.toString() + NwConstants.FLOWID_SEPARATOR + tableId
-                + NwConstants.FLOWID_SEPARATOR + destPrefix + NwConstants.FLOWID_SEPARATOR + vpnId;
+                + NwConstants.FLOWID_SEPARATOR + destPrefix + NwConstants.FLOWID_SEPARATOR + routerId;
     }
 }
index db11a13578ae05d02c5d2802d42533c597df7493..42f07a2cc43f3b373fee8db7bbf44377316cbbd8 100644 (file)
@@ -61,7 +61,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
@@ -318,7 +317,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
                                      IpVersionChoice.IPV6, routerId, true)) {
                         neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
                                 true);
-                        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
+                        neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
                     }
                 }
                 if (! subnetMapList.isEmpty()) {
@@ -426,7 +425,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
             if (vpnInstanceInternetIpVersionRemoved) {
                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
                         IpVersionChoice.IPV6, false);
-                neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid, false);
+                neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
             }
         }
     }
@@ -442,14 +441,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
         if (isExternal) {
             Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
             if (vpnInternetId != null) {
-                if (isRtrGwRemoved) {
-                     //Set VPN type BGPVPNExternal from BGPVPNInternet for removal case
-                    neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal,
-                            vpnInternetId);
-                } else {
-                    //Set VPN type BGPVPNInternet from BGPVPNExternal for add case
-                    neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet,
-                            vpnInternetId);
+                if (!isRtrGwRemoved) {
                     nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
                 }
                 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
index 00a145aeed9492c9a01898bce8a4a8e172ee020e..0c52cdf6be298f813cc6fb3f7d9ab18b9ac23e60 100644 (file)
@@ -52,6 +52,7 @@ import org.opendaylight.genius.infra.Datastore.Configuration;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.infra.TypedWriteTransaction;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -312,8 +313,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 if (vpnId != null) {
                     builder.setVpnId(vpnId);
                 }
-                builder.setInternetVpnId(internetvpnId);
-
+                if (neutronvpnUtils.getIpVersionFromString(sn.get().getSubnetIp()) == IpVersionChoice.IPV6) {
+                    builder.setInternetVpnId(internetvpnId);
+                }
                 Subnetmap subnetmap = builder.build();
                 LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
@@ -1782,8 +1784,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
          * associated with internet BGP-VPN.
          */
         if (vpnExtUuid != null) {
-            //Update V6 Internet default route match with new VPN metadata
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnExtUuid, isBeingAssociated);
+            /* Update V6 Internet default route match with new VPN metadata.
+             * isBeingAssociated = true means oldVpnId is same as routerId
+             * isBeingAssociated = false means newVpnId is same as routerId
+            */
+            if (isBeingAssociated) {
+                neutronvpnUtils.updateVpnInstanceWithFallback(oldVpnId, vpnExtUuid, true);
+            } else {
+                neutronvpnUtils.updateVpnInstanceWithFallback(newVpnId, vpnExtUuid, true);
+            }
         }
         //Update Router Interface first synchronously.
         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
@@ -2313,6 +2322,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
 
+        clearFromVpnMaps(vpnId, routerId, null);
         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Subnetmap sn : subMapList) {
@@ -2329,7 +2339,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
                     false);
         }
-        clearFromVpnMaps(vpnId, routerId, null);
         try {
             checkAndPublishRouterDisassociatedFromVpnNotification(routerId, vpnId);
             LOG.debug("notification upon disassociation of router {} from VPN {} published", routerId.getValue(),
@@ -2351,6 +2360,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected List<String> associateNetworksToVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
+        boolean isExternalNetwork = false;
         if (networkList.isEmpty()) {
             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
             failedNwList.add(String.format("Failed to associate networks with VPN %s as given networks list is empty",
@@ -2404,6 +2414,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                             nw.getValue(), vpnId.getValue()));
                     continue;
                 }
+                if (NeutronvpnUtils.getIsExternal(network)) {
+                    isExternalNetwork = true;
+                }
                 List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
                 if (subnetmapList == null || subnetmapList.isEmpty()) {
                     passedNwList.add(nw);
@@ -2449,7 +2462,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
                     networkList, e));
         }
-        updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
+        //VpnMap update for ext-nw is already done in associateExtNetworkToVpn() method.
+        if (!isExternalNetwork) {
+            updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
+        }
         LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList.toString(), vpnId.getValue());
         return failedNwList;
     }
@@ -2467,6 +2483,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             LOG.info("associateExtNetworkToVpn: set type {} for VPN {}", BgpvpnType.BGPVPNInternet, vpnId.getValue());
             neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, vpnId);
         }
+        //Update VpnMap with ext-nw is needed first before processing V6 internet default fallback flows
+        List<Uuid> extNwList = Collections.singletonList(extNet.key().getUuid());
+        updateVpnMaps(vpnId, null, null, null, extNwList);
         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
@@ -2475,6 +2494,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 continue;
             }
             IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
+                continue;
+            }
             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
                 updateVpnInternetForSubnet(sm, vpnId, true);
             }
@@ -2482,10 +2504,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 ipVersion = ipVersion.addVersion(ipVers);
             }
         }
-        if (!ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
+        if (ipVersion != IpVersionChoice.UNDEFINED) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, true);
             LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, true);
+            neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, true);
         }
         return true;
     }
@@ -2538,7 +2560,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (NeutronvpnUtils.getIsExternal(network)) {
                 if (disassociateExtNetworkFromVpn(vpnId, network)) {
                     passedNwList.add(nw);
-                    continue;
                 } else {
                     LOG.error("dissociateNetworksFromVpn: Failed to withdraw Provider Network {} from VPN {}",
                               nw.getValue(), vpnId.getValue());
@@ -2547,7 +2568,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     continue;
                 }
             }
-            Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
             IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
             for (Uuid subnet : networkSubnets) {
                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
@@ -2555,12 +2575,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 if (!ipVersion.isIpVersionChosen(ipVers)) {
                     ipVersion = ipVersion.addVersion(ipVers);
                 }
-                LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
-                          vpnId.getValue());
-                removeSubnetFromVpn(vpnId, subnet, null);
-                vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
-                        vpnId.getValue());
-                passedNwList.add(nw);
+                if (!NeutronvpnUtils.getIsExternal(network)) {
+                    LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
+                            vpnId.getValue());
+                    removeSubnetFromVpn(vpnId, subnet, null);
+                    Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+                    vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
+                            vpnId.getValue());
+                    passedNwList.add(nw);
+                }
             }
             if (ipVersion != IpVersionChoice.UNDEFINED) {
                 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
@@ -2603,6 +2626,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 continue;
             }
             IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
+                continue;
+            }
             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
                 updateVpnInternetForSubnet(sm, vpnId, false);
             }
@@ -2610,11 +2636,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 ipVersion = ipVersion.addVersion(ipVers);
             }
         }
-        if (!ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
+        if (ipVersion != IpVersionChoice.UNDEFINED) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
             LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}",
                     vpnId.getValue());
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, false);
+            neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, false);
         }
         return true;
     }
@@ -3332,24 +3358,27 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected void addV6PrivateSubnetToExtNetwork(@Nonnull Uuid routerId, @Nonnull Uuid internetVpnId,
                                                   @Nonnull Subnetmap subnetMap) {
         updateVpnInternetForSubnet(subnetMap, internetVpnId, true);
-        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
-                IpVersionChoice.IPV6, routerId, true)) {
+        neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
+        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(IpVersionChoice.IPV6, routerId, true)) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, true);
             LOG.info("addV6PrivateSubnetToExtNetwork: Advertise IPv6 Private Subnet {} to Internet VPN {}",
-                    subnetMap.getId(), internetVpnId.getValue());
+                    subnetMap.getId().getValue(), internetVpnId.getValue());
         }
-        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
     }
 
     protected void removeV6PrivateSubnetToExtNetwork(@Nonnull Uuid routerId, @Nonnull Uuid internetVpnId,
                                                      @Nonnull Subnetmap subnetMap) {
         updateVpnInternetForSubnet(subnetMap, internetVpnId, false);
-        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
-                IpVersionChoice.IPV6, routerId, false)) {
-            neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, false);
-            LOG.info("removeV6PrivateSubnetToExtNetwork: withdraw IPv6 Private subnet {} from Internet VPN {}",
-                    subnetMap.getId(), internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, false);
+    }
+
+    protected void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove) {
+        if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
+            LOG.debug("processV6InternetFlowsForRtr: Successfully {} V6 internet vpn {} default fallback rule "
+                            + "for the router {}", addOrRemove == NwConstants.ADD_FLOW ? "added" : "removed",
+                    internetVpnId.getValue(), routerId.getValue());
+            neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, addOrRemove == NwConstants.ADD_FLOW
+                    ? true : false);
         }
-        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, false);
     }
 }
index 5663de7f58ad2aafb54aaa4487419e044aeddc43..3b8a27bfb3e52a9aac8ba8ce7ed54e786fa2a192 100644 (file)
@@ -96,4 +96,9 @@ public class NeutronvpnManagerImpl implements INeutronVpnManager {
     public String getOpenDaylightVniRangesConfig() {
         return nvManager.getOpenDaylightVniRangesConfig();
     }
+
+    @Override
+    public void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove) {
+        nvManager.programV6InternetFallbackFlow(routerId, internetVpnId, addOrRemove);
+    }
 }
index 200d13288785e72e8705da889ffa5a6db7bbd5a9..eb64a970cf476627ef189571cb3364df9aa1914c 100644 (file)
@@ -28,7 +28,6 @@ import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
-import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
@@ -56,7 +55,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.ExternalGatewayInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
@@ -347,27 +345,6 @@ public class NeutronvpnNatManager implements AutoCloseable {
             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, netsIdentifier,
                     networkss);
             LOG.trace("Updated externalnetworks successfully to CONFIG Datastore");
-            //get vpn external form this network external to setup vpnInternet for ipv6
-            Uuid vpnExternal = neutronvpnUtils.getVpnForNetwork(extNetId);
-            if (vpnExternal == null) {
-                LOG.debug("addExternalNetworkToRouter : no vpnExternal for Network {}", extNetId);
-            }
-            LOG.debug("addExternalNetworkToRouter : the vpnExternal {}", vpnExternal);
-            //get subnetmap associate to the router, any subnetmap "external" could be existing
-            List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
-            LOG.debug("addExternalNetworkToRouter : the vpnExternal {} subnetmap to be set with vpnInternet {}",
-                    vpnExternal, snList);
-            for (Subnetmap sn : snList) {
-                if (sn.getInternetVpnId() == null) {
-                    continue;
-                }
-                IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
-                if (ipVers == IpVersionChoice.IPV6) {
-                    LOG.debug("addExternalNetworkToRouter : setup vpnInternet IPv6 for vpnExternal {} subnetmap {}",
-                            vpnExternal, sn);
-                    nvpnManager.updateVpnInternetForSubnet(sn, vpnExternal, true);
-                }
-            }
         } catch (TransactionCommitFailedException | ReadFailedException ex) {
             LOG.error("Creation of externalnetworks failed for {}",
                 extNetId.getValue(), ex);
@@ -421,26 +398,6 @@ public class NeutronvpnNatManager implements AutoCloseable {
             LOG.error("removeExternalNetworkFromRouter: Failed to remove provider network {} from router {}",
                       origExtNetId.getValue(), routerId.getValue(), ex);
         }
-
-        // Remove the vpnInternetId fromSubnetmap
-        Network net = neutronvpnUtils.getNeutronNetwork(nets.getId());
-        List<Uuid> submapIds = neutronvpnUtils.getPrivateSubnetsToExport(net, /*internetVpnId*/ null);
-        for (Uuid snId : submapIds) {
-            Subnetmap subnetMap = neutronvpnUtils.getSubnetmap(snId);
-            if (subnetMap == null || subnetMap.getInternetVpnId() == null) {
-                LOG.error("removeExternalNetworkFromRouter: Can not find Subnetmap for SubnetId {} in ConfigDS",
-                          snId.getValue());
-                continue;
-            }
-            LOG.trace("removeExternalNetworkFromRouter: Remove Internet VPN Id {} from SubnetMap {}",
-                      subnetMap.getInternetVpnId(), subnetMap.getId());
-            IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetMap.getSubnetIp());
-            if (ipVers == IpVersionChoice.IPV6) {
-                nvpnManager.updateVpnInternetForSubnet(subnetMap, subnetMap.getInternetVpnId(), false);
-                LOG.debug("removeExternalNetworkFromRouter: Withdraw IPv6 routes from VPN {}",
-                          subnetMap.getInternetVpnId());
-            }
-        }
     }
 
     public void addExternalRouter(Router update) {
index cacacf9844b29132bda550ebc5368a916bf2111d..c365c1ea54f11b8094501a5eb04dae4bb277851d 100644 (file)
@@ -1550,21 +1550,21 @@ public class NeutronvpnUtils {
     }
 
     public void updateVpnInstanceWithIpFamily(String vpnName, IpVersionChoice ipVersion, boolean add) {
-        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnId(vpnName);
-        if (vpnInstanceOpDataEntry == null) {
-            return;
-        }
-        if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
-            LOG.debug("updateVpnInstanceWithIpFamily: Update VpnInstance {} with ipFamily {}."
-                    + "VpnInstanceOpDataEntry is L2 instance. Do nothing.", vpnName, ipVersion);
-            return;
-        }
-        if (ipVersion == IpVersionChoice.UNDEFINED) {
-            LOG.debug("updateVpnInstanceWithIpFamily: Update VpnInstance {} with Undefined address family"
-                    + "is not allowed. Do nothing", vpnName);
-            return;
-        }
         jobCoordinator.enqueueJob("VPN-" + vpnName, () -> {
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnId(vpnName);
+            if (vpnInstanceOpDataEntry == null) {
+                return Collections.emptyList();
+            }
+            if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
+                LOG.debug("updateVpnInstanceWithIpFamily: Update VpnInstance {} with ipFamily {}."
+                        + "VpnInstanceOpDataEntry is L2 instance. Do nothing.", vpnName, ipVersion);
+                return Collections.emptyList();
+            }
+            if (ipVersion == IpVersionChoice.UNDEFINED) {
+                LOG.debug("updateVpnInstanceWithIpFamily: Update VpnInstance {} with Undefined address family"
+                        + "is not allowed. Do nothing", vpnName);
+                return Collections.emptyList();
+            }
             VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder(vpnInstanceOpDataEntry);
             boolean ipConfigured = add;
             if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4AND6)) {
@@ -1678,19 +1678,26 @@ public class NeutronvpnUtils {
                           router.getUuid().getValue(), extNet.getUuid().getValue());
                 continue;
             }
-            subList.addAll(getSubnetsforVpn(rtrId));
+            subList.addAll(getNeutronRouterSubnetIds(rtrId));
         }
         return subList;
     }
 
-    public void updateVpnInstanceWithFallback(Uuid vpnName, boolean add) {
+    public void updateVpnInstanceWithFallback(Uuid routerId, Uuid vpnName, boolean add) {
         VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnId(vpnName.getValue());
         if (vpnInstanceOpDataEntry == null) {
             LOG.error("updateVpnInstanceWithFallback: vpnInstanceOpDataEntry not found for vpn {}", vpnName);
             return;
         }
         Long internetBgpVpnId = vpnInstanceOpDataEntry.getVpnId();
-        List<Uuid> routerIds = getRouterIdListforVpn(vpnName);
+        List<Uuid> routerIds = new ArrayList<>();
+        //Handle router specific V6 internet fallback flow else handle all V6 external routers
+        if (routerId != null) {
+            routerIds.add(routerId);
+        } else {
+            //This block will execute for ext-nw to Internet VPN association/disassociation event.
+            routerIds = getRouterIdListforVpn(vpnName);
+        }
         if (routerIds == null || routerIds.isEmpty()) {
             LOG.error("updateVpnInstanceWithFallback: router not found for vpn {}", vpnName);
             return;
@@ -1715,9 +1722,9 @@ public class NeutronvpnUtils {
             }
             for (BigInteger dpnId : dpnIds) {
                 if (add) {
-                    ipV6InternetDefRt.installDefaultRoute(dpnId, internetBgpVpnId, vpnId);
+                    ipV6InternetDefRt.installDefaultRoute(dpnId, rtrId.getValue(), internetBgpVpnId, vpnId);
                 } else {
-                    ipV6InternetDefRt.removeDefaultRoute(dpnId, internetBgpVpnId, vpnId);
+                    ipV6InternetDefRt.removeDefaultRoute(dpnId, rtrId.getValue(), internetBgpVpnId, vpnId);
                 }
             }
         }
@@ -1886,4 +1893,19 @@ public class NeutronvpnUtils {
                 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
                         .VpnInstance::getVpnId).orElse(null);
     }
+
+    protected boolean isV6SubnetPartOfRouter(Uuid routerId) {
+        List<Subnetmap> subnetList = getNeutronRouterSubnetMapList(routerId);
+        for (Subnetmap sm: subnetList) {
+            if (sm == null) {
+                continue;
+            }
+            IpVersionChoice ipVers = getIpVersionFromString(sm.getSubnetIp());
+            //skip further subnet processing once found first V6 subnet for the router
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }