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
8 package org.opendaylight.netvirt.vpnmanager;
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;
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;
49 public SubnetRoutePacketInHandler(final DataBroker dataBroker,
50 final PacketProcessingService packetService) {
51 this.dataBroker = dataBroker;
52 this.packetService =packetService;
55 public void onPacketReceived(PacketReceived notification) {
56 LOG.trace("SubnetRoutePacketInHandler: PacketReceived invoked...");
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");
64 BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
65 Ethernet res = new Ethernet();
67 if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
68 LOG.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
70 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
71 } catch (Exception e) {
72 LOG.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
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);
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);
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);
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) !=
105 LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
106 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
109 long elanTag = getElanTagFromSubnetRouteMetadata(metadata);
111 LOG.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
112 " Packet received with Target IP {}", dstIpStr);
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);
127 } catch (Exception ex) {
128 //Failed to handle packet
129 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
133 //All Arp responses learning for invisble IPs is handled by ArpNotificationHandler
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);
144 InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
145 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
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,
156 if (!optionalSubs.isPresent()) {
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);
165 dpnid = subOpEntry.getNhDpnId();
174 private static String toStringIpAddress(byte[] ipAddress)
177 if (ipAddress == null) {
182 ip = InetAddress.getByAddress(ipAddress).getHostAddress();
183 } catch(UnknownHostException e) {
184 LOG.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
190 public static long getElanTagFromSubnetRouteMetadata(BigInteger metadata) {
191 return ((metadata.and(MetaDataUtil.METADATA_MASK_ELAN_SUBNET_ROUTE)).shiftRight(32)).longValue();
194 static InstanceIdentifier<VpnIds>
195 getVpnIdToVpnInstanceIdentifier(long vpnId) {
196 return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
198 new VpnIdsKey(Long.valueOf(vpnId))).build();