afe297006bed4a914f794421ae3c66a92a4aec87
[netvirt.git] /
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         BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
61         Ethernet res = new Ethernet();
62
63         if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
64             LOG.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
65             try {
66                 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
67             } catch (Exception e) {
68                 LOG.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
69                 return;
70             }
71             try {
72                 Packet pkt = res.getPayload();
73                 if (pkt instanceof IPv4) {
74                     IPv4 ipv4 = (IPv4) pkt;
75                     byte[] srcMac = res.getSourceMACAddress();
76                     byte[] dstMac = res.getDestinationMACAddress();
77                     byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
78                     byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
79                     String dstIpStr = toStringIpAddress(dstIp);
80                     String srcIpStr = toStringIpAddress(srcIp);
81                     /*if (VpnUtil.getNeutronPortNamefromPortFixedIp(dataBroker, dstIpStr) != null) {
82                         LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
83                                 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
84                         return;
85                     }*/
86                     long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
87                     LOG.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
88                             + "and Target IP {} and vpnId {}", srcIpStr, dstIpStr, vpnId);
89
90                     InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = getVpnIdToVpnInstanceIdentifier(vpnId);
91                     Optional<VpnIds> vpnIdsOptional = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
92                     if(!vpnIdsOptional.isPresent()) {
93                         // Donot trigger subnetroute logic for packets from unknown VPNs
94                         LOG.info("Ignoring IPv4 packet with destination Ip {} and source Ip {} as it came on unknown VPN with ID {}", dstIpStr, srcIpStr, vpnId);
95                         return;
96                     }
97                     // It is an ARP request on a configured VPN.  So we must attempt to respond.
98                     VpnIds vpnIds = vpnIdsOptional.get();
99                     if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIds.getVpnInstanceName(), dstIpStr) !=
100                             null) {
101                         LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
102                                 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
103                         return;
104                     }
105                     long elanTag = getElanTagFromSubnetRouteMetadata(metadata);
106                     if (elanTag == 0) {
107                         LOG.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
108                                 " Packet received with Target IP {}", dstIpStr);
109                         return;
110                     }
111                     LOG.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
112                             + "and Target IP {} and elan Tag {}", srcIpStr, dstIpStr, elanTag);
113                     BigInteger dpnId = getTargetDpnForPacketOut(dataBroker, elanTag, ipv4.getDestinationAddress());
114                     //Handle subnet routes ip requests
115                     if (dpnId != BigInteger.ZERO) {
116                         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
117                         String key = srcIpStr + dstIpStr;
118                         TransmitPacketInput arpRequestInput = ArpUtils.createArpRequestInput(dpnId, groupid, srcMac, srcIp, dstIp);
119                         packetService.transmitPacket(arpRequestInput);
120                     }
121                     return;
122                 }
123             } catch (Exception ex) {
124                 //Failed to handle packet
125                 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
126             }
127             return;
128         }
129         //All Arp responses learning for invisble IPs will now be handled by VpnManager
130
131         /*if (tableId == NwConstants.L3_INTERFACE_TABLE) {
132             LOG.trace("SubnetRoutePacketInHandler: Packet from Table {} received as {}",
133                     NwConstants.L3_INTERFACE_TABLE, notification);
134             try {
135                 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
136             } catch (Exception e) {
137                 LOG.warn("SubnetRoutePacketInHandler: Failed to decode Table " + NwConstants.L3_INTERFACE_TABLE + " Packet ", e);
138                 return;
139             }
140             try {
141                 Packet pkt = res.getPayload();
142                 if (pkt instanceof ARP) {
143                     LOG.debug("SubnetRoutePacketInHandler: ARP packet received");
144                     ARP arpPacket = (ARP) pkt;
145                     boolean arpReply = (arpPacket.getOpCode() == 2) ? true : false;
146                     if (arpReply) {
147                         //Handle subnet routes arp responses
148                         LOG.debug("SubnetRoutePacketInHandler: ARP reply received");
149                         byte[] respSrc = arpPacket.getSenderProtocolAddress();
150                         byte[] respDst = arpPacket.getTargetProtocolAddress();
151                         String respIp = toStringIpAddress(respSrc);
152                         String check = toStringIpAddress(respDst) + respIp;
153                         if (VpnUtil.getNeutronPortNamefromPortFixedIp(dataBroker, respIp) != null) {
154                             LOG.debug("SubnetRoutePacketInHandler: ARP reply Packet received with "
155                                     + "Source IP {} which is a valid Neutron port, ignoring subnet route processing", respIp);
156                             return;
157                         }
158                         String destination = VpnUtil.getIpPrefix(respIp);
159                         String srcIp = toStringIpAddress(respSrc);
160                         String destIp = toStringIpAddress(respDst);
161                         long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
162                         LOG.info("SubnetRoutePacketInHandler: Processing ARP response Packet received with Source IP {} "
163                                 + "and Target IP {} and vpnId {}", srcIp, destIp, vpnId);
164                         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds> vpnIdsInstanceIdentifier = getVpnIdToVpnInstanceIdentifier(vpnId);
165                         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds> vpnIdsOptional = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
166                         if(!vpnIdsOptional.isPresent()) {
167                             // Donot trigger subnetroute logic for packets from unknown VPNs
168                             LOG.info("Ignoring ARP response packet with destination Ip {} and source Ip {} as it came on with VPN ID {}", destIp, srcIp, vpnId);
169                             return;
170                         }
171                         // It is an ARP request on a configured VPN.  So we must attempt to respond.
172                         org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds vpnIds = vpnIdsOptional.get();
173                         if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIds.getVpnInstanceName(), srcIp) != null) {
174                             LOG.debug("SubnetRoutePacketInHandler: ARP response Packet received with "
175                                     + "Target IP {} is a valid Neutron port, ignoring subnet route processing", destIp);
176                             return;
177                         }
178                         String destination = VpnUtil.getIpPrefix(srcIp);
179                         long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
180                         LOG.info("SubnetRoutePacketInHandler: ARP reply received for target IP {} from LPort {}" + srcIp, portTag);
181                         IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(dataBroker, portTag);
182                         String ifName = interfaceInfo.getInterfaceName();
183                         InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
184                         VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(dataBroker, ifName);
185
186                         //Get VPN interface adjacencies
187                         if (vpnInterface != null) {
188                             InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
189                             Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
190                             String nextHopIpAddr = null;
191                             String nextHopMacAddress = null;
192                             if (adjacencies.isPresent()) {
193                                 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
194                                 for (Adjacency adjacs : adjacencyList) {
195                                     if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
196                                         nextHopIpAddr = adjacs.getIpAddress();
197                                         nextHopMacAddress = adjacs.getMacAddress();
198                                         break;
199                                     }
200                                 }
201                                 if (nextHopMacAddress != null && destination != null) {
202                                     String rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
203                                     long label =
204                                             VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
205                                                     VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
206                                     String nextHopIp = nextHopIpAddr.split("/")[0];
207                                     // FIXME 9: To be fixed with VPNManager patch
208                                     // Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
209                                             (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
210                                     adjacencyList.add(newAdj);
211                                     Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
212                                             (new AdjacencyKey(destination)).setNextHopIpList(Arrays.asList(nextHopIp)).build();
213                                     adjacencyList.add(newAdj);
214                                     Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
215                                     VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
216                                             setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
217                                             addAugmentation(Adjacencies.class, aug).build();
218                                     VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
219                                     LOG.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
220                                 }
221                             }
222                         }
223                     }
224                 }
225             } catch (Exception ex) {
226                 //Failed to decode packet
227                 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute Table " + NwConstants.L3_INTERFACE_TABLE +
228                         " packets ", ex);
229             }
230         }*/
231     }
232
233     private static BigInteger getTargetDpnForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
234         BigInteger dpnid = BigInteger.ZERO;
235         ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
236         if (elanInfo == null) {
237             LOG.trace("SubnetRoutePacketInHandler: Unable to retrieve ElanInfo for elanTag {}", elanTag);
238             return dpnid;
239         }
240         InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
241                 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
242
243         Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
244         if (optionalNetworkMap.isPresent()) {
245             List<Uuid> subnetList = optionalNetworkMap.get().getSubnetIdList();
246             LOG.trace("SubnetRoutePacketInHandler: Obtained subnetList as " + subnetList);
247             for (Uuid subnetId : subnetList) {
248                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
249                         child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
250                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
251                         subOpIdentifier);
252                 if (!optionalSubs.isPresent()) {
253                     continue;
254                 }
255                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
256                 if (subOpEntry.getNhDpnId() != null) {
257                     LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId);
258                     boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
259                     LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
260                     if (match) {
261                         dpnid = subOpEntry.getNhDpnId();
262                         return dpnid;
263                     }
264                 }
265             }
266         }
267         return dpnid;
268     }
269
270     private static String toStringIpAddress(byte[] ipAddress)
271     {
272         String ip = null;
273         if (ipAddress == null) {
274             return ip;
275         }
276
277         try {
278             ip = InetAddress.getByAddress(ipAddress).getHostAddress();
279         } catch(UnknownHostException e) {
280             LOG.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
281         }
282
283         return ip;
284     }
285
286     public static long getElanTagFromSubnetRouteMetadata(BigInteger metadata) {
287         return ((metadata.and(MetaDataUtil.METADATA_MASK_ELAN_SUBNET_ROUTE)).shiftRight(32)).longValue();
288     }
289
290     static InstanceIdentifier<VpnIds>
291     getVpnIdToVpnInstanceIdentifier(long vpnId) {
292         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
293                 .child(VpnIds.class,
294                         new VpnIdsKey(Long.valueOf(vpnId))).build();
295     }
296 }