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 BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
61 Ethernet res = new Ethernet();
63 if (tableId == NwConstants.L3_SUBNET_ROUTE_TABLE) {
64 LOG.trace("SubnetRoutePacketInHandler: Some packet received as {}", notification);
66 res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
67 } catch (Exception e) {
68 LOG.warn("SubnetRoutePacketInHandler: Failed to decode Packet ", e);
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);
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);
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);
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) !=
101 LOG.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
102 + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
105 long elanTag = getElanTagFromSubnetRouteMetadata(metadata);
107 LOG.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
108 " Packet received with Target IP {}", dstIpStr);
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);
123 } catch (Exception ex) {
124 //Failed to handle packet
125 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets ", ex);
129 //All Arp responses learning for invisble IPs will now be handled by VpnManager
131 /*if (tableId == NwConstants.L3_INTERFACE_TABLE) {
132 LOG.trace("SubnetRoutePacketInHandler: Packet from Table {} received as {}",
133 NwConstants.L3_INTERFACE_TABLE, notification);
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);
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;
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);
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);
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);
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);
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();
201 if (nextHopMacAddress != null && destination != null) {
202 String rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
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);
225 } catch (Exception ex) {
226 //Failed to decode packet
227 LOG.error("SubnetRoutePacketInHandler: Failed to handle subnetroute Table " + NwConstants.L3_INTERFACE_TABLE +
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);
240 InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
241 .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
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,
252 if (!optionalSubs.isPresent()) {
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);
261 dpnid = subOpEntry.getNhDpnId();
270 private static String toStringIpAddress(byte[] ipAddress)
273 if (ipAddress == null) {
278 ip = InetAddress.getByAddress(ipAddress).getHostAddress();
279 } catch(UnknownHostException e) {
280 LOG.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
286 public static long getElanTagFromSubnetRouteMetadata(BigInteger metadata) {
287 return ((metadata.and(MetaDataUtil.METADATA_MASK_ELAN_SUBNET_ROUTE)).shiftRight(32)).longValue();
290 static InstanceIdentifier<VpnIds>
291 getVpnIdToVpnInstanceIdentifier(long vpnId) {
292 return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
294 new VpnIdsKey(Long.valueOf(vpnId))).build();