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