de7a5cc412b903d8bd8118d99a41e66d8bf63da6
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / 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
9 package org.opendaylight.vpnservice;
10
11 import com.google.common.base.Optional;
12 import com.google.common.primitives.Ints;
13 import org.opendaylight.controller.liblldp.EtherTypes;
14 import org.opendaylight.controller.liblldp.NetUtils;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
18 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
19 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.SubnetOpData;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.*;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NetworkMaps;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMap;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMapKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
40 import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
41 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
42 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
43 import org.opendaylight.controller.liblldp.Packet;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import java.math.BigInteger;
47 import java.net.InetAddress;
48 import java.net.UnknownHostException;
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.nio.charset.StandardCharsets;
52 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
53 import org.opendaylight.vpnservice.mdsalutil.ActionType;
54 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
55
56 public class SubnetRoutePacketInHandler implements PacketProcessingListener {
57
58     private static final Logger s_logger = LoggerFactory.getLogger(SubnetRoutePacketInHandler.class);
59     private final DataBroker broker;
60     private PacketProcessingService packetService;
61     private VpnInterfaceManager ifManager;
62     private IdManagerService idManager;
63     //List maintains info about the arp request sent - id src+dst ip
64     private ArrayList<String> arpList = new ArrayList();
65
66     public SubnetRoutePacketInHandler(DataBroker dataBroker, IdManagerService idManager) {
67         broker = dataBroker;
68         this.idManager = idManager;
69     }
70
71     public void onPacketReceived(PacketReceived notification) {
72
73         s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
74
75         short tableId = notification.getTableId().getValue();
76         byte[] data = notification.getPayload();
77         BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
78         Ethernet res = new Ethernet();
79
80         if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
81             try {
82                 s_logger.debug("SubnetRoutePacketInHandler: Some packet received");
83                 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
84                 Packet pkt = res.getPayload();
85                 if (pkt instanceof IPv4) {
86                     IPv4 ipv4 = (IPv4) pkt;
87                     byte[] srcMac = res.getSourceMACAddress();
88                     byte[] dstMac = res.getDestinationMACAddress();
89                     byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
90                     byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
91                     String dstIpStr = toStringIpAddress(dstIp);
92                     String srcIpStr = toStringIpAddress(srcIp);
93                     if (VpnUtil.getNeutronPortNamefromPortFixedIp(broker, dstIpStr) != null) {
94                         s_logger.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
95                                 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
96                         return;
97                     }
98                     long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
99                     s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
100                     if (elanTag == 0) {
101                         s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
102                                 "Packet received with Target IP {}", dstIpStr);
103                         return;
104                     }
105                     s_logger.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
106                             + "and Target IP {}", srcIpStr, dstIpStr);
107                     BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag,  ipv4.getDestinationAddress());
108                     //Handle subnet routes ip requests
109                     if (dpnId != BigInteger.ZERO) {
110                         long groupid = VpnUtil.getRemoteBCGroup(elanTag);
111                         String key = srcIpStr + dstIpStr;
112                         sendArpRequest(dpnId, groupid, srcMac, srcIp, dstIp);
113                         arpList.add(key);
114                     }
115                     return;
116                 }
117
118                 if (pkt instanceof ARP) {
119                     s_logger.debug("SubnetRoutePacketInHandler: ARP packet received");
120                     ARP arpPacket = (ARP) pkt;
121                     boolean arpReply = (arpPacket.getOpCode() == 2) ? true : false;
122                     if (arpReply) {
123                         //Handle subnet routes arp responses
124                         s_logger.debug("SubnetRoutePacketInHandler: ARP reply received");
125                         byte[] respSrc = arpPacket.getSenderProtocolAddress();
126                         byte[] respDst = arpPacket.getTargetProtocolAddress();
127                         String respIp = toStringIpAddress(respSrc);
128                         String check = toStringIpAddress(respDst) + respIp;
129                         if (arpList.contains(check)) {
130                             s_logger.debug("SubnetRoutePacketInHandler: ARP reply received for listening target IP " + respIp);
131                             String destination = VpnUtil.getIpPrefix(respIp);
132                             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
133                             s_logger.debug("SubnetRoutePacketInHandler Lport Tag of arp replier " + portTag);
134                             IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
135                             String ifName = interfaceInfo.getInterfaceName();
136                             InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
137                             VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
138
139                             //Get VPN interface adjacencies
140                             if (vpnInterface != null) {
141                                 InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
142                                 Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
143                                 String nextHopIpAddr = null;
144                                 String nextHopMacAddress = null;
145                                 if (adjacencies.isPresent()) {
146                                     List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
147                                     for (Adjacency adjacs : adjacencyList) {
148                                         if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
149                                             nextHopIpAddr = adjacs.getIpAddress();
150                                             nextHopMacAddress = adjacs.getMacAddress();
151                                             break;
152                                         }
153                                     }
154                                     if (nextHopMacAddress != null && destination != null) {
155                                         String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
156                                         long label =
157                                                 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
158                                                         VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
159                                         String nextHopIp = nextHopIpAddr.split("/")[0];
160                                         Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
161                                                 (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
162                                         adjacencyList.add(newAdj);
163                                         Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
164                                         VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
165                                                 setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
166                                                 addAugmentation(Adjacencies.class, aug).build();
167                                         VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
168                                         s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
169                                     }
170                                 }
171                             }
172                             //Remove from list once response was processed
173                             arpList.remove(check);
174                         }
175                     }
176                 }
177             } catch (Exception ex) {
178                 //Failed to decode packet
179                 s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
180             }
181         }
182     }
183
184     private static BigInteger getTargetDpnForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
185         BigInteger dpnid = BigInteger.ZERO;
186         ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
187         if (elanInfo == null) {
188             s_logger.trace("SubnetRoutePacketInHandler: Unable to retrieve ElanInfo for elanTag {}", elanTag);
189             return dpnid;
190         }
191         InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
192                 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
193         s_logger.trace("SubnetRoutePacketInHandler: Obtained target ip address as " + ipAddress);
194         s_logger.trace("SubnetRoutePacketInHandler: Obtained elanTag as " + elanTag);
195         s_logger.trace("SubnetRoutePacketInHandler: Obtained elanInfo as " + elanInfo);
196         s_logger.trace("SubnetRoutePacketInHandler: Obtained network name as " + elanInfo.getName());
197
198         Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
199         if (optionalNetworkMap.isPresent()) {
200             List<Uuid> subnetList = optionalNetworkMap.get().getSubnetIdList();
201             s_logger.trace("SubnetRoutePacketInHandler: Obtained subnetList as " + subnetList);
202             for (Uuid subnetId : subnetList) {
203                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
204                         child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
205                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
206                         subOpIdentifier);
207                 if (!optionalSubs.isPresent()) {
208                     continue;
209                 }
210                 s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId.getValue());
211                 SubnetOpDataEntry subOpEntry = optionalSubs.get();
212                 if (subOpEntry.getNhDpnId() != null) {
213                     boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
214                     s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
215                     if (match) {
216                         dpnid = subOpEntry.getNhDpnId();
217                         return dpnid;
218                     }
219                 }
220             }
221         }
222         return dpnid;
223     }
224
225     private static String toStringIpAddress(byte[] ipAddress)
226     {
227         String ip = null;
228         if (ipAddress == null) {
229             return ip;
230         }
231
232         try {
233             ip = InetAddress.getByAddress(ipAddress).getHostAddress();
234         } catch(UnknownHostException e) {
235             s_logger.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
236         }
237
238         return ip;
239     }
240
241     public void setPacketProcessingService(PacketProcessingService service) {
242         this.packetService = service;
243     }
244
245     private long getDpnIdFromPktRcved(PacketReceived packet) {
246         InstanceIdentifier<?> identifier = packet.getIngress().getValue();
247         NodeId id = identifier.firstKeyOf(Node.class, NodeKey.class).getId();
248         return getDpnIdFromNodeName(id.getValue());
249     }
250
251     private long getDpnIdFromNodeName(String nodeName) {
252         String dpId = nodeName.substring(nodeName.lastIndexOf(":") + 1);
253         return Long.parseLong(dpId);
254     }
255
256     private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
257                                 byte[] abyTargetIpAddress) {
258
259         s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderMAC {}, senderIPAddress {}, targetIPAddress {}",
260                 dpnId, groupId,new String(abySenderMAC, StandardCharsets.UTF_8),
261                 toStringIpAddress(abySenderIpAddress),toStringIpAddress(abyTargetIpAddress));
262         if (abySenderIpAddress != null) {
263             byte[] arpPacket;
264             byte[] ethPacket;
265             List<ActionInfo> lstActionInfo;
266             TransmitPacketInput transmitPacketInput;
267
268             arpPacket = createARPPacket(ARP.REQUEST, abySenderMAC, abySenderIpAddress, VpnConstants.MAC_Broadcast,
269                     abyTargetIpAddress);
270             ethPacket = createEthernetPacket(abySenderMAC, VpnConstants.EthernetDestination_Broadcast, arpPacket);
271             lstActionInfo = new ArrayList<ActionInfo>();
272             lstActionInfo.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
273             transmitPacketInput = MDSALUtil.getPacketOutDefault(lstActionInfo, ethPacket, dpnId);
274             packetService.transmitPacket(transmitPacketInput);
275         } else {
276             s_logger.info("SubnetRoutePacketInHandler: Unable to send ARP request because client port has no IP  ");
277         }
278     }
279
280     private static byte[] createARPPacket(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress,
281                                           byte[] targetIP) {
282         ARP arp = new ARP();
283         byte[] rawArpPkt = null;
284         try {
285             arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
286             arp.setProtocolType(EtherTypes.IPv4.shortValue());
287             arp.setHardwareAddressLength((byte) 6);
288             arp.setProtocolAddressLength((byte) 4);
289             arp.setOpCode(opCode);
290             arp.setSenderHardwareAddress(senderMacAddress);
291             arp.setSenderProtocolAddress(senderIP);
292             arp.setTargetHardwareAddress(targetMacAddress);
293             arp.setTargetProtocolAddress(targetIP);
294             rawArpPkt = arp.serialize();
295         } catch (Exception ex) {
296             s_logger.error("VPNUtil:  Serialized ARP packet with senderMacAddress {} senderIp {} targetIP {} exception {}",
297                     senderMacAddress, senderIP, targetIP, ex);
298         }
299
300         return rawArpPkt;
301     }
302
303     private static byte[] createEthernetPacket(byte[] sourceMAC, byte[] targetMAC, byte[] arp) {
304         Ethernet ethernet = new Ethernet();
305         byte[] rawEthPkt = null;
306         try {
307             ethernet.setSourceMACAddress(sourceMAC);
308             ethernet.setDestinationMACAddress(targetMAC);
309             ethernet.setEtherType(EtherTypes.ARP.shortValue());
310             ethernet.setRawPayload(arp);
311             rawEthPkt = ethernet.serialize();
312         } catch (Exception ex) {
313             s_logger.error("VPNUtil:  Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception {}",
314                     sourceMAC, targetMAC, ex);
315         }
316         return rawEthPkt;
317     }
318 }