NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / TunnelInterfaceStateListener.java
index ef4df54b2d4140f7292fdc3ffeb4d55524e4d4b3..85d3dc0af934035d128bd329cacdfbd4408e4209 100644 (file)
@@ -11,40 +11,39 @@ import static java.util.Collections.emptyList;
 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.util.concurrent.ListenableFuture;
-
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.locks.ReentrantLock;
-import javax.annotation.PostConstruct;
+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.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.utils.JvmGlobalLocks;
 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.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
-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.vpn._interface.VpnInstanceNames;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
@@ -68,11 +67,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
-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.port.op.data.PortOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
 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.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
+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.vpn._interface.VpnInstanceNames;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.Uint32;
@@ -81,8 +82,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
-public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
-        TunnelInterfaceStateListener> {
+public class TunnelInterfaceStateListener extends AbstractAsyncDataTreeChangeListener<StateTunnelList> {
 
     private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
 
@@ -94,6 +94,7 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
     private final JobCoordinator jobCoordinator;
     private final VpnUtil vpnUtil;
+    private static final int RETRY_COUNT = 3;
 
     protected enum UpdateRouteAction {
         ADVERTISE_ROUTE, WITHDRAW_ROUTE
@@ -123,7 +124,9 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                                         final VpnSubnetRouteHandler vpnSubnetRouteHandler,
                                         final JobCoordinator jobCoordinator,
                                         VpnUtil vpnUtil) {
-        super(StateTunnelList.class, TunnelInterfaceStateListener.class);
+        super(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class),
+                Executors.newListeningSingleThreadExecutor("TunnelInterfaceStateListener", LOG));
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.fibManager = fibManager;
@@ -132,26 +135,23 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
         this.jobCoordinator = jobCoordinator;
         this.vpnUtil = vpnUtil;
+        start();
     }
 
-    @PostConstruct
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
-        registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
     }
 
     @Override
-    protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
-        return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
+    @PreDestroy
+    public void close() {
+        super.close();
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
-    @Override
-    protected TunnelInterfaceStateListener getDataTreeChangeListener() {
-        return TunnelInterfaceStateListener.this;
-    }
 
     @Override
-    protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
+    public void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
         LOG.trace("remove: Tunnel deletion---- {}", del);
         if (isGreTunnel(del)) {
             programDcGwLoadBalancingGroup(del, NwConstants.MOD_FLOW, false);
@@ -160,7 +160,7 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
     }
 
     @Override
-    protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
+    public void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
                           StateTunnelList update) {
         LOG.trace("update: Tunnel updation---- {}", update);
         LOG.info("update: ITM Tunnel {} of type {} state event changed from :{} to :{}",
@@ -220,7 +220,7 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
     }
 
     @Override
-    protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
+    public void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
         LOG.trace("add: Tunnel addition---- {}", add);
         TunnelOperStatus tunOpStatus = add.getOperState();
         if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) {
@@ -236,8 +236,10 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
             programDcGwLoadBalancingGroup(add, NwConstants.ADD_FLOW, isTunnelUp);
         }
         LOG.info("add: ITM Tunnel ,type {} ,added between src: {} and dest: {}",
-                fibManager.getTransportTypeStr(add.getTransportType().toString()),
-                add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
+                fibManager.getTransportTypeStr(add.getTransportType() != null
+                        ? add.getTransportType().toString() : "Invalid"),
+                add.getSrcInfo() != null ? add.getSrcInfo().getTepDeviceId() : "0",
+                add.getDstInfo() != null ? add.getDstInfo().getTepDeviceId() : "0");
         handleTunnelEventForDPN(add, TunnelAction.TUNNEL_EP_ADD);
     }
 
@@ -258,9 +260,12 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
-        final Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
-        final String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
-        String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
+        final Uint64 srcDpnId = stateTunnelList.getSrcInfo() != null
+                ? Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern() : Uint64.ZERO;
+        final String srcTepIp = stateTunnelList.getSrcInfo() != null
+                ? stateTunnelList.getSrcInfo().getTepIp().stringValue() : "0";
+        String destTepIp = stateTunnelList.getDstInfo() != null
+                ? stateTunnelList.getDstInfo().getTepIp().stringValue() : "0";
         String rd;
         Uint64 remoteDpnId = null;
         boolean isTepDeletedOnDpn = false;
@@ -321,7 +326,8 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
             }
             // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                remoteDpnId = Uint64.valueOf(stateTunnelList.getDstInfo().getTepDeviceId()).intern();
+                remoteDpnId = Uint64.valueOf(stateTunnelList.getDstInfo() != null
+                        ? stateTunnelList.getDstInfo().getTepDeviceId() : "0").intern();
                 try {
                     result = intfRpcService.getDpnInterfaceList(
                             new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
@@ -411,6 +417,24 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                     }
                 }
             }
+            /*
+             * Program the BGP routes of all the VPNs which have footprint on the source DPN.
+             *
+             * DC-GW LB groups are programmed in DJC Jobs, so DJC with same key is used here to make sure
+             * groups are programmed first, then only BGP routes are programmed.
+             */
+            jobCoordinator.enqueueJob(FibHelper.getJobKeyForDcGwLoadBalancingGroup(srcDpnId), () -> {
+                listVpnName.forEach(vpnName -> {
+                    Uint32 vpnId = vpnUtil.getVpnId(vpnName);
+                    final String vrfId = vpnIdRdMap.get(vpnId);
+                    if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
+                            && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
+                        fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, vrfId,
+                                srcTepIp, destTepIp);
+                    }
+                });
+                return Collections.emptyList();
+            },RETRY_COUNT);
         } catch (RuntimeException e) {
             LOG.error("handleTunnelEventForDpn: Unable to handle the tunnel event for srcDpnId {} srcTepIp {}"
                     + " remoteDpnId {} destTepIp {}", srcDpnId, srcTepIp, remoteDpnId, destTepIp, e);
@@ -426,13 +450,17 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                                             VpnInterface cfgVpnInterface) {
         String rd;
         String intfName = cfgVpnInterface.getName();
-        final Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
-        String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
-        String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
+        final Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo() != null
+                ? stateTunnelList.getSrcInfo().getTepDeviceId() : "0").intern();
+        String destTepIp = stateTunnelList.getDstInfo() != null ? stateTunnelList.getDstInfo().getTepIp().stringValue()
+                : null;
+        String srcTepIp = stateTunnelList.getSrcInfo() != null ? stateTunnelList.getSrcInfo().getTepIp().stringValue()
+                : null;
         int tunTypeVal = getTunnelType(stateTunnelList);
         Uint64 remoteDpnId = null;
         if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-            remoteDpnId = Uint64.valueOf(stateTunnelList.getDstInfo().getTepDeviceId()).intern();
+            remoteDpnId = Uint64.valueOf(stateTunnelList.getDstInfo() != null
+                    ? stateTunnelList.getDstInfo().getTepDeviceId() : "0").intern();
         }
         if (cfgVpnInterface.getVpnInstanceNames() == null) {
             LOG.warn("handleTunnelEventForDpn: no vpnName found for interface {}", intfName);
@@ -508,7 +536,7 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                     }
                 }
             }
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("handleTunnelEventForDPN: Failed to read data store for interface {} srcDpn {} srcTep {} "
                     + "dstTep {}", intfName, srcDpnId, srcTepIp, destTepIp);
         }
@@ -550,6 +578,9 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
 
     private int getTunnelType(StateTunnelList stateTunnelList) {
         int tunTypeVal = 0;
+        if (stateTunnelList.getDstInfo() == null) {
+            return VpnConstants.ITMTunnelLocType.Invalid.getValue();
+        }
         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {