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:
Srivats P 2016-01-28 20:01:19 +05:30
parent e3a3a0cf1f
commit f6c852495d
6 changed files with 84 additions and 39 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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_)

View File

@ -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);

View File

@ -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):