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