ECMP UC2 Enhancement: Support for more than two DC-GWs
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / TunnelInterfaceStateListener.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.vpnmanager;
9
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13
14 import com.google.common.base.Optional;
15 import com.google.common.base.Strings;
16 import com.google.common.util.concurrent.ListenableFuture;
17
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.locks.ReentrantLock;
29 import javax.annotation.PostConstruct;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
36 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.genius.utils.JvmGlobalLocks;
42 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
43 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
44 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
45 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
46 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
47 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
48 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.get.dpn._interface.list.output.Interfaces;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.extraroute.rds.map.extraroute.rds.DestPrefixes;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 @Singleton
83 public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
84         TunnelInterfaceStateListener> {
85
86     private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
87
88     private final DataBroker dataBroker;
89     private final ManagedNewTransactionRunner txRunner;
90     private final IFibManager fibManager;
91     private final OdlInterfaceRpcService intfRpcService;
92     private final VpnInterfaceManager vpnInterfaceManager;
93     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
94     private final JobCoordinator jobCoordinator;
95     private final VpnUtil vpnUtil;
96
97     protected enum UpdateRouteAction {
98         ADVERTISE_ROUTE, WITHDRAW_ROUTE
99     }
100
101     protected enum TunnelAction {
102         TUNNEL_EP_ADD,
103         TUNNEL_EP_DELETE,
104         TUNNEL_EP_UPDATE
105     }
106
107     /**
108      * Responsible for listening to tunnel interface state change.
109      * @param dataBroker Data Broker
110      * @param fibManager FIB APIs
111      * @param ifaceMgrRpcService Interface Manager RPC
112      * @param vpnInterfaceManager Vpn Interface APIs
113      * @param vpnSubnetRouteHandler Subnet-Route APIs
114      * @param jobCoordinator Key based job serialization mechanism
115      * @param vpnUtil Vpn Utility
116      */
117     @Inject
118     public TunnelInterfaceStateListener(final DataBroker dataBroker,
119                                         final IFibManager fibManager,
120                                         final OdlInterfaceRpcService ifaceMgrRpcService,
121                                         final VpnInterfaceManager vpnInterfaceManager,
122                                         final VpnSubnetRouteHandler vpnSubnetRouteHandler,
123                                         final JobCoordinator jobCoordinator,
124                                         VpnUtil vpnUtil) {
125         super(StateTunnelList.class, TunnelInterfaceStateListener.class);
126         this.dataBroker = dataBroker;
127         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
128         this.fibManager = fibManager;
129         this.intfRpcService = ifaceMgrRpcService;
130         this.vpnInterfaceManager = vpnInterfaceManager;
131         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
132         this.jobCoordinator = jobCoordinator;
133         this.vpnUtil = vpnUtil;
134     }
135
136     @PostConstruct
137     public void start() {
138         LOG.info("{} start", getClass().getSimpleName());
139         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
140     }
141
142     @Override
143     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
144         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
145     }
146
147     @Override
148     protected TunnelInterfaceStateListener getDataTreeChangeListener() {
149         return TunnelInterfaceStateListener.this;
150     }
151
152     @Override
153     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
154         LOG.trace("remove: Tunnel deletion---- {}", del);
155         if (isGreTunnel(del)) {
156             programDcGwLoadBalancingGroup(del, NwConstants.MOD_FLOW, false);
157         }
158         handleTunnelEventForDPN(del, TunnelAction.TUNNEL_EP_DELETE);
159     }
160
161     @Override
162     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
163                           StateTunnelList update) {
164         LOG.trace("update: Tunnel updation---- {}", update);
165         LOG.info("update: ITM Tunnel {} of type {} state event changed from :{} to :{}",
166                 update.getTunnelInterfaceName(),
167                 fibManager.getTransportTypeStr(update.getTransportType().toString()),
168                 original.getOperState(), update.getOperState());
169         TunnelOperStatus tunOpStatus = update.getOperState();
170         if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) {
171             LOG.info("update: Returning from unsupported tunnelOperStatus {} for tunnel interface {}", tunOpStatus,
172                     update.getTunnelInterfaceName());
173             return;
174         }
175         boolean isTunnelUp = TunnelOperStatus.Up == update.getOperState();
176         if (isGreTunnel(update)) {
177             programDcGwLoadBalancingGroup(update, NwConstants.MOD_FLOW, isTunnelUp);
178         }
179
180         //Remove the corresponding nexthop from the routepath under extraroute in fibentries.
181         BigInteger srcDpnId = new BigInteger(update.getSrcInfo().getTepDeviceId());
182         String srcTepIp = update.getSrcInfo().getTepIp().stringValue();
183         List<VpnInstanceOpDataEntry> vpnInstanceOpData = vpnUtil.getAllVpnInstanceOpData();
184         if (vpnInstanceOpData == null) {
185             LOG.trace("update: No vpnInstanceOpdata present");
186             return;
187         }
188         vpnInstanceOpData.stream()
189                 .filter(opData -> opData.getVpnToDpnList() != null
190                         && opData.getVpnToDpnList().stream().anyMatch(
191                             vpnToDpn -> Objects.equals(vpnToDpn.getDpnId(), srcDpnId)))
192                 .forEach(opData -> {
193                     List<DestPrefixes> prefixes = VpnExtraRouteHelper.getExtraRouteDestPrefixes(dataBroker,
194                             opData.getVpnId());
195                     prefixes.forEach(destPrefix -> {
196                         VrfEntry vrfEntry = vpnUtil.getVrfEntry(opData.getVrfId(),
197                                 destPrefix.getDestPrefix());
198                         if (vrfEntry == null || vrfEntry.getRoutePaths() == null) {
199                             return;
200                         }
201                         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
202                         routePaths.forEach(routePath -> {
203                             if (Objects.equals(routePath.getNexthopAddress(), srcTepIp)) {
204                                 String prefix = destPrefix.getDestPrefix();
205                                 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(opData.getVpnInstanceName(),
206                                         prefix);
207                                 // FIXME: separate out to somehow?
208                                 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
209                                 lock.lock();
210                                 try {
211                                     fibManager.refreshVrfEntry(opData.getVrfId(), prefix);
212                                 } finally {
213                                     lock.unlock();
214                                 }
215                             }
216                         });
217                     });
218                 });
219     }
220
221     @Override
222     protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
223         LOG.trace("add: Tunnel addition---- {}", add);
224         TunnelOperStatus tunOpStatus = add.getOperState();
225         if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) {
226             LOG.info("add: Returning from unsupported tunnelOperStatus {} for tunnel interface {}", tunOpStatus,
227                     add.getTunnelInterfaceName());
228             return;
229         }
230         if (tunOpStatus != TunnelOperStatus.Up) {
231             LOG.error("add: Tunnel {} is not yet UP.", add.getTunnelInterfaceName());
232         }
233         boolean isTunnelUp = TunnelOperStatus.Up == add.getOperState();
234         if (isGreTunnel(add)) {
235             programDcGwLoadBalancingGroup(add, NwConstants.ADD_FLOW, isTunnelUp);
236         }
237         LOG.info("add: ITM Tunnel ,type {} ,added between src: {} and dest: {}",
238                 fibManager.getTransportTypeStr(add.getTransportType().toString()),
239                 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
240         handleTunnelEventForDPN(add, TunnelAction.TUNNEL_EP_ADD);
241     }
242
243     public enum TunnelEventProcessingMethod {
244         POPULATESUBNETS(0), MANAGEREMOTEROUTES(1);
245
246         private final int method;
247
248         TunnelEventProcessingMethod(int id) {
249             this.method = id;
250         }
251
252         public int getValue() {
253             return method;
254         }
255     }
256
257     // TODO Clean up the exception handling
258     @SuppressWarnings("checkstyle:IllegalCatch")
259     private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
260         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
261         final String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
262         String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
263         String rd;
264         BigInteger remoteDpnId = null;
265         boolean isTepDeletedOnDpn = false;
266
267         LOG.info("handleTunnelEventForDPN: Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ",
268                 srcDpnId, srcTepIp, destTepIp);
269         int tunTypeVal = getTunnelType(stateTunnelList);
270         LOG.trace("handleTunnelEventForDPN: tunTypeVal is {}", tunTypeVal);
271         try {
272             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
273                 LOG.info("handleTunnelEventForDPN: Tunnel ADD event received for Dpn {} VTEP Ip {} destTepIp {}",
274                         srcDpnId, srcTepIp, destTepIp);
275                 if (isTunnelInLogicalGroup(stateTunnelList)) {
276                     return;
277                 }
278             } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
279                 LOG.info("handleTunnelEventForDPN: Tunnel DELETE event received for Dpn {} VTEP Ip {} DestTepIp {}",
280                         srcDpnId, srcTepIp, destTepIp);
281                 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
282                 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
283                 // Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
284                 // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted.
285                 // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted.
286                 String endpointIpForDPN;
287                 try {
288                     endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
289                 } catch (Exception e) {
290                     LOG.error("handleTunnelEventForDPN: Unable to resolve endpoint IP for srcDpn {}", srcDpnId);
291                     /* this dpn does not have the VTEP */
292                     endpointIpForDPN = null;
293                 }
294
295                 if (endpointIpForDPN == null) {
296                     LOG.info("handleTunnelEventForDPN: Tunnel TEP is deleted on Dpn {} VTEP Ip {} destTepIp {}",
297                             srcDpnId, srcTepIp, destTepIp);
298                     isTepDeletedOnDpn = true;
299                 }
300             }
301
302             // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted
303             Future<RpcResult<GetDpnInterfaceListOutput>> result;
304             List<Interfaces> srcDpninterfacelist = new ArrayList<>();
305             List<Interfaces> destDpninterfacelist = new ArrayList<>();
306             try {
307                 result = intfRpcService.getDpnInterfaceList(
308                         new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build());
309                 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
310                 if (!rpcResult.isSuccessful()) {
311                     LOG.error("handleTunnelEventForDPN: RPC Call to GetDpnInterfaceList for srcDpnid {} srcTepIp {}"
312                                     + " destTepIP {} returned with Errors {}", srcDpnId, srcTepIp, destTepIp,
313                             rpcResult.getErrors());
314                 } else {
315                     srcDpninterfacelist = rpcResult.getResult().nonnullInterfaces();
316                 }
317             } catch (Exception e) {
318                 LOG.error("handleTunnelEventForDPN: Exception when querying for GetDpnInterfaceList for srcDpnid {}"
319                         + " srcTepIp {} destTepIp {}", srcDpnId, srcTepIp, destTepIp, e);
320             }
321             // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
322             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
323                 remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
324                 try {
325                     result = intfRpcService.getDpnInterfaceList(
326                             new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
327                     RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
328                     if (!rpcResult.isSuccessful()) {
329                         LOG.error("handleTunnelEventForDPN: RPC Call to GetDpnInterfaceList for remoteDpnid {}"
330                                         + " srcTepIP {} destTepIp {} returned with Errors {}", remoteDpnId, srcTepIp,
331                                 destTepIp, rpcResult.getErrors());
332                     } else {
333                         destDpninterfacelist = rpcResult.getResult().nonnullInterfaces();
334                     }
335                 } catch (Exception e) {
336                     LOG.error("handleTunnelEventForDPN: Exception when querying for GetDpnInterfaceList"
337                                     + " for remoteDpnid {} srcTepIp {} destTepIp {}", remoteDpnId,
338                             srcTepIp, destTepIp, e);
339                 }
340             }
341
342             /*
343              * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj.
344              * Update the adjacencies with the updated nexthop.
345              */
346             List<Uuid> subnetList = new ArrayList<>();
347             Map<Long, String> vpnIdRdMap = new HashMap<>();
348             Set<String> listVpnName = new HashSet<>();
349
350             for (Interfaces interfaces : srcDpninterfacelist) {
351                 if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
352                     LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
353                     continue;
354                 }
355                 String intfName = interfaces.getInterfaceName();
356                 VpnInterface vpnInterface =
357                      vpnUtil.getConfiguredVpnInterface(intfName);
358                 if (vpnInterface != null) {
359                     listVpnName.addAll(VpnHelper
360                         .getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
361                     handleTunnelEventForDPNVpn(stateTunnelList, vpnIdRdMap,
362                             tunnelAction, isTepDeletedOnDpn,
363                             subnetList, TunnelEventProcessingMethod.POPULATESUBNETS,
364                             vpnInterface);
365                 }
366             }
367             /*
368              * Iterate over the list of VpnInterface for destDPN and get the prefix .
369              * Create remote rule for each of those prefix on srcDPN.
370              */
371             for (Interfaces interfaces : destDpninterfacelist) {
372                 if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
373                     LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
374                     continue;
375                 }
376                 String intfName = interfaces.getInterfaceName();
377                 VpnInterface vpnInterface =
378                         vpnUtil.getConfiguredVpnInterface(intfName);
379                 if (vpnInterface != null) {
380                     handleTunnelEventForDPNVpn(stateTunnelList, vpnIdRdMap,
381                             tunnelAction, isTepDeletedOnDpn,
382                             subnetList, TunnelEventProcessingMethod.MANAGEREMOTEROUTES,
383                             vpnInterface);
384                 }
385             }
386
387             //Iterate over the VpnId-to-Rd map.
388             for (Map.Entry<Long, String> entry : vpnIdRdMap.entrySet()) {
389                 Long vpnId = entry.getKey();
390                 rd = entry.getValue();
391                 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD
392                     && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
393                     fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
394                 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE
395                     && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
396                     fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
397                 }
398             }
399             if (listVpnName.size() >= 1) {
400                 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
401                     for (Uuid subnetId : subnetList) {
402                         // Populate the List of subnets
403                         vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
404                     }
405                 }
406                 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
407                     for (Uuid subnetId : subnetList) {
408                         // Populate the List of subnets
409                         vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
410                     }
411                 }
412             }
413         } catch (RuntimeException e) {
414             LOG.error("handleTunnelEventForDpn: Unable to handle the tunnel event for srcDpnId {} srcTepIp {}"
415                     + " remoteDpnId {} destTepIp {}", srcDpnId, srcTepIp, remoteDpnId, destTepIp, e);
416         }
417     }
418
419     // TODO Clean up the exception handling
420     @SuppressWarnings("checkstyle:IllegalCatch")
421     private void handleTunnelEventForDPNVpn(StateTunnelList stateTunnelList,
422                                             Map<Long, String> vpnIdRdMap, TunnelAction tunnelAction,
423                                             boolean isTepDeletedOnDpn, List<Uuid> subnetList,
424                                             TunnelEventProcessingMethod method,
425                                             VpnInterface cfgVpnInterface) {
426         String rd;
427         String intfName = cfgVpnInterface.getName();
428         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
429         String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
430         String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
431         int tunTypeVal = getTunnelType(stateTunnelList);
432         BigInteger remoteDpnId = null;
433         if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
434             remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
435         }
436         if (cfgVpnInterface.getVpnInstanceNames() == null) {
437             LOG.warn("handleTunnelEventForDpn: no vpnName found for interface {}", intfName);
438             return;
439         }
440         try {
441             for (VpnInstanceNames vpnInstance : cfgVpnInterface.getVpnInstanceNames()) {
442                 String vpnName = vpnInstance.getVpnName();
443                 if (method == TunnelEventProcessingMethod.POPULATESUBNETS) {
444                     Optional<VpnInterfaceOpDataEntry> opVpnInterface = vpnUtil
445                             .getVpnInterfaceOpDataEntry(intfName, vpnName);
446                     if (opVpnInterface.isPresent()) {
447                         VpnInterfaceOpDataEntry vpnInterface  = opVpnInterface.get();
448                         jobCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
449                                 new UpdateVpnInterfaceOnTunnelEvent(tunnelAction,
450                                         vpnInterface,
451                                         stateTunnelList,
452                                         isTepDeletedOnDpn));
453
454                         // Populate the List of subnets
455                         InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
456                                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
457                                         new PortOpDataEntryKey(intfName)).build();
458                         Optional<PortOpDataEntry> optionalPortOp =
459                                 SingleTransactionDataBroker.syncReadOptional(dataBroker,
460                                         LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
461                         if (optionalPortOp.isPresent()) {
462                             List<Uuid> subnetIdList = optionalPortOp.get().getSubnetIds();
463                             if (subnetIdList != null) {
464                                 for (Uuid subnetId : subnetIdList) {
465                                     if (!subnetList.contains(subnetId)) {
466                                         subnetList.add(subnetId);
467                                     }
468                                 }
469                             }
470                         }
471                         //Populate the map for VpnId-to-Rd
472                         long vpnId = vpnUtil.getVpnId(vpnName);
473                         rd = vpnUtil.getVpnRd(vpnName);
474                         vpnIdRdMap.put(vpnId, rd);
475                     }
476                 } else if (method == TunnelEventProcessingMethod.MANAGEREMOTEROUTES) {
477                     Optional<VpnInterfaceOpDataEntry> opVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(intfName,
478                             vpnName);
479                     if (opVpnInterface.isPresent()) {
480                         VpnInterfaceOpDataEntry vpnInterface  = opVpnInterface.get();
481                         AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
482                         List<Adjacency> adjList =
483                             adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency()
484                                 : emptyList();
485                         String prefix = null;
486                         long vpnId = vpnUtil.getVpnId(vpnInterface.getVpnInstanceName());
487                         if (vpnIdRdMap.containsKey(vpnId)) {
488                             rd = vpnIdRdMap.get(vpnId);
489                             LOG.info("handleTunnelEventForDPN: Remote DpnId {} VpnId {} rd {} VpnInterface {}"
490                                     + " srcTepIp {} destTepIp {}", remoteDpnId, vpnId, rd , vpnInterface, srcTepIp,
491                                     destTepIp);
492                             for (Adjacency adj : adjList) {
493                                 prefix = adj.getIpAddress();
494                                 long label = adj.getLabel();
495                                 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD
496                                         && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
497                                     fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp,
498                                             label);
499                                 }
500                                 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE
501                                         && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
502                                     fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp,
503                                             label);
504                                 }
505                             }
506                         }
507                     }
508                 }
509             }
510         } catch (ReadFailedException e) {
511             LOG.error("handleTunnelEventForDPN: Failed to read data store for interface {} srcDpn {} srcTep {} "
512                     + "dstTep {}", intfName, srcDpnId, srcTepIp, destTepIp);
513         }
514     }
515
516     private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
517         private final VpnInterfaceOpDataEntry vpnInterface;
518         private final StateTunnelList stateTunnelList;
519         private final TunnelAction tunnelAction;
520         private final boolean isTepDeletedOnDpn;
521
522         UpdateVpnInterfaceOnTunnelEvent(TunnelAction tunnelAction,
523                                         VpnInterfaceOpDataEntry vpnInterface,
524                                         StateTunnelList stateTunnelList,
525                                         boolean isTepDeletedOnDpn) {
526             this.stateTunnelList = stateTunnelList;
527             this.vpnInterface = vpnInterface;
528             this.tunnelAction = tunnelAction;
529             this.isTepDeletedOnDpn = isTepDeletedOnDpn;
530         }
531
532         @Override
533         public List<ListenableFuture<Void>> call() {
534             List<ListenableFuture<Void>> futures = new ArrayList<>(2);
535             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx ->
536                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
537                     if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
538                         vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList, confTx, operTx);
539                     }
540
541                     if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
542                         vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList, confTx,
543                             operTx);
544                     }
545                 }))));
546             return futures;
547         }
548     }
549
550     private int getTunnelType(StateTunnelList stateTunnelList) {
551         int tunTypeVal = 0;
552         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
553             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
554         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
555             tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
556         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
557             tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
558         } else {
559             tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
560         }
561         return tunTypeVal;
562     }
563
564     private boolean isGreTunnel(StateTunnelList del) {
565         return del.getTransportType() == TunnelTypeMplsOverGre.class;
566     }
567
568     private void programDcGwLoadBalancingGroup(StateTunnelList tunnelState, int addOrRemove, boolean isTunnelUp) {
569         IpAddress dcGwIp = tunnelState.getDstInfo().getTepIp();
570         String dcGwIpAddress = String.valueOf(dcGwIp.stringValue());
571         BigInteger dpId = new BigInteger(tunnelState.getSrcInfo().getTepDeviceId());
572         fibManager.programDcGwLoadBalancingGroup(dpId, dcGwIpAddress, addOrRemove, isTunnelUp,
573                 tunnelState.getTransportType());
574     }
575
576     private boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
577         String ifaceName = stateTunnelList.getTunnelInterfaceName();
578         if (getTunnelType(stateTunnelList) == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
579             Interface configIface = InterfaceUtils.getInterface(dataBroker, stateTunnelList.getTunnelInterfaceName());
580             IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
581             if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
582                 ParentRefs refs = configIface.augmentation(ParentRefs.class);
583                 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
584                     return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
585                 }
586             }
587         }
588         LOG.trace("isTunnelInLogicalGroup: MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName);
589         return false;
590     }
591 }