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