<artifactId>elanmanager-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ipv6service-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- Testing dependencies -->
<dependency>
import org.opendaylight.genius.arputil.api.ArpConstants;
import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
String vpnName = value.getVpnName();
MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, value.getPortName(),
value.getCreationTime());
- jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
- new ArpMonitorStartTask(macEntry, arpMonitorProfileId, dataBroker, alivenessManager,
- neutronVpnService, interfaceManager));
+
+ if (NWUtil.isIpv4Address(value.getPortFixedip())) {
+ jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
+ new ArpMonitorStartTask(macEntry, arpMonitorProfileId, dataBroker, alivenessManager,
+ neutronVpnService, interfaceManager));
+ } else {
+ // TODO: Handle for IPv6 case
+ LOG.warn("IPv6 address monitoring is not yet supported - add(). LearntVpnVipToPort={}", value);
+ }
} catch (UnknownHostException e) {
LOG.error("Error in deserializing packet {} with exception", value, e);
}
String interfaceName = value.getPortName();
MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, interfaceName,
value.getCreationTime());
- jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
- new ArpMonitorStopTask(macEntry, dataBroker, alivenessManager, Boolean.FALSE));
+
+ if (NWUtil.isIpv4Address(value.getPortFixedip())) {
+ jobCoordinator.enqueueJob(buildJobKey(srcInetAddr.toString(), vpnName),
+ new ArpMonitorStopTask(macEntry, dataBroker, alivenessManager, Boolean.FALSE));
+ } else {
+ // TODO: Handle for IPv6 case
+ LOG.warn("IPv6 address monitoring is not yet supported - remove(). LearntVpnVipToPort={}", value);
+ }
} catch (UnknownHostException e) {
LOG.error("Error in deserializing packet {} with exception", value, e);
}
+++ /dev/null
-/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.netvirt.vpnmanager;
-
-import com.google.common.base.Optional;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import java.math.BigInteger;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.commons.lang3.tuple.Pair;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
-import org.opendaylight.genius.mdsalutil.NWUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Singleton
-public class ArpNotificationHandler implements OdlArputilListener {
- private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
- // temp where Key is VPNInstance+IP and value is timestamp
- private final Cache<Pair<String, String>, BigInteger> migrateArpCache;
-
- private final DataBroker dataBroker;
- private final IdManagerService idManager;
- private final IInterfaceManager interfaceManager;
- private final VpnConfig config;
-
- @Inject
- public ArpNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
- IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
- this.dataBroker = dataBroker;
- this.idManager = idManager;
- this.interfaceManager = interfaceManager;
- this.config = vpnConfig;
-
- long duration = config.getArpLearnTimeout() * 10;
- long cacheSize = config.getArpCacheSize().longValue();
- migrateArpCache =
- CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration,
- TimeUnit.MILLISECONDS).build();
- }
-
- @Override
- public void onMacChanged(MacChanged notification) {
-
- }
-
- @Override
- public void onArpRequestReceived(ArpRequestReceived notification) {
- String srcInterface = notification.getInterface();
- IpAddress srcIP = notification.getSrcIpaddress();
- PhysAddress srcMac = notification.getSrcMac();
- IpAddress targetIP = notification.getDstIpaddress();
- BigInteger metadata = notification.getMetadata();
- boolean isGarp = srcIP.equals(targetIP);
- if (!isGarp) {
- LOG.info("ArpNotification Non-Gratuitous Request Received from "
- + "interface {} and IP {} having MAC {} target destination {}, ignoring..",
- srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
- targetIP.getIpv4Address().getValue());
- return;
- }
- LOG.info("ArpNotification Gratuitous Request Received from "
- + "interface {} and IP {} having MAC {} target destination {}, learning MAC",
- srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
- targetIP.getIpv4Address().getValue());
- processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
- }
-
- @Override
- public void onArpResponseReceived(ArpResponseReceived notification) {
- String srcInterface = notification.getInterface();
- IpAddress srcIP = notification.getSrcIpaddress();
- PhysAddress srcMac = notification.getSrcMac();
- LOG.info("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
- srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
- List<Adjacency> adjacencies = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker, srcInterface);
- if (adjacencies != null) {
- for (Adjacency adj : adjacencies) {
- String ipAddress = adj.getIpAddress();
- try {
- if (NWUtil.isIpInSubnet(NWUtil.ipAddressToInt(srcIP.getIpv4Address().getValue()), ipAddress)) {
- return;
- }
- } catch (UnknownHostException e) {
- LOG.error("Subnet string {} not convertible to InetAdddress", srcIP, e);
- }
- }
- }
- BigInteger metadata = notification.getMetadata();
- IpAddress targetIP = notification.getDstIpaddress();
- LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
- srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
- processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
- }
-
- private void processArpLearning(String srcInterface, IpAddress srcIP, PhysAddress srcMac, BigInteger metadata,
- IpAddress dstIP) {
- if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
- Optional<List<String>> vpnList = VpnUtil
- .getVpnHandlingIpv4AssociatedWithInterface(dataBroker, srcInterface);
- if (vpnList.isPresent()) {
- for (String vpnName : vpnList.get()) {
- LOG.info("Received ARP for sender MAC {} and sender IP {} via interface {}",
- srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
- String srcIpToQuery = srcIP.getIpv4Address().getValue();
- String destIpToQuery = dstIP.getIpv4Address().getValue();
- LOG.info("ARP being processed for Source IP {}", srcIpToQuery);
- VpnPortipToPort vpnPortipToPort =
- VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, srcIpToQuery);
- if (vpnPortipToPort != null) {
- /* This is a well known neutron port and so should be ignored
- * from being discovered
- */
- continue;
- }
- LearntVpnVipToPort learntVpnVipToPort = VpnUtil.getLearntVpnVipToPort(dataBroker,
- vpnName, srcIpToQuery);
- if (learntVpnVipToPort != null) {
- String oldPortName = learntVpnVipToPort.getPortName();
- String oldMac = learntVpnVipToPort.getMacAddress();
- if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
- //MAC has changed for requested IP
- LOG.info("ARP Source IP/MAC data modified for IP {} with MAC {} and Port {}",
- srcIpToQuery, srcMac, srcInterface);
- synchronized ((vpnName + srcIpToQuery).intern()) {
- VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery,
- oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null);
- putVpnIpToMigrateArpCache(vpnName, srcIpToQuery, srcMac);
- }
- }
- } else if (!isIpInArpMigrateCache(vpnName, srcIpToQuery)) {
- learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac, dstIP);
- }
- }
- } else {
- LOG.info("ARP NO_RESOLVE: VPN not configured. Ignoring responding to ARP requests from this"
- + " Interface {}.", srcInterface);
- return;
-
- }
- }
- }
-
- private void learnMacFromArpPackets(String vpnName, String srcInterface,
- IpAddress srcIP, PhysAddress srcMac, IpAddress dstIP) {
- String srcIpToQuery = srcIP.getIpv4Address().getValue();
- String destIpToQuery = dstIP.getIpv4Address().getValue();
- synchronized ((vpnName + srcIpToQuery).intern()) {
- VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery, srcInterface,
- srcMac.getValue(), LearntVpnVipToPortEventAction.Add, null);
- }
- }
-
- private void putVpnIpToMigrateArpCache(String vpnName, String ipToQuery, PhysAddress srcMac) {
- long cacheSize = config.getArpCacheSize().longValue();
- if (migrateArpCache.size() >= cacheSize) {
- LOG.debug("ARP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
- + " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
- }
- LOG.debug("ARP_MIGRATE_CACHE: add to dirty cache IP {} vpnName {} with MAC {}", ipToQuery, vpnName, srcMac);
- migrateArpCache.put(new ImmutablePair<>(vpnName, ipToQuery),
- new BigInteger(String.valueOf(System.currentTimeMillis())));
- }
-
- private boolean isIpInArpMigrateCache(String vpnName, String ipToQuery) {
- if (migrateArpCache == null || migrateArpCache.size() == 0) {
- return false;
- }
- Pair<String, String> keyPair = new ImmutablePair<>(vpnName, ipToQuery);
- BigInteger prevTimeStampCached = migrateArpCache.getIfPresent(keyPair);
- if (prevTimeStampCached == null) {
- LOG.debug("ARP_MIGRATE_CACHE: there is no IP {} vpnName {} in dirty cache, so learn it",
- ipToQuery, vpnName);
- return false;
- }
- if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
- LOG.debug("ARP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
- ipToQuery, vpnName);
- migrateArpCache.invalidate(keyPair);
- return false;
- }
- LOG.debug("ARP_MIGRATE_CACHE: younger than timeout value - ignore learning IP {} vpnName {}",
- ipToQuery, vpnName);
- return true;
- }
-}
/*
- * Copyright © 2016, 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2016, 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
import org.opendaylight.netvirt.vpnmanager.api.ICentralizedSwitchProvider;
import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
import org.opendaylight.netvirt.vpnmanager.utilities.VpnManagerCounters;
+import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
+import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
import org.opendaylight.openflowplugin.libraries.liblldp.HexEncode;
import org.opendaylight.openflowplugin.libraries.liblldp.NetUtils;
import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
private final ICentralizedSwitchProvider centralizedSwitchProvider;
private final IInterfaceManager interfaceManager;
private final VpnManagerCounters vpnManagerCounters;
+ private final Ipv6NdutilService ipv6NdutilService;
@Inject
public SubnetRoutePacketInHandler(final DataBroker dataBroker, final PacketProcessingService packetService,
final OdlInterfaceRpcService odlInterfaceRpcService,
- final ICentralizedSwitchProvider centralizedSwitchProvider,
- final IInterfaceManager interfaceManager, VpnManagerCounters vpnManagerCounters) {
+ final ICentralizedSwitchProvider centralizedSwitchProvider, final IInterfaceManager interfaceManager,
+ VpnManagerCounters vpnManagerCounters, final Ipv6NdutilService ipv6NdutilService) {
this.dataBroker = dataBroker;
this.packetService = packetService;
this.odlInterfaceRpcService = odlInterfaceRpcService;
this.centralizedSwitchProvider = centralizedSwitchProvider;
this.interfaceManager = interfaceManager;
this.vpnManagerCounters = vpnManagerCounters;
+ this.ipv6NdutilService = ipv6NdutilService;
}
@Override
vpnManagerCounters.subnetRoutePacketFailed();
return;
}
+ byte[] srcIpBytes = null;
+ byte[] dstIpBytes = null;
+ String srcIpStr;
+ String dstIpStr;
+ String srcMac = NWUtil.toStringMacAddress(res.getSourceMACAddress());
try {
Packet pkt = res.getPayload();
if (pkt instanceof IPv4) {
IPv4 ipv4 = (IPv4) pkt;
- byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
- byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
- String dstIpStr = NWUtil.toStringIpAddress(dstIp);
- String srcIpStr = NWUtil.toStringIpAddress(srcIp);
+ srcIpBytes = Ints.toByteArray(ipv4.getSourceAddress());
+ dstIpBytes = Ints.toByteArray(ipv4.getDestinationAddress());
// It is an ARP request on a configured VPN. So we must
// attempt to respond.
- long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
-
- LOG.info("{} onPacketReceived: Processing IPv4 Packet received with Source IP {} and Target IP {}"
- + " and vpnId {}", LOGGING_PREFIX, srcIpStr, dstIpStr, vpnId);
-
- Optional<VpnIds> vpnIdsOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
- LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId));
-
- if (!vpnIdsOptional.isPresent()) {
- // Donot trigger subnetroute logic for packets from
- // unknown VPNs
- vpnManagerCounters.subnetRoutePacketIgnored();
- LOG.info("{} onPacketReceived: Ignoring IPv4 packet with destination Ip {} and source Ip {}"
- + " as it came on unknown VPN with ID {}", LOGGING_PREFIX, dstIpStr, srcIpStr, vpnId);
- return;
- }
-
- String vpnIdVpnInstanceName = vpnIdsOptional.get().getVpnInstanceName();
- if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
- vpnManagerCounters.subnetRoutePacketIgnored();
- LOG.info("{} onPacketReceived: IPv4 Packet received with Target IP {} source IP {} vpnId {} "
- + "is a valid Neutron port,ignoring subnet route processing", LOGGING_PREFIX, dstIpStr,
- srcIp, vpnId);
- return;
- }
-
- if (VpnUtil.getLearntVpnVipToPort(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
- vpnManagerCounters.subnetRoutePacketIgnored();
- LOG.info("{} onPacketReceived: IPv4 Packet received with Target IP {} source Ip {} vpnId {}"
- + " is an already discovered IPAddress, ignoring subnet route processing",
- LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
- return;
- }
-
- long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
- if (elanTag == 0L) {
- vpnManagerCounters.subnetRoutePacketFailed();
- LOG.error("{} onPacketReceived: elanTag value from metadata found to be 0, for IPv4 "
- + " Packet received with Target IP {} src Ip {} vpnId {}",
- LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
- return;
+ } else {
+ // IPv6 case
+ // TODO: IPv6 deserializer
+ int ethType = BitBufferHelper.getInt(
+ BitBufferHelper.getBits(data, VpnConstants.ETHTYPE_START, VpnConstants.TWO_BYTES));
+ if (ethType == VpnConstants.IP_V6_ETHTYPE) {
+ srcIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 64, 128);
+ dstIpBytes = BitBufferHelper.getBits(data, VpnConstants.IP_V6_HDR_START + 192, 128);
}
+ }
+ if (srcIpBytes == null || dstIpBytes == null) {
+ LOG.trace("{} onPacketReceived: Non-IP packet received as {}", LOGGING_PREFIX, notification);
+ return;
+ }
+ srcIpStr = NWUtil.toStringIpAddress(srcIpBytes);
+ dstIpStr = NWUtil.toStringIpAddress(dstIpBytes);
- if (!vpnIdsOptional.get().isExternalVpn()) {
- handleInternalVpnSubnetRoutePacket(metadata, dstIp, srcIpStr, dstIpStr,
- ipv4.getDestinationAddress(), vpnIdVpnInstanceName, elanTag);
- return;
- }
+ handleIpPackets(srcIpBytes, dstIpBytes, srcIpStr, dstIpStr, srcMac, metadata);
- byte[] srcMac = res.getSourceMACAddress();
- handleBgpVpnSubnetRoute(ipv4, srcMac, dstIp, dstIpStr, srcIpStr, elanTag);
- }
- } catch (UnknownHostException | InterruptedException | ExecutionException ex) {
+ } catch (UnknownHostException | InterruptedException | ExecutionException | BufferException ex) {
// Failed to handle packet
vpnManagerCounters.subnetRoutePacketFailed();
LOG.error("{} onPacketReceived: Failed to handle subnetroute packet.", LOGGING_PREFIX, ex);
}
- private void handleBgpVpnSubnetRoute(IPv4 ipv4, byte[] srcMac, byte[] dstIp, String dstIpStr, String srcIpStr,
+ private void handleIpPackets(byte[] srcIp, byte[] dstIp, String srcIpStr, String dstIpStr, String srcMac,
+ BigInteger metadata)
+ throws UnknownHostException, InterruptedException, ExecutionException, ReadFailedException {
+ long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
+
+ LOG.info("{} onPacketReceived: Processing IP Packet received with Source IP {} and Target IP {}"
+ + " and vpnId {}", LOGGING_PREFIX, srcIpStr, dstIpStr, vpnId);
+
+ Optional<VpnIds> vpnIdsOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+ LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId));
+
+ if (!vpnIdsOptional.isPresent()) {
+ // Donot trigger subnetroute logic for packets from
+ // unknown VPNs
+ vpnManagerCounters.subnetRoutePacketIgnored();
+ LOG.info("{} onPacketReceived: Ignoring IPv4 packet with destination Ip {} and source Ip {}"
+ + " as it came on unknown VPN with ID {}", LOGGING_PREFIX, dstIpStr, srcIpStr, vpnId);
+ return;
+ }
+
+ String vpnIdVpnInstanceName = vpnIdsOptional.get().getVpnInstanceName();
+ if (VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
+ vpnManagerCounters.subnetRoutePacketIgnored();
+ LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source IP {} vpnId {} "
+ + "is a valid Neutron port,ignoring subnet route processing", LOGGING_PREFIX, dstIpStr,
+ srcIp, vpnId);
+ return;
+ }
+
+ if (VpnUtil.getLearntVpnVipToPort(dataBroker, vpnIdVpnInstanceName, dstIpStr) != null) {
+ vpnManagerCounters.subnetRoutePacketIgnored();
+ LOG.info("{} onPacketReceived: IP Packet received with Target IP {} source Ip {} vpnId {}"
+ + " is an already discovered IPAddress, ignoring subnet route processing",
+ LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
+ return;
+ }
+
+ long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+ if (elanTag == 0L) {
+ vpnManagerCounters.subnetRoutePacketFailed();
+ LOG.error("{} onPacketReceived: elanTag value from metadata found to be 0, for IP "
+ + " Packet received with Target IP {} src Ip {} vpnId {}",
+ LOGGING_PREFIX, dstIpStr, srcIp, vpnId);
+ return;
+ }
+
+ if (!vpnIdsOptional.get().isExternalVpn()) {
+ handleInternalVpnSubnetRoutePacket(metadata, dstIp, srcIpStr, dstIpStr, vpnIdVpnInstanceName,
+ elanTag);
+ return;
+ }
+
+ handleBgpVpnSubnetRoute(srcMac, dstIp, dstIpStr, srcIpStr, elanTag);
+ }
+
+ private void handleBgpVpnSubnetRoute(String srcMac, byte[] dstIp, String dstIpStr, String srcIpStr,
long elanTag) throws UnknownHostException {
- LOG.info("{} handleBgpVpnSubnetRoute: Processing IPv4 Packet received with Source IP {} and Target IP {}"
+ LOG.info("{} handleBgpVpnSubnetRoute: Processing IP Packet received with Source IP {} and Target IP {}"
+ " and elan Tag {}", LOGGING_PREFIX, srcIpStr, dstIpStr, elanTag);
SubnetOpDataEntry targetSubnetForPacketOut =
- getTargetSubnetForPacketOut(dataBroker, elanTag, ipv4.getDestinationAddress());
+ getTargetSubnetForPacketOut(dataBroker, elanTag, dstIpStr);
if (targetSubnetForPacketOut != null) {
// Handle subnet routes ip requests
- transmitArpPacket(targetSubnetForPacketOut.getNhDpnId(), srcIpStr, NWUtil.toStringMacAddress(srcMac), dstIp,
- elanTag);
+ transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), srcIpStr, srcMac, dstIp, dstIpStr, elanTag);
} else {
vpnManagerCounters.subnetRoutePacketFailed();
LOG.debug("{} handleBgpVpnSubnetRoute: Could not find target subnet for packet out {}", LOGGING_PREFIX,
}
private void handleInternalVpnSubnetRoutePacket(BigInteger metadata, byte[] dstIp, String srcIpStr, String dstIpStr,
- int destinationAddress, String vpnIdVpnInstanceName, long elanTag)
+ String vpnIdVpnInstanceName, long elanTag)
throws InterruptedException, ExecutionException, UnknownHostException {
String vmVpnInterfaceName = VpnUtil.getVpnInterfaceName(odlInterfaceRpcService, metadata);
if (isTunnel(vmVpnInterfaceName)) {
- handlePacketFromTunnelToExternalNetwork(vpnIdVpnInstanceName,
- srcIpStr, dstIp, elanTag);
+ handlePacketFromTunnelToExternalNetwork(vpnIdVpnInstanceName, srcIpStr, dstIp, dstIpStr, elanTag);
}
VpnInterface vmVpnInterface = VpnUtil.getVpnInterface(dataBroker, vmVpnInterfaceName);
if (vmVpnInterface == null) {
vmVpnInterface.getVpnInstanceNames())
&& !VpnUtil.isBgpVpnInternet(dataBroker, vpnIdVpnInstanceName)) {
LOG.trace("Unknown IP is in internal network");
- handlePacketToInternalNetwork(dstIp, dstIpStr, destinationAddress, elanTag);
+ handlePacketToInternalNetwork(dstIp, dstIpStr, elanTag);
} else {
LOG.trace("Unknown IP is in external network");
- String vpnName = VpnUtil.getInternetVpnFromVpnInstanceList(dataBroker,
- vmVpnInterface.getVpnInstanceNames());
+ String vpnName =
+ VpnUtil.getInternetVpnFromVpnInstanceList(dataBroker, vmVpnInterface.getVpnInstanceNames());
if (vpnName != null) {
- handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName),
- vpnName, dstIp, elanTag);
+ handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
} else {
vpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vmVpnInterface);
- LOG.trace("Unknown IP is in external network, but internet VPN not found."
- + " fallback to first VPN");
- handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName),
- vpnName, dstIp, elanTag);
+ LOG.trace("Unknown IP is in external network, but internet VPN not found." + " fallback to first VPN");
+ handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), vpnName, dstIp, dstIpStr, elanTag);
}
}
}
- private void transmitArpPacket(BigInteger dpnId, String sourceIpAddress, String sourceMac, byte[] dstIp,
- long elanTag) throws UnknownHostException {
- LOG.debug("Sending arp with elan tag {}", elanTag);
- vpnManagerCounters.subnetRoutePacketArpSent();
+ private void transmitArpOrNsPacket(BigInteger dpnId, String sourceIpAddress, String sourceMac, byte[] dstIpBytes,
+ String dstIpAddress, long elanTag) throws UnknownHostException {
long groupid = VpnUtil.getRemoteBCGroup(elanTag);
- TransmitPacketInput arpRequestInput = ArpUtils.createArpRequestInput(dpnId, groupid,
- HexEncode.bytesFromHexString(sourceMac), InetAddress.getByName(sourceIpAddress).getAddress(), dstIp);
+ if (NWUtil.isIpv4Address(dstIpAddress)) {
+ LOG.debug("Sending ARP: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}", sourceIpAddress, sourceMac,
+ dstIpAddress, dpnId, elanTag);
+ vpnManagerCounters.subnetRoutePacketArpSent();
+
+ TransmitPacketInput packetInput =
+ ArpUtils.createArpRequestInput(dpnId, groupid, HexEncode.bytesFromHexString(sourceMac),
+ InetAddress.getByName(sourceIpAddress).getAddress(), dstIpBytes);
+ JdkFutures.addErrorLogging(packetService.transmitPacket(packetInput), LOG, "Transmit packet");
+ } else {
+ // IPv6 case
+ LOG.debug("Sending NS: srcIp={}, srcMac={}, dstIp={}, dpId={}, elan-tag={}", sourceIpAddress, sourceMac,
+ dstIpAddress, dpnId, elanTag);
+ vpnManagerCounters.subnetRoutePacketNsSent();
- JdkFutures.addErrorLogging(packetService.transmitPacket(arpRequestInput), LOG, "Transmit packet");
+ VpnUtil.sendNeighborSolicationToOfGroup(this.ipv6NdutilService, new Ipv6Address(sourceIpAddress),
+ new MacAddress(sourceMac), new Ipv6Address(dstIpAddress), groupid, dpnId);
+ }
}
- private void handlePacketToInternalNetwork(byte[] dstIp, String dstIpStr, int destinationAddress, long elanTag)
+ private void handlePacketToInternalNetwork(byte[] dstIp, String dstIpStr, long elanTag)
throws UnknownHostException {
try {
SubnetOpDataEntry targetSubnetForPacketOut =
- getTargetSubnetForPacketOut(dataBroker, elanTag, destinationAddress);
+ getTargetSubnetForPacketOut(dataBroker, elanTag, dstIpStr);
if (targetSubnetForPacketOut == null) {
LOG.debug("Couldn't find matching subnet for elan tag {} and destination ip {}", elanTag, dstIpStr);
return;
}
- transmitArpPacket(targetSubnetForPacketOut.getNhDpnId(), sourceIp, sourceMac, dstIp, elanTag);
+ transmitArpOrNsPacket(targetSubnetForPacketOut.getNhDpnId(), sourceIp, sourceMac, dstIp, dstIpStr, elanTag);
} catch (ReadFailedException e) {
LOG.error("handlePacketToInternalNetwork: Failed to read data store for destIp {} elanTag {}", dstIpStr,
elanTag);
}
}
- private void handlePacketFromTunnelToExternalNetwork(String vpnIdVpnInstanceName,
- String srcIpStr, byte[] dstIp, long elanTag)
- throws UnknownHostException {
+ private void handlePacketFromTunnelToExternalNetwork(String vpnIdVpnInstanceName, String srcIpStr, byte[] dstIp,
+ String dstIpStr, long elanTag) throws UnknownHostException {
String routerId = VpnUtil.getAssociatedExternalRouter(dataBroker, srcIpStr);
if (null == routerId) {
LOG.debug("This ip is not associated with any external router: {}", srcIpStr);
}
- handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), routerId, dstIp, elanTag);
+ handlePacketToExternalNetwork(new Uuid(vpnIdVpnInstanceName), routerId, dstIp, dstIpStr, elanTag);
}
- private void handlePacketToExternalNetwork(Uuid vpnInstanceNameUuid, String routerId, byte[] dstIp,
+ private void handlePacketToExternalNetwork(Uuid vpnInstanceNameUuid, String routerId, byte[] dstIp, String dstIpStr,
long elanTag) throws UnknownHostException {
Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId);
if (externalRouter == null) {
return;
}
- transmitArpPacket(dpnId, externalIp.get().getIpAddress(), externalRouter.getExtGwMacAddress(), dstIp, elanTag);
+ transmitArpOrNsPacket(dpnId, externalIp.get().getIpAddress(), externalRouter.getExtGwMacAddress(), dstIp,
+ dstIpStr, elanTag);
}
// return only the first VPN subnetopdataentry
- private static SubnetOpDataEntry getTargetSubnetForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
+ private static SubnetOpDataEntry getTargetSubnetForPacketOut(DataBroker broker, long elanTag, String ipAddress) {
ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
if (elanInfo == null) {
LOG.error("{} getTargetDpnForPacketOut: Unable to retrieve ElanInfo for elanTag {}", LOGGING_PREFIX,
SubnetOpDataEntry subOpEntry = optionalSubs.get();
if (subOpEntry.getNhDpnId() != null) {
LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {}", LOGGING_PREFIX, subnetId.getValue());
- boolean match = NWUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
+ IpPrefix cidr = new IpPrefix(subOpEntry.getSubnetCidr().toCharArray());
+ boolean match = NWUtil.isIpAddressInRange(new IpAddress(ipAddress.toCharArray()), cidr);
LOG.trace("{} getTargetDpnForPacketOut: Viewing Subnet {} matching {}", LOGGING_PREFIX,
subnetId.getValue(), match);
if (match) {
long LOWER_PSEUDO_LPORT_TAG = Long.getLong("lower.lport.gid", 170001);
long UPPER_PSEUDO_LPORT_TAG = Long.getLong("upper.lport.gid", 270000);
+ int IP_V6_ETHTYPE = 0x86DD;
+ int ETHTYPE_START = 96;
+ int TWO_BYTES = 16;
+ int IP_V6_HDR_START = 112;
+
enum ITMTunnelLocType {
Invalid(0), Internal(1), External(2), Hwvtep(3);
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNamesBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.SendNeighborSolicitationToOfGroupOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.L3nexthop;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthops;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
import org.slf4j.LoggerFactory;
public final class VpnUtil {
+
private static final Logger LOG = LoggerFactory.getLogger(VpnUtil.class);
- private static final int DEFAULT_PREFIX_LENGTH = 32;
+
static final int SINGLE_TRANSACTION_BROKER_NO_RETRY = 1;
- private static final String PREFIX_SEPARATOR = "/";
/**
* Class to generate timestamps with microsecond precision.
private VpnUtil() {
}
- static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
+ public static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
return InstanceIdentifier.builder(VpnInterfaces.class)
.child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
}
- static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
+ public static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
String vpnInterfaceName, String vpnName) {
return InstanceIdentifier.builder(VpnInterfaceOpData.class)
.child(VpnInterfaceOpDataEntry.class,
return null;
}
- static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
+ public static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
final InstanceIdentifier<VpnInterface> identifier = getVpnInterfaceIdentifier(intfName);
InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
return new AllocatedRdsBuilder().withKey(new AllocatedRdsKey(nexthop)).setNexthop(nexthop).setRd(rd);
}
- static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
+ public static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
return new AdjacenciesBuilder().setAdjacency(nextHopList).build();
}
return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
}
- static Optional<List<String>> getVpnHandlingIpv4AssociatedWithInterface(DataBroker broker, String interfaceName) {
+ public static Optional<List<String>> getVpnHandlingAssociatedWithInterface(DataBroker broker,
+ String interfaceName) {
InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
Optional<List<String>> vpnOptional = Optional.absent();
Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
if (optVpnInstanceList.isPresent()) {
List<String> vpnList = new ArrayList<>();
for (VpnInstanceNames vpnInstance : optVpnInstanceList.get()) {
- if (vpnInstance.getAssociatedSubnetType().equals(AssociatedSubnetType.V6Subnet)) {
- continue;
- }
vpnList.add(vpnInstance.getVpnName());
}
vpnOptional = Optional.of(vpnList);
public static String getIpPrefix(String prefix) {
String[] prefixValues = prefix.split("/");
if (prefixValues.length == 1) {
- prefix = prefix + PREFIX_SEPARATOR + DEFAULT_PREFIX_LENGTH;
+ prefix = NWUtil.toIpPrefix(prefix);
}
return prefix;
}
}
}
- protected static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
+ public static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
portName, String macAddress, WriteTransaction writeOperTxn) {
synchronized ((vpnName + fixedIp).intern()) {
InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
} else {
MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
}
- LOG.debug("createLearntVpnVipToPort: ARP learned for fixedIp: {}, vpn {}, interface {}, mac {},"
+ LOG.debug("createLearntVpnVipToPort: ARP/NA learned for fixedIp: {}, vpn {}, interface {}, mac {},"
+ " added to LearntVpnVipToPort DS", fixedIp, vpnName, portName, macAddress);
}
}
new LearntVpnVipToPortKey(fixedIp, vpnName)).build();
}
- protected static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp,
- WriteTransaction writeOperTxn) {
+ public static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp,
+ WriteTransaction writeOperTxn) {
synchronized ((vpnName + fixedIp).intern()) {
InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
if (writeOperTxn != null) {
}
}
- protected static void createLearntVpnVipToPortEvent(DataBroker broker, String vpnName, String srcIp, String destIP,
+ public static void createLearntVpnVipToPortEvent(DataBroker broker, String vpnName, String srcIp, String destIP,
String portName, String macAddress,
LearntVpnVipToPortEventAction action,
WriteTransaction writeOperTxn) {
return null;
}
- static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
+ public static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
Optional<LearntVpnVipToPort> learntVpnVipToPort = read(broker, LogicalDatastoreType.OPERATIONAL, id);
if (learntVpnVipToPort.isPresent()) {
return extNetwork != null ? extNetwork.getVpnid() : null;
}
- static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
+ public static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
Networks extNetwork = getExternalNetwork(dataBroker, networkId);
return extNetwork != null ? extNetwork.getRouterIds() : Collections.emptyList();
}
return optionalSubnets.isPresent() ? optionalSubnets.get() : null;
}
- static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
+ public static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId.getValue());
if (externalRouter != null && externalRouter.getExternalIps() != null) {
for (ExternalIps externalIp : externalRouter.getExternalIps()) {
}
}
}
+
+ public static void sendNeighborSolicationToOfGroup(Ipv6NdutilService ipv6NdutilService, Ipv6Address srcIpv6Address,
+ MacAddress srcMac, Ipv6Address dstIpv6Address, Long ofGroupId, BigInteger dpId) {
+ SendNeighborSolicitationToOfGroupInput input = new SendNeighborSolicitationToOfGroupInputBuilder()
+ .setSourceIpv6(srcIpv6Address).setSourceLlAddress(srcMac).setTargetIpAddress(dstIpv6Address)
+ .setOfGroupId(ofGroupId).setDpId(dpId).build();
+ try {
+ Future<RpcResult<SendNeighborSolicitationToOfGroupOutput>> result = ipv6NdutilService
+ .sendNeighborSolicitationToOfGroup(input);
+ RpcResult<SendNeighborSolicitationToOfGroupOutput> rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ LOG.error("sendNeighborSolicitationToOfGroup: RPC Call failed for input={} and Errors={}", input,
+ rpcResult.getErrors());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to send NS packet to ELAN group, input={}", input, e);
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Alten Calsoft Labs India Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.vpnmanager.iplearn;
+
+import com.google.common.base.Optional;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.netvirt.vpnmanager.VpnUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AbstractIpLearnNotificationHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractIpLearnNotificationHandler.class);
+
+ // temp where Key is VPNInstance+IP and value is timestamp
+ private final Cache<Pair<String, String>, BigInteger> migrateIpCache;
+
+ protected final DataBroker dataBroker;
+ protected final IdManagerService idManager;
+ protected final IInterfaceManager interfaceManager;
+ protected final VpnConfig config;
+
+ public AbstractIpLearnNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+ IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+ this.dataBroker = dataBroker;
+ this.idManager = idManager;
+ this.interfaceManager = interfaceManager;
+ this.config = vpnConfig;
+
+ long duration = config.getArpLearnTimeout() * 10;
+ long cacheSize = config.getArpCacheSize().longValue();
+ migrateIpCache =
+ CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration,
+ TimeUnit.MILLISECONDS).build();
+ }
+
+ protected void validateAndProcessIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac,
+ IpAddress targetIP, BigInteger metadata) {
+ List<Adjacency> adjacencies = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker, srcInterface);
+ if (adjacencies != null) {
+ for (Adjacency adj : adjacencies) {
+ IpPrefix ipPrefix = new IpPrefix(adj.getIpAddress().toCharArray());
+ if (NWUtil.isIpAddressInRange(srcIP, ipPrefix)) {
+ return;
+ }
+ }
+ }
+
+ LOG.trace("ARP/NA Notification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+ srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue());
+ processIpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
+ }
+
+ protected void processIpLearning(String srcInterface, IpAddress srcIP, MacAddress srcMac, BigInteger metadata,
+ IpAddress dstIP) {
+ if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
+ Optional<List<String>> vpnList = VpnUtil.getVpnHandlingAssociatedWithInterface(dataBroker, srcInterface);
+ if (vpnList.isPresent()) {
+ String srcIpToQuery = String.valueOf(srcIP.getValue());
+ String destIpToQuery = String.valueOf(dstIP.getValue());
+ for (String vpnName : vpnList.get()) {
+ LOG.info("Received ARP/NA for sender MAC {} and sender IP {} via interface {}",
+ srcMac.getValue(), srcIpToQuery, srcInterface);
+ VpnPortipToPort vpnPortipToPort =
+ VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, srcIpToQuery);
+ if (vpnPortipToPort != null) {
+ /* This is a well known neutron port and so should be ignored
+ * from being discovered
+ */
+ continue;
+ }
+ LearntVpnVipToPort learntVpnVipToPort = VpnUtil.getLearntVpnVipToPort(dataBroker,
+ vpnName, srcIpToQuery);
+ if (learntVpnVipToPort != null) {
+ String oldPortName = learntVpnVipToPort.getPortName();
+ String oldMac = learntVpnVipToPort.getMacAddress();
+ if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
+ //MAC has changed for requested IP
+ LOG.info("ARP/NA Source IP/MAC data modified for IP {} with MAC {} and Port {}",
+ srcIpToQuery, srcMac, srcInterface);
+ synchronized ((vpnName + srcIpToQuery).intern()) {
+ VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery,
+ oldPortName, oldMac, LearntVpnVipToPortEventAction.Delete, null);
+ putVpnIpToMigrateIpCache(vpnName, srcIpToQuery, srcMac);
+ }
+ }
+ } else if (!isIpInMigrateCache(vpnName, srcIpToQuery)) {
+ learnMacFromIncomingPacket(vpnName, srcInterface, srcIP, srcMac, dstIP);
+ }
+ }
+ } else {
+ LOG.info("IP LEARN NO_RESOLVE: VPN not configured. Ignoring responding to ARP/NA requests from this"
+ + " Interface {}.", srcInterface);
+ return;
+
+ }
+ }
+ }
+
+ private void learnMacFromIncomingPacket(String vpnName, String srcInterface, IpAddress srcIP, MacAddress srcMac,
+ IpAddress dstIP) {
+ String srcIpToQuery = String.valueOf(srcIP.getValue());
+ String destIpToQuery = String.valueOf(dstIP.getValue());
+ synchronized ((vpnName + srcIpToQuery).intern()) {
+ VpnUtil.createLearntVpnVipToPortEvent(dataBroker, vpnName, srcIpToQuery, destIpToQuery, srcInterface,
+ srcMac.getValue(), LearntVpnVipToPortEventAction.Add, null);
+ }
+ }
+
+ private void putVpnIpToMigrateIpCache(String vpnName, String ipToQuery, MacAddress srcMac) {
+ long cacheSize = config.getArpCacheSize().longValue();
+ if (migrateIpCache.size() >= cacheSize) {
+ LOG.debug("IP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
+ + " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
+ }
+ LOG.debug("IP_MIGRATE_CACHE: add to dirty cache IP {} vpnName {} with MAC {}", ipToQuery, vpnName, srcMac);
+ migrateIpCache.put(new ImmutablePair<>(vpnName, ipToQuery),
+ new BigInteger(String.valueOf(System.currentTimeMillis())));
+ }
+
+ private boolean isIpInMigrateCache(String vpnName, String ipToQuery) {
+ if (migrateIpCache == null || migrateIpCache.size() == 0) {
+ return false;
+ }
+ Pair<String, String> keyPair = new ImmutablePair<>(vpnName, ipToQuery);
+ BigInteger prevTimeStampCached = migrateIpCache.getIfPresent(keyPair);
+ if (prevTimeStampCached == null) {
+ LOG.debug("IP_MIGRATE_CACHE: there is no IP {} vpnName {} in dirty cache, so learn it",
+ ipToQuery, vpnName);
+ return false;
+ }
+ if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
+ LOG.debug("IP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
+ ipToQuery, vpnName);
+ migrateIpCache.invalidate(keyPair);
+ return false;
+ }
+ LOG.debug("IP_MIGRATE_CACHE: younger than timeout value - ignore learning IP {} vpnName {}",
+ ipToQuery, vpnName);
+ return true;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netvirt.vpnmanager.iplearn;
+
+import java.math.BigInteger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ArpNotificationHandler extends AbstractIpLearnNotificationHandler implements OdlArputilListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
+
+ @Inject
+ public ArpNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+ IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+ super(dataBroker, idManager, interfaceManager, vpnConfig);
+ }
+
+ @Override
+ public void onMacChanged(MacChanged notification) {
+
+ }
+
+ @Override
+ public void onArpRequestReceived(ArpRequestReceived notification) {
+ String srcInterface = notification.getInterface();
+ IpAddress srcIP = notification.getSrcIpaddress();
+ MacAddress srcMac = MacAddress.getDefaultInstance(notification.getSrcMac().getValue());
+ IpAddress targetIP = notification.getDstIpaddress();
+ BigInteger metadata = notification.getMetadata();
+ boolean isGarp = srcIP.equals(targetIP);
+ if (!isGarp) {
+ LOG.info(
+ "ArpNotification Non-Gratuitous Request Received from "
+ + "interface {} and IP {} having MAC {} target destination {}, ignoring..",
+ srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue(),
+ String.valueOf(targetIP.getValue()));
+ return;
+ }
+ LOG.info(
+ "ArpNotification Gratuitous Request Received from interface {} and IP {} having MAC {} "
+ + "target destination {}, learning MAC",
+ srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue(), String.valueOf(targetIP.getValue()));
+
+ processIpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
+ }
+
+ @Override
+ public void onArpResponseReceived(ArpResponseReceived notification) {
+ String srcInterface = notification.getInterface();
+ IpAddress srcIP = notification.getSrcIpaddress();
+ MacAddress srcMac = MacAddress.getDefaultInstance(notification.getSrcMac().getValue());
+ BigInteger metadata = notification.getMetadata();
+ IpAddress targetIP = notification.getDstIpaddress();
+ LOG.info("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+ srcInterface, String.valueOf(srcIP.getValue()), srcMac.getValue());
+
+ validateAndProcessIpLearning(srcInterface, srcIP, srcMac, targetIP, metadata);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Alten Calsoft Labs India Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.vpnmanager.iplearn;
+
+import java.math.BigInteger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.NaReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class Ipv6NaNotificationHandler extends AbstractIpLearnNotificationHandler implements Ipv6NdutilListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Ipv6NaNotificationHandler.class);
+
+ @Inject
+ public Ipv6NaNotificationHandler(DataBroker dataBroker, IdManagerService idManager,
+ IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
+ super(dataBroker, idManager, interfaceManager, vpnConfig);
+ }
+
+ @Override
+ public void onNaReceived(NaReceived naPacket) {
+ String srcInterface = naPacket.getInterface();
+ IpAddress srcIP = new IpAddress(naPacket.getSourceIpv6());
+ MacAddress srcMac = naPacket.getSourceMac();
+ IpAddress targetIP = new IpAddress(naPacket.getTargetAddress());
+ BigInteger metadata = naPacket.getMetadata();
+ LOG.debug("NA notification received from interface {} and IP {} having MAC {}, targetIP={}", srcInterface,
+ String.valueOf(srcIP.getValue()), srcMac.getValue(), String.valueOf(targetIP.getValue()));
+
+ validateAndProcessIpLearning(srcInterface, srcIP, srcMac, targetIP, metadata);
+ }
+}
private final Meter subnetRoutePacketIgnoredMeter;
private final Meter subnetRoutePacketFailedMeter;
private final Meter subnetRoutePacketArpSentMeter;
+ private final Meter subnetRoutePacketNsSentMeter;
private final Meter garpAddNotificationMeter;
private final Meter garpUpdateNotificationMeter;
private final Meter garpSentMeter;
this.subnetRoutePacketIgnoredMeter = meter(metricProvider, "subnet_route_packet_ignored");
this.subnetRoutePacketFailedMeter = meter(metricProvider, "subnet_route_packet_failed");
this.subnetRoutePacketArpSentMeter = meter(metricProvider, "subnet_route_packet_arp_sent");
+ this.subnetRoutePacketNsSentMeter = meter(metricProvider, "subnet_route_packet_ns_sent");
this.garpAddNotificationMeter = meter(metricProvider, "garp_add_notification");
this.garpUpdateNotificationMeter = meter(metricProvider, "garp_update_notification");
this.garpSentMeter = meter(metricProvider, "garp_sent");
subnetRoutePacketArpSentMeter.mark();
}
+ public void subnetRoutePacketNsSent() {
+ subnetRoutePacketNsSentMeter.mark();
+ }
+
public void garpAddNotification() {
garpAddNotificationMeter.mark();
}
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService" />
<odl:rpc-service id="itmRpcService"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService"/>
+ <odl:rpc-service id="ipv6NdutilService"
+ interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilService"/>
<service ref="dpnInVpnChangeListener" odl:type="default"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.OdlL3vpnListener" />
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener" />
<odl:notification-listener ref="arpNotificationHandler" />
+ <service ref="ipv6NaNotificationHandler" odl:type="default"
+ interface="org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.ipv6util.rev170210.Ipv6NdutilListener" />
+ <odl:notification-listener ref="ipv6NaNotificationHandler" />
+
<service ref="vpnManagerImpl"
interface="org.opendaylight.netvirt.vpnmanager.api.IVpnManager" />