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