SNAT Ext. Router scheduling broken w/ upgrade 08/66608/14
authorJosh <jhershbe@redhat.com>
Tue, 19 Dec 2017 10:21:12 +0000 (12:21 +0200)
committerSam Hague <shague@redhat.com>
Wed, 24 Jan 2018 18:48:13 +0000 (18:48 +0000)
Depends on this gerrit from genius:
https://git.opendaylight.org/gerrit/#/c/65894/

SNAT requires that all the nodes be in the operational datastore
at the time the external router configurations are pushed to ODL.
At this point the external router is "scheduled", that is, a
switch is chosen to get the flows and track the sessions. In the
case of upgrade, there are in fact no nodes connected to ODL.

Solution:
Wait until all the nodes are connected and only then schedule
the external routers.
1) if the upgrading flag is set, don't schedule external routers
2) When the listener fires, schedule all the external routers

Change-Id: Ib349450905ef9c33fe3640753bb88e65c8ebf967
Signed-off-by: Josh <jhershbe@redhat.com>
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/UpgradeStateListener.java [new file with mode: 0644]
vpnservice/natservice/natservice-impl/src/main/resources/org/opendaylight/blueprint/natservice.xml

index 7cc8a5eff121bc387c6e181390aa51c2773b509f..4a90d3922c9c4ef9b0b4577edd686dc7f445f42b 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.UpgradeState;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
@@ -166,6 +167,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     private final INeutronVpnManager nvpnManager;
     private final IElanService elanManager;
     private final JobCoordinator coordinator;
+    private final UpgradeState upgradeState;
 
     @Inject
     public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
@@ -187,7 +189,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                    final CentralizedSwitchScheduler centralizedSwitchScheduler,
                                    final NatserviceConfig config,
                                    final IElanService elanManager,
-                                   final JobCoordinator coordinator) {
+                                   final JobCoordinator coordinator,
+                                   final UpgradeState upgradeState) {
         super(Routers.class, ExternalRoutersListener.class);
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
@@ -209,6 +212,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         this.elanManager = elanManager;
         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
         this.coordinator = coordinator;
+        this.upgradeState = upgradeState;
         if (config != null) {
             this.natMode = config.getNatMode();
         } else {
@@ -239,7 +243,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         long routerId = NatUtil.getVpnId(dataBroker, routerName);
         NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
-        if (natMode == NatMode.Conntrack) {
+        if (natMode == NatMode.Conntrack && !upgradeState.isUpgradeInProgress()) {
             if (bgpVpnUuid != null) {
                 return;
             }
@@ -1188,7 +1192,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         boolean updatedSNATEnabled = update.isEnableSnat();
         LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
             + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
-        if (natMode == NatMode.Conntrack) {
+        if (natMode == NatMode.Conntrack && !upgradeState.isUpgradeInProgress()) {
             if (originalSNATEnabled != updatedSNATEnabled) {
                 BigInteger primarySwitchId;
                 if (originalSNATEnabled) {
diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/UpgradeStateListener.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/UpgradeStateListener.java
new file mode 100644 (file)
index 0000000..1147844
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.natservice.internal;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.datastoreutils.listeners.AbstractClusteredSyncDataTreeChangeListener;
+import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
+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.routers.ExternalIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsalutil.rev170830.Config;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<Config> {
+    private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
+
+    private final DataBroker dataBroker;
+    private final CentralizedSwitchScheduler centralizedSwitchScheduler;
+    private final NatserviceConfig.NatMode natMode;
+
+    @Inject
+    public UpgradeStateListener(final DataBroker dataBroker,
+                                final CentralizedSwitchScheduler centralizedSwitchScheduler,
+                                final NatserviceConfig config) {
+        super(dataBroker, new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Config.class)));
+        this.dataBroker = dataBroker;
+        this.centralizedSwitchScheduler = centralizedSwitchScheduler;
+        if (config != null) {
+            this.natMode = config.getNatMode();
+        } else {
+            this.natMode = NatserviceConfig.NatMode.Controller;
+        }
+        LOG.trace("UpgradeStateListener (nat) initialized");
+    }
+
+    @Override
+    public void add(@Nonnull Config newDataObject) {
+    }
+
+    @Override
+    public void remove(@Nonnull Config removedDataObject) {
+    }
+
+    @Override
+    public void update(@Nonnull Config original, Config updated) {
+        if (natMode != NatserviceConfig.NatMode.Conntrack) {
+            return;
+        }
+
+        LOG.info("UpgradeStateListener update from {} to {}", original, updated);
+        if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
+            return;
+        }
+
+        SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
+        ExtRouters routers;
+        try {
+            routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
+                    InstanceIdentifier.create(ExtRouters.class));
+        } catch (ReadFailedException e) {
+            LOG.error("Error reading external routers", e);
+            return;
+        }
+
+        for (Routers router : routers.getRouters()) {
+            List<ExternalIps> externalIps = router.getExternalIps();
+            if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
+                centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
+            }
+        }
+    }
+}
index b8bd267b7eb16e1bae1785a09b09de964074edcc..4cf4a820eb1b96be2f9ed8d5787d9b66e4e57249 100644 (file)
@@ -26,6 +26,8 @@
              availability="optional"/>
   <reference id="jobCoordinator"
              interface="org.opendaylight.infrautils.jobcoordinator.JobCoordinator"/>
+  <reference id="upgradeState"
+             interface="org.opendaylight.genius.mdsalutil.UpgradeState"/>
 
   <odl:rpc-service id="idManagerService"
                    interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService" />