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.Collections.emptyList;
11 import static java.util.stream.Collectors.toList;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14 import static org.opendaylight.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
16 import com.google.common.base.Optional;
17 import com.google.common.base.Strings;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Objects;
27 import java.util.concurrent.Callable;
28 import java.util.concurrent.Future;
29 import javax.annotation.PostConstruct;
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
35 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
36 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
37 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
42 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
43 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
44 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
45 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
46 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
47 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.get.dpn._interface.list.output.Interfaces;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.extraroute.rds.map.extraroute.rds.DestPrefixes;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
84 TunnelInterfaceStateListener> {
86 private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
88 private final DataBroker dataBroker;
89 private final ManagedNewTransactionRunner txRunner;
90 private final IFibManager fibManager;
91 private final OdlInterfaceRpcService intfRpcService;
92 private final VpnInterfaceManager vpnInterfaceManager;
93 private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
94 private final JobCoordinator jobCoordinator;
95 private final VpnUtil vpnUtil;
97 protected enum UpdateRouteAction {
98 ADVERTISE_ROUTE, WITHDRAW_ROUTE
101 protected enum TunnelAction {
108 * Responsible for listening to tunnel interface state change.
109 * @param dataBroker Data Broker
110 * @param fibManager FIB APIs
111 * @param ifaceMgrRpcService Interface Manager RPC
112 * @param vpnInterfaceManager Vpn Interface APIs
113 * @param vpnSubnetRouteHandler Subnet-Route APIs
114 * @param jobCoordinator Key based job serialization mechanism
115 * @param vpnUtil Vpn Utility
118 public TunnelInterfaceStateListener(final DataBroker dataBroker,
119 final IFibManager fibManager,
120 final OdlInterfaceRpcService ifaceMgrRpcService,
121 final VpnInterfaceManager vpnInterfaceManager,
122 final VpnSubnetRouteHandler vpnSubnetRouteHandler,
123 final JobCoordinator jobCoordinator,
125 super(StateTunnelList.class, TunnelInterfaceStateListener.class);
126 this.dataBroker = dataBroker;
127 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
128 this.fibManager = fibManager;
129 this.intfRpcService = ifaceMgrRpcService;
130 this.vpnInterfaceManager = vpnInterfaceManager;
131 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
132 this.jobCoordinator = jobCoordinator;
133 this.vpnUtil = vpnUtil;
137 public void start() {
138 LOG.info("{} start", getClass().getSimpleName());
139 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
143 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
144 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
148 protected TunnelInterfaceStateListener getDataTreeChangeListener() {
149 return TunnelInterfaceStateListener.this;
153 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
154 LOG.trace("remove: Tunnel deletion---- {}", del);
155 if (isGreTunnel(del)) {
156 programDcGwLoadBalancingGroup(del, NwConstants.DEL_FLOW);
158 handleTunnelEventForDPN(del, TunnelAction.TUNNEL_EP_DELETE);
162 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
163 StateTunnelList update) {
164 LOG.trace("update: Tunnel updation---- {}", update);
165 LOG.info("update: ITM Tunnel {} of type {} state event changed from :{} to :{}",
166 update.getTunnelInterfaceName(),
167 fibManager.getTransportTypeStr(update.getTransportType().toString()),
168 original.getOperState(), update.getOperState());
169 TunnelOperStatus tunOpStatus = update.getOperState();
170 if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) {
171 LOG.info("update: Returning from unsupported tunnelOperStatus {} for tunnel interface {}", tunOpStatus,
172 update.getTunnelInterfaceName());
175 if (isGreTunnel(update)) {
176 programDcGwLoadBalancingGroup(update, NwConstants.MOD_FLOW);
179 //Remove the corresponding nexthop from the routepath under extraroute in fibentries.
180 BigInteger srcDpnId = new BigInteger(update.getSrcInfo().getTepDeviceId());
181 String srcTepIp = update.getSrcInfo().getTepIp().stringValue();
182 List<VpnInstanceOpDataEntry> vpnInstanceOpData = vpnUtil.getAllVpnInstanceOpData();
183 if (vpnInstanceOpData == null) {
184 LOG.trace("update: No vpnInstanceOpdata present");
187 vpnInstanceOpData.stream()
188 .filter(opData -> opData.getVpnToDpnList() != null
189 && opData.getVpnToDpnList().stream().anyMatch(
190 vpnToDpn -> Objects.equals(vpnToDpn.getDpnId(), srcDpnId)))
192 List<DestPrefixes> prefixes = VpnExtraRouteHelper.getExtraRouteDestPrefixes(dataBroker,
194 prefixes.forEach(destPrefix -> {
195 VrfEntry vrfEntry = vpnUtil.getVrfEntry(opData.getVrfId(),
196 destPrefix.getDestPrefix());
197 if (vrfEntry == null || vrfEntry.getRoutePaths() == null) {
200 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
201 routePaths.forEach(routePath -> {
202 if (Objects.equals(routePath.getNexthopAddress(), srcTepIp)) {
203 String prefix = destPrefix.getDestPrefix();
204 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(opData.getVpnInstanceName(),
206 synchronized (vpnPrefixKey.intern()) {
207 fibManager.refreshVrfEntry(opData.getVrfId(), prefix);
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;
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 = requireNonNullElse(rpcResult.getResult().getInterfaces(), emptyList());
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 = requireNonNullElse(rpcResult.getResult().getInterfaces(), emptyList());
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 List<Uuid> subnetList = new ArrayList<>();
340 Map<Long, String> vpnIdRdMap = new HashMap<>();
341 Set<String> listVpnName = new HashSet<>();
343 for (Interfaces interfaces : srcDpninterfacelist) {
344 if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
345 LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
348 String intfName = interfaces.getInterfaceName();
349 VpnInterface vpnInterface =
350 vpnUtil.getConfiguredVpnInterface(intfName);
351 if (vpnInterface != null) {
352 listVpnName.addAll(VpnHelper
353 .getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
354 handleTunnelEventForDPNVpn(stateTunnelList, vpnIdRdMap,
355 tunnelAction, isTepDeletedOnDpn,
356 subnetList, TunnelEventProcessingMethod.POPULATESUBNETS,
361 * Iterate over the list of VpnInterface for destDPN and get the prefix .
362 * Create remote rule for each of those prefix on srcDPN.
364 for (Interfaces interfaces : destDpninterfacelist) {
365 if (!L2vlan.class.equals(interfaces.getInterfaceType())) {
366 LOG.info("handleTunnelEventForDPN: Interface {} not of type L2Vlan", interfaces.getInterfaceName());
369 String intfName = interfaces.getInterfaceName();
370 VpnInterface vpnInterface =
371 vpnUtil.getConfiguredVpnInterface(intfName);
372 if (vpnInterface != null) {
373 handleTunnelEventForDPNVpn(stateTunnelList, vpnIdRdMap,
374 tunnelAction, isTepDeletedOnDpn,
375 subnetList, TunnelEventProcessingMethod.MANAGEREMOTEROUTES,
380 //Iterate over the VpnId-to-Rd map.
381 for (Map.Entry<Long, String> entry : vpnIdRdMap.entrySet()) {
382 Long vpnId = entry.getKey();
383 rd = entry.getValue();
384 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD
385 && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
386 fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
387 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE
388 && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
389 fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
392 if (listVpnName.size() >= 1) {
393 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
394 for (Uuid subnetId : subnetList) {
395 // Populate the List of subnets
396 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
399 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
400 for (Uuid subnetId : subnetList) {
401 // Populate the List of subnets
402 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
406 } catch (RuntimeException e) {
407 LOG.error("handleTunnelEventForDpn: Unable to handle the tunnel event for srcDpnId {} srcTepIp {}"
408 + " remoteDpnId {} destTepIp {}", srcDpnId, srcTepIp, remoteDpnId, destTepIp, e);
412 // TODO Clean up the exception handling
413 @SuppressWarnings("checkstyle:IllegalCatch")
414 private void handleTunnelEventForDPNVpn(StateTunnelList stateTunnelList,
415 Map<Long, String> vpnIdRdMap, TunnelAction tunnelAction,
416 boolean isTepDeletedOnDpn, List<Uuid> subnetList,
417 TunnelEventProcessingMethod method,
418 VpnInterface cfgVpnInterface) {
420 String intfName = cfgVpnInterface.getName();
421 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
422 String destTepIp = stateTunnelList.getDstInfo().getTepIp().stringValue();
423 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
424 int tunTypeVal = getTunnelType(stateTunnelList);
425 BigInteger remoteDpnId = null;
426 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
427 remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
429 if (cfgVpnInterface.getVpnInstanceNames() == null) {
430 LOG.warn("handleTunnelEventForDpn: no vpnName found for interface {}", intfName);
434 for (VpnInstanceNames vpnInstance : cfgVpnInterface.getVpnInstanceNames()) {
435 String vpnName = vpnInstance.getVpnName();
436 if (method == TunnelEventProcessingMethod.POPULATESUBNETS) {
437 Optional<VpnInterfaceOpDataEntry> opVpnInterface = vpnUtil
438 .getVpnInterfaceOpDataEntry(intfName, vpnName);
439 if (opVpnInterface.isPresent()) {
440 VpnInterfaceOpDataEntry vpnInterface = opVpnInterface.get();
441 jobCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
442 new UpdateVpnInterfaceOnTunnelEvent(tunnelAction,
447 // Populate the List of subnets
448 InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
449 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
450 new PortOpDataEntryKey(intfName)).build();
451 Optional<PortOpDataEntry> optionalPortOp =
452 SingleTransactionDataBroker.syncReadOptional(dataBroker,
453 LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
454 if (optionalPortOp.isPresent()) {
455 List<Uuid> subnetIdList = optionalPortOp.get().getSubnetIds();
456 if (subnetIdList != null) {
457 for (Uuid subnetId : subnetIdList) {
458 if (!subnetList.contains(subnetId)) {
459 subnetList.add(subnetId);
464 //Populate the map for VpnId-to-Rd
465 long vpnId = vpnUtil.getVpnId(vpnName);
466 rd = vpnUtil.getVpnRd(vpnName);
467 vpnIdRdMap.put(vpnId, rd);
469 } else if (method == TunnelEventProcessingMethod.MANAGEREMOTEROUTES) {
470 Optional<VpnInterfaceOpDataEntry> opVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(intfName,
472 if (opVpnInterface.isPresent()) {
473 VpnInterfaceOpDataEntry vpnInterface = opVpnInterface.get();
474 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
475 List<Adjacency> adjList =
476 adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency()
478 String prefix = null;
479 long vpnId = vpnUtil.getVpnId(vpnInterface.getVpnInstanceName());
480 if (vpnIdRdMap.containsKey(vpnId)) {
481 rd = vpnIdRdMap.get(vpnId);
482 LOG.info("handleTunnelEventForDPN: Remote DpnId {} VpnId {} rd {} VpnInterface {}"
483 + " srcTepIp {} destTepIp {}", remoteDpnId, vpnId, rd , vpnInterface, srcTepIp,
485 for (Adjacency adj : adjList) {
486 prefix = adj.getIpAddress();
487 long label = adj.getLabel();
488 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD
489 && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
490 fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp,
493 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE
494 && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
495 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp,
503 } catch (ReadFailedException e) {
504 LOG.error("handleTunnelEventForDPN: Failed to read data store for interface {} srcDpn {} srcTep {} "
505 + "dstTep {}", intfName, srcDpnId, srcTepIp, destTepIp);
509 private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
510 private final VpnInterfaceOpDataEntry vpnInterface;
511 private final StateTunnelList stateTunnelList;
512 private final TunnelAction tunnelAction;
513 private final boolean isTepDeletedOnDpn;
515 UpdateVpnInterfaceOnTunnelEvent(TunnelAction tunnelAction,
516 VpnInterfaceOpDataEntry vpnInterface,
517 StateTunnelList stateTunnelList,
518 boolean isTepDeletedOnDpn) {
519 this.stateTunnelList = stateTunnelList;
520 this.vpnInterface = vpnInterface;
521 this.tunnelAction = tunnelAction;
522 this.isTepDeletedOnDpn = isTepDeletedOnDpn;
526 public List<ListenableFuture<Void>> call() {
527 List<ListenableFuture<Void>> futures = new ArrayList<>(2);
528 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx ->
529 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
530 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
531 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList, confTx, operTx);
534 if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) {
535 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList, confTx,
543 private int getTunnelType(StateTunnelList stateTunnelList) {
545 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
546 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
547 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
548 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
549 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
550 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
552 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
557 private boolean isGreTunnel(StateTunnelList del) {
558 return del.getTransportType() == TunnelTypeMplsOverGre.class;
561 private void programDcGwLoadBalancingGroup(StateTunnelList tunnelState, int addOrRemove) {
562 IpAddress dcGwIp = tunnelState.getDstInfo().getTepIp();
563 String dcGwIpAddress = dcGwIp.stringValue();
564 List<String> availableDcGws = getDcGwIps();
565 BigInteger dpId = new BigInteger(tunnelState.getSrcInfo().getTepDeviceId());
566 boolean isTunnelUp = TunnelOperStatus.Up == tunnelState.getOperState();
567 fibManager.programDcGwLoadBalancingGroup(availableDcGws, dpId, dcGwIpAddress, addOrRemove, isTunnelUp,
568 tunnelState.getTransportType());
571 private List<String> getDcGwIps() {
572 InstanceIdentifier<DcGatewayIpList> dcGatewayIpListid =
573 InstanceIdentifier.builder(DcGatewayIpList.class).build();
574 DcGatewayIpList dcGatewayIpListConfig =
575 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, dcGatewayIpListid).orNull();
576 if (dcGatewayIpListConfig == null) {
579 return dcGatewayIpListConfig.getDcGatewayIp()
581 .filter(dcGwIp -> dcGwIp.getTunnnelType().equals(TunnelTypeMplsOverGre.class))
582 .map(dcGwIp -> dcGwIp.getIpAddress().stringValue()).sorted()
586 private boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
587 String ifaceName = stateTunnelList.getTunnelInterfaceName();
588 if (getTunnelType(stateTunnelList) == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
589 Interface configIface = InterfaceUtils.getInterface(dataBroker, stateTunnelList.getTunnelInterfaceName());
590 IfTunnel ifTunnel = configIface != null ? configIface.augmentation(IfTunnel.class) : null;
591 if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
592 ParentRefs refs = configIface.augmentation(ParentRefs.class);
593 if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
594 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
598 LOG.trace("isTunnelInLogicalGroup: MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName);