diff --git a/server/abstractport.cpp b/server/abstractport.cpp index 42e636e..0a97ff9 100644 --- a/server/abstractport.cpp +++ b/server/abstractport.cpp @@ -625,6 +625,19 @@ void AbstractPort::clearDeviceNeighbors() void AbstractPort::resolveDeviceNeighbors() { + // For a user triggered 'Resolve Neighbors', the behaviour we want is + // IP not in cache - send ARP/NDP request + // IP present in cache, but unresolved - re-send ARP/NDP request + // IP present in cache and resolved - don't sent ARP/NDP + // + // Device does not resend ARP/NDP requests if the IP address is + // already present in the cache, irrespective of whether it is + // resolved or not (this is done to avoid sending duplicate requests). + // + // So, to get the behaviour we want, let's clear all unresolved neighbors + // before calling resolve + deviceManager_->clearDeviceNeighbors(Device::kUnresolvedNeighbors); + // Resolve gateway for each device first ... deviceManager_->resolveDeviceGateways(); diff --git a/server/device.cpp b/server/device.cpp index 34ea989..6655af3 100644 --- a/server/device.cpp +++ b/server/device.cpp @@ -265,10 +265,33 @@ void Device::resolveGateway() sendNeighborSolicit(ip6Gateway_); } -void Device::clearNeighbors() +void Device::clearNeighbors(Device::NeighborSet set) { - arpTable_.clear(); - ndpTable_.clear(); + QMutableHashIterator arpIter(arpTable_); + QMutableHashIterator ndpIter(ndpTable_); + + switch (set) { + case kAllNeighbors: + arpTable_.clear(); + ndpTable_.clear(); + break; + + case kUnresolvedNeighbors: + while (arpIter.hasNext()) { + arpIter.next(); + if (arpIter.value() == 0) + arpIter.remove(); + } + + while (ndpIter.hasNext()) { + ndpIter.next(); + if (ndpIter.value() == 0) + ndpIter.remove(); + } + break; + default: + Q_ASSERT(false); // Unreachable! + } } // Resolve the Neighbor IP address for this to-be-transmitted pktBuf @@ -564,8 +587,12 @@ void Device::sendArpRequest(quint32 tgtIp) if (!tgtIp) return; - // Do we already have a ARP entry (resolved or unresolved)? - // XXX: No NDP state machine for now + // This function will be called once per unique stream - which + // may all have the same dst IP; even if dst IP are different the + // gateway for the different dst IP may all be same. However, + // we don't want to send duplicate ARP requests, so we check + // if the tgtIP is already in the cache (resolved or unresolved) + // and if so, we don't resend it if (arpTable_.contains(tgtIp)) return; @@ -945,7 +972,7 @@ void Device::sendNeighborSolicit(UInt128 tgtIp) return; // Do we already have a NDP entry (resolved or unresolved)? - // XXX: No ARP state machine for now + // If so, don't resend (see note in sendArpRequest()) if (ndpTable_.contains(tgtIp)) return; diff --git a/server/device.h b/server/device.h index fda1a2e..f77615b 100644 --- a/server/device.h +++ b/server/device.h @@ -39,6 +39,11 @@ class Device public: static const quint16 kVlanTpid = 0x8100; + enum NeighborSet { + kAllNeighbors, + kUnresolvedNeighbors + }; + public: Device(DeviceManager *deviceManager); @@ -61,7 +66,7 @@ public: void resolveGateway(); - void clearNeighbors(); + void clearNeighbors(Device::NeighborSet set); void resolveNeighbor(PacketBuffer *pktBuf); void getNeighbors(OstEmul::DeviceNeighborList *neighbors); diff --git a/server/devicemanager.cpp b/server/devicemanager.cpp index 013fe7e..9db224c 100644 --- a/server/devicemanager.cpp +++ b/server/devicemanager.cpp @@ -258,10 +258,10 @@ void DeviceManager::resolveDeviceGateways() } } -void DeviceManager::clearDeviceNeighbors() +void DeviceManager::clearDeviceNeighbors(Device::NeighborSet set) { foreach(Device *device, deviceList_) - device->clearNeighbors(); + device->clearNeighbors(set); } void DeviceManager::getDeviceNeighbors( diff --git a/server/devicemanager.h b/server/devicemanager.h index 9d472e6..92d4cd0 100644 --- a/server/devicemanager.h +++ b/server/devicemanager.h @@ -55,7 +55,7 @@ public: void resolveDeviceGateways(); - void clearDeviceNeighbors(); + void clearDeviceNeighbors(Device::NeighborSet set = Device::kAllNeighbors); void resolveDeviceNeighbor(PacketBuffer *pktBuf); void getDeviceNeighbors(OstProto::PortNeighborList *neighborList);