diff --git a/server/device.cpp b/server/device.cpp index c174f05..e4eadd7 100644 --- a/server/device.cpp +++ b/server/device.cpp @@ -51,7 +51,7 @@ Device::Device(DeviceManager *deviceManager) clearKey(); } -void Device::setVlan(int index, quint16 vlan) +void Device::setVlan(int index, quint16 vlan, quint16 tpid) { int ofs; @@ -61,7 +61,7 @@ void Device::setVlan(int index, quint16 vlan) return; } - vlan_[index] = vlan; + vlan_[index] = (tpid << 16) | vlan; ofs = index * sizeof(quint16); key_[ofs] = vlan >> 8; @@ -105,7 +105,30 @@ void Device::getConfig(OstEmul::Device *deviceConfig) QString Device::config() { return QString("") - .arg(vlan_[0]).arg(vlan_[1]).arg(vlan_[2]).arg(vlan_[3]) + .arg((vlan_[0] >> 16) != kVlanTpid ? + QString("0x%1-%2") + .arg(vlan_[0] >> 16, 4, kBaseHex, QChar('0')) + .arg(vlan_[0] & 0xFFFF) : + QString("%1") + .arg(vlan_[0] & 0xFFFF)) + .arg((vlan_[1] >> 16) != kVlanTpid ? + QString("0x%1-%2") + .arg(vlan_[1] >> 16, 4, kBaseHex, QChar('0')) + .arg(vlan_[1] & 0xFFFF) : + QString("%1") + .arg(vlan_[1] & 0xFFFF)) + .arg((vlan_[2] >> 16) != kVlanTpid ? + QString("0x%1-%2") + .arg(vlan_[2] >> 16, 4, kBaseHex, QChar('0')) + .arg(vlan_[2] & 0xFFFF) : + QString("%1") + .arg(vlan_[2] & 0xFFFF)) + .arg((vlan_[3] >> 16) != kVlanTpid ? + QString("0x%1-%2") + .arg(vlan_[3] >> 16, 4, kBaseHex, QChar('0')) + .arg(vlan_[3] & 0xFFFF) : + QString("%1") + .arg(vlan_[3] & 0xFFFF)) .arg(mac_, 12, kBaseHex, QChar('0')) .arg(QHostAddress(ip4_).toString()) .arg(ip4PrefixLength_); @@ -147,7 +170,7 @@ void Device::encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type) *(quint16*)(p + 10) = qToBigEndian(quint16(srcMac & 0xffff)); ofs = 12; for (int i = 0; i < numVlanTags_; i++) { - *(quint32*)(p + ofs) = qToBigEndian(quint32((0x8100 << 16)|vlan_[i])); + *(quint32*)(p + ofs) = qToBigEndian(vlan_[i]); ofs += 4; } *(quint16*)(p + ofs) = qToBigEndian(type); diff --git a/server/device.h b/server/device.h index 4ef0192..4e173ae 100644 --- a/server/device.h +++ b/server/device.h @@ -35,10 +35,13 @@ class DeviceKey: public QByteArray class Device { +public: + static const quint16 kVlanTpid = 0x8100; + public: Device(DeviceManager *deviceManager); - void setVlan(int index, quint16 vlan); + void setVlan(int index, quint16 vlan, quint16 tpid = kVlanTpid); quint64 mac(); void setMac(quint64 mac); void setIp4(quint32 address, int prefixLength, quint32 gateway); @@ -71,7 +74,7 @@ private: // data DeviceManager *deviceManager_; int numVlanTags_; - quint16 vlan_[kMaxVlan]; // FIXME: vlan tpid + quint32 vlan_[kMaxVlan]; quint64 mac_; quint32 ip4_; int ip4PrefixLength_; diff --git a/server/devicemanager.cpp b/server/devicemanager.cpp index 79b3444..f28e4e5 100644 --- a/server/devicemanager.cpp +++ b/server/devicemanager.cpp @@ -192,7 +192,7 @@ _eth_type: ethType = qFromBigEndian(pktData + offset); qDebug("%s: ethType 0x%x", __PRETTY_FUNCTION__, ethType); - if (ethType == 0x8100) { + if (tpidList_.contains(ethType)) { offset += 2; vlan = qFromBigEndian(pktData + offset); dk.setVlan(idx++, vlan); @@ -296,7 +296,7 @@ _eth_type: ethType = qFromBigEndian(pktData + offset); qDebug("%s: ethType 0x%x", __PRETTY_FUNCTION__, ethType); - if (ethType == 0x8100) { + if (tpidList_.contains(ethType)) { offset += 2; vlan = qFromBigEndian(pktData + offset); dk.setVlan(idx++, vlan); @@ -372,8 +372,30 @@ void DeviceManager::enumerateDevices( */ vlanCount.append(n); for (int i = numTags - 1; i >= 0 ; i--) { - n *= pbVlan.stack(i).count(); + OstEmul::VlanEmulation::Vlan vlan = pbVlan.stack(i); + n *= vlan.count(); vlanCount.prepend(n); + + // Update TPID list + switch (oper) { + case kAdd: + tpidList_[vlan.tpid()]++; + break; + case kDelete: + tpidList_[vlan.tpid()]--; + if (tpidList_[vlan.tpid()] == 0) + tpidList_.remove(vlan.tpid()); + break; + default: + Q_ASSERT(0); // Unreachable + } + } + + QHash::const_iterator iter = tpidList_.constBegin(); + qDebug("Port %s TPID List:", port_->name()); + while (iter != tpidList_.constEnd()) { + qDebug("tpid: %x (%d)", iter.key(), iter.value()); + iter++; } for (int i = 0; i < vlanCount.at(0); i++) { @@ -381,7 +403,7 @@ void DeviceManager::enumerateDevices( OstEmul::VlanEmulation::Vlan vlan = pbVlan.stack(j); quint16 vlanAdd = (i/vlanCount.at(j+1) % vlan.count())*vlan.step(); - dk.setVlan(j, vlan.vlan_tag() + vlanAdd); + dk.setVlan(j, vlan.vlan_tag() + vlanAdd, vlan.tpid()); } for (uint k = 0; k < deviceGroup->device_count(); k++) { diff --git a/server/devicemanager.h b/server/devicemanager.h index 8f2ca2f..e2658b9 100644 --- a/server/devicemanager.h +++ b/server/devicemanager.h @@ -71,6 +71,7 @@ private: QHash deviceGroupList_; QHash deviceList_; QMultiHash bcastList_; + QHash tpidList_; // Key: TPID, Value: RefCount }; #endif diff --git a/test/emultest.py b/test/emultest.py index 6ff15c4..b9786a3 100644 --- a/test/emultest.py +++ b/test/emultest.py @@ -261,10 +261,15 @@ def dut_vlans(request, dut_ports): for dev in devices.rx+devices.tx: for k in range(vcfg['count']): vlan_id = vcfg['base'] + k + if 'tpid' in vcfg and vcfg['tpid'] == 0x88a8: + tpid = '802.1ad' + else: + tpid = '802.1q' dev_name = dev + '.' + str(vlan_id) sudo('ip link add link ' + dev + ' name ' + dev_name - + ' type vlan id ' + str(vlan_id)) + + ' type vlan id ' + str(vlan_id) + + ' proto ' + tpid) sudo('ip link set ' + dev_name + ' up') if dev in devices.rx: new_devs.rx.append(dev_name) @@ -549,6 +554,9 @@ def test_multiEmulDevNoVlan(drone, ports, dut, dut_ports, stream_id, [{'base': 11, 'count': 2}, {'base': 21, 'count': 3}], + [{'base': 11, 'count': 2, 'tpid': 0x88a8}, + {'base': 21, 'count': 3}], + [{'base': 11, 'count': 2}, {'base': 21, 'count': 3}, {'base': 31, 'count': 2}], @@ -590,12 +598,15 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, vlan_filter.append('') ids = dut_vlans.vlans[i].split('.') for j in range(len(ids)): - filter = '(frame[:4]==8100:)' \ + filter = '(frame[:4]==:)' \ .replace('', str(12+j*4)) \ + .replace('', '{:04x}'.format( + vlan_cfg[j].get('tpid', 0x8100))) \ .replace('', '{:04x}'.format(int(ids[j]))) if len(vlan_filter[i]) > 0: vlan_filter[i] += ' && ' vlan_filter[i] += filter + print i, vlan_filter[i] # configure the tx device(s) devgrp_cfg = ost_pb.DeviceGroupConfigList() @@ -607,6 +618,8 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, v = dg.encap.Extensions[emul.vlan].stack.add() v.vlan_tag = vcfg['base'] v.count = vcfg['count'] + if 'tpid' in vcfg: + v.tpid = vcfg['tpid'] dg.device_count = num_devs_per_vlan dg.Extensions[emul.mac].address = 0x000102030a01 ip = dg.Extensions[emul.ip4] @@ -626,6 +639,8 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, v = dg.encap.Extensions[emul.vlan].stack.add() v.vlan_tag = vcfg['base'] v.count = vcfg['count'] + if 'tpid' in vcfg: + v.tpid = vcfg['tpid'] dg.device_count = num_devs_per_vlan dg.Extensions[emul.mac].address = 0x000102030b01 ip = dg.Extensions[emul.ip4] @@ -668,10 +683,13 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, p.Extensions[mac].src_mac_mode = Mac.e_mm_resolve ids = dut_vlans.vlans[i].split('.') - for id in ids: + for id, j in zip(ids, range(len(ids))): p = s.protocol.add() p.protocol_id.id = ost_pb.Protocol.kVlanFieldNumber p.Extensions[vlan].vlan_tag = int(id) + if 'tpid' in vlan_cfg[j]: + p.Extensions[vlan].tpid = vlan_cfg[j]['tpid'] + p.Extensions[vlan].is_override_tpid = True p = s.protocol.add() p.protocol_id.id = ost_pb.Protocol.kEth2FieldNumber @@ -721,7 +739,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, print(cap_pkts) log.info('dumping Tx capture buffer (all pkts - vlans only)') cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap', - '-Tfields', '-eframe.number', '-evlan.id']) + '-Tfields', '-eframe.number', '-eieee8021ad.id', '-evlan.id']) print(cap_pkts) log.info('dumping Tx capture buffer (filtered)') for i in range(num_vlans): @@ -743,7 +761,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, print(cap_pkts) log.info('dumping Rx capture buffer (all pkts - vlans only)') cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap', - '-Tfields', '-eframe.number', '-evlan.id']) + '-Tfields', '-eframe.number', '-eieee8021ad.id', '-evlan.id']) print(cap_pkts) log.info('dumping Rx capture buffer (filtered)') for i in range(num_vlans): @@ -804,7 +822,7 @@ def test_multiEmulDevPerVlan(request, drone, ports, dut, dut_ports, stream_id, print(cap_pkts) log.info('dumping Tx capture buffer (all pkts - vlans only)') cap_pkts = subprocess.check_output([tshark, '-nr', 'capture.pcap', - '-Tfields', '-eframe.number', '-evlan.id']) + '-Tfields', '-eframe.number', '-eieee8021ad.id', '-evlan.id']) print(cap_pkts) log.info('dumping Rx capture buffer (filtered)') for i in range(num_vlans):