Device Emulation (contd.): resolveNeighbors() now resolves the device gateway also in addition to looking at transmit packet content to figure out which IPs to resolve
This commit is contained in:
parent
e3a3a0cf1f
commit
f6c852495d
@ -625,7 +625,10 @@ void AbstractPort::clearDeviceNeighbors()
|
|||||||
|
|
||||||
void AbstractPort::resolveDeviceNeighbors()
|
void AbstractPort::resolveDeviceNeighbors()
|
||||||
{
|
{
|
||||||
// Resolve neighbor for each unique frame of each stream
|
// Resolve gateway for each device first ...
|
||||||
|
deviceManager_->resolveDeviceGateways();
|
||||||
|
|
||||||
|
// ... then resolve neighbor for each unique frame of each stream
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// 1. All the frames may have the same destination ip,but may have
|
// 1. All the frames may have the same destination ip,but may have
|
||||||
// different source ip so may belong to a different emulated device;
|
// different source ip so may belong to a different emulated device;
|
||||||
|
@ -256,6 +256,15 @@ void Device::transmitPacket(PacketBuffer *pktBuf)
|
|||||||
deviceManager_->transmitPacket(pktBuf);
|
deviceManager_->transmitPacket(pktBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::resolveGateway()
|
||||||
|
{
|
||||||
|
if (hasIp4_)
|
||||||
|
sendArpRequest(ip4Gateway_);
|
||||||
|
|
||||||
|
if (hasIp6_)
|
||||||
|
sendNeighborSolicit(ip6Gateway_);
|
||||||
|
}
|
||||||
|
|
||||||
void Device::clearNeighbors()
|
void Device::clearNeighbors()
|
||||||
{
|
{
|
||||||
arpTable_.clear();
|
arpTable_.clear();
|
||||||
@ -524,11 +533,9 @@ _invalid_exit:
|
|||||||
// pktBuf points to start of IP header
|
// pktBuf points to start of IP header
|
||||||
void Device::sendArpRequest(PacketBuffer *pktBuf)
|
void Device::sendArpRequest(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
PacketBuffer *reqPkt;
|
|
||||||
uchar *pktData = pktBuf->data();
|
uchar *pktData = pktBuf->data();
|
||||||
int offset = 0;
|
int ipHdrLen = (pktData[0] & 0x0F) << 2;
|
||||||
int ipHdrLen = (pktData[offset] & 0x0F) << 2;
|
quint32 srcIp = ip4_, dstIp, mask, tgtIp;
|
||||||
quint32 srcIp, dstIp, mask, tgtIp;
|
|
||||||
|
|
||||||
if (pktBuf->length() < ipHdrLen) {
|
if (pktBuf->length() < ipHdrLen) {
|
||||||
qDebug("incomplete IPv4 header: expected %d, actual %d",
|
qDebug("incomplete IPv4 header: expected %d, actual %d",
|
||||||
@ -536,25 +543,28 @@ void Device::sendArpRequest(PacketBuffer *pktBuf)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: not required - caller is checking for origin anyway
|
|
||||||
// Extract srcIp first to check quickly that this packet originates
|
|
||||||
// from this device
|
|
||||||
srcIp = qFromBigEndian<quint32>(pktData + ipHdrLen - 8);
|
|
||||||
if (srcIp != ip4_) {
|
|
||||||
qDebug("%s: srcIp %s is not me %s", __FUNCTION__,
|
|
||||||
qPrintable(QHostAddress(srcIp).toString()),
|
|
||||||
qPrintable(QHostAddress(ip4_).toString()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dstIp = qFromBigEndian<quint32>(pktData + ipHdrLen - 4);
|
dstIp = qFromBigEndian<quint32>(pktData + ipHdrLen - 4);
|
||||||
|
|
||||||
mask = ~0 << (32 - ip4PrefixLength_);
|
mask = ~0 << (32 - ip4PrefixLength_);
|
||||||
qDebug("dst %x src %x mask %x", dstIp, srcIp, mask);
|
qDebug("dst %x src %x mask %x", dstIp, srcIp, mask);
|
||||||
tgtIp = ((dstIp & mask) == (srcIp & mask)) ? dstIp : ip4Gateway_;
|
tgtIp = ((dstIp & mask) == (srcIp & mask)) ? dstIp : ip4Gateway_;
|
||||||
|
|
||||||
|
sendArpRequest(tgtIp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::sendArpRequest(quint32 tgtIp)
|
||||||
|
{
|
||||||
|
quint32 srcIp = ip4_;
|
||||||
|
PacketBuffer *reqPkt;
|
||||||
|
uchar *pktData;
|
||||||
|
|
||||||
|
// Validate target IP
|
||||||
|
if (!tgtIp)
|
||||||
|
return;
|
||||||
|
|
||||||
// Do we already have a ARP entry (resolved or unresolved)?
|
// Do we already have a ARP entry (resolved or unresolved)?
|
||||||
// FIXME: do we need a timer to resend ARP for unresolved entries?
|
// XXX: No NDP state machine for now
|
||||||
if (arpTable_.contains(tgtIp))
|
if (arpTable_.contains(tgtIp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -902,9 +912,8 @@ _invalid_exit:
|
|||||||
// pktBuf should point to start of IP header
|
// pktBuf should point to start of IP header
|
||||||
void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
PacketBuffer *reqPkt;
|
|
||||||
uchar *pktData = pktBuf->data();
|
uchar *pktData = pktBuf->data();
|
||||||
UInt128 srcIp, dstIp, mask, tgtIp;
|
UInt128 srcIp = ip6_, dstIp, mask, tgtIp;
|
||||||
|
|
||||||
if (pktBuf->length() < kIp6HdrLen) {
|
if (pktBuf->length() < kIp6HdrLen) {
|
||||||
qDebug("incomplete IPv6 header: expected %d, actual %d",
|
qDebug("incomplete IPv6 header: expected %d, actual %d",
|
||||||
@ -912,7 +921,6 @@ void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
srcIp = qFromBigEndian<UInt128>(pktData + 8);
|
|
||||||
dstIp = qFromBigEndian<UInt128>(pktData + 24);
|
dstIp = qFromBigEndian<UInt128>(pktData + 24);
|
||||||
|
|
||||||
mask = ~UInt128(0, 0) << (128 - ip6PrefixLength_);
|
mask = ~UInt128(0, 0) << (128 - ip6PrefixLength_);
|
||||||
@ -922,8 +930,21 @@ void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
|||||||
qPrintable(QHostAddress(mask.toArray()).toString()));
|
qPrintable(QHostAddress(mask.toArray()).toString()));
|
||||||
tgtIp = ((dstIp & mask) == (srcIp & mask)) ? dstIp : ip6Gateway_;
|
tgtIp = ((dstIp & mask) == (srcIp & mask)) ? dstIp : ip6Gateway_;
|
||||||
|
|
||||||
|
sendNeighborSolicit(tgtIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::sendNeighborSolicit(UInt128 tgtIp)
|
||||||
|
{
|
||||||
|
UInt128 dstIp, srcIp = ip6_;
|
||||||
|
PacketBuffer *reqPkt;
|
||||||
|
uchar *pktData;
|
||||||
|
|
||||||
|
// Validate target IP
|
||||||
|
if (tgtIp == UInt128(0, 0))
|
||||||
|
return;
|
||||||
|
|
||||||
// Do we already have a NDP entry (resolved or unresolved)?
|
// Do we already have a NDP entry (resolved or unresolved)?
|
||||||
// FIXME: do we need a timer to resend NS for unresolved entries?
|
// XXX: No ARP state machine for now
|
||||||
if (ndpTable_.contains(tgtIp))
|
if (ndpTable_.contains(tgtIp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ public:
|
|||||||
void receivePacket(PacketBuffer *pktBuf);
|
void receivePacket(PacketBuffer *pktBuf);
|
||||||
void transmitPacket(PacketBuffer *pktBuf);
|
void transmitPacket(PacketBuffer *pktBuf);
|
||||||
|
|
||||||
|
void resolveGateway();
|
||||||
|
|
||||||
void clearNeighbors();
|
void clearNeighbors();
|
||||||
void resolveNeighbor(PacketBuffer *pktBuf);
|
void resolveNeighbor(PacketBuffer *pktBuf);
|
||||||
void getNeighbors(OstEmul::DeviceNeighborList *neighbors);
|
void getNeighbors(OstEmul::DeviceNeighborList *neighbors);
|
||||||
@ -69,6 +71,7 @@ public:
|
|||||||
private: // methods
|
private: // methods
|
||||||
void receiveArp(PacketBuffer *pktBuf);
|
void receiveArp(PacketBuffer *pktBuf);
|
||||||
void sendArpRequest(PacketBuffer *pktBuf);
|
void sendArpRequest(PacketBuffer *pktBuf);
|
||||||
|
void sendArpRequest(quint32 tgtIp);
|
||||||
|
|
||||||
void receiveIp4(PacketBuffer *pktBuf);
|
void receiveIp4(PacketBuffer *pktBuf);
|
||||||
void sendIp4Reply(PacketBuffer *pktBuf);
|
void sendIp4Reply(PacketBuffer *pktBuf);
|
||||||
@ -83,6 +86,7 @@ private: // methods
|
|||||||
|
|
||||||
void receiveNdp(PacketBuffer *pktBuf);
|
void receiveNdp(PacketBuffer *pktBuf);
|
||||||
void sendNeighborSolicit(PacketBuffer *pktBuf);
|
void sendNeighborSolicit(PacketBuffer *pktBuf);
|
||||||
|
void sendNeighborSolicit(UInt128 tgtIp);
|
||||||
void sendNeighborAdvertisement(PacketBuffer *pktBuf);
|
void sendNeighborAdvertisement(PacketBuffer *pktBuf);
|
||||||
|
|
||||||
private: // data
|
private: // data
|
||||||
|
@ -260,6 +260,13 @@ void DeviceManager::transmitPacket(PacketBuffer *pktBuf)
|
|||||||
port_->sendEmulationPacket(pktBuf);
|
port_->sendEmulationPacket(pktBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceManager::resolveDeviceGateways()
|
||||||
|
{
|
||||||
|
foreach(Device *device, deviceList_) {
|
||||||
|
device->resolveGateway();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceManager::clearDeviceNeighbors()
|
void DeviceManager::clearDeviceNeighbors()
|
||||||
{
|
{
|
||||||
foreach(Device *device, deviceList_)
|
foreach(Device *device, deviceList_)
|
||||||
|
@ -52,6 +52,8 @@ public:
|
|||||||
void receivePacket(PacketBuffer *pktBuf);
|
void receivePacket(PacketBuffer *pktBuf);
|
||||||
void transmitPacket(PacketBuffer *pktBuf);
|
void transmitPacket(PacketBuffer *pktBuf);
|
||||||
|
|
||||||
|
void resolveDeviceGateways();
|
||||||
|
|
||||||
void clearDeviceNeighbors();
|
void clearDeviceNeighbors();
|
||||||
void resolveDeviceNeighbor(PacketBuffer *pktBuf);
|
void resolveDeviceNeighbor(PacketBuffer *pktBuf);
|
||||||
void getDeviceNeighbors(OstProto::PortNeighborList *neighborList);
|
void getDeviceNeighbors(OstProto::PortNeighborList *neighborList);
|
||||||
|
@ -594,7 +594,7 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
|||||||
print(cap_pkts)
|
print(cap_pkts)
|
||||||
assert cap_pkts.count('\n') == 1
|
assert cap_pkts.count('\n') == 1
|
||||||
|
|
||||||
# verify *no* ARP Requests sent out from rx port
|
# verify ARP Requests sent out from rx port
|
||||||
buff = drone.getCaptureBuffer(emul_ports.port_id[1])
|
buff = drone.getCaptureBuffer(emul_ports.port_id[1])
|
||||||
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
||||||
log.info('dumping Rx capture buffer (all)')
|
log.info('dumping Rx capture buffer (all)')
|
||||||
@ -621,7 +621,7 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
|||||||
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap',
|
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap',
|
||||||
'-Y', filter])
|
'-Y', filter])
|
||||||
print(cap_pkts)
|
print(cap_pkts)
|
||||||
assert cap_pkts.count('\n') == 0
|
assert cap_pkts.count('\n') == 1
|
||||||
|
|
||||||
# retrieve and verify ARP/NDP Table on tx/rx ports
|
# retrieve and verify ARP/NDP Table on tx/rx ports
|
||||||
log.info('retrieving ARP/NDP entries on tx port')
|
log.info('retrieving ARP/NDP entries on tx port')
|
||||||
@ -636,8 +636,7 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
|||||||
for arp in device.arp:
|
for arp in device.arp:
|
||||||
print('%s: %s %012x' %
|
print('%s: %s %012x' %
|
||||||
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||||
str(ipaddress.ip_address(arp.ip4)),
|
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||||
arp.mac))
|
|
||||||
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
||||||
resolved = True
|
resolved = True
|
||||||
assert resolved
|
assert resolved
|
||||||
@ -646,32 +645,36 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
|||||||
for ndp in device.ndp:
|
for ndp in device.ndp:
|
||||||
print('%s: %s %012x' %
|
print('%s: %s %012x' %
|
||||||
(str(ip6_address(dev_cfg.ip6)),
|
(str(ip6_address(dev_cfg.ip6)),
|
||||||
str(ip6_address(ndp.ip6)),
|
str(ip6_address(ndp.ip6)), ndp.mac))
|
||||||
ndp.mac))
|
|
||||||
if (ndp.ip6 == dev_cfg.ip6_default_gateway) and (ndp.mac):
|
if (ndp.ip6 == dev_cfg.ip6_default_gateway) and (ndp.mac):
|
||||||
resolved = True
|
resolved = True
|
||||||
assert resolved
|
assert resolved
|
||||||
|
|
||||||
log.info('retrieving ARP/NDP entries on rx port')
|
log.info('retrieving ARP/NDP entries on rx port')
|
||||||
device_list = drone.getDeviceList(emul_ports.port_id[0])
|
device_list = drone.getDeviceList(emul_ports.port_id[1])
|
||||||
device_config = device_list.Extensions[emul.port_device]
|
device_config = device_list.Extensions[emul.port_device]
|
||||||
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
||||||
devices = neigh_list.Extensions[emul.devices]
|
devices = neigh_list.Extensions[emul.devices]
|
||||||
log.info('ARP/NDP Table on rx port')
|
log.info('ARP/NDP Table on rx port')
|
||||||
for dev_cfg, device in zip(device_config, devices):
|
for dev_cfg, device in zip(device_config, devices):
|
||||||
# verify *no* ARPs/NDPs learnt on rx port
|
|
||||||
if has_ip4:
|
if has_ip4:
|
||||||
|
resolved = False
|
||||||
for arp in device.arp:
|
for arp in device.arp:
|
||||||
print('%s: %s %012x' %
|
print('%s: %s %012x' %
|
||||||
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||||
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||||
assert len(device.arp) == 0
|
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
||||||
|
resolved = True
|
||||||
|
assert resolved
|
||||||
if has_ip6:
|
if has_ip6:
|
||||||
|
resolved = False
|
||||||
for ndp in device.ndp:
|
for ndp in device.ndp:
|
||||||
print('%s: %s %012x' %
|
print('%s: %s %012x' %
|
||||||
(str(ip6_address(dev_cfg.ip6)),
|
(str(ip6_address(dev_cfg.ip6)),
|
||||||
str(ip6_address(ndp.ip6)), ndp.mac))
|
str(ip6_address(ndp.ip6)), ndp.mac))
|
||||||
assert len(device.ndp) == 0
|
if (ndp.ip6 == dev_cfg.ip6_default_gateway) and (ndp.mac):
|
||||||
|
resolved = True
|
||||||
|
assert resolved
|
||||||
|
|
||||||
# ping the tx devices from the DUT
|
# ping the tx devices from the DUT
|
||||||
for i in range(num_devs):
|
for i in range(num_devs):
|
||||||
@ -998,8 +1001,8 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
|||||||
print(cap_pkts)
|
print(cap_pkts)
|
||||||
assert cap_pkts.count('\n') == 1
|
assert cap_pkts.count('\n') == 1
|
||||||
|
|
||||||
# verify *no* ARP/NDP Requests sent out from rx port
|
# verify ARP/NDP Requests sent out from rx port
|
||||||
buff = drone.getCaptureBuffer(emul_ports.port_id[0])
|
buff = drone.getCaptureBuffer(emul_ports.port_id[1])
|
||||||
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
||||||
log.info('dumping Rx capture buffer (all)')
|
log.info('dumping Rx capture buffer (all)')
|
||||||
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap'])
|
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap'])
|
||||||
@ -1030,7 +1033,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
|||||||
cap_pkts = subprocess.check_output([tshark, '-nr',
|
cap_pkts = subprocess.check_output([tshark, '-nr',
|
||||||
'capture.pcap', '-Y', filter])
|
'capture.pcap', '-Y', filter])
|
||||||
print(cap_pkts)
|
print(cap_pkts)
|
||||||
assert cap_pkts.count('\n') == 0
|
assert cap_pkts.count('\n') == 1
|
||||||
|
|
||||||
# retrieve and verify ARP/NDP Table on tx/rx ports
|
# retrieve and verify ARP/NDP Table on tx/rx ports
|
||||||
log.info('retrieving ARP/NDP entries on tx port')
|
log.info('retrieving ARP/NDP entries on tx port')
|
||||||
@ -1063,7 +1066,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
|||||||
assert resolved
|
assert resolved
|
||||||
|
|
||||||
log.info('retrieving ARP entries on rx port')
|
log.info('retrieving ARP entries on rx port')
|
||||||
device_list = drone.getDeviceList(emul_ports.port_id[0])
|
device_list = drone.getDeviceList(emul_ports.port_id[1])
|
||||||
device_config = device_list.Extensions[emul.port_device]
|
device_config = device_list.Extensions[emul.port_device]
|
||||||
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
||||||
devices = neigh_list.Extensions[emul.devices]
|
devices = neigh_list.Extensions[emul.devices]
|
||||||
@ -1072,19 +1075,24 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
|||||||
vlans = ''
|
vlans = ''
|
||||||
for v in dev_cfg.vlan:
|
for v in dev_cfg.vlan:
|
||||||
vlans += str(v & 0xffff) + ' '
|
vlans += str(v & 0xffff) + ' '
|
||||||
# verify *no* ARPs/NDPs learnt on rx port
|
|
||||||
if has_ip4:
|
if has_ip4:
|
||||||
|
resolved = False
|
||||||
for arp in device.arp:
|
for arp in device.arp:
|
||||||
print('%s%s: %s %012x' %
|
print('%s%s: %s %012x' %
|
||||||
(vlans, str(ipaddress.ip_address(dev_cfg.ip4)),
|
(vlans, str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||||
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||||
assert len(device.arp) == 0
|
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
||||||
|
resolved = True
|
||||||
|
assert resolved
|
||||||
if has_ip6:
|
if has_ip6:
|
||||||
|
resolved = False
|
||||||
for ndp in device.ndp:
|
for ndp in device.ndp:
|
||||||
print('%s%s: %s %012x' %
|
print('%s%s: %s %012x' %
|
||||||
(vlans, str(ip6_address(dev_cfg.ip6)),
|
(vlans, str(ip6_address(dev_cfg.ip6)),
|
||||||
str(ip6_address(ndp.ip6)), ndp.mac))
|
str(ip6_address(ndp.ip6)), ndp.mac))
|
||||||
assert len(device.ndp) == 0
|
if (ndp.ip6 == dev_cfg.ip6_default_gateway) and (ndp.mac):
|
||||||
|
resolved = True
|
||||||
|
assert resolved
|
||||||
|
|
||||||
# ping the tx devices from the DUT
|
# ping the tx devices from the DUT
|
||||||
for i in range(num_vlans):
|
for i in range(num_vlans):
|
||||||
|
Loading…
Reference in New Issue
Block a user