NETVIRT-1519: MIP entry duplicated in FIB
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / SubnetRoutePacketInHandler.java
1 /*
2  * Copyright (c) 2016, 2018 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.Collections.emptyList;
11 import static org.opendaylight.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
12
13 import com.google.common.base.Optional;
14 import com.google.common.primitives.Ints;
15 import java.math.BigInteger;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import javax.annotation.Nullable;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
28 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
29 import org.opendaylight.genius.mdsalutil.NWUtil;
30 import org.opendaylight.genius.mdsalutil.NwConstants;
31 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
32 import org.opendaylight.genius.mdsalutil.packet.IPv4;
33 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
34 import org.opendaylight.netvirt.vpnmanager.api.ICentralizedSwitchProvider;
35 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
36 import org.opendaylight.netvirt.vpnmanager.iplearn.ipv4.ArpUtils;
37 import org.opendaylight.netvirt.vpnmanager.utilities.VpnManagerCounters;
38 import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
39 import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
40 import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
41 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
42 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
43 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefixBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
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.rpcs.rev160406.OdlInterfaceRpcService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.Ipv6NdUtilService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 @Singleton
69 public class SubnetRoutePacketInHandler implements PacketProcessingListener {
70     private static final Logger LOG = LoggerFactory.getLogger(SubnetRoutePacketInHandler.class);
71     private static final String LOGGING_PREFIX = "SUBNETROUTE:";
72     private final DataBroker dataBroker;
73     private final PacketProcessingService packetService;
74     private final OdlInterfaceRpcService odlInterfaceRpcService;
75     private final ICentralizedSwitchProvider centralizedSwitchProvider;
76     private final IInterfaceManager interfaceManager;
77     private final VpnManagerCounters vpnManagerCounters;
78     private final Ipv6NdUtilService ipv6NdUtilService;
79     private final VpnUtil vpnUtil;
80
81     @Inject
82     public SubnetRoutePacketInHandler(final DataBroker dataBroker, final PacketProcessingService packetService,
83             final OdlInterfaceRpcService odlInterfaceRpcService,
84             final ICentralizedSwitchProvider centralizedSwitchProvider, final IInterfaceManager interfaceManager,
85             VpnManagerCounters vpnManagerCounters, final Ipv6NdUtilService ipv6NdUtilService, VpnUtil vpnUtil) {
86         this.dataBroker = dataBroker;
87         this.packetService = packetService;
88         this.odlInterfaceRpcService = odlInterfaceRpcService;
89         this.centralizedSwitchProvider = centralizedSwitchProvider;
90         this.interfaceManager = interfaceManager;
91         this.vpnManagerCounters = vpnManagerCounters;
92         this.ipv6NdUtilService = ipv6NdUtilService;
93         this.vpnUtil = vpnUtil;
94     }
95
96     @Override
97     public void onPacketReceived(PacketReceived notification) {
98
99         short tableId = notification.getTableId().getValue();
100         LOG.trace("{} onPacketReceived: Packet punted from table {}", LOGGING_PREFIX, tableId);
101         if (!vpnUtil.isArpLearningEnabled()) {
102             LOG.trace("Not handling packet as ARP Based Learning is disabled");
103             return;
104         }
105         byte[] data = notification.getPayload();
106         if (notification.getMatch() == null || notification.getMatch().getMetadata() == null) {
107             LOG.error("{} onPacketReceived: Received from table {} where the match or metadata are null",
108                     LOGGING_PREFIX, tableId);
109             return;
110         }
111         BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
112         Ethernet res = new Ethernet();
113
114         if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
115             LOG.trace("{} onPacketReceived: Some packet received as {}", LOGGING_PREFIX, notification);
116             try {
117                 res.deserialize(data, 0, data.length * Byte.SIZE);
118             } catch (PacketException e) {
119                 LOG.error("{} onPacketReceived: Failed to decode Packet ", LOGGING_PREFIX, e);
120                 vpnManagerCounters.subnetRoutePacketFailed();
121                 return;
122             }
123             byte[] srcIpBytes = null;
124             byte[] dstIpBytes = null;
125             String srcIpStr;
126             String dstIpStr;
127             String srcMac = NWUtil.toStringMacAddress(res.getSourceMACAddress());
128             try {
129                 Packet pkt = res.getPayload();
130                 if (pkt instanceof IPv4) {
131                     IPv4 ipv4 = (IPv4) pkt;
132                     srcIpBytes = Ints.toByteArray(ipv4.getSourceAddress());
133                     dstIpBytes = Ints.toByteArray(ipv4.getDestinationAddress());
134                     // It is an ARP request on a configured VPN. So we must
135                     // attempt to respond.
136                 } else {
137                     // IPv6 case
138                     // TODO: IPv6 deserializer
139                     int ethType = BitBufferHelper.getInt(
140                             BitBufferHelper.getBits(data, VpnConstants.ETHTYPE_START, VpnConstants.TWO_BYTES));
141                     if (ethType == VpnConstants.IP_V6_ETHTYPE) {
142                         srcIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 64, 128);
143                         dstIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 192, 128);
144                     }
145                 }
146                 if (srcIpBytes == null || dstIpBytes == null) {
147                     LOG.trace("{} onPacketReceived: Non-IP packet received as {}", LOGGING_PREFIX, notification);
148                     return;
149                 }
150                 srcIpStr = NWUtil.toStringIpAddress(srcIpBytes);
151                 dstIpStr = NWUtil.toStringIpAddress(dstIpBytes);
152
153                 handleIpPackets(srcIpBytes, dstIpBytes, srcIpStr, dstIpStr, srcMac, metadata);
154
155             } catch (UnknownHostException | InterruptedException | ExecutionException | BufferException ex) {
156                 // Failed to handle packet
157                 vpnManagerCounters.subnetRoutePacketFailed();
158                 LOG.error("{} onPacketReceived: Failed to handle subnetroute packet.", LOGGING_PREFIX, ex);
159             } catch (ReadFailedException e) {
160                 vpnManagerCounters.subnetRoutePacketFailed();
161                 LOG.error("{} onPacketReceived: Failed to read data-store.", LOGGING_PREFIX, e);
162             }
163             return;
164         }
165         // All Arp responses learning for invisble IPs is handled by
166         // ArpNotificationHandler
167
168     }
169
170     private void handleIpPackets(byte[] srcIp, byte[] dstIp, String srcIpStr, String dstIpStr, String srcMac,
171             BigInteger metadata)
172             throws UnknownHostException, InterruptedException, ExecutionException, ReadFailedException {
173         long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
174
175         LOG.info("{} onPacketReceived: Processing IP Packet received with Source IP {} and Target IP {}"
176                 + " and vpnId {}", LOGGING_PREFIX, srcIpStr, dstIpStr, vpnId);
177
178         Optional<VpnIds> vpnIdsOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
179                 LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId));
180
181         if (!vpnIdsOptional.isPresent()) {
182             // Donot trigger subnetroute logic for packets from
183             // unknown VPNs
184             vpnManagerCounters.subnetRoutePacketIgnored();
185             LOG.info("{} onPacketReceived: Ignoring IPv4 packet with destination Ip {} and source Ip {}"
186                     + " as it came on unknown VPN with ID {}", LOGGING_PREFIX, dstIpStr, srcIpStr, vpnId);
187             return;
188         }
189
190         String vpnIdVpnInstanceName = vpnIdsOptional.get().getVpnInstanceName();
191         VpnPortipToPort persistedIP =
192                 vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnIdVpnInstanceName, dstIpStr);
193         if (persistedIP != null && !persistedIP.isLearntIp()) {
194             vpnManagerCounters.subnetRoutePacketIgnored();
195             LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source IP {} vpnId {} "
196                     + "is a valid Neutron port,ignoring subnet route processing", LOGGING_PREFIX, dstIpStr,
197                     srcIp, vpnId);
198             return;
199         }
200
201         if (vpnUtil.getLearntVpnVipToPort(vpnIdVpnInstanceName, dstIpStr) != null) {
202             vpnManagerCounters.subnetRoutePacketIgnored();
203             LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source Ip {} vpnId {}"
204                     + " is an already discovered IPAddress, ignoring subnet route processing",
205                     LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
206             return;
207         }
208
209         long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
210         if (elanTag == 0L) {
211             vpnManagerCounters.subnetRoutePacketFailed();
212             LOG.error("{} onPacketReceived: elanTag value from metadata found to be 0, for IP "
213                     + " Packet received with Target IP {} src Ip {} vpnId {}",
214                     LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
215             return;
216         }
217
218         if (!vpnIdsOptional.get().isExternalVpn()) {
219             handleInternalVpnSubnetRoutePacket(metadata, dstIp, srcIpStr, dstIpStr, vpnIdVpnInstanceName,
220                     elanTag);
221             return;
222         }
223
224         handleBgpVpnSubnetRoute(srcMac, dstIp, dstIpStr, srcIpStr, elanTag);
225     }
226
227     private void handleBgpVpnSubnetRoute(String srcMac, byte[] dstIp, String dstIpStr, String srcIpStr,
228             long elanTag) throws UnknownHostException {
229         LOG.info("{} handleBgpVpnSubnetRoute: Processing IP Packet received with Source IP {} and Target IP {}"
230                 + " and elan Tag {}", LOGGING_PREFIX, srcIpStr, dstIpStr, elanTag);
231         SubnetOpDataEntry targetSubnetForPacketOut =
232                 getTargetSubnetForPacketOut(elanTag, dstIpStr);
233         if (targetSubnetForPacketOut != null) {
234             // Handle subnet routes ip requests
235             transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), srcIpStr, srcMac, dstIp, dstIpStr, elanTag);
236         } else {
237             vpnManagerCounters.subnetRoutePacketFailed();
238             LOG.debug("{} handleBgpVpnSubnetRoute: Could not find target subnet for packet out {}", LOGGING_PREFIX,
239                     dstIpStr);
240         }
241     }
242
243     private void handleInternalVpnSubnetRoutePacket(BigInteger metadata, byte[] dstIp, String srcIpStr, String dstIpStr,
244             String vpnIdVpnInstanceName, long elanTag)
245             throws InterruptedException, ExecutionException, UnknownHostException {
246         String vmVpnInterfaceName = vpnUtil.getVpnInterfaceName(metadata);
247         if (isTunnel(vmVpnInterfaceName)) {
248             handlePacketFromTunnelToExternalNetwork(vpnIdVpnInstanceName, srcIpStr, dstIp, dstIpStr, elanTag);
249         }
250         VpnInterface vmVpnInterface = vpnUtil.getVpnInterface(vmVpnInterfaceName);
251         if (vmVpnInterface == null) {
252             LOG.error("Vpn interface {} doesn't exist.", vmVpnInterfaceName);
253             vpnManagerCounters.subnetRoutePacketFailed();
254             return;
255         }
256         if (VpnHelper.doesVpnInterfaceBelongToVpnInstance(vpnIdVpnInstanceName,
257                vmVpnInterface.getVpnInstanceNames())
258                && !vpnUtil.isBgpVpnInternet(vpnIdVpnInstanceName)) {
259             LOG.trace("Unknown IP is in internal network");
260             handlePacketToInternalNetwork(dstIp, dstIpStr, elanTag);
261         } else {
262             LOG.trace("Unknown IP is in external network");
263             String vpnName = vpnUtil.getInternetVpnFromVpnInstanceList(vmVpnInterface.getVpnInstanceNames());
264             if (vpnName != null) {
265                 handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
266             } else {
267                 vpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vmVpnInterface);
268                 LOG.trace("Unknown IP is in external network, but internet VPN not found." + " fallback to first VPN");
269                 handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
270
271             }
272         }
273     }
274
275     private void transmitArpOrNsPacket(BigInteger dpnId, String sourceIpAddress, String sourceMac, byte[] dstIpBytes,
276             String dstIpAddress, long elanTag) throws UnknownHostException {
277         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
278         if (NWUtil.isIpv4Address(dstIpAddress)) {
279             LOG.debug("Sending ARP: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}, groupid={}", sourceIpAddress,
280                     sourceMac, dstIpAddress, dpnId, elanTag, groupid);
281             vpnManagerCounters.subnetRoutePacketArpSent();
282
283             TransmitPacketInput packetInput =
284                     ArpUtils.createArpRequestInput(dpnId, groupid, HexEncode.bytesFromHexString(sourceMac),
285                             InetAddress.getByName(sourceIpAddress).getAddress(), dstIpBytes);
286             JdkFutures.addErrorLogging(packetService.transmitPacket(packetInput), LOG, "Transmit packet");
287         } else {
288             // IPv6 case
289             LOG.debug("Sending NS: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}, groupid={}", sourceIpAddress,
290                     sourceMac, dstIpAddress, dpnId, elanTag, groupid);
291             vpnManagerCounters.subnetRoutePacketNsSent();
292
293             VpnUtil.sendNeighborSolicationToOfGroup(this.ipv6NdUtilService, new Ipv6Address(sourceIpAddress),
294                     new MacAddress(sourceMac), new Ipv6Address(dstIpAddress), groupid, dpnId);
295         }
296     }
297
298     private void handlePacketToInternalNetwork(byte[] dstIp, String dstIpStr, long elanTag)
299             throws UnknownHostException {
300         try {
301             SubnetOpDataEntry targetSubnetForPacketOut =
302                     getTargetSubnetForPacketOut(elanTag, dstIpStr);
303
304             if (targetSubnetForPacketOut == null) {
305                 LOG.debug("Couldn't find matching subnet for elan tag {} and destination ip {}", elanTag, dstIpStr);
306                 vpnManagerCounters.subnetRoutePacketFailed();
307                 return;
308             }
309
310             Optional<Subnetmap> subnetMap = SingleTransactionDataBroker.syncReadOptional(dataBroker,
311                     LogicalDatastoreType.CONFIGURATION,
312                     VpnUtil.buildSubnetmapIdentifier(targetSubnetForPacketOut.getSubnetId()));
313             if (!subnetMap.isPresent()) {
314                 LOG.debug("Couldn't find subnet map for subnet {}", targetSubnetForPacketOut.getSubnetId());
315                 vpnManagerCounters.subnetRoutePacketFailed();
316                 return;
317             }
318
319             String sourceIp = subnetMap.get().getRouterInterfaceFixedIp();
320             if (sourceIp == null) {
321                 LOG.debug("Subnet map {} doesn't have a router interface ip defined", subnetMap.get().getId());
322                 vpnManagerCounters.subnetRoutePacketFailed();
323                 return;
324             }
325
326             String sourceMac = subnetMap.get().getRouterIntfMacAddress();
327             if (sourceMac == null) {
328                 LOG.debug("Subnet map {} doesn't have a router interface mac address defined",
329                         subnetMap.get().getId());
330                 vpnManagerCounters.subnetRoutePacketFailed();
331                 return;
332             }
333
334             transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), sourceIp, sourceMac, dstIp, dstIpStr, elanTag);
335         } catch (ReadFailedException e) {
336             LOG.error("handlePacketToInternalNetwork: Failed to read data store for destIp {} elanTag {}", dstIpStr,
337                     elanTag);
338         }
339     }
340
341     private void handlePacketFromTunnelToExternalNetwork(String vpnIdVpnInstanceName, String srcIpStr, byte[] dstIp,
342         String dstIpStr, long elanTag) throws UnknownHostException {
343         String routerId = vpnUtil.getAssociatedExternalRouter(srcIpStr);
344         if (null == routerId) {
345             LOG.debug("This ip is not associated with any external router: {}", srcIpStr);
346             return;
347         }
348         handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), routerId, dstIp, dstIpStr, elanTag);
349     }
350
351     private void handlePacketToExternalNetwork(Uuid vpnInstanceNameUuid, String routerId, byte[] dstIp, String dstIpStr,
352             long elanTag) throws UnknownHostException {
353         Routers externalRouter = vpnUtil.getExternalRouter(routerId);
354         if (externalRouter == null) {
355             vpnManagerCounters.subnetRoutePacketFailed();
356             LOG.debug("{} handlePacketToExternalNetwork: Can't find external router with id {}", LOGGING_PREFIX,
357                     routerId);
358             return;
359         }
360
361         List<ExternalIps> externalIps = externalRouter.getExternalIps();
362         if (externalIps == null || externalIps.isEmpty()) {
363             vpnManagerCounters.subnetRoutePacketFailed();
364             LOG.debug("{} handlePacketToExternalNetwork: Router {} doesn't have any external ips.",
365                     LOGGING_PREFIX, externalRouter.getRouterName());
366             return;
367         }
368
369         java.util.Optional<ExternalIps> externalIp = externalRouter.getExternalIps().stream()
370                 .filter(eip -> vpnInstanceNameUuid.equals(eip.getSubnetId())).findFirst();
371         if (!externalIp.isPresent()) {
372             vpnManagerCounters.subnetRoutePacketFailed();
373             LOG.debug("{} handlePacketToExternalNetwork: Router {} doesn't have an external ip for subnet id {}.",
374                     LOGGING_PREFIX, externalRouter.getRouterName(), vpnInstanceNameUuid);
375             return;
376         }
377
378         BigInteger dpnId = centralizedSwitchProvider.getPrimarySwitchForRouter(externalRouter.getRouterName());
379         if (BigInteger.ZERO.equals(dpnId)) {
380             vpnManagerCounters.subnetRoutePacketFailed();
381             LOG.debug("{} handlePacketToExternalNetwork: Could not find primary switch for router {}.",
382                     LOGGING_PREFIX, externalRouter.getRouterName());
383             return;
384         }
385
386         transmitArpOrNsPacket(dpnId, externalIp.get().getIpAddress(), externalRouter.getExtGwMacAddress(), dstIp,
387                 dstIpStr, elanTag);
388     }
389
390     // return only the first VPN subnetopdataentry
391     @Nullable
392     private SubnetOpDataEntry getTargetSubnetForPacketOut(long elanTag, String ipAddress) {
393         ElanTagName elanInfo = vpnUtil.getElanInfoByElanTag(elanTag);
394         if (elanInfo == null) {
395             LOG.error("{} getTargetDpnForPacketOut: Unable to retrieve ElanInfo for elanTag {}", LOGGING_PREFIX,
396                     elanTag);
397             return null;
398         }
399         try {
400             Optional<NetworkMap> optionalNetworkMap = SingleTransactionDataBroker.syncReadOptional(dataBroker,
401                     LogicalDatastoreType.CONFIGURATION, VpnUtil.buildNetworkMapIdentifier(new Uuid(
402                             elanInfo.getName())));
403             if (!optionalNetworkMap.isPresent()) {
404                 LOG.debug("{} getTargetDpnForPacketOut: No network map found for elan info {}", LOGGING_PREFIX,
405                         elanInfo.getName());
406                 return null;
407             }
408             List<Uuid> subnetList = requireNonNullElse(optionalNetworkMap.get().getSubnetIdList(), emptyList());
409             LOG.debug("{} getTargetDpnForPacketOut: Obtained subnetList as {} for network {}", LOGGING_PREFIX,
410                     subnetList, elanInfo.getName());
411             for (Uuid subnetId : subnetList) {
412                 String vpnName = null;
413                 Subnetmap sn = vpnUtil.getSubnetmapFromItsUuid(subnetId);
414                 if (sn != null && sn.getVpnId() != null) {
415                     vpnName = sn.getVpnId().getValue();
416                 }
417                 if (vpnName == null) {
418                     continue;
419                 }
420                 Optional<SubnetOpDataEntry> optionalSubs;
421                 optionalSubs = SingleTransactionDataBroker.syncReadOptional(dataBroker,
422                         LogicalDatastoreType.OPERATIONAL, VpnUtil.buildSubnetOpDataEntryInstanceIdentifier(subnetId));
423                 if (!optionalSubs.isPresent()) {
424                     continue;
425                 }
426                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
427                 if (subOpEntry.getNhDpnId() != null) {
428                     LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {}", LOGGING_PREFIX, subnetId.getValue());
429                     IpPrefix cidr = IpPrefixBuilder.getDefaultInstance(subOpEntry.getSubnetCidr());
430                     boolean match = NWUtil.isIpAddressInRange(IpAddressBuilder.getDefaultInstance(ipAddress), cidr);
431                     LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {} matching {}", LOGGING_PREFIX,
432                             subnetId.getValue(), match);
433                     if (match) {
434                         return subOpEntry;
435                     }
436                 }
437             }
438         } catch (ReadFailedException e) {
439             LOG.error("{} getTargetDpnForPacketOut: Failed to read data store for elan {}", LOGGING_PREFIX,
440                     elanInfo.getName());
441         }
442         return null;
443     }
444
445     public boolean isTunnel(String interfaceName) {
446         return interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName).augmentation(IfTunnel.class) != null;
447     }
448 }