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