2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
10 import static java.util.stream.Collectors.toList;
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;
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;
81 public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
82 TunnelInterfaceStateListener> {
84 private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
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;
95 protected enum UpdateRouteAction {
96 ADVERTISE_ROUTE, WITHDRAW_ROUTE
99 protected enum TunnelAction {
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
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,
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;
135 public void start() {
136 LOG.info("{} start", getClass().getSimpleName());
137 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
141 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
142 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
146 protected TunnelInterfaceStateListener getDataTreeChangeListener() {
147 return TunnelInterfaceStateListener.this;
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);
156 handleTunnelEventForDPN(del, TunnelAction.TUNNEL_EP_DELETE);
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());
173 if (isGreTunnel(update)) {
174 programDcGwLoadBalancingGroup(update, NwConstants.MOD_FLOW);
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");
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)))
191 List<DestPrefixes> prefixes = VpnExtraRouteHelper.getExtraRouteDestPrefixes(dataBroker,
193 prefixes.forEach(destPrefix -> {
194 VrfEntry vrfEntry = vpnUtil.getVrfEntry(opData.getVrfId(),
195 destPrefix.getDestPrefix());
196 if (vrfEntry == null || vrfEntry.getRoutePaths() == null) {
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(),
205 synchronized (vpnPrefixKey.intern()) {
206 fibManager.refreshVrfEntry(opData.getVrfId(), prefix);
212 ), LOG, "Error updating route paths for FIB entries");
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());
224 if (tunOpStatus != TunnelOperStatus.Up) {
225 LOG.error("add: Tunnel {} is not yet UP.", add.getTunnelInterfaceName());
227 if (isGreTunnel(add)) {
228 programDcGwLoadBalancingGroup(add, NwConstants.ADD_FLOW);
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);
236 public enum TunnelEventProcessingMethod {
237 POPULATESUBNETS(0), MANAGEREMOTEROUTES(1);
239 private final int method;
241 TunnelEventProcessingMethod(int id) {
245 public int getValue() {
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();
257 BigInteger remoteDpnId = null;
258 boolean isTepDeletedOnDpn = false;
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);
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)) {
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;
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;
288 if (endpointIpForDPN == null) {
289 LOG.info("handleTunnelEventForDPN: Tunnel TEP is deleted on Dpn {} VTEP Ip {} destTepIp {}",
290 srcDpnId, srcTepIp, destTepIp);
291 isTepDeletedOnDpn = true;
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<>();
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());
308 srcDpninterfacelist = rpcResult.getResult().getInterfaces();
310 } catch (Exception e) {
311 LOG.error("handleTunnelEventForDPN: Exception when querying for GetDpnInterfaceList for srcDpnid {}"
312 + " srcTepIp {} destTepIp {}", srcDpnId, srcTepIp, destTepIp, e);
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());
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());
326 destDpninterfacelist = rpcResult.getResult().getInterfaces();
328 } catch (Exception e) {
329 LOG.error("handleTunnelEventForDPN: Exception when querying for GetDpnInterfaceList"
330 + " for remoteDpnid {} srcTepIp {} destTepIp {}", remoteDpnId,
331 srcTepIp, destTepIp, e);
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.
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<>();
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());
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,
365 * Iterate over the list of VpnInterface for destDPN and get the prefix .
366 * Create remote rule for each of those prefix on srcDPN.
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());
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,
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);
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);
405 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
406 for (Uuid subnetId : subnetList) {
407 // Populate the List of subnets
408 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
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);
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) {
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());
435 if (cfgVpnInterface.getVpnInstanceNames() == null) {
436 LOG.warn("handleTunnelEventForDpn: no vpnName found for interface {}", intfName);
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,
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);
470 //Populate the map for VpnId-to-Rd
471 long vpnId = vpnUtil.getVpnId(vpnName);
472 rd = vpnUtil.getVpnRd(vpnName);
473 vpnIdRdMap.put(vpnId, rd);
475 } else if (method == TunnelEventProcessingMethod.MANAGEREMOTEROUTES) {
476 Optional<VpnInterfaceOpDataEntry> opVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(intfName,
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,
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,
498 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE
499 && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
500 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp,
508 } catch (ReadFailedException e) {
509 LOG.error("handleTunnelEventForDPN: Failed to read data store for interface {} srcDpn {} srcTep {} "
510 + "dstTep {}", intfName, srcDpnId, srcTepIp, destTepIp);
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;
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;
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,
540 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
541 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList, confTx,
549 private int getTunnelType(StateTunnelList stateTunnelList) {
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();
558 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
563 private boolean isGreTunnel(StateTunnelList del) {
564 return del.getTransportType() == TunnelTypeMplsOverGre.class;
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());
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;
585 return dcGatewayIpListConfig.getDcGatewayIp()
587 .filter(dcGwIp -> dcGwIp.getTunnnelType().equals(TunnelTypeMplsOverGre.class))
588 .map(dcGwIp -> dcGwIp.getIpAddress().stringValue()).sorted()
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
604 LOG.trace("isTunnelInLogicalGroup: MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName);