Bug 7298: NPE in vpn manager
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / SubnetRoutePacketInHandler.java
1 /*
2  * Copyright (c) 2016 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.ArrayList;
16 import java.util.List;
17 import org.opendaylight.controller.liblldp.NetUtils;
18 import org.opendaylight.controller.liblldp.Packet;
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.mdsalutil.MetaDataUtil;
22 import org.opendaylight.genius.mdsalutil.NwConstants;
23 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
24 import org.opendaylight.genius.mdsalutil.packet.IPv4;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 public class SubnetRoutePacketInHandler implements PacketProcessingListener {
45     private static final Logger LOG = LoggerFactory.getLogger(SubnetRoutePacketInHandler.class);
46     private final DataBroker dataBroker;
47     private final PacketProcessingService packetService;
48
49     public SubnetRoutePacketInHandler(final DataBroker dataBroker,
50                                       final PacketProcessingService packetService) {
51         this.dataBroker = dataBroker;
52         this.packetService =packetService;
53     }
54
55     public void onPacketReceived(PacketReceived notification) {
56         LOG.trace("SubnetRoutePacketInHandler: PacketReceived invoked...");
57
58         short tableId = notification.getTableId().getValue();
59         byte[] data = notification.getPayload();
60         if (notification.getMatch() == null || notification.getMatch().getMetadata() == null) {
61             LOG.debug("on packet received where the match or metadata are null");
62             return;
63         }
64         BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
65         Ethernet res = new Ethernet();
66
67         if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
68             LOG.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
69             try {
70                 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
71             } catch (Exception e) {
72                 LOG.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
73                 return;
74             }
75             try {
76                 Packet pkt = res.getPayload();
77                 if (pkt instanceof IPv4) {
78                     IPv4 ipv4 = (IPv4) pkt;
79                     byte[] srcMac = res.getSourceMACAddress();
80                     byte[] dstMac = res.getDestinationMACAddress();
81                     byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
82                     byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
83                     String dstIpStr = toStringIpAddress(dstIp);
84                     String srcIpStr = toStringIpAddress(srcIp);
85                     /*if (VpnUtil.getNeutronPortNamefromPortFixedIp(dataBroker, dstIpStr) != null) {
86                         LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
87                                 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
88                         return;
89                     }*/
90                     long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
91                     LOG.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
92                             + "and Target IP {} and vpnId {}", srcIpStr, dstIpStr, vpnId);
93
94                     InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = getVpnIdToVpnInstanceIdentifier(vpnId);
95                     Optional<VpnIds> vpnIdsOptional = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
96                     if(!vpnIdsOptional.isPresent()) {
97                         // Donot trigger subnetroute logic for packets from unknown VPNs
98                         LOG.info("Ignoring IPv4 packet with destination Ip {} and source Ip {} as it came on unknown VPN with ID {}", dstIpStr, srcIpStr, vpnId);
99                         return;
100                     }
101                     // It is an ARP request on a configured VPN.  So we must attempt to respond.
102                     VpnIds vpnIds = vpnIdsOptional.get();
103                     if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIds.getVpnInstanceName(), dstIpStr) !=
104                             null) {
105                         LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
106                                 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
107                         return;
108                     }
109                     long elanTag = getElanTagFromSubnetRouteMetadata(metadata);
110                     if (elanTag == 0) {
111                         LOG.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
112                                 " Packet received with Target IP {}", dstIpStr);
113                         return;
114                     }
115                     LOG.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
116                             + "and Target IP {} and elan Tag {}", srcIpStr, dstIpStr, elanTag);
117                     BigInteger dpnId = getTargetDpnForPacketOut(dataBroker, elanTag, ipv4.getDestinationAddress());
118                     //Handle subnet routes ip requests
119                     if (dpnId != BigInteger.ZERO) {
120                         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
121                         String key = srcIpStr + dstIpStr;
122                         TransmitPacketInput arpRequestInput = ArpUtils.createArpRequestInput(dpnId, groupid, srcMac, srcIp, dstIp);
123                         packetService.transmitPacket(arpRequestInput);
124                     }
125                     return;
126                 }
127             } catch (Exception ex) {
128                 //Failed to handle packet
129                 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
130             }
131             return;
132         }
133         //All Arp responses learning for invisble IPs is handled by ArpNotificationHandler
134
135     }
136
137     private static BigInteger getTargetDpnForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
138         BigInteger dpnid = BigInteger.ZERO;
139         ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
140         if (elanInfo == null) {
141             LOG.trace("SubnetRoutePacketInHandler: Unable to retrieve ElanInfo for elanTag {}", elanTag);
142             return dpnid;
143         }
144         InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
145                 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
146
147         Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
148         if (optionalNetworkMap.isPresent()) {
149             List<Uuid> subnetList = optionalNetworkMap.get().getSubnetIdList();
150             LOG.trace("SubnetRoutePacketInHandler: Obtained subnetList as " + subnetList);
151             for (Uuid subnetId : subnetList) {
152                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
153                         child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
154                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
155                         subOpIdentifier);
156                 if (!optionalSubs.isPresent()) {
157                     continue;
158                 }
159                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
160                 if (subOpEntry.getNhDpnId() != null) {
161                     LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId);
162                     boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
163                     LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
164                     if (match) {
165                         dpnid = subOpEntry.getNhDpnId();
166                         return dpnid;
167                     }
168                 }
169             }
170         }
171         return dpnid;
172     }
173
174     private static String toStringIpAddress(byte[] ipAddress)
175     {
176         String ip = null;
177         if (ipAddress == null) {
178             return ip;
179         }
180
181         try {
182             ip = InetAddress.getByAddress(ipAddress).getHostAddress();
183         } catch(UnknownHostException e) {
184             LOG.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
185         }
186
187         return ip;
188     }
189
190     public static long getElanTagFromSubnetRouteMetadata(BigInteger metadata) {
191         return ((metadata.and(MetaDataUtil.METADATA_MASK_ELAN_SUBNET_ROUTE)).shiftRight(32)).longValue();
192     }
193
194     static InstanceIdentifier<VpnIds>
195     getVpnIdToVpnInstanceIdentifier(long vpnId) {
196         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
197                 .child(VpnIds.class,
198                         new VpnIdsKey(Long.valueOf(vpnId))).build();
199     }
200 }