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