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