2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.vpnservice;
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;
56 public class SubnetRoutePacketInHandler implements PacketProcessingListener {
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();
66 public SubnetRoutePacketInHandler(DataBroker dataBroker, IdManagerService idManager) {
68 this.idManager = idManager;
71 public void onPacketReceived(PacketReceived notification) {
73 s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
75 short tableId = notification.getTableId().getValue();
76 byte[] data = notification.getPayload();
77 BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
78 Ethernet res = new Ethernet();
80 if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
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);
98 long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
99 s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
101 s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
102 "Packet received with Target IP {}", dstIpStr);
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);
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;
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);
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();
154 if (nextHopMacAddress != null && destination != null) {
155 String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
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);
172 //Remove from list once response was processed
173 arpList.remove(check);
177 } catch (Exception ex) {
178 //Failed to decode packet
179 s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
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);
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());
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,
207 if (!optionalSubs.isPresent()) {
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);
216 dpnid = subOpEntry.getNhDpnId();
225 private static String toStringIpAddress(byte[] ipAddress)
228 if (ipAddress == null) {
233 ip = InetAddress.getByAddress(ipAddress).getHostAddress();
234 } catch(UnknownHostException e) {
235 s_logger.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
241 public void setPacketProcessingService(PacketProcessingService service) {
242 this.packetService = service;
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());
251 private long getDpnIdFromNodeName(String nodeName) {
252 String dpId = nodeName.substring(nodeName.lastIndexOf(":") + 1);
253 return Long.parseLong(dpId);
256 private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
257 byte[] abyTargetIpAddress) {
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) {
265 List<ActionInfo> lstActionInfo;
266 TransmitPacketInput transmitPacketInput;
268 arpPacket = createARPPacket(ARP.REQUEST, abySenderMAC, abySenderIpAddress, VpnConstants.MAC_Broadcast,
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);
276 s_logger.info("SubnetRoutePacketInHandler: Unable to send ARP request because client port has no IP ");
280 private static byte[] createARPPacket(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress,
283 byte[] rawArpPkt = null;
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);
303 private static byte[] createEthernetPacket(byte[] sourceMAC, byte[] targetMAC, byte[] arp) {
304 Ethernet ethernet = new Ethernet();
305 byte[] rawEthPkt = null;
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);