neutronvpn: update bgpvpn fallback pipeline rules for ipv6 13/57413/153
authorPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 28 Nov 2017 09:44:26 +0000 (09:44 +0000)
committerValentina <valentina.krasnobaeva@6wind.com>
Wed, 14 Feb 2018 10:52:36 +0000 (11:52 +0100)
When associating a BGPVPN to an external network, the identifier
associated to that BGPVPN is already used for all the underlying
external subnets declared in that network.

For IPv6 GUA subnets that are "behind that external network", that is
to say behind a router which has that external network linked, that same
identifier is used to write a specific fallback route for those IPv6 GUA
to access the Internet through BGPVPN. Indeed, when the router has no
more entries in its FIB table, a fallback rule is written for IPv6 GU
traffic against possibly BGPVPN IPv6 entries. That fallback rule
resubmits the packet to the FIB table, but with an ID set to the BGPVPN
id. Like that, all IPv6 traffic that has an entry associated may be
redirected to the correct DC-GW.

The modification here consists in adding that zero priority fallback,
rule, in the case a BGPVPN is present on external network, on the
presence of the first IPv6 subnet; removing the fallback rule, if the
BGPVPN is detached or the last subnet ipv6 is removed.

Change-Id: Iebd754ae10fa6db08512980a98e07c3a02ebb6d5
Signed-off-by: Noel De Prandieres <prandieres@6wind.com>
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
Signed-off-by: Valentina Krasnobaeva <valentina.krasnobaeva@6wind.com>
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronPortChangeListener.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnManager.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnUtils.java
vpnservice/neutronvpn/neutronvpn-impl/src/test/java/org/opendaylight/netvirt/neutronvpn/NeutronPortChangeListenerTest.java

index 70b8d0a63d44dac35908b9566053d4c1c797fa85..99e709e96e3ec3300344b0a191bcff06ddb86d22 100644 (file)
@@ -312,6 +312,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
                                      IpVersionChoice.IPV6, internetVpnId)) {
                         neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(),
                                                                      IpVersionChoice.IPV6, true);
+                        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId.getValue(), true);
                     }
                 }
                 if (! subnetMapList.isEmpty()) {
@@ -411,6 +412,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
             if (vpnInstanceInternetIpVersionRemoved) {
                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
                                                              IpVersionChoice.IPV6, false);
+                neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid.getValue(), false);
             }
         }
     }
index fe58ce11e333c78f63ba8364b34ac5281e484cb7..54e76736210598f72c495d25e48194ff3ac9646f 100644 (file)
@@ -2306,6 +2306,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                                             .getInternetVpnId().getValue(),
                                                    neutronvpnUtils.getIpVersionFromString(sn
                                                             .getSubnetIp()), true);
+                                            neutronvpnUtils.updateVpnInstanceWithFallback(
+                                                          sn.getInternetVpnId().getValue(), true);
                                         }
                                     }
                                     addSubnetToVpn(vpn, subnet, sn != null ? sn.getInternetVpnId() : null);
@@ -2339,6 +2341,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                         if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(sm, vpn)) {
                                             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpn.getValue(),
                                                     neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp()), true);
+                                            neutronvpnUtils.updateVpnInstanceWithFallback(vpn.getValue(),
+                                                    true);
                                         }
                                     }
                                 }
@@ -2398,11 +2402,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                         vpnInstanceIpVersionsToRemove, false);
                             }
                             if (vpnInstanceInternetIpVersionRemoved) {
+                                neutronvpnUtils.updateVpnInstanceWithFallback(
+                                               vpnIdInternet.getValue(), false);
                                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnIdInternet.getValue(),
                                                    IpVersionChoice.IPV6, false);
                             }
                         }
                         if (neutronvpnUtils.getIsExternal(network)) {
+                            neutronvpnUtils.updateVpnInstanceWithFallback(vpn.getValue(),
+                                                    false);
                             neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry
                                              .BgpvpnType.VPN, vpn);
                             LOG.debug("Removing IPv6 network subnets...");
index 5f7f8ab8e06a51bff12da9688660ff884b2e7ffc..a992556aa03e23c9518a4dbc4c1cf7b767c97df0 100644 (file)
@@ -84,6 +84,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
 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.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
@@ -177,13 +178,15 @@ public class NeutronvpnUtils {
     private final DataBroker dataBroker;
     private final IdManagerService idManager;
     private final JobCoordinator jobCoordinator;
+    private IPV6InternetDefaultRouteProgrammer ipV6InternetDefRt;
 
     @Inject
     public NeutronvpnUtils(final DataBroker dataBroker, final IdManagerService idManager,
-            final JobCoordinator jobCoordinator) {
+            final JobCoordinator jobCoordinator, final IPV6InternetDefaultRouteProgrammer ipV6InternetDefRt) {
         this.dataBroker = dataBroker;
         this.idManager = idManager;
         this.jobCoordinator = jobCoordinator;
+        this.ipV6InternetDefRt = ipV6InternetDefRt;
     }
 
     protected Subnetmap getSubnetmap(Uuid subnetId) {
@@ -1599,6 +1602,33 @@ public class NeutronvpnUtils {
         return subList;
     }
 
+    public void updateVpnInstanceWithFallback(String vpnName, boolean add) {
+        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnId(vpnName);
+        if (vpnInstanceOpDataEntry == null) {
+            // BGPVPN context not found
+            return;
+        }
+        String routerIdUuid = getRouterIdfromVpnInstance(dataBroker, vpnInstanceOpDataEntry.getVrfId());
+        if (routerIdUuid != null) {
+            List<BigInteger> dpnIds = getDpnsForRouter(dataBroker, routerIdUuid);
+            if (!dpnIds.isEmpty()) {
+                Long vpnId = vpnInstanceOpDataEntry.getVpnId();
+                VpnInstanceOpDataEntry vpnOpDataEntry = getVpnInstanceOpDataEntryFromVpnId(routerIdUuid);
+                Long routerIdAsLong = vpnOpDataEntry.getVpnId();
+                if (routerIdAsLong == null) {
+                    return;
+                }
+                for (BigInteger dpnId : dpnIds) {
+                    if (add) {
+                        ipV6InternetDefRt.installDefaultRoute(dpnId, vpnId, routerIdAsLong);
+                    } else {
+                        ipV6InternetDefRt.removeDefaultRoute(dpnId, vpnId, routerIdAsLong);
+                    }
+                }
+            }
+        }
+    }
+
     public void updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType choice, @Nonnull Uuid vpn) {
         String primaryRd = getVpnRd(vpn.getValue());
         if (primaryRd == null) {
@@ -1634,4 +1664,46 @@ public class NeutronvpnUtils {
         }
         return;
     }
+
+    @Nonnull
+    public List<BigInteger> getDpnsForRouter(DataBroker dataBroker, String routerUuid) {
+        InstanceIdentifier id = InstanceIdentifier.builder(NeutronRouterDpns.class)
+            .child(RouterDpnList.class, new RouterDpnListKey(routerUuid)).build();
+        Optional<RouterDpnList> routerDpnListData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, id);
+        List<BigInteger> dpns = new ArrayList<>();
+        if (routerDpnListData.isPresent()) {
+            List<DpnVpninterfacesList> dpnVpninterfacesList = routerDpnListData.get().getDpnVpninterfacesList();
+            for (DpnVpninterfacesList dpnVpnInterface : dpnVpninterfacesList) {
+                dpns.add(dpnVpnInterface.getDpnId());
+            }
+        }
+        return dpns;
+    }
+
+    public String getRouterIdfromVpnInstance(DataBroker broker, String vpnName) {
+        // returns only router, attached to IPv4 networks
+        InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
+            .child(VpnMap.class, new VpnMapKey(new Uuid(vpnName))).build();
+        Optional<VpnMap> optionalVpnMap = SingleTransactionDataBroker
+                .syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, LogicalDatastoreType.CONFIGURATION,
+                        vpnMapIdentifier);
+        if (!optionalVpnMap.isPresent()) {
+            LOG.error("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
+            return null;
+        }
+        Uuid routerId = optionalVpnMap.get().getRouterId();
+        if (routerId != null) {
+            return routerId.getValue();
+        }
+        LOG.info("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
+        return null;
+    }
+
+    public InstanceIdentifier<Router> buildNeutronRouterIdentifier(Uuid routerUuid) {
+        InstanceIdentifier<Router> routerInstanceIdentifier = InstanceIdentifier.create(Neutron.class)
+             .child(Routers.class).child(Router.class, new RouterKey(routerUuid));
+        return routerInstanceIdentifier;
+    }
 }
index 16de148c3a4069fde8033d297758b035b45c9c41..e6ad50336e3c2ffeff69169fbc29077fa7f387e2 100644 (file)
@@ -85,6 +85,10 @@ public class NeutronPortChangeListenerTest {
     IInterfaceManager interfaceManager;
     @Mock
     IdManagerService idManager;
+    @Mock
+    NeutronvpnUtils neutronvpnUtils;
+    @Mock
+    IPV6InternetDefaultRouteProgrammer ipV6InternetDefRt;
 
     MetricProvider metricProvider = new TestMetricProviderImpl();
 
@@ -98,7 +102,8 @@ public class NeutronPortChangeListenerTest {
         when(mockReadTx.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class)))
             .thenReturn(Futures.immediateCheckedFuture(Optional.of(mockNetwork)));
         neutronPortChangeListener = new NeutronPortChangeListener(dataBroker, neutronvpnManager, neutronvpnNatManager,
-                gwMacResolver, elanService, jobCoordinator, new NeutronvpnUtils(dataBroker, idManager, jobCoordinator),
+                gwMacResolver, elanService, jobCoordinator, new NeutronvpnUtils(dataBroker, idManager, jobCoordinator,
+                        ipV6InternetDefRt),
                 new HostConfigCache(dataBroker, new GuavaCacheProvider(new CacheManagersRegistryImpl())));
         InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
                 .child(ElanInstance.class,