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