Bug 7939 - CSIT Sporadic failures - Flow(s) missing in VPNService suite on
[netvirt.git] / vpnservice / neutronvpn / neutronvpn-impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
index 3e70bf6789f9c7f19ab511b50bbce5f1466d00d5..dae53b2f6d45be84502a91bcf8d71b2cf17ddd31 100644 (file)
@@ -21,15 +21,23 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import javax.annotation.PreDestroy;
+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.NotificationPublishService;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.netvirt.neutronvpn.evpn.manager.NeutronEvpnManager;
+import org.opendaylight.netvirt.neutronvpn.evpn.utils.NeutronEvpnUtils;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
 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.af.config.VpnTargets;
@@ -110,6 +118,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.A
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.OperationalPortStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.Features;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.Feature;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
@@ -128,6 +141,7 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Singleton
 public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, EventListener {
     private static final Logger LOG = LoggerFactory.getLogger(NeutronvpnManager.class);
     private final DataBroker dataBroker;
@@ -137,12 +151,16 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     private final NeutronFloatingToFixedIpMappingChangeListener floatingIpMapListener;
     private final IElanService elanService;
     private final NeutronvpnConfig neutronvpnConfig;
+    private final IVpnManager vpnManager;
+    private final NeutronEvpnManager neutronEvpnManager;
+    private final NeutronEvpnUtils neutronEvpnUtils;
 
+    @Inject
     public NeutronvpnManager(
             final DataBroker dataBroker, final NotificationPublishService notiPublishService,
             final NeutronvpnNatManager vpnNatMgr, final VpnRpcService vpnRpcSrv, final IElanService elanService,
             final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
-            final NeutronvpnConfig neutronvpnConfig) {
+            final NeutronvpnConfig neutronvpnConfig, final IVpnManager vpnManager) {
         this.dataBroker = dataBroker;
         nvpnNatManager = vpnNatMgr;
         notificationPublishService = notiPublishService;
@@ -150,15 +168,33 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         this.elanService = elanService;
         floatingIpMapListener = neutronFloatingToFixedIpMappingChangeListener;
         this.neutronvpnConfig = neutronvpnConfig;
+        this.vpnManager = vpnManager;
+        neutronEvpnManager = new NeutronEvpnManager(dataBroker, this);
+        neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager);
+
+        configureFeatures();
     }
 
     @Override
+    @PreDestroy
     public void close() throws Exception {
         LOG.info("{} close", getClass().getSimpleName());
     }
 
-    public NeutronvpnConfig getNeutronvpnConfig() {
-        return neutronvpnConfig;
+    private void configureFeatures() {
+        InstanceIdentifier<Feature> iid = InstanceIdentifier.builder(
+                        Neutron.class).child(Features.class).child(
+                        Feature.class, new FeatureKey(OperationalPortStatus.class)).build();
+        Feature feature = new FeatureBuilder().setKey(new FeatureKey(OperationalPortStatus.class)).build();
+        try {
+            SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, iid, feature);
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Error configuring feature " + feature, e);
+        }
+    }
+
+    public String getOpenDaylightVniRangesConfig() {
+        return neutronvpnConfig.getOpendaylightVniRanges();
     }
 
     // TODO Clean up the exception handling
@@ -188,7 +224,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
+    protected Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
         Subnetmap subnetmap = null;
         SubnetmapBuilder builder = null;
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
@@ -398,6 +434,28 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
+    public void updateVpnInstanceWithRDs(String vpnInstanceId, final List<String> rds) {
+        InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
+            .child(VpnInstance.class, new VpnInstanceKey(vpnInstanceId)).build();
+        Optional<VpnInstance> vpnInstanceConfig =
+            NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
+        if (!vpnInstanceConfig.isPresent()) {
+            LOG.debug("No VpnInstance present under config vpnInstance:{}", vpnInstanceId);
+            return;
+        }
+        VpnInstance vpnInstance = vpnInstanceConfig.get();
+        VpnInstanceBuilder updateVpnInstanceBuilder = new VpnInstanceBuilder(vpnInstance);
+        Ipv4FamilyBuilder ipv4FamilyBuilder = new Ipv4FamilyBuilder(vpnInstance.getIpv4Family());
+        updateVpnInstanceBuilder.setIpv4Family(ipv4FamilyBuilder.setRouteDistinguisher(rds).build());
+        LOG.debug("Updating Config vpn-instance: {} with the list of RDs: {}", vpnInstanceId,rds);
+        try {
+            SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier,
+                    updateVpnInstanceBuilder.build());
+        } catch (TransactionCommitFailedException ex) {
+            LOG.warn("Error configuring feature ", ex);
+        }
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void updateVpnInstanceNode(String vpnName, List<String> rd, List<String> irt, List<String> ert,
@@ -868,15 +926,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 l3vni = vpn.getL3vni();
             }
 
-            if (vpn.getRouteDistinguisher().size() > 1) {
-                msg = String.format("Creation of VPN failed for VPN %s due to multiple RD input %s",
-                        vpn.getId().getValue(), vpn.getRouteDistinguisher());
-                LOG.warn(msg);
-                error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
-                errorList.add(error);
-                warningcount++;
-                continue;
-            }
             List<String> existingRDs = NeutronvpnUtils.getExistingRDs(dataBroker);
             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
                 msg = String.format("Creation of L3VPN failed for VPN %s as another VPN with the same RD %s "
@@ -1157,6 +1206,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
 
         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
+        final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+        if (isVpnOfTypeL2(vpnInstance)) {
+            neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+                    NeutronEvpnUtils.Operation.ADD);
+        }
         // Check if there are ports on this subnet and add corresponding
         // vpn-interfaces
         List<Uuid> portList = sn.getPortList();
@@ -1185,17 +1239,18 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             return;
         }
 
-        final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-        if (sn.getRouterInterfacePortId() != null) {
-            portDataStoreCoordinator.enqueueJob("PORT-" + sn.getRouterInterfacePortId().getValue(), () -> {
-                WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                updateVpnInterface(newVpnId, oldVpnId,
-                        NeutronvpnUtils.getNeutronPort(dataBroker, sn.getRouterInterfacePortId()),
-                        isBeingAssociated, true, wrtConfigTxn);
-                futures.add(wrtConfigTxn.submit());
-                return futures;
-            });
+        //Update Router Interface first synchronously.
+        //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
+        try {
+            WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
+            updateVpnInterface(newVpnId, oldVpnId,
+                    NeutronvpnUtils.getNeutronPort(dataBroker, sn.getRouterInterfacePortId()),
+                    isBeingAssociated, true, wrtConfigTxn);
+            wrtConfigTxn.submit().checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, returning",
+                    sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId);
+            return;
         }
 
         // Check for ports on this subnet and update association of
@@ -1205,6 +1260,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             for (Uuid port : portList) {
                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
                     port.getValue(), isBeingAssociated);
+                final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
                 portDataStoreCoordinator.enqueueJob("PORT-" + port.getValue(), () -> {
                     WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
                     List<ListenableFuture<Void>> futures = new ArrayList<>();
@@ -1497,7 +1553,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void removeVpn(Uuid id) {
+    public void removeVpn(Uuid id) {
         // read VPNMaps
         VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, id);
         Uuid router = (vpnMap != null) ? vpnMap.getRouterId() : null;
@@ -1527,6 +1583,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         final Uuid routerId = vpnMap.getRouterId();
         Subnetmap sn = NeutronvpnUtils.getSubnetmap(dataBroker, subnet);
+        final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+        if (isVpnOfTypeL2(vpnInstance)) {
+            neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+                    NeutronEvpnUtils.Operation.DELETE);
+        }
         if (sn != null) {
             // Check if there are ports on this subnet; remove corresponding vpn-interfaces
             List<Uuid> portList = sn.getPortList();
@@ -1556,6 +1617,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
+    private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
+        return vpnInstance != null && vpnInstance.getType() == VpnInstance.Type.L2;
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
@@ -1611,6 +1676,13 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         List<String> failedNwList = new ArrayList<>();
         List<Uuid> passedNwList = new ArrayList<>();
         if (!networks.isEmpty()) {
+            VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpn.getValue());
+            if (vpnInstance == null) {
+                LOG.error("VPN %s not present when associating network to it", vpn.getValue());
+                failedNwList.add(String.format("Failed to associate network on vpn %s as vpn is not present",
+                        vpn.getValue()));
+                return failedNwList;
+            }
             // process corresponding subnets for VPN
             for (Uuid nw : networks) {
                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
@@ -1628,6 +1700,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 } else if (vpnId != null) {
                     failedNwList.add(String.format("network %s already associated to another VPN %s", nw.getValue(),
                             vpnId.getValue()));
+                } else if (isVpnOfTypeL2(vpnInstance)
+                        && (neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance))) {
+                    LOG.error("EVPN supports only one network to be associated");
+                    failedNwList.add(String.format("EVPN supports only one network to be associated"));
                 } else {
                     List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
                     LOG.debug("Adding network subnets...{}", networkSubnets);
@@ -1741,16 +1817,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return result;
     }
 
-    @Override
-    public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
-        return null;
-    }
-
-    @Override
-    public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
-        return null;
-    }
-
     /**
      * It handles the invocations to the neutronvpn:associateRouter RPC method.
      */
@@ -1896,11 +1962,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return result;
     }
 
-    @Override
-    public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
-        return null;
-    }
-
     /**
      * It handles the invocations to the neutronvpn:dissociateRouter RPC method.
      */
@@ -1962,14 +2023,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return result;
     }
 
-    public String getOpenDaylightVniRangesConfig() {
-        return neutronvpnConfig.getOpendaylightVniRanges();
-    }
-
-    public Boolean getEnforceOpenstackSemanticsConfig() {
-        return neutronvpnConfig.isEnforceOpenstackSemantics();
-    }
-
     protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
         // check if the router is associated to some VPN
         Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
@@ -2218,7 +2271,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
                 .setName(infName)
                 .setVpnInstanceName(vpnId.getValue())
-                .setIsRouterInterface(isRouterInterface);
+                .setRouterInterface(isRouterInterface);
         if (adjacencies != null) {
             vpnb.addAugmentation(Adjacencies.class, adjacencies);
         }
@@ -2260,4 +2313,19 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
     }
-}
\ No newline at end of file
+
+    @Override
+    public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
+        return neutronEvpnManager.createEVPN(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
+        return neutronEvpnManager.getEVPN(input);
+    }
+
+    @Override
+    public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
+        return neutronEvpnManager.deleteEVPN(input);
+    }
+}