Feature (contd.): Device Emulation - added test cases for multiple ip4 devices with and without VLANs; fixed bugs discovered via these cases

This commit is contained in:
Srivats P 2015-10-03 13:18:44 +05:30
parent 246bc95c74
commit 0c98e30a93
5 changed files with 397 additions and 114 deletions

View File

@ -130,7 +130,7 @@ void Device::encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type)
*(quint16*)(p + 10) = qToBigEndian(quint16(srcMac & 0xffff)); *(quint16*)(p + 10) = qToBigEndian(quint16(srcMac & 0xffff));
ofs = 12; ofs = 12;
for (int i = 0; i < numVlanTags_; i++) { for (int i = 0; i < numVlanTags_; i++) {
*(quint16*)(p + ofs) = qToBigEndian(quint32((0x8100 << 16)|vlan_[i])); *(quint32*)(p + ofs) = qToBigEndian(quint32((0x8100 << 16)|vlan_[i]));
ofs += 4; ofs += 4;
} }
*(quint16*)(p + ofs) = qToBigEndian(type); *(quint16*)(p + ofs) = qToBigEndian(type);
@ -166,6 +166,8 @@ void Device::receivePacket(PacketBuffer *pktBuf)
default: default:
break; break;
} }
// FIXME: temporary hack till DeviceManager clones pbufs
pktBuf->push(2);
} }
// //

View File

@ -169,7 +169,7 @@ _eth_type:
vlan = qFromBigEndian<quint16>(pktData + offset); vlan = qFromBigEndian<quint16>(pktData + offset);
dk.setVlan(idx++, vlan); dk.setVlan(idx++, vlan);
offset += 2; offset += 2;
qDebug("%s: idx: %d vlan 0x%x", __FUNCTION__, idx, vlan); qDebug("%s: idx: %d vlan %d", __FUNCTION__, idx, vlan);
goto _eth_type; goto _eth_type;
} }
@ -177,6 +177,11 @@ _eth_type:
if (dstMac == kBcastMac) { if (dstMac == kBcastMac) {
QList<Device*> list = bcastList_.values(dk.key()); QList<Device*> list = bcastList_.values(dk.key());
// FIXME: We need to clone the pktBuf before passing to each
// device, otherwise only the first device gets the original
// packet - all subsequent ones get the modified packet!
// NOTE: modification may not be in the pkt data buffer but
// in the HDTE pointers - which is bad as well!
foreach(Device *device, list) foreach(Device *device, list)
device->receivePacket(pktBuf); device->receivePacket(pktBuf);
goto _exit; goto _exit;
@ -228,7 +233,7 @@ void DeviceManager::enumerateDevices(
break; break;
case OstEmul::VlanEmulation::kRepeat: case OstEmul::VlanEmulation::kRepeat:
default: default:
vlanAdd %= vlan.count(); vlanAdd %= vlan.step() * vlan.count();
break; break;
} }
@ -237,8 +242,8 @@ void DeviceManager::enumerateDevices(
for (uint k = 0; k < pbDevice.count(); k++) { for (uint k = 0; k < pbDevice.count(); k++) {
Device *device; Device *device;
quint64 macAdd = i*k*pbDevice.mac().step(); quint64 macAdd = (i*pbDevice.count()+k)*pbDevice.mac().step();
quint32 ip4Add = i*k*pbDevice.ip4().step(); quint32 ip4Add = (i*pbDevice.count()+k)*pbDevice.ip4().step();
switch (pbDevice.mode()) { switch (pbDevice.mode()) {
case OstEmul::Device::kNoRepeat: case OstEmul::Device::kNoRepeat:
@ -246,8 +251,8 @@ void DeviceManager::enumerateDevices(
break; break;
case OstEmul::Device::kRepeat: case OstEmul::Device::kRepeat:
default: default:
macAdd %= pbDevice.count(); macAdd %= pbDevice.mac().step() * pbDevice.count();
ip4Add %= pbDevice.count(); ip4Add %= pbDevice.ip4().step() * pbDevice.count();
break; break;
} }
@ -265,12 +270,12 @@ void DeviceManager::enumerateDevices(
dk.setMac(kBcastMac); dk.setMac(kBcastMac);
bcastList_.insert(dk.key(), device); bcastList_.insert(dk.key(), device);
qDebug("enumerate (add): %s", qPrintable(device->config())); qDebug("enumerate(add): %s", qPrintable(device->config()));
break; break;
case kDelete: case kDelete:
device = deviceList_.take(dk.key()); device = deviceList_.take(dk.key());
qDebug("enumerate (del): %s", qPrintable(device->config())); qDebug("enumerate(del): %s", qPrintable(device->config()));
delete device; delete device;
dk.setMac(kBcastMac); dk.setMac(kBcastMac);

View File

@ -918,6 +918,7 @@ void PcapPort::PortReceiver::run()
int flag = PCAP_OPENFLAG_PROMISCUOUS; int flag = PCAP_OPENFLAG_PROMISCUOUS;
char errbuf[PCAP_ERRBUF_SIZE] = ""; char errbuf[PCAP_ERRBUF_SIZE] = "";
struct bpf_program bpf; struct bpf_program bpf;
const char *capture_filter = "arp or (vlan and arp)";
const int optimize = 1; const int optimize = 1;
qDebug("In %s", __PRETTY_FUNCTION__); qDebug("In %s", __PRETTY_FUNCTION__);
@ -947,7 +948,7 @@ _retry:
} }
// FIXME: hardcoded filter // FIXME: hardcoded filter
if (pcap_compile(handle_, &bpf, "arp", optimize, 0) < 0) if (pcap_compile(handle_, &bpf, capture_filter, optimize, 0) < 0)
{ {
qWarning("%s: error compiling filter: %s", qPrintable(device_), qWarning("%s: error compiling filter: %s", qPrintable(device_),
pcap_geterr(handle_)); pcap_geterr(handle_));

View File

@ -3,18 +3,20 @@
# standard modules # standard modules
import logging import logging
import os import os
import re
import subprocess import subprocess
import sys import sys
import time import time
from fabric.api import run, env, sudo from fabric.api import run, env, sudo
from harness import Test, TestSuite from harness import Test, TestSuite, TestPreRequisiteError
sys.path.insert(1, '../binding') sys.path.insert(1, '../binding')
from core import ost_pb, emul, DroneProxy from core import ost_pb, emul, DroneProxy
from rpc import RpcError from rpc import RpcError
from protocols.mac_pb2 import mac from protocols.mac_pb2 import mac
from protocols.ip4_pb2 import ip4, Ip4 from protocols.ip4_pb2 import ip4, Ip4
from protocols.vlan_pb2 import vlan
use_defaults = False use_defaults = False
@ -22,7 +24,6 @@ use_defaults = False
host_name = '127.0.0.1' host_name = '127.0.0.1'
tx_port_number = -1 tx_port_number = -1
rx_port_number = -1 rx_port_number = -1
#FIXME:drone_version = ['0', '0', '0']
if sys.platform == 'win32': if sys.platform == 'win32':
tshark = r'C:\Program Files\Wireshark\tshark.exe' tshark = r'C:\Program Files\Wireshark\tshark.exe'
@ -70,19 +71,23 @@ suite = TestSuite()
if not use_defaults: if not use_defaults:
s = raw_input('Drone\'s Hostname/IP [%s]: ' % (host_name)) s = raw_input('Drone\'s Hostname/IP [%s]: ' % (host_name))
host_name = s or host_name host_name = s or host_name
drone = DroneProxy(host_name) drone = DroneProxy(host_name)
try: try:
# ----------------------------------------------------------------- # # ----------------------------------------------------------------- #
# Baseline Configuration for subsequent testcases # Baseline Configuration for subsequent testcases
# NOTES
# * All test cases will emulate devices on both rx and tx ports
# * Each test case will create traffic streams corresponding to
# the devices to check
# ----------------------------------------------------------------- # # ----------------------------------------------------------------- #
# FIXME: get inputs for dut rx/tx ports # FIXME: get inputs for dut rx/tx ports
# configure the DUT # Enable IP forwarding on the DUT (aka make it a router)
sudo('sysctl -w net.ipv4.ip_forward=1') sudo('sysctl -w net.ipv4.ip_forward=1')
sudo('ifconfig ' + dut_rx_port + ' 10.10.1.1 netmask 255.255.255.0')
sudo('ifconfig ' + dut_tx_port + ' 10.10.2.1 netmask 255.255.255.0')
# connect to drone # connect to drone
log.info('connecting to drone(%s:%d)' log.info('connecting to drone(%s:%d)'
@ -135,62 +140,38 @@ try:
rx_port = ost_pb.PortIdList() rx_port = ost_pb.PortIdList()
rx_port.port_id.add().id = rx_port_number; rx_port.port_id.add().id = rx_port_number;
#---------------------------------------------# # ----------------------------------------------------------------- #
# configure emulated device(s) on tx/rx ports # # create emulated device(s) on tx/rx ports - each test case will
#---------------------------------------------# # modify and reuse these devices as per its needs
# ----------------------------------------------------------------- #
# delete existing devices, if any, on tx port # delete existing devices, if any, on tx port
dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0]) tx_dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0])
drone.deleteDeviceGroup(dgid_list) drone.deleteDeviceGroup(tx_dgid_list)
# add a emulated device on tx port # add a emulated device on tx port
dgid_list = ost_pb.DeviceGroupIdList() tx_dgid_list = ost_pb.DeviceGroupIdList()
dgid_list.port_id.CopyFrom(tx_port.port_id[0]) tx_dgid_list.port_id.CopyFrom(tx_port.port_id[0])
dgid_list.device_group_id.add().id = 1 tx_dgid_list.device_group_id.add().id = 1
log.info('adding tx device_group %d' % dgid_list.device_group_id[0].id) log.info('adding tx device_group %d' % tx_dgid_list.device_group_id[0].id)
drone.addDeviceGroup(dgid_list) drone.addDeviceGroup(tx_dgid_list)
# configure the device
devgrp_cfg = ost_pb.DeviceGroupConfigList()
devgrp_cfg.port_id.CopyFrom(tx_port.port_id[0])
dg = devgrp_cfg.device_group.add()
dg.device_group_id.id = dgid_list.device_group_id[0].id
dg.core.name = "Host1"
d = dg.Extensions[emul.device]
d.mac.address = 0x000102030001
d.ip4.address = 0x0a0a0164
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0101
drone.modifyDeviceGroup(devgrp_cfg)
# delete existing devices, if any, on rx port # delete existing devices, if any, on rx port
dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0]) rx_dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0])
drone.deleteDeviceGroup(dgid_list) drone.deleteDeviceGroup(rx_dgid_list)
# add a emulated device on rx port # add a emulated device on rx port
dgid_list = ost_pb.DeviceGroupIdList() rx_dgid_list = ost_pb.DeviceGroupIdList()
dgid_list.port_id.CopyFrom(rx_port.port_id[0]) rx_dgid_list.port_id.CopyFrom(rx_port.port_id[0])
dgid_list.device_group_id.add().id = 1 rx_dgid_list.device_group_id.add().id = 1
log.info('adding rx device_group %d' % dgid_list.device_group_id[0].id) log.info('adding rx device_group %d' % rx_dgid_list.device_group_id[0].id)
drone.addDeviceGroup(dgid_list) drone.addDeviceGroup(rx_dgid_list)
# configure the device # ----------------------------------------------------------------- #
devgrp_cfg = ost_pb.DeviceGroupConfigList() # create stream on tx port - each test case will modify and reuse
devgrp_cfg.port_id.CopyFrom(rx_port.port_id[0]) # this stream as per its needs
dg = devgrp_cfg.device_group.add() # ----------------------------------------------------------------- #
dg.device_group_id.id = dgid_list.device_group_id[0].id
dg.core.name = "Host1"
d = dg.Extensions[emul.device]
d.mac.address = 0x000102030002
d.ip4.address = 0x0a0a0264
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0201
drone.modifyDeviceGroup(devgrp_cfg)
#--------------------------------------#
# configure traffic stream(s)
#--------------------------------------#
# delete existing streams, if any, on tx port # delete existing streams, if any, on tx port
sid_list = drone.getStreamIdList(tx_port.port_id[0]) sid_list = drone.getStreamIdList(tx_port.port_id[0])
drone.deleteStream(sid_list) drone.deleteStream(sid_list)
@ -202,57 +183,109 @@ try:
log.info('adding tx_stream %d' % stream_id.stream_id[0].id) log.info('adding tx_stream %d' % stream_id.stream_id[0].id)
drone.addStream(stream_id) drone.addStream(stream_id)
# configure the stream # ================================================================= #
stream_cfg = ost_pb.StreamConfigList() # ----------------------------------------------------------------- #
stream_cfg.port_id.CopyFrom(tx_port.port_id[0]) # TEST CASES
s = stream_cfg.stream.add() # ----------------------------------------------------------------- #
s.stream_id.id = stream_id.stream_id[0].id # ================================================================= #
s.core.is_enabled = True
#s.core.frame_len = 128
s.control.packets_per_sec = 20
s.control.num_packets = 10
# setup stream protocols as mac:eth2:ip4:udp:payload
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kMacFieldNumber
p.Extensions[mac].dst_mac = 0x0800278df2b4 #FIXME: hardcoding
p.Extensions[mac].src_mac = 0x00aabbccddee
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber
# reduce typing by creating a shorter reference to p.Extensions[ip4]
ip = p.Extensions[ip4]
ip.src_ip = 0x0a0a0164
ip.dst_ip = 0x0a0a0264
s.protocol.add().protocol_id.id = ost_pb.Protocol.kUdpFieldNumber
s.protocol.add().protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber
log.info('configuring tx_stream %d' % stream_id.stream_id[0].id)
drone.modifyStream(stream_cfg)
# all test cases will use this stream by modifying it as per its needs
# clear tx/rx stats
log.info('clearing tx/rx stats')
drone.clearStats(tx_port)
drone.clearStats(rx_port)
# ----------------------------------------------------------------- # # ----------------------------------------------------------------- #
# TESTCASE: FIXME # TESTCASE: Emulate multiple IPv4 devices (no vlans)
# DUT
# /.1 \.1
# / \
# 10.10.1/24 10.10.2/24
# / \
# /.101-105 \.101-105
# Host1(s) Host2(s)
# ----------------------------------------------------------------- # # ----------------------------------------------------------------- #
passed = False passed = False
suite.test_begin('startTransmitDuringTransmitIsNopNotRestart') suite.test_begin('multiEmulDev')
# clear arp on DUT
sudo('arp -d ' + '10.10.1.100', warn_only=True) num_devs = 5
sudo('arp -d ' + '10.10.2.100', warn_only=True)
run('arp -a')
drone.startCapture(rx_port)
drone.startTransmit(tx_port)
try: try:
# configure the DUT
sudo('ip address add 10.10.1.1/24 dev ' + dut_rx_port)
sudo('ip address add 10.10.2.1/24 dev ' + dut_tx_port)
# configure the tx device(s)
devgrp_cfg = ost_pb.DeviceGroupConfigList()
devgrp_cfg.port_id.CopyFrom(tx_port.port_id[0])
dg = devgrp_cfg.device_group.add()
dg.device_group_id.id = tx_dgid_list.device_group_id[0].id
dg.core.name = "Host1"
d = dg.Extensions[emul.device]
d.count = num_devs
d.mac.address = 0x000102030a01
d.ip4.address = 0x0a0a0165
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0101
drone.modifyDeviceGroup(devgrp_cfg)
# configure the rx device(s)
devgrp_cfg = ost_pb.DeviceGroupConfigList()
devgrp_cfg.port_id.CopyFrom(rx_port.port_id[0])
dg = devgrp_cfg.device_group.add()
dg.device_group_id.id = rx_dgid_list.device_group_id[0].id
dg.core.name = "Host1"
d = dg.Extensions[emul.device]
d.count = num_devs
d.mac.address = 0x000102030b01
d.ip4.address = 0x0a0a0265
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0201
drone.modifyDeviceGroup(devgrp_cfg)
# configure the tx stream
stream_cfg = ost_pb.StreamConfigList()
stream_cfg.port_id.CopyFrom(tx_port.port_id[0])
s = stream_cfg.stream.add()
s.stream_id.id = stream_id.stream_id[0].id
s.core.is_enabled = True
s.control.packets_per_sec = 20
s.control.num_packets = 10
# setup stream protocols as mac:eth2:ip4:udp:payload
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kMacFieldNumber
p.Extensions[mac].dst_mac = 0x0800278df2b4 #FIXME: hardcoding
p.Extensions[mac].src_mac = 0x00aabbccddee
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber
ip = p.Extensions[ip4]
ip.src_ip = 0x0a0a0165
ip.src_ip_mode = Ip4.e_im_inc_host
ip.src_ip_count = num_devs
ip.dst_ip = 0x0a0a0265
ip.dst_ip_mode = Ip4.e_im_inc_host
ip.dst_ip_count = num_devs
s.protocol.add().protocol_id.id = ost_pb.Protocol.kUdpFieldNumber
s.protocol.add().protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber
log.info('configuring tx_stream %d' % stream_id.stream_id[0].id)
drone.modifyStream(stream_cfg)
# clear tx/rx stats
log.info('clearing tx/rx stats')
drone.clearStats(tx_port)
drone.clearStats(rx_port)
# clear arp on DUT
sudo('ip neigh flush all')
arp_cache = run('ip neigh show')
if re.search('10.10.2.10[1-5].*lladdr', arp_cache):
raise TestPreRequisiteError('ARP cache not cleared')
drone.startCapture(rx_port)
drone.startTransmit(tx_port)
log.info('waiting for transmit to finish ...') log.info('waiting for transmit to finish ...')
time.sleep(7) time.sleep(7)
drone.stopTransmit(tx_port) drone.stopTransmit(tx_port)
@ -260,26 +293,261 @@ try:
buff = drone.getCaptureBuffer(rx_port.port_id[0]) buff = drone.getCaptureBuffer(rx_port.port_id[0])
drone.saveCaptureBuffer(buff, 'capture.pcap') drone.saveCaptureBuffer(buff, 'capture.pcap')
log.info('dumping Rx capture buffer') log.info('dumping Rx capture buffer (all)')
cap_pkts = subprocess.check_output([tshark, '-r', 'capture.pcap']) cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap'])
print(cap_pkts) print(cap_pkts)
if '10.10.2.100' in cap_pkts: log.info('dumping Rx capture buffer (filtered)')
fail = 0
for i in range(num_devs):
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap',
'-R', '(ip.src == 10.10.1.' + str(101+i) + ') '
' && (ip.dst == 10.10.2.' + str(101+i) + ')'
' && (eth.dst == 00:01:02:03:0b:'
+ format(1+i, '02x')+')'])
print(cap_pkts)
if cap_pkts.count('\n') != s.control.num_packets/ip.src_ip_count:
fail = fail + 1
if fail == 0:
passed = True passed = True
os.remove('capture.pcap') os.remove('capture.pcap')
except RpcError as e: except RpcError as e:
raise raise
finally: finally:
drone.stopTransmit(tx_port) drone.stopTransmit(tx_port)
run('arp -a') run('ip neigh show')
# unconfigure DUT
sudo('ip address delete 10.10.1.1/24 dev ' + dut_rx_port)
sudo('ip address delete 10.10.2.1/24 dev ' + dut_tx_port)
suite.test_end(passed) suite.test_end(passed)
# ----------------------------------------------------------------- #
# TESTCASE: Emulate multiple IPv4 device per multiple single-tag VLANs
#
# +- DUT -+
# .1/ \.1
# / \
# 10.1.1/24 10.1.2/24
# v[201-205] v[201-205]
# / \
# /.101-103 \.101-103
# Host1(s) Host2(s)
# ----------------------------------------------------------------- #
passed = False
suite.test_begin('multiEmulDevPerVlan')
num_vlans = 5
vlan_base = 201
num_devs = 3
dev_ip_base = 101
try:
# configure the DUT
for i in range(num_vlans):
vlan_id = vlan_base+i
vrf = 'v' + str(vlan_id)
vlan_rx_dev = dut_rx_port + '.' + str(vlan_id)
vlan_tx_dev = dut_tx_port + '.' + str(vlan_id)
sudo('ip netns add ' + vrf)
sudo('ip link add link ' + dut_rx_port
+ ' name ' + vlan_rx_dev
+ ' type vlan id ' + str(vlan_id))
sudo('ip link set ' + vlan_rx_dev
+ ' netns ' + vrf)
sudo('ip netns exec ' + vrf
+ ' ip addr add 10.1.1.1/24'
+ ' dev ' + vlan_rx_dev)
sudo('ip netns exec ' + vrf
+ ' ip link set ' + vlan_rx_dev + ' up')
sudo('ip link add link ' + dut_tx_port
+ ' name ' + vlan_tx_dev
+ ' type vlan id ' + str(vlan_id))
sudo('ip link set ' + vlan_tx_dev
+ ' netns ' + vrf)
sudo('ip netns exec ' + vrf
+ ' ip addr add 10.1.2.1/24'
+ ' dev ' + vlan_tx_dev)
sudo('ip netns exec ' + vrf
+ ' ip link set ' + vlan_tx_dev + ' up')
# configure the tx device(s)
devgrp_cfg = ost_pb.DeviceGroupConfigList()
devgrp_cfg.port_id.CopyFrom(tx_port.port_id[0])
dg = devgrp_cfg.device_group.add()
dg.device_group_id.id = tx_dgid_list.device_group_id[0].id
dg.core.name = "Host1"
v = dg.Extensions[emul.vlan].stack.add()
v.vlan_tag = vlan_base
v.count = num_vlans
d = dg.Extensions[emul.device]
d.count = num_devs
d.mac.address = 0x000102030a01
d.ip4.address = 0x0a010165
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0101
drone.modifyDeviceGroup(devgrp_cfg)
# configure the rx device(s)
devgrp_cfg = ost_pb.DeviceGroupConfigList()
devgrp_cfg.port_id.CopyFrom(rx_port.port_id[0])
dg = devgrp_cfg.device_group.add()
dg.device_group_id.id = rx_dgid_list.device_group_id[0].id
dg.core.name = "Host1"
v = dg.Extensions[emul.vlan].stack.add()
v.vlan_tag = vlan_base
v.count = num_vlans
d = dg.Extensions[emul.device]
d.count = num_devs
#d.mode = emul.Device.kNoRepeat
d.mac.address = 0x000102030b01
d.ip4.address = 0x0a010265
d.ip4.prefix_length = 24
d.ip4.default_gateway = 0x0a0a0201
drone.modifyDeviceGroup(devgrp_cfg)
# configure the tx stream(s)
# we need more than one stream, so delete old one
# and create as many as we need
# FIXME: restore the single stream at end?
log.info('deleting tx_stream %d' % stream_id.stream_id[0].id)
drone.deleteStream(stream_id)
stream_id = ost_pb.StreamIdList()
stream_id.port_id.CopyFrom(tx_port.port_id[0])
for i in range(num_vlans):
stream_id.stream_id.add().id = i
log.info('adding tx_stream %d' % stream_id.stream_id[i].id)
drone.addStream(stream_id)
stream_cfg = ost_pb.StreamConfigList()
stream_cfg.port_id.CopyFrom(tx_port.port_id[0])
for i in range(num_vlans):
s = stream_cfg.stream.add()
s.stream_id.id = stream_id.stream_id[i].id
s.core.is_enabled = True
s.core.ordinal = i
s.control.packets_per_sec = 10
s.control.num_packets = num_devs
# setup stream protocols as mac:vlan:eth2:ip4:udp:payload
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kMacFieldNumber
p.Extensions[mac].dst_mac = 0x0800278df2b4 #FIXME: hardcoding
p.Extensions[mac].src_mac = 0x00aabbccddee
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kVlanFieldNumber
p.Extensions[vlan].vlan_tag = vlan_base+i
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kIp4FieldNumber
ip = p.Extensions[ip4]
ip.src_ip = 0x0a010165
ip.src_ip_mode = Ip4.e_im_inc_host
ip.dst_ip = 0x0a010265
ip.dst_ip_mode = Ip4.e_im_inc_host
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kUdpFieldNumber
p = s.protocol.add()
p.protocol_id.id = ost_pb.Protocol.kPayloadFieldNumber
log.info('configuring tx_stream %d' % stream_id.stream_id[0].id)
drone.modifyStream(stream_cfg)
# clear tx/rx stats
log.info('clearing tx/rx stats')
drone.clearStats(tx_port)
drone.clearStats(rx_port)
# clear arp on DUT
for i in range(num_vlans):
vlan_id = vlan_base + i
vrf = 'v' + str(vlan_id)
vlan_rx_dev = dut_rx_port + '.' + str(vlan_id)
vlan_tx_dev = dut_tx_port + '.' + str(vlan_id)
sudo('ip netns exec ' + vrf
+ ' ip neigh flush dev ' + vlan_rx_dev)
sudo('ip netns exec ' + vrf
+ ' ip neigh flush dev ' + vlan_tx_dev)
sudo('ip netns exec ' + vrf
+ ' ip neigh show')
drone.startCapture(rx_port)
drone.startTransmit(tx_port)
log.info('waiting for transmit to finish ...')
time.sleep(5)
drone.stopTransmit(tx_port)
drone.stopCapture(rx_port)
buff = drone.getCaptureBuffer(rx_port.port_id[0])
drone.saveCaptureBuffer(buff, 'capture.pcap')
log.info('dumping Rx capture buffer (all)')
cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap'])
print(cap_pkts)
log.info('dumping Rx capture buffer (filtered)')
fail = 0
for i in range(num_vlans):
for j in range(num_devs):
cap_pkts = subprocess.check_output(
[tshark, '-nr', 'capture.pcap',
'-R', '(vlan.id == ' + str(201+i) + ')'
' && (ip.src == 10.1.1.' + str(101+j) + ') '
' && (ip.dst == 10.1.2.' + str(101+j) + ')'
' && (eth.dst == 00:01:02:03:0b:'
+ format(1+j, '02x')+')'])
print(cap_pkts)
if cap_pkts.count('\n') != 1:
fail = fail + 1
if fail == 0:
passed = True
os.remove('capture.pcap')
except RpcError as e:
raise
finally:
drone.stopTransmit(tx_port)
# show arp on DUT
for i in range(num_vlans):
vrf = 'v' + str(vlan_base + i)
sudo('ip netns exec ' + vrf
+ ' ip neigh show')
# un-configure the DUT
for i in range(num_vlans):
vlan_id = vlan_base + i
vrf = 'v' + str(vlan_id)
sudo('ip netns delete ' + vrf)
suite.test_end(passed)
# TODO:
# ----------------------------------------------------------------- #
# TESTCASE: Emulate one IPv4 device per multiple double-tag VLANs
# vlanMode: repeat (default)
# TESTCASE: Emulate multiple IPv4 devices per multiple double-tag VLANs
# vlanMode: no-repeat; ip4Mode: repeat (default)
# TESTCASE: Emulate multiple IPv4 devices per multiple quad-tag VLANs
# vlanMode: repeat (default); ip4Mode: repeat (default)
# TESTCASE: Emulate multiple IPv4 devices per multiple quad-tag VLANs
# vlanMode: no-repeat; ip4Mode: no-repeat
# ----------------------------------------------------------------- #
suite.complete() suite.complete()
# delete streams # delete stream(s)
log.info('deleting tx_stream %d' % stream_id.stream_id[0].id) log.info('deleting tx_stream %d' % stream_id.stream_id[0].id)
drone.deleteStream(stream_id) drone.deleteStream(stream_id)
# delete devices # delete device(s)
dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0]) dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0])
drone.deleteDeviceGroup(dgid_list) drone.deleteDeviceGroup(dgid_list)
dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0]) dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0])
@ -287,6 +555,7 @@ try:
# bye for now # bye for now
drone.disconnect() drone.disconnect()
#disconnect_all()
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)

View File

@ -46,6 +46,12 @@ class TestSuite:
def passed(self): def passed(self):
return passed == total and self.completed return passed == total and self.completed
class TestPreRequisiteError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
def extract_column(text, col): def extract_column(text, col):
"""Given a text table, return items in the specified column as a list""" """Given a text table, return items in the specified column as a list"""
lines = text.splitlines() lines = text.splitlines()