NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / iplearn / LearntVpnVipToPortEventProcessor.java
index 5093ccd1d8cc64afc174a889a827565690b675df..18a7b56e988d76e7d04b3c13a5182ce61af1bfc3 100644 (file)
@@ -7,59 +7,58 @@
  */
 package org.opendaylight.netvirt.vpnmanager.iplearn;
 
-import static java.util.Collections.emptyList;
-import static org.opendaylight.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
-
-import com.google.common.base.Optional;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.Callable;
-import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
 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.common.api.data.LogicalDatastoreType;
-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.AsyncClusteredDataTreeChangeListenerBase;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.infra.Datastore;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.mdsal.eos.binding.api.Entity;
 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
+import org.opendaylight.serviceutils.tools.listener.AbstractClusteredAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacencyList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.event.data.LearntVpnVipToPortEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency.AdjacencyType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint32;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
 public class LearntVpnVipToPortEventProcessor
-        extends AsyncClusteredDataTreeChangeListenerBase<LearntVpnVipToPortEvent, LearntVpnVipToPortEventProcessor> {
+        extends AbstractClusteredAsyncDataTreeChangeListener<LearntVpnVipToPortEvent> {
     private static final Logger LOG = LoggerFactory.getLogger(LearntVpnVipToPortEventProcessor.class);
     private final DataBroker dataBroker;
     private final ManagedNewTransactionRunner txRunner;
@@ -73,18 +72,20 @@ public class LearntVpnVipToPortEventProcessor
     @Inject
     public LearntVpnVipToPortEventProcessor(final DataBroker dataBroker, IInterfaceManager interfaceManager,
             EntityOwnershipService entityOwnershipService, final JobCoordinator jobCoordinator, VpnUtil vpnUtil) {
-        super(LearntVpnVipToPortEvent.class, LearntVpnVipToPortEventProcessor.class);
+        super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier
+                .create(LearntVpnVipToPortEventData.class).child(LearntVpnVipToPortEvent.class),
+                Executors.newListeningSingleThreadExecutor("LearntVpnVipToPortEventProcessor", LOG));
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.interfaceManager = interfaceManager;
         this.jobCoordinator = jobCoordinator;
         this.entityOwnershipUtils = new EntityOwnershipUtils(entityOwnershipService);
         this.vpnUtil = vpnUtil;
+        start();
     }
 
-    @PostConstruct
     public void start() {
-        registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+        LOG.info("{} start", getClass().getSimpleName());
         try {
             candidateRegistration = entityOwnershipUtils.getEntityOwnershipService()
                     .registerCandidate(new Entity(VpnConstants.IP_MONITORING_ENTITY,
@@ -104,24 +105,14 @@ public class LearntVpnVipToPortEventProcessor
     }
 
     @Override
-    protected InstanceIdentifier<LearntVpnVipToPortEvent> getWildCardPath() {
-        return InstanceIdentifier.create(LearntVpnVipToPortEventData.class).child(LearntVpnVipToPortEvent.class);
-    }
-
-    @Override
-    protected LearntVpnVipToPortEventProcessor getDataTreeChangeListener() {
-        return this;
-    }
-
-    @Override
-    protected void update(InstanceIdentifier<LearntVpnVipToPortEvent> id, LearntVpnVipToPortEvent value,
+    public void update(InstanceIdentifier<LearntVpnVipToPortEvent> id, LearntVpnVipToPortEvent value,
             LearntVpnVipToPortEvent dataObjectModificationAfter) {
         // Updates does not make sense on an event queue .
         // NOTE: DONOT ADD ANY CODE HERE AND MAKE A CIRCUS
     }
 
     @Override
-    protected void add(InstanceIdentifier<LearntVpnVipToPortEvent> identifier, LearntVpnVipToPortEvent value) {
+    public void add(InstanceIdentifier<LearntVpnVipToPortEvent> identifier, LearntVpnVipToPortEvent value) {
         // AFTER PROCESSING THE EVENT, REMOVE THE EVENT FROM THE QUEUE
         entityOwnershipUtils.runOnlyInOwnerNode(VpnConstants.IP_MONITORING_ENTITY, VpnConstants.IP_MONITORING_ENTITY,
             jobCoordinator, "LearntVpnVipToPortEvent-Handler", () -> {
@@ -144,12 +135,12 @@ public class LearntVpnVipToPortEventProcessor
     }
 
     @Override
-    protected void remove(InstanceIdentifier<LearntVpnVipToPortEvent> key, LearntVpnVipToPortEvent value) {
+    public void remove(InstanceIdentifier<LearntVpnVipToPortEvent> key, LearntVpnVipToPortEvent value) {
         // Removals are triggered by add handling.
         // NOTE: DONOT ADD ANY CODE HERE AND MAKE A CIRCUS
     }
 
-    private class AddMipAdjacencyWorker implements Callable<List<ListenableFuture<Void>>> {
+    private class AddMipAdjacencyWorker implements Callable<List<? extends ListenableFuture<?>>> {
         String vpnName;
         String interfaceName;
         String srcIpAddress;
@@ -169,6 +160,8 @@ public class LearntVpnVipToPortEventProcessor
             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
                                                                         Datastore.OPERATIONAL, operTx -> {
                     addMipAdjacency(vpnName, interfaceName, srcIpAddress, macAddress, destIpAddress);
+                    vpnUtil.createVpnPortFixedIpToPort(vpnName, srcIpAddress,
+                            interfaceName, Boolean.TRUE, macAddress, null);
                     vpnUtil.createLearntVpnVipToPort(vpnName, srcIpAddress, interfaceName, macAddress, operTx);
                 }));
         }
@@ -177,105 +170,85 @@ public class LearntVpnVipToPortEventProcessor
                                      String dstPrefix) {
             LOG.trace("Adding {} adjacency to VPN Interface {} ", srcPrefix, vpnInterface);
             InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
-            InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
+            // FIXME: separate out to somehow?
+            final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnInterface);
+            lock.lock();
             try {
-                synchronized (vpnInterface.intern()) {
-                    Optional<Adjacencies> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                            LogicalDatastoreType.CONFIGURATION, path);
-                    String nextHopIpAddr = null;
-                    String nextHopMacAddress = null;
-                    String ip = srcPrefix;
-                    if (interfaceManager.isExternalInterface(vpnInterface)) {
-                        String subnetId = getSubnetId(vpnInstName, dstPrefix);
-                        if (subnetId == null) {
-                            LOG.trace("Can't find corresponding subnet for src IP {}, src MAC {}, dst IP {},"
-                                    + "  in VPN {}", srcPrefix, mipMacAddress, dstPrefix, vpnInstName);
-                            return;
-                        }
-                        ip = VpnUtil.getIpPrefix(ip);
-                        AdjacencyBuilder newAdjBuilder = new AdjacencyBuilder().setIpAddress(ip)
-                                .withKey(new AdjacencyKey(ip)).setAdjacencyType(AdjacencyType.PrimaryAdjacency)
-                                .setMacAddress(mipMacAddress).setSubnetId(new Uuid(subnetId)).setPhysNetworkFunc(true);
-
-                        List<Adjacency> adjacencyList = new ArrayList<>(requireNonNullElse(
-                            adjacencies.toJavaUtil().map(AdjacencyList::getAdjacency).orElse(null), emptyList()));
-
-                        adjacencyList.add(newAdjBuilder.build());
+                Optional<VpnInterface> optVpnInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, vpnIfId);
+                if (!optVpnInterface.isPresent()) {
+                    LOG.error("Config VpnInterface not found for interface={}", interfaceName);
+                    return;
+                }
+                Adjacencies configAdjacencies = optVpnInterface.get().augmentation(Adjacencies.class);
+                List<Adjacency> adjacencyList = configAdjacencies == null ? new ArrayList<>()
+                        : new ArrayList<>(configAdjacencies.getAdjacency());
 
-                        Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
-                        Optional<VpnInterface> optionalVpnInterface = SingleTransactionDataBroker.syncReadOptional(
-                                dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId);
-                        VpnInterface newVpnIntf;
-                        if (optionalVpnInterface.isPresent()) {
-                            newVpnIntf =
-                                    new VpnInterfaceBuilder(optionalVpnInterface.get())
-                                            .addAugmentation(Adjacencies.class, aug)
-                                            .build();
-                            SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                    vpnIfId, newVpnIntf, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
-                        }
-                        LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
+                String ip = VpnUtil.getIpPrefix(srcPrefix);
+                AdjacencyBuilder newAdjBuilder;
+                if (interfaceManager.isExternalInterface(vpnInterface)) {
+                    String subnetId = getSubnetId(vpnInstName, dstPrefix);
+                    if (subnetId == null) {
+                        LOG.trace("Can't find corresponding subnet for src IP {}, src MAC {}, dst IP {},"
+                                + "  in VPN {}", srcPrefix, mipMacAddress, dstPrefix, vpnInstName);
                         return;
                     }
-
-                    if (adjacencies.isPresent()) {
-                        List<Adjacency> adjacencyList =
-                            requireNonNullElse(adjacencies.get().getAdjacency(), emptyList());
-                        ip = VpnUtil.getIpPrefix(ip);
-                        for (Adjacency adjacs : adjacencyList) {
-                            if (adjacs.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
-                                if (Objects.equals(adjacs.getIpAddress(), ip)) {
-                                    LOG.error("The MIP {} is already present as a primary adjacency for interface {}"
-                                            + "vpn {} Skipping adjacency addition.", ip, vpnInterface, vpnInstName);
-                                    return;
-                                }
-                                nextHopIpAddr = adjacs.getIpAddress();
-                                nextHopMacAddress = adjacs.getMacAddress();
-                                break;
-                            }
-                        }
-                        if (nextHopIpAddr != null) {
-                            String rd = vpnUtil.getVpnRd(vpnInstName);
-                            long label =
-                                    vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
-                                            VpnUtil.getNextHopLabelKey(rd != null ? rd : vpnInstName, ip));
-                            if (label == 0) {
-                                LOG.error("Unable to fetch label from Id Manager. Bailing out of adding MIP"
-                                        + " adjacency {} to vpn interface {} for vpn {}", ip, vpnInterface,
-                                        vpnInstName);
+                    newAdjBuilder = new AdjacencyBuilder().setIpAddress(ip).withKey(new AdjacencyKey(ip))
+                            .setAdjacencyType(AdjacencyType.PrimaryAdjacency).setMacAddress(mipMacAddress)
+                            .setSubnetId(new Uuid(subnetId)).setPhysNetworkFunc(true);
+                } else {
+                    String nextHopIp = null;
+                    String nextHopMacAddress = null;
+                    for (Adjacency adjacency : adjacencyList) {
+                        if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
+                            if (adjacency.getIpAddress().equals(ip)) {
+                                LOG.error("The MIP {} is already present as a primary adjacency for interface {}."
+                                        + "Skipping adjacency addition.", ip, interfaceName);
                                 return;
+                            } else if (NWUtil.getEtherTypeFromIpPrefix(ip) == NWUtil
+                                    .getEtherTypeFromIpPrefix(adjacency.getIpAddress())) {
+                                nextHopIp = adjacency.getIpAddress().split("/")[0];
+                                nextHopMacAddress = adjacency.getMacAddress();
+                                break;
                             }
-                            String nextHopIp = nextHopIpAddr.split("/")[0];
-                            AdjacencyBuilder newAdjBuilder =
-                                    new AdjacencyBuilder().setIpAddress(ip).withKey(new AdjacencyKey(ip))
-                                            .setNextHopIpList(Collections.singletonList(nextHopIp))
-                                            .setAdjacencyType(AdjacencyType.LearntIp);
-                            if (mipMacAddress != null && !mipMacAddress.equalsIgnoreCase(nextHopMacAddress)) {
-                                newAdjBuilder.setMacAddress(mipMacAddress);
-                            }
-                            adjacencyList.add(newAdjBuilder.build());
-                            Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
-                            Optional<VpnInterface> optionalVpnInterface =
-                                    SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                                            LogicalDatastoreType.CONFIGURATION, vpnIfId);
-                            VpnInterface newVpnIntf;
-                            if (optionalVpnInterface.isPresent()) {
-                                newVpnIntf =
-                                        new VpnInterfaceBuilder(optionalVpnInterface.get())
-                                                .addAugmentation(Adjacencies.class, aug).build();
-                                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                        vpnIfId, newVpnIntf, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
-                            }
-                            LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
                         }
                     }
+                    if (nextHopIp == null) {
+                        LOG.error("Next Hop IP not found for MIP={}, interface={}, vpnName {}. Skipping adjacency "
+                                + "addition.", ip, interfaceName, vpnName);
+                        return;
+                    }
+
+                    String rd = vpnUtil.getVpnRd(vpnInstName);
+                    Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
+                        VpnUtil.getNextHopLabelKey(rd != null ? rd : vpnInstName, ip));
+                    if (label.longValue() == VpnConstants.INVALID_LABEL) {
+                        LOG.error("Unable to fetch label from Id Manager. Bailing out of adding MIP adjacency {}"
+                                + " to vpn interface {} for vpn {}", ip, vpnInterface, vpnInstName);
+                        return;
+                    }
+                    newAdjBuilder = new AdjacencyBuilder().setIpAddress(ip).withKey(new AdjacencyKey(ip))
+                            .setNextHopIpList(Collections.singletonList(nextHopIp))
+                            .setAdjacencyType(AdjacencyType.LearntIp);
+                    if (mipMacAddress != null && !mipMacAddress.equalsIgnoreCase(nextHopMacAddress)) {
+                        newAdjBuilder.setMacAddress(mipMacAddress);
+                    }
                 }
-            } catch (ReadFailedException e) {
+                adjacencyList.add(newAdjBuilder.build());
+                Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
+                VpnInterface newVpnIntf = new VpnInterfaceBuilder(optVpnInterface.get())
+                        .addAugmentation(Adjacencies.class, aug).build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId,
+                    newVpnIntf, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
+                LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
+            } catch (InterruptedException | ExecutionException e) {
                 LOG.error("addMipAdjacency: Failed to read data store for interface {} vpn {} ip {} mac {}",
                         vpnInterface, vpnInstName, srcPrefix, mipMacAddress);
             } catch (TransactionCommitFailedException e) {
                 LOG.error("addMipAdjacency: Failed to commit to data store for interface {} vpn {} ip {} mac {}",
                         vpnInterface, vpnInstName, srcPrefix, mipMacAddress);
+            } finally {
+                lock.unlock();
             }
         }
 
@@ -285,11 +258,13 @@ public class LearntVpnVipToPortEventProcessor
             VpnPortipToPort vpnPortipToPort =
                     vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnInstName, ip);
             if (vpnPortipToPort != null && vpnPortipToPort.isSubnetIp()) {
-                List<Adjacency> adjacencies = requireNonNullElse(vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(
-                        vpnPortipToPort.getPortName()), emptyList());
-                for (Adjacency adjacency : adjacencies) {
-                    if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
-                        return adjacency.getSubnetId().getValue();
+                List<Adjacency> adjacencies =
+                    vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(vpnPortipToPort.getPortName());
+                if (adjacencies != null) {
+                    for (Adjacency adjacency : adjacencies) {
+                        if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
+                            return adjacency.getSubnetId().getValue();
+                        }
                     }
                 }
             }
@@ -314,7 +289,7 @@ public class LearntVpnVipToPortEventProcessor
         }
     }
 
-    private class DeleteMipAdjacencyWorker implements Callable<List<ListenableFuture<Void>>> {
+    private class DeleteMipAdjacencyWorker implements Callable<List<? extends ListenableFuture<?>>> {
         String vpnName;
         String interfaceName;
         String ipAddress;