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()
|
||||
{
|
||||
// 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:
|
||||
// 1. All the frames may have the same destination ip,but may have
|
||||
// different source ip so may belong to a different emulated device;
|
||||
|
@ -256,6 +256,15 @@ void Device::transmitPacket(PacketBuffer *pktBuf)
|
||||
deviceManager_->transmitPacket(pktBuf);
|
||||
}
|
||||
|
||||
void Device::resolveGateway()
|
||||
{
|
||||
if (hasIp4_)
|
||||
sendArpRequest(ip4Gateway_);
|
||||
|
||||
if (hasIp6_)
|
||||
sendNeighborSolicit(ip6Gateway_);
|
||||
}
|
||||
|
||||
void Device::clearNeighbors()
|
||||
{
|
||||
arpTable_.clear();
|
||||
@ -524,11 +533,9 @@ _invalid_exit:
|
||||
// pktBuf points to start of IP header
|
||||
void Device::sendArpRequest(PacketBuffer *pktBuf)
|
||||
{
|
||||
PacketBuffer *reqPkt;
|
||||
uchar *pktData = pktBuf->data();
|
||||
int offset = 0;
|
||||
int ipHdrLen = (pktData[offset] & 0x0F) << 2;
|
||||
quint32 srcIp, dstIp, mask, tgtIp;
|
||||
int ipHdrLen = (pktData[0] & 0x0F) << 2;
|
||||
quint32 srcIp = ip4_, dstIp, mask, tgtIp;
|
||||
|
||||
if (pktBuf->length() < ipHdrLen) {
|
||||
qDebug("incomplete IPv4 header: expected %d, actual %d",
|
||||
@ -536,25 +543,28 @@ void Device::sendArpRequest(PacketBuffer *pktBuf)
|
||||
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);
|
||||
|
||||
mask = ~0 << (32 - ip4PrefixLength_);
|
||||
qDebug("dst %x src %x mask %x", dstIp, srcIp, mask);
|
||||
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)?
|
||||
// FIXME: do we need a timer to resend ARP for unresolved entries?
|
||||
// XXX: No NDP state machine for now
|
||||
if (arpTable_.contains(tgtIp))
|
||||
return;
|
||||
|
||||
@ -902,9 +912,8 @@ _invalid_exit:
|
||||
// pktBuf should point to start of IP header
|
||||
void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
||||
{
|
||||
PacketBuffer *reqPkt;
|
||||
uchar *pktData = pktBuf->data();
|
||||
UInt128 srcIp, dstIp, mask, tgtIp;
|
||||
UInt128 srcIp = ip6_, dstIp, mask, tgtIp;
|
||||
|
||||
if (pktBuf->length() < kIp6HdrLen) {
|
||||
qDebug("incomplete IPv6 header: expected %d, actual %d",
|
||||
@ -912,7 +921,6 @@ void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
||||
return;
|
||||
}
|
||||
|
||||
srcIp = qFromBigEndian<UInt128>(pktData + 8);
|
||||
dstIp = qFromBigEndian<UInt128>(pktData + 24);
|
||||
|
||||
mask = ~UInt128(0, 0) << (128 - ip6PrefixLength_);
|
||||
@ -922,8 +930,21 @@ void Device::sendNeighborSolicit(PacketBuffer *pktBuf)
|
||||
qPrintable(QHostAddress(mask.toArray()).toString()));
|
||||
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)?
|
||||
// FIXME: do we need a timer to resend NS for unresolved entries?
|
||||
// XXX: No ARP state machine for now
|
||||
if (ndpTable_.contains(tgtIp))
|
||||
return;
|
||||
|
||||
|
@ -59,6 +59,8 @@ public:
|
||||
void receivePacket(PacketBuffer *pktBuf);
|
||||
void transmitPacket(PacketBuffer *pktBuf);
|
||||
|
||||
void resolveGateway();
|
||||
|
||||
void clearNeighbors();
|
||||
void resolveNeighbor(PacketBuffer *pktBuf);
|
||||
void getNeighbors(OstEmul::DeviceNeighborList *neighbors);
|
||||
@ -69,6 +71,7 @@ public:
|
||||
private: // methods
|
||||
void receiveArp(PacketBuffer *pktBuf);
|
||||
void sendArpRequest(PacketBuffer *pktBuf);
|
||||
void sendArpRequest(quint32 tgtIp);
|
||||
|
||||
void receiveIp4(PacketBuffer *pktBuf);
|
||||
void sendIp4Reply(PacketBuffer *pktBuf);
|
||||
@ -83,6 +86,7 @@ private: // methods
|
||||
|
||||
void receiveNdp(PacketBuffer *pktBuf);
|
||||
void sendNeighborSolicit(PacketBuffer *pktBuf);
|
||||
void sendNeighborSolicit(UInt128 tgtIp);
|
||||
void sendNeighborAdvertisement(PacketBuffer *pktBuf);
|
||||
|
||||
private: // data
|
||||
|
@ -260,6 +260,13 @@ void DeviceManager::transmitPacket(PacketBuffer *pktBuf)
|
||||
port_->sendEmulationPacket(pktBuf);
|
||||
}
|
||||
|
||||
void DeviceManager::resolveDeviceGateways()
|
||||
{
|
||||
foreach(Device *device, deviceList_) {
|
||||
device->resolveGateway();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceManager::clearDeviceNeighbors()
|
||||
{
|
||||
foreach(Device *device, deviceList_)
|
||||
|
@ -52,6 +52,8 @@ public:
|
||||
void receivePacket(PacketBuffer *pktBuf);
|
||||
void transmitPacket(PacketBuffer *pktBuf);
|
||||
|
||||
void resolveDeviceGateways();
|
||||
|
||||
void clearDeviceNeighbors();
|
||||
void resolveDeviceNeighbor(PacketBuffer *pktBuf);
|
||||
void getDeviceNeighbors(OstProto::PortNeighborList *neighborList);
|
||||
|
@ -594,7 +594,7 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
||||
print(cap_pkts)
|
||||
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])
|
||||
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
||||
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',
|
||||
'-Y', filter])
|
||||
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
|
||||
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:
|
||||
print('%s: %s %012x' %
|
||||
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||
str(ipaddress.ip_address(arp.ip4)),
|
||||
arp.mac))
|
||||
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
||||
resolved = True
|
||||
assert resolved
|
||||
@ -646,32 +645,36 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, dut_ip,
|
||||
for ndp in device.ndp:
|
||||
print('%s: %s %012x' %
|
||||
(str(ip6_address(dev_cfg.ip6)),
|
||||
str(ip6_address(ndp.ip6)),
|
||||
ndp.mac))
|
||||
str(ip6_address(ndp.ip6)), ndp.mac))
|
||||
if (ndp.ip6 == dev_cfg.ip6_default_gateway) and (ndp.mac):
|
||||
resolved = True
|
||||
assert resolved
|
||||
|
||||
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]
|
||||
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
||||
devices = neigh_list.Extensions[emul.devices]
|
||||
log.info('ARP/NDP Table on rx port')
|
||||
for dev_cfg, device in zip(device_config, devices):
|
||||
# verify *no* ARPs/NDPs learnt on rx port
|
||||
if has_ip4:
|
||||
resolved = False
|
||||
for arp in device.arp:
|
||||
print('%s: %s %012x' %
|
||||
(str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||
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:
|
||||
resolved = False
|
||||
for ndp in device.ndp:
|
||||
print('%s: %s %012x' %
|
||||
(str(ip6_address(dev_cfg.ip6)),
|
||||
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
|
||||
for i in range(num_devs):
|
||||
@ -998,8 +1001,8 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
||||
print(cap_pkts)
|
||||
assert cap_pkts.count('\n') == 1
|
||||
|
||||
# verify *no* ARP/NDP Requests sent out from rx port
|
||||
buff = drone.getCaptureBuffer(emul_ports.port_id[0])
|
||||
# verify ARP/NDP Requests sent out from rx port
|
||||
buff = drone.getCaptureBuffer(emul_ports.port_id[1])
|
||||
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
||||
log.info('dumping Rx capture buffer (all)')
|
||||
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',
|
||||
'capture.pcap', '-Y', filter])
|
||||
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
|
||||
log.info('retrieving ARP/NDP entries on tx port')
|
||||
@ -1063,7 +1066,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
||||
assert resolved
|
||||
|
||||
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]
|
||||
neigh_list = drone.getDeviceNeighbors(emul_ports.port_id[1])
|
||||
devices = neigh_list.Extensions[emul.devices]
|
||||
@ -1072,19 +1075,24 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports,
|
||||
vlans = ''
|
||||
for v in dev_cfg.vlan:
|
||||
vlans += str(v & 0xffff) + ' '
|
||||
# verify *no* ARPs/NDPs learnt on rx port
|
||||
if has_ip4:
|
||||
resolved = False
|
||||
for arp in device.arp:
|
||||
print('%s%s: %s %012x' %
|
||||
(vlans, str(ipaddress.ip_address(dev_cfg.ip4)),
|
||||
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||
assert len(device.arp) == 0
|
||||
str(ipaddress.ip_address(arp.ip4)), arp.mac))
|
||||
if (arp.ip4 == dev_cfg.ip4_default_gateway) and (arp.mac):
|
||||
resolved = True
|
||||
assert resolved
|
||||
if has_ip6:
|
||||
resolved = False
|
||||
for ndp in device.ndp:
|
||||
print('%s%s: %s %012x' %
|
||||
(vlans, str(ip6_address(dev_cfg.ip6)),
|
||||
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
|
||||
for i in range(num_vlans):
|
||||
|
Loading…
Reference in New Issue
Block a user