Feature (contd.): Device Emulation - user now configures a device group instead of a single device for easier creation of multiple devices; refactored and redistributed functionality between DeviceManager and Device; external functionality wise same as last commit; added initial code for vlans but not tested
This commit is contained in:
parent
ab433dc22b
commit
246bc95c74
@ -21,46 +21,74 @@ import "protocol.proto";
|
|||||||
|
|
||||||
package OstEmul;
|
package OstEmul;
|
||||||
|
|
||||||
message MacEmulation {
|
// ======
|
||||||
optional uint64 addr = 10;
|
// VLAN
|
||||||
}
|
// ======
|
||||||
|
|
||||||
extend OstProto.Device {
|
|
||||||
optional MacEmulation mac = 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
message VlanEmulation {
|
message VlanEmulation {
|
||||||
|
enum Mode {
|
||||||
|
kNoRepeat = 0;
|
||||||
|
kRepeat = 1;
|
||||||
|
}
|
||||||
message Vlan {
|
message Vlan {
|
||||||
optional uint32 tpid = 1 [default = 0x8100];
|
optional uint32 tpid = 1 [default = 0x8100];
|
||||||
optional uint32 vlan_tag = 2; // includes prio, cfi and vlanid
|
|
||||||
|
// includes prio, cfi and vlanid
|
||||||
|
optional uint32 vlan_tag = 2 [default = 100];
|
||||||
|
|
||||||
|
optional uint32 count = 10 [default = 1];
|
||||||
|
optional uint32 step = 11 [default = 1];
|
||||||
|
optional Mode mode = 12 [default = kRepeat];
|
||||||
}
|
}
|
||||||
// FIXME: rename as just stack?
|
|
||||||
repeated Vlan vlan_stack = 11; // outer to inner
|
repeated Vlan stack = 1; // outer to inner
|
||||||
}
|
}
|
||||||
|
|
||||||
extend OstProto.Device {
|
extend OstProto.DeviceGroup {
|
||||||
optional VlanEmulation vlan = 201;
|
optional VlanEmulation vlan = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========
|
||||||
|
// Device
|
||||||
|
// ========
|
||||||
|
message MacEmulation {
|
||||||
|
optional uint64 address = 1; // FIXME: default value
|
||||||
|
|
||||||
|
optional uint64 step = 10 [default = 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Ip4Emulation {
|
message Ip4Emulation {
|
||||||
optional uint32 addr = 2;
|
optional uint32 address = 1;
|
||||||
optional uint32 prefix_length = 3;
|
optional uint32 prefix_length = 2;
|
||||||
optional uint32 gateway = 4; // FIXME: rename to default_gateway?
|
optional uint32 default_gateway = 3;
|
||||||
}
|
|
||||||
|
|
||||||
extend OstProto.Device {
|
optional uint64 step = 10 [default = 1];
|
||||||
optional Ip4Emulation ip4 = 300;
|
// FIXME: step for gateway?
|
||||||
}
|
}
|
||||||
|
|
||||||
message Ip6Emulation {
|
message Ip6Emulation {
|
||||||
optional uint64 addr_hi = 31;
|
optional uint64 address_hi = 1;
|
||||||
optional uint64 addr_lo = 32;
|
optional uint64 address_lo = 2;
|
||||||
optional uint32 prefix_length = 33;
|
optional uint32 prefix_length = 3;
|
||||||
optional uint64 gateway_hi = 34;
|
optional uint64 default_gateway_hi = 4;
|
||||||
optional uint64 gateway_lo = 35;
|
optional uint64 default_gateway_lo = 5;
|
||||||
|
|
||||||
|
optional uint64 step_hi = 10 [default = 0];
|
||||||
|
optional uint64 step_lo = 11 [default = 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
extend OstProto.Device {
|
message Device {
|
||||||
optional Ip6Emulation ip6 = 301;
|
enum Mode {
|
||||||
|
kNoRepeat = 0;
|
||||||
|
kRepeat = 1;
|
||||||
|
}
|
||||||
|
optional MacEmulation mac = 1;
|
||||||
|
optional Ip4Emulation ip4 = 2;
|
||||||
|
optional Ip6Emulation ip6 = 3;
|
||||||
|
|
||||||
|
optional uint32 count = 10 [default = 1];
|
||||||
|
optional Mode mode = 11 [default = kRepeat]; // FIXME: per proto mode?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extend OstProto.DeviceGroup {
|
||||||
|
optional Device device = 201;
|
||||||
|
}
|
||||||
|
@ -278,32 +278,33 @@ message Notification {
|
|||||||
* Protocol Emulation
|
* Protocol Emulation
|
||||||
* FIXME: review/fix tag numbers
|
* FIXME: review/fix tag numbers
|
||||||
* FIXME: move xxxEmulation to their own .proto files?
|
* FIXME: move xxxEmulation to their own .proto files?
|
||||||
* FIXME: What will be the contents of a default device created by addDevice()?
|
* FIXME: What will be the contents of a default device created by addDeviceGroup()?
|
||||||
* FIXME: decide default values for device and protoEmulations
|
* FIXME: decide default values for device and protoEmulations
|
||||||
|
* FIXME: rename 'DeviceGroup'?
|
||||||
*/
|
*/
|
||||||
message DeviceId {
|
message DeviceGroupId {
|
||||||
required uint32 id = 1;
|
required uint32 id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceCore {
|
message DeviceGroupCore {
|
||||||
optional string name = 1;
|
optional string name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceIdList {
|
message DeviceGroupIdList {
|
||||||
required PortId port_id = 1;
|
required PortId port_id = 1;
|
||||||
repeated DeviceId device_id = 2;
|
repeated DeviceGroupId device_group_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Device {
|
message DeviceGroup {
|
||||||
required DeviceId device_id = 1;
|
required DeviceGroupId device_group_id = 1;
|
||||||
optional DeviceCore core = 2;
|
optional DeviceGroupCore core = 2;
|
||||||
|
|
||||||
extensions 200 to 500; // For use by Protocol Emulations
|
extensions 200 to 500; // For use by Protocol Emulations
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceConfigList {
|
message DeviceGroupConfigList {
|
||||||
required PortId port_id = 1;
|
required PortId port_id = 1;
|
||||||
repeated Device device = 2;
|
repeated DeviceGroup device_group = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
service OstService {
|
service OstService {
|
||||||
@ -329,11 +330,11 @@ service OstService {
|
|||||||
|
|
||||||
rpc checkVersion(VersionInfo) returns (VersionCompatibility);
|
rpc checkVersion(VersionInfo) returns (VersionCompatibility);
|
||||||
|
|
||||||
// Device Protocol Emulation
|
// Device/Protocol Emulation
|
||||||
rpc getDeviceIdList(PortId) returns (DeviceIdList);
|
rpc getDeviceGroupIdList(PortId) returns (DeviceGroupIdList);
|
||||||
rpc getDeviceConfig(DeviceIdList) returns (DeviceConfigList);
|
rpc getDeviceGroupConfig(DeviceGroupIdList) returns (DeviceGroupConfigList);
|
||||||
rpc addDevice(DeviceIdList) returns (Ack);
|
rpc addDeviceGroup(DeviceGroupIdList) returns (Ack);
|
||||||
rpc deleteDevice(DeviceIdList) returns (Ack);
|
rpc deleteDeviceGroup(DeviceGroupIdList) returns (Ack);
|
||||||
rpc modifyDevice(DeviceConfigList) returns (Ack);
|
rpc modifyDeviceGroup(DeviceGroupConfigList) returns (Ack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,78 +23,99 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
#include "packetbuffer.h"
|
#include "packetbuffer.h"
|
||||||
|
|
||||||
|
#include <QHostAddress>
|
||||||
#include <qendian.h>
|
#include <qendian.h>
|
||||||
|
|
||||||
QHash<quint64, Device*> Device::macHash_;
|
const int kBaseHex = 16;
|
||||||
QHash<quint32, Device*> Device::ip4Hash_;
|
const int kMaxVlan = 4;
|
||||||
|
|
||||||
Device::Device(quint32 id, DeviceManager *deviceManager)
|
/*
|
||||||
|
* NOTE:
|
||||||
|
* 1. Device Key is (VLANS + MAC) - is assumed to be unique for a device
|
||||||
|
* 2. Device clients/users (viz. DeviceManager) should take care when
|
||||||
|
* setting params that change the key, if the key is used elsewhere
|
||||||
|
* (e.g. in a hash)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Device::Device(DeviceManager *deviceManager)
|
||||||
{
|
{
|
||||||
deviceManager_ = deviceManager;
|
deviceManager_ = deviceManager;
|
||||||
data_.mutable_device_id()->set_id(id);
|
|
||||||
// FIXME: choose a better default mac address
|
|
||||||
data_.MutableExtension(OstEmul::mac)->set_addr(0x001122330000ULL + id);
|
|
||||||
|
|
||||||
Device::macHash_.insert(myMac(), this);
|
for (int i = 0; i < kMaxVlan; i++)
|
||||||
|
vlan_[i] = 0;
|
||||||
|
numVlanTags_ = 0;
|
||||||
|
mac_ = 0;
|
||||||
|
ip4_ = 0;
|
||||||
|
ip4PrefixLength_ = 0;
|
||||||
|
|
||||||
|
clearKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device()
|
void Device::setVlan(int index, quint16 vlan)
|
||||||
{
|
{
|
||||||
macHash_.remove(myMac());
|
int ofs;
|
||||||
ip4Hash_.remove(myIp4());
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 Device::id()
|
if ((index < 0) || (index >= kMaxVlan)) {
|
||||||
{
|
qWarning("%s: vlan index %d out of range (0 - %d)", __FUNCTION__,
|
||||||
return data_.device_id().id();
|
index, kMaxVlan - 1);
|
||||||
}
|
return;
|
||||||
|
|
||||||
void Device::protoDataCopyFrom(const OstProto::Device &device)
|
|
||||||
{
|
|
||||||
quint64 oldMac, newMac;
|
|
||||||
quint32 oldIp4, newIp4;
|
|
||||||
|
|
||||||
// Save old mac and ip before updating the device data
|
|
||||||
oldMac = myMac();
|
|
||||||
oldIp4 = myIp4();
|
|
||||||
|
|
||||||
data_.CopyFrom(device);
|
|
||||||
|
|
||||||
// Get new mac and ip for comparison
|
|
||||||
newMac = myMac();
|
|
||||||
newIp4 = myIp4();
|
|
||||||
|
|
||||||
// Update MacHash if mac has changed
|
|
||||||
if (newMac != oldMac) {
|
|
||||||
macHash_.remove(oldMac);
|
|
||||||
macHash_.insert(newMac, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Ip4Hash if ip4 has changed
|
vlan_[index] = vlan;
|
||||||
if (newIp4 != oldIp4) {
|
|
||||||
ip4Hash_.remove(oldIp4);
|
ofs = index * sizeof(quint16);
|
||||||
ip4Hash_.insert(newIp4, this);
|
key_[ofs] = vlan >> 8;
|
||||||
}
|
key_[ofs+1] = vlan & 0xff;
|
||||||
|
|
||||||
|
if (index >= numVlanTags_)
|
||||||
|
numVlanTags_ = index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::protoDataCopyInto(OstProto::Device &device) const
|
void Device::setMac(quint64 mac)
|
||||||
{
|
{
|
||||||
device.CopyFrom(data_);
|
int ofs = kMaxVlan * sizeof(quint16);
|
||||||
|
|
||||||
|
mac_ = mac;
|
||||||
|
memcpy(key_.data() + ofs, (char*)&mac, sizeof(mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setIp4(quint32 address, int prefixLength)
|
||||||
|
{
|
||||||
|
ip4_ = address;
|
||||||
|
ip4PrefixLength_ = prefixLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Device::config()
|
||||||
|
{
|
||||||
|
return QString("<vlans=%1/%2/%3/%4 mac=%5 ip4=%6/%7>")
|
||||||
|
.arg(vlan_[0]).arg(vlan_[1]).arg(vlan_[2]).arg(vlan_[3])
|
||||||
|
.arg(mac_, 12, kBaseHex, QChar('0'))
|
||||||
|
.arg(QHostAddress(ip4_).toString())
|
||||||
|
.arg(ip4PrefixLength_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceKey Device::key()
|
||||||
|
{
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::clearKey()
|
||||||
|
{
|
||||||
|
key_.fill(0, kMaxVlan * sizeof(quint16) + sizeof(quint64));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Device::encapSize()
|
int Device::encapSize()
|
||||||
{
|
{
|
||||||
int size = 14; // ethernet header size
|
// ethernet header + vlans
|
||||||
|
int size = 14 + 4*numVlanTags_;
|
||||||
if (data_.HasExtension(OstEmul::vlan))
|
|
||||||
size += 4 * data_.GetExtension(OstEmul::vlan).vlan_stack_size();
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type)
|
void Device::encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type)
|
||||||
{
|
{
|
||||||
quint64 srcMac = myMac();
|
int ofs;
|
||||||
|
quint64 srcMac = mac_;
|
||||||
uchar *p = pktBuf->push(encapSize());
|
uchar *p = pktBuf->push(encapSize());
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
@ -107,90 +128,52 @@ void Device::encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type)
|
|||||||
*(quint16*)(p + 4) = qToBigEndian(quint16(dstMac & 0xffff));
|
*(quint16*)(p + 4) = qToBigEndian(quint16(dstMac & 0xffff));
|
||||||
*(quint32*)(p + 6) = qToBigEndian(quint32(srcMac >> 16));
|
*(quint32*)(p + 6) = qToBigEndian(quint32(srcMac >> 16));
|
||||||
*(quint16*)(p + 10) = qToBigEndian(quint16(srcMac & 0xffff));
|
*(quint16*)(p + 10) = qToBigEndian(quint16(srcMac & 0xffff));
|
||||||
// TODO: Vlan Encap
|
ofs = 12;
|
||||||
*(quint16*)(p + 12) = qToBigEndian(type);
|
for (int i = 0; i < numVlanTags_; i++) {
|
||||||
|
*(quint16*)(p + ofs) = qToBigEndian(quint32((0x8100 << 16)|vlan_[i]));
|
||||||
|
ofs += 4;
|
||||||
|
}
|
||||||
|
*(quint16*)(p + ofs) = qToBigEndian(type);
|
||||||
|
ofs += 2;
|
||||||
|
|
||||||
|
Q_ASSERT(ofs == encapSize());
|
||||||
|
|
||||||
_exit:
|
_exit:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Private Methods
|
|
||||||
//
|
|
||||||
quint64 Device::myMac()
|
|
||||||
{
|
|
||||||
if (data_.HasExtension(OstEmul::mac))
|
|
||||||
return data_.GetExtension(OstEmul::mac).addr();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 Device::myIp4()
|
|
||||||
{
|
|
||||||
if (data_.HasExtension(OstEmul::ip4))
|
|
||||||
return data_.GetExtension(OstEmul::ip4).addr();
|
|
||||||
|
|
||||||
return 0; // FIXME: how to indicate that we don't have a IP?
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::transmitPacket(PacketBuffer *pktBuf)
|
void Device::transmitPacket(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
deviceManager_->transmitPacket(pktBuf);
|
deviceManager_->transmitPacket(pktBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We expect pktBuf to point to EthType on entry
|
||||||
void Device::receivePacket(PacketBuffer *pktBuf)
|
void Device::receivePacket(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
uchar *pktData = pktBuf->data();
|
quint16 ethType = qFromBigEndian<quint16>(pktBuf->data());
|
||||||
int offset = 0;
|
pktBuf->pull(2);
|
||||||
Device *device;
|
|
||||||
const quint64 bcastMac = 0xffffffffffffULL;
|
|
||||||
quint64 dstMac;
|
|
||||||
quint16 ethType;
|
|
||||||
|
|
||||||
// We assume pkt is ethernet
|
qDebug("%s: ethType 0x%x", __PRETTY_FUNCTION__, ethType);
|
||||||
// TODO: extend for other link layer types
|
|
||||||
|
|
||||||
// Extract dstMac
|
|
||||||
dstMac = qFromBigEndian<quint32>(pktData + offset);
|
|
||||||
offset += 4;
|
|
||||||
dstMac = (dstMac << 16) | qFromBigEndian<quint16>(pktData + offset);
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
// Skip srcMac - don't care
|
|
||||||
offset += 6;
|
|
||||||
qDebug("dstMac %llx", dstMac);
|
|
||||||
|
|
||||||
// Is it destined for us?
|
|
||||||
device = macHash_.value(dstMac);
|
|
||||||
if (!device && (dstMac != bcastMac)) {
|
|
||||||
qDebug("%s: dstMac %llx is not us", __FUNCTION__, dstMac);
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ethType = qFromBigEndian<quint16>(pktData + offset);
|
|
||||||
offset += 2;
|
|
||||||
qDebug("%s: ethType 0x%x", __FUNCTION__, ethType);
|
|
||||||
|
|
||||||
switch(ethType)
|
switch(ethType)
|
||||||
{
|
{
|
||||||
case 0x0806: // ARP
|
case 0x0806: // ARP
|
||||||
pktBuf->pull(offset);
|
receiveArp(pktBuf);
|
||||||
receiveArp(device, pktBuf);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8100: // VLAN
|
|
||||||
case 0x0800: // IPv4
|
case 0x0800: // IPv4
|
||||||
case 0x86dd: // IPv6
|
case 0x86dd: // IPv6
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_exit:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::receiveArp(Device *device, PacketBuffer *pktBuf)
|
//
|
||||||
|
// Private Methods
|
||||||
|
//
|
||||||
|
void Device::receiveArp(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
|
PacketBuffer *rspPkt;
|
||||||
uchar *pktData = pktBuf->data();
|
uchar *pktData = pktBuf->data();
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
quint16 hwType, protoType;
|
quint16 hwType, protoType;
|
||||||
@ -199,6 +182,15 @@ void Device::receiveArp(Device *device, PacketBuffer *pktBuf)
|
|||||||
quint64 srcMac, tgtMac;
|
quint64 srcMac, tgtMac;
|
||||||
quint32 srcIp, tgtIp;
|
quint32 srcIp, tgtIp;
|
||||||
|
|
||||||
|
// Extract tgtIp first to check quickly if this packet is for us or not
|
||||||
|
tgtIp = qFromBigEndian<quint32>(pktData + 24);
|
||||||
|
if (tgtIp != ip4_) {
|
||||||
|
qDebug("tgtIp %s is not me %s",
|
||||||
|
qPrintable(QHostAddress(tgtIp).toString()),
|
||||||
|
qPrintable(QHostAddress(ip4_).toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Extract annd verify ARP packet contents
|
// Extract annd verify ARP packet contents
|
||||||
hwType = qFromBigEndian<quint16>(pktData + offset);
|
hwType = qFromBigEndian<quint16>(pktData + offset);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
@ -236,43 +228,33 @@ void Device::receiveArp(Device *device, PacketBuffer *pktBuf)
|
|||||||
tgtMac = (tgtMac << 16) | qFromBigEndian<quint16>(pktData + offset);
|
tgtMac = (tgtMac << 16) | qFromBigEndian<quint16>(pktData + offset);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
tgtIp = qFromBigEndian<quint32>(pktData + offset);
|
|
||||||
offset += 4;
|
|
||||||
|
|
||||||
switch (opCode)
|
switch (opCode)
|
||||||
{
|
{
|
||||||
case 1: // ARP Request
|
case 1: // ARP Request
|
||||||
if (!device)
|
rspPkt = new PacketBuffer;
|
||||||
device = ip4Hash_.value(tgtIp);
|
rspPkt->reserve(encapSize());
|
||||||
if (device->myIp4() == tgtIp) {
|
pktData = rspPkt->put(28);
|
||||||
PacketBuffer *pktBuf = new PacketBuffer;
|
if (pktData) {
|
||||||
uchar *p;
|
|
||||||
|
|
||||||
pktBuf->reserve(device->encapSize());
|
|
||||||
p = pktBuf->put(28); // FIXME: hardcoding
|
|
||||||
if (p) {
|
|
||||||
// HTYP, PTYP
|
// HTYP, PTYP
|
||||||
*(quint32*)(p ) = qToBigEndian(quint32(0x00010800));
|
*(quint32*)(pktData ) = qToBigEndian(quint32(0x00010800));
|
||||||
// HLEN, PLEN, OPER
|
// HLEN, PLEN, OPER
|
||||||
*(quint32*)(p+ 4) = qToBigEndian(quint32(0x06040002));
|
*(quint32*)(pktData+ 4) = qToBigEndian(quint32(0x06040002));
|
||||||
// Source H/W Addr, Proto Addr
|
// Source H/W Addr, Proto Addr
|
||||||
*(quint32*)(p+ 8) = qToBigEndian(
|
*(quint32*)(pktData+ 8) = qToBigEndian(quint32(mac_ >> 16));
|
||||||
quint32(device->myMac() >> 16));
|
*(quint16*)(pktData+12) = qToBigEndian(quint16(mac_ & 0xffff));
|
||||||
*(quint16*)(p+12) = qToBigEndian(
|
*(quint32*)(pktData+14) = qToBigEndian(ip4_);
|
||||||
quint16(device->myMac() & 0xffff));
|
|
||||||
*(quint32*)(p+14) = qToBigEndian(tgtIp);
|
|
||||||
// Target H/W Addr, Proto Addr
|
// Target H/W Addr, Proto Addr
|
||||||
*(quint32*)(p+18) = qToBigEndian(quint32(srcMac >> 16));
|
*(quint32*)(pktData+18) = qToBigEndian(quint32(srcMac >> 16));
|
||||||
*(quint16*)(p+22) = qToBigEndian(quint16(srcMac & 0xffff));
|
*(quint16*)(pktData+22) = qToBigEndian(quint16(srcMac & 0xffff));
|
||||||
*(quint32*)(p+24) = qToBigEndian(srcIp);
|
*(quint32*)(pktData+24) = qToBigEndian(srcIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
device->encap(pktBuf, srcMac, 0x0806);
|
encap(rspPkt, srcMac, 0x0806);
|
||||||
device->transmitPacket(pktBuf);
|
transmitPacket(rspPkt);
|
||||||
|
|
||||||
qDebug("Sent ARP Reply for srcIp/tgtIp=0x%x/0x%x",
|
qDebug("Sent ARP Reply for srcIp/tgtIp=%s/%s",
|
||||||
srcIp, tgtIp);
|
qPrintable(QHostAddress(srcIp).toString()),
|
||||||
}
|
qPrintable(QHostAddress(tgtIp).toString()));
|
||||||
break;
|
break;
|
||||||
case 2: // ARP Response
|
case 2: // ARP Response
|
||||||
default:
|
default:
|
||||||
|
@ -22,45 +22,45 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "../common/protocol.pb.h"
|
#include "../common/protocol.pb.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QByteArray>
|
||||||
|
|
||||||
class DeviceManager;
|
class DeviceManager;
|
||||||
class PacketBuffer;
|
class PacketBuffer;
|
||||||
|
|
||||||
|
typedef QByteArray DeviceKey;
|
||||||
|
|
||||||
class Device
|
class Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Device(quint32 id, DeviceManager *deviceManager);
|
Device(DeviceManager *deviceManager);
|
||||||
~Device();
|
|
||||||
|
|
||||||
quint32 id();
|
void setVlan(int index, quint16 vlan);
|
||||||
|
void setMac(quint64 mac);
|
||||||
|
void setIp4(quint32 address, int prefixLength);
|
||||||
|
QString config();
|
||||||
|
|
||||||
void protoDataCopyFrom(const OstProto::Device &device);
|
DeviceKey key();
|
||||||
void protoDataCopyInto(OstProto::Device &device) const;
|
void clearKey();
|
||||||
|
|
||||||
int encapSize();
|
int encapSize();
|
||||||
void encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type);
|
void encap(PacketBuffer *pktBuf, quint64 dstMac, quint16 type);
|
||||||
|
|
||||||
// receivePacket() is a class method 'coz we don't have the target
|
void receivePacket(PacketBuffer *pktBuf);
|
||||||
// device yet; transmitPacket() is always from a particular device
|
|
||||||
void transmitPacket(PacketBuffer *pktBuf);
|
void transmitPacket(PacketBuffer *pktBuf);
|
||||||
static void receivePacket(PacketBuffer *pktBuf);
|
|
||||||
|
|
||||||
private: // methods
|
private: // methods
|
||||||
// receiveArp() is a class method 'coz ARP request is broadcast, so
|
void receiveArp(PacketBuffer *pktBuf);
|
||||||
// we can't identify the target device till we parse the ARP header
|
|
||||||
static void receiveArp(Device *device, PacketBuffer *pktBuf);
|
|
||||||
|
|
||||||
quint64 myMac();
|
|
||||||
quint32 myIp4();
|
|
||||||
|
|
||||||
private: // data
|
private: // data
|
||||||
// Class data
|
|
||||||
static QHash<quint64, Device*> macHash_;
|
|
||||||
static QHash<quint32, Device*> ip4Hash_;
|
|
||||||
|
|
||||||
DeviceManager *deviceManager_;
|
DeviceManager *deviceManager_;
|
||||||
OstProto::Device data_;
|
|
||||||
|
int numVlanTags_;
|
||||||
|
quint16 vlan_[4]; // FIXME: vlan tpid
|
||||||
|
quint64 mac_;
|
||||||
|
quint32 ip4_;
|
||||||
|
int ip4PrefixLength_;
|
||||||
|
|
||||||
|
DeviceKey key_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,9 +23,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "packetbuffer.h"
|
#include "packetbuffer.h"
|
||||||
|
|
||||||
|
#include "../common/emulproto.pb.h"
|
||||||
|
|
||||||
#include <qendian.h>
|
#include <qendian.h>
|
||||||
|
|
||||||
// FIXME: add lock to protect deviceList_ operations?
|
const quint64 kBcastMac = 0xffffffffffffULL;
|
||||||
|
|
||||||
|
// FIXME: add lock to protect deviceGroupList_ operations?
|
||||||
|
|
||||||
DeviceManager::DeviceManager(AbstractPort *parent)
|
DeviceManager::DeviceManager(AbstractPort *parent)
|
||||||
{
|
{
|
||||||
@ -36,6 +40,90 @@ DeviceManager::~DeviceManager()
|
|||||||
{
|
{
|
||||||
foreach(Device *dev, deviceList_)
|
foreach(Device *dev, deviceList_)
|
||||||
delete dev;
|
delete dev;
|
||||||
|
|
||||||
|
foreach(OstProto::DeviceGroup *devGrp, deviceGroupList_)
|
||||||
|
delete devGrp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeviceManager::deviceGroupCount()
|
||||||
|
{
|
||||||
|
return deviceGroupList_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const OstProto::DeviceGroup* DeviceManager::deviceGroupAtIndex(int index)
|
||||||
|
{
|
||||||
|
if ((index < 0) || (index >= deviceGroupCount())) {
|
||||||
|
qWarning("%s: index %d out of range (0 - %d)", __FUNCTION__,
|
||||||
|
index, deviceGroupCount() - 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort List by 'id', get the id at 'index' and then corresponding devGrp
|
||||||
|
return deviceGroupList_.value(deviceGroupList_.uniqueKeys().value(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const OstProto::DeviceGroup* DeviceManager::deviceGroup(uint deviceGroupId)
|
||||||
|
{
|
||||||
|
return deviceGroupList_.value(deviceGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceManager::addDeviceGroup(uint deviceGroupId)
|
||||||
|
{
|
||||||
|
OstProto::DeviceGroup *deviceGroup;
|
||||||
|
|
||||||
|
if (deviceGroupList_.contains(deviceGroupId)) {
|
||||||
|
qWarning("%s: deviceGroup id %u already exists", __FUNCTION__,
|
||||||
|
deviceGroupId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceGroup = new OstProto::DeviceGroup;
|
||||||
|
deviceGroup->mutable_device_group_id()->set_id(deviceGroupId);
|
||||||
|
deviceGroupList_.insert(deviceGroupId, deviceGroup);
|
||||||
|
|
||||||
|
enumerateDevices(deviceGroup, kAdd);
|
||||||
|
|
||||||
|
// Start emulation when first device is added
|
||||||
|
if ((deviceCount() == 1) && port_)
|
||||||
|
port_->startDeviceEmulation();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceManager::deleteDeviceGroup(uint deviceGroupId)
|
||||||
|
{
|
||||||
|
OstProto::DeviceGroup *deviceGroup;
|
||||||
|
if (!deviceGroupList_.contains(deviceGroupId)) {
|
||||||
|
qWarning("%s: deviceGroup id %u does not exist", __FUNCTION__,
|
||||||
|
deviceGroupId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceGroup = deviceGroupList_.take(deviceGroupId);
|
||||||
|
enumerateDevices(deviceGroup, kDelete);
|
||||||
|
delete deviceGroup;
|
||||||
|
|
||||||
|
// Stop emulation if no devices remain
|
||||||
|
if ((deviceCount() == 0) && port_)
|
||||||
|
port_->stopDeviceEmulation();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceManager::modifyDeviceGroup(const OstProto::DeviceGroup *deviceGroup)
|
||||||
|
{
|
||||||
|
quint32 id = deviceGroup->device_group_id().id();
|
||||||
|
OstProto::DeviceGroup *myDeviceGroup = deviceGroupList_.value(id);
|
||||||
|
if (!myDeviceGroup) {
|
||||||
|
qWarning("%s: deviceGroup id %u does not exist", __FUNCTION__, id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enumerateDevices(myDeviceGroup, kDelete);
|
||||||
|
myDeviceGroup->CopyFrom(*deviceGroup);
|
||||||
|
enumerateDevices(myDeviceGroup, kAdd);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DeviceManager::deviceCount()
|
int DeviceManager::deviceCount()
|
||||||
@ -43,75 +131,155 @@ int DeviceManager::deviceCount()
|
|||||||
return deviceList_.size();
|
return deviceList_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* DeviceManager::deviceAtIndex(int index)
|
|
||||||
{
|
|
||||||
if ((index < 0) || (index >= deviceCount())) {
|
|
||||||
qWarning("%s: index %d out of range (max %d)", __FUNCTION__,
|
|
||||||
index, deviceCount());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return deviceList_.value(deviceList_.uniqueKeys().value(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
Device* DeviceManager::device(uint deviceId)
|
|
||||||
{
|
|
||||||
return deviceList_.value(deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceManager::addDevice(uint deviceId)
|
|
||||||
{
|
|
||||||
Device *device;
|
|
||||||
|
|
||||||
if (deviceList_.contains(deviceId)) {
|
|
||||||
qWarning("%s: device id %u already exists", __FUNCTION__, deviceId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
device = new Device(deviceId, this);
|
|
||||||
deviceList_.insert(deviceId, device);
|
|
||||||
|
|
||||||
if ((deviceCount() == 1) && port_)
|
|
||||||
port_->startDeviceEmulation();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceManager::deleteDevice(uint deviceId)
|
|
||||||
{
|
|
||||||
if (!deviceList_.contains(deviceId)) {
|
|
||||||
qWarning("%s: device id %u does not exist", __FUNCTION__, deviceId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete deviceList_.take(deviceId);
|
|
||||||
|
|
||||||
if ((deviceCount() == 0) && port_)
|
|
||||||
port_->stopDeviceEmulation();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceManager::modifyDevice(const OstProto::Device *device)
|
|
||||||
{
|
|
||||||
quint32 id = device->device_id().id();
|
|
||||||
Device *myDevice = deviceList_.value(id);
|
|
||||||
if (!myDevice) {
|
|
||||||
qWarning("%s: device id %u does not exist", __FUNCTION__, id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
myDevice->protoDataCopyFrom(*device);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::receivePacket(PacketBuffer *pktBuf)
|
void DeviceManager::receivePacket(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
Device::receivePacket(pktBuf);
|
uchar *pktData = pktBuf->data();
|
||||||
|
int offset = 0;
|
||||||
|
Device dk(this);
|
||||||
|
Device *device;
|
||||||
|
quint64 dstMac;
|
||||||
|
quint16 ethType;
|
||||||
|
quint16 vlan;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
// We assume pkt is ethernet
|
||||||
|
// TODO: extend for other link layer types
|
||||||
|
|
||||||
|
// FIXME: validate before extracting if the offset is within pktLen
|
||||||
|
|
||||||
|
// Extract dstMac
|
||||||
|
dstMac = qFromBigEndian<quint32>(pktData + offset);
|
||||||
|
offset += 4;
|
||||||
|
dstMac = (dstMac << 16) | qFromBigEndian<quint16>(pktData + offset);
|
||||||
|
dk.setMac(dstMac);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
// Skip srcMac - don't care
|
||||||
|
offset += 6;
|
||||||
|
|
||||||
|
qDebug("dstMac %llx", dstMac);
|
||||||
|
|
||||||
|
_eth_type:
|
||||||
|
// Extract EthType
|
||||||
|
ethType = qFromBigEndian<quint16>(pktData + offset);
|
||||||
|
qDebug("%s: ethType 0x%x", __PRETTY_FUNCTION__, ethType);
|
||||||
|
|
||||||
|
if (ethType == 0x8100) {
|
||||||
|
offset += 2;
|
||||||
|
vlan = qFromBigEndian<quint16>(pktData + offset);
|
||||||
|
dk.setVlan(idx++, vlan);
|
||||||
|
offset += 2;
|
||||||
|
qDebug("%s: idx: %d vlan 0x%x", __FUNCTION__, idx, vlan);
|
||||||
|
goto _eth_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
pktBuf->pull(offset);
|
||||||
|
|
||||||
|
if (dstMac == kBcastMac) {
|
||||||
|
QList<Device*> list = bcastList_.values(dk.key());
|
||||||
|
foreach(Device *device, list)
|
||||||
|
device->receivePacket(pktBuf);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it destined for us?
|
||||||
|
device = deviceList_.value(dk.key());
|
||||||
|
if (!device) {
|
||||||
|
qDebug("%s: dstMac %012llx is not us", __FUNCTION__, dstMac);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->receivePacket(pktBuf);
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::transmitPacket(PacketBuffer *pktBuf)
|
void DeviceManager::transmitPacket(PacketBuffer *pktBuf)
|
||||||
{
|
{
|
||||||
port_->sendEmulationPacket(pktBuf);
|
port_->sendEmulationPacket(pktBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceManager::enumerateDevices(
|
||||||
|
const OstProto::DeviceGroup *deviceGroup,
|
||||||
|
Operation oper)
|
||||||
|
{
|
||||||
|
Device dk(this);
|
||||||
|
OstEmul::VlanEmulation pbVlan = deviceGroup->GetExtension(OstEmul::vlan);
|
||||||
|
OstEmul::Device pbDevice = deviceGroup->GetExtension(OstEmul::device);
|
||||||
|
int numTags = pbVlan.stack_size();
|
||||||
|
int vlanCount = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < numTags; i++)
|
||||||
|
vlanCount *= pbVlan.stack(i).count();
|
||||||
|
|
||||||
|
// If we have no vlans, we still have the non-vlan-segmented LAN
|
||||||
|
if (vlanCount == 0)
|
||||||
|
vlanCount = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < vlanCount; i++) {
|
||||||
|
for (int j = 0; j < numTags; j++) {
|
||||||
|
OstEmul::VlanEmulation::Vlan vlan = pbVlan.stack(j);
|
||||||
|
quint16 vlanAdd = i*vlan.step();
|
||||||
|
|
||||||
|
switch (vlan.mode()) {
|
||||||
|
case OstEmul::VlanEmulation::kNoRepeat:
|
||||||
|
/* Do nothing */
|
||||||
|
break;
|
||||||
|
case OstEmul::VlanEmulation::kRepeat:
|
||||||
|
default:
|
||||||
|
vlanAdd %= vlan.count();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dk.setVlan(j, vlan.vlan_tag() + vlanAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint k = 0; k < pbDevice.count(); k++) {
|
||||||
|
Device *device;
|
||||||
|
quint64 macAdd = i*k*pbDevice.mac().step();
|
||||||
|
quint32 ip4Add = i*k*pbDevice.ip4().step();
|
||||||
|
|
||||||
|
switch (pbDevice.mode()) {
|
||||||
|
case OstEmul::Device::kNoRepeat:
|
||||||
|
/* Do Nothing*/
|
||||||
|
break;
|
||||||
|
case OstEmul::Device::kRepeat:
|
||||||
|
default:
|
||||||
|
macAdd %= pbDevice.count();
|
||||||
|
ip4Add %= pbDevice.count();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dk.setMac(pbDevice.mac().address() + macAdd);
|
||||||
|
dk.setIp4(pbDevice.ip4().address() + ip4Add,
|
||||||
|
pbDevice.ip4().prefix_length());
|
||||||
|
|
||||||
|
// TODO: fill in other pbDevice data
|
||||||
|
|
||||||
|
switch (oper) {
|
||||||
|
case kAdd:
|
||||||
|
device = new Device(this);
|
||||||
|
*device = dk;
|
||||||
|
deviceList_.insert(dk.key(), device);
|
||||||
|
|
||||||
|
dk.setMac(kBcastMac);
|
||||||
|
bcastList_.insert(dk.key(), device);
|
||||||
|
qDebug("enumerate (add): %s", qPrintable(device->config()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kDelete:
|
||||||
|
device = deviceList_.take(dk.key());
|
||||||
|
qDebug("enumerate (del): %s", qPrintable(device->config()));
|
||||||
|
delete device;
|
||||||
|
|
||||||
|
dk.setMac(kBcastMac);
|
||||||
|
bcastList_.take(dk.key()); // device already freed above
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(0); // Unreachable
|
||||||
|
}
|
||||||
|
} // foreach device
|
||||||
|
} // foreach vlan
|
||||||
|
}
|
||||||
|
@ -20,14 +20,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#ifndef _DEVICE_MANAGER_H
|
#ifndef _DEVICE_MANAGER_H
|
||||||
#define _DEVICE_MANAGER_H
|
#define _DEVICE_MANAGER_H
|
||||||
|
|
||||||
#include "../common/protocol.pb.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QMultiHash>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
class AbstractPort;
|
class AbstractPort;
|
||||||
class Device;
|
|
||||||
class PacketBuffer;
|
class PacketBuffer;
|
||||||
|
namespace OstProto {
|
||||||
|
class DeviceGroup;
|
||||||
|
};
|
||||||
|
|
||||||
class DeviceManager
|
class DeviceManager
|
||||||
{
|
{
|
||||||
@ -35,19 +38,30 @@ public:
|
|||||||
DeviceManager(AbstractPort *parent = 0);
|
DeviceManager(AbstractPort *parent = 0);
|
||||||
~DeviceManager();
|
~DeviceManager();
|
||||||
|
|
||||||
int deviceCount();
|
int deviceGroupCount();
|
||||||
Device* deviceAtIndex(int index);
|
const OstProto::DeviceGroup* deviceGroupAtIndex(int index);
|
||||||
Device* device(uint deviceId);
|
const OstProto::DeviceGroup* deviceGroup(uint deviceGroupId);
|
||||||
|
|
||||||
bool addDevice(uint deviceId);
|
bool addDeviceGroup(uint deviceGroupId);
|
||||||
bool deleteDevice(uint deviceId);
|
bool deleteDeviceGroup(uint deviceGroupId);
|
||||||
bool modifyDevice(const OstProto::Device *device);
|
bool modifyDeviceGroup(const OstProto::DeviceGroup *deviceGroup);
|
||||||
|
|
||||||
|
int deviceCount();
|
||||||
|
|
||||||
void receivePacket(PacketBuffer *pktBuf);
|
void receivePacket(PacketBuffer *pktBuf);
|
||||||
void transmitPacket(PacketBuffer *pktBuf);
|
void transmitPacket(PacketBuffer *pktBuf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum Operation { kAdd, kDelete };
|
||||||
|
|
||||||
|
void enumerateDevices(
|
||||||
|
const OstProto::DeviceGroup *deviceGroup,
|
||||||
|
Operation oper);
|
||||||
|
|
||||||
AbstractPort *port_;
|
AbstractPort *port_;
|
||||||
QHash<uint, Device*> deviceList_;
|
QHash<uint, OstProto::DeviceGroup*> deviceGroupList_;
|
||||||
|
QHash<DeviceKey, Device*> deviceList_;
|
||||||
|
QMultiHash<DeviceKey, Device*> bcastList_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,8 +33,8 @@ LIBS += -lprotobuf
|
|||||||
HEADERS += drone.h \
|
HEADERS += drone.h \
|
||||||
myservice.h
|
myservice.h
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
device.cpp \
|
|
||||||
devicemanager.cpp \
|
devicemanager.cpp \
|
||||||
|
device.cpp \
|
||||||
drone_main.cpp \
|
drone_main.cpp \
|
||||||
drone.cpp \
|
drone.cpp \
|
||||||
portmanager.cpp \
|
portmanager.cpp \
|
||||||
|
@ -602,9 +602,10 @@ _invalid_version:
|
|||||||
* streams/ports and devices independent?
|
* streams/ports and devices independent?
|
||||||
* ===================================================================
|
* ===================================================================
|
||||||
*/
|
*/
|
||||||
void MyService::getDeviceIdList(::google::protobuf::RpcController* controller,
|
void MyService::getDeviceGroupIdList(
|
||||||
|
::google::protobuf::RpcController* controller,
|
||||||
const ::OstProto::PortId* request,
|
const ::OstProto::PortId* request,
|
||||||
::OstProto::DeviceIdList* response,
|
::OstProto::DeviceGroupIdList* response,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
DeviceManager *devMgr;
|
DeviceManager *devMgr;
|
||||||
@ -620,12 +621,12 @@ void MyService::getDeviceIdList(::google::protobuf::RpcController* controller,
|
|||||||
|
|
||||||
response->mutable_port_id()->set_id(portId);
|
response->mutable_port_id()->set_id(portId);
|
||||||
portLock[portId]->lockForRead();
|
portLock[portId]->lockForRead();
|
||||||
for (int i = 0; i < devMgr->deviceCount(); i++)
|
for (int i = 0; i < devMgr->deviceGroupCount(); i++)
|
||||||
{
|
{
|
||||||
OstProto::DeviceId *d;
|
OstProto::DeviceGroupId *dgid;
|
||||||
|
|
||||||
d = response->add_device_id();
|
dgid = response->add_device_group_id();
|
||||||
d->set_id(devMgr->deviceAtIndex(i)->id());
|
dgid->CopyFrom(devMgr->deviceGroupAtIndex(i)->device_group_id());
|
||||||
}
|
}
|
||||||
portLock[portId]->unlock();
|
portLock[portId]->unlock();
|
||||||
|
|
||||||
@ -637,9 +638,10 @@ _invalid_port:
|
|||||||
done->Run();
|
done->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyService::getDeviceConfig(::google::protobuf::RpcController* controller,
|
void MyService::getDeviceGroupConfig(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
::OstProto::DeviceConfigList* response,
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
|
::OstProto::DeviceGroupConfigList* response,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
DeviceManager *devMgr;
|
DeviceManager *devMgr;
|
||||||
@ -655,17 +657,15 @@ void MyService::getDeviceConfig(::google::protobuf::RpcController* controller,
|
|||||||
|
|
||||||
response->mutable_port_id()->set_id(portId);
|
response->mutable_port_id()->set_id(portId);
|
||||||
portLock[portId]->lockForRead();
|
portLock[portId]->lockForRead();
|
||||||
for (int i = 0; i < request->device_id_size(); i++)
|
for (int i = 0; i < request->device_group_id_size(); i++)
|
||||||
{
|
{
|
||||||
Device *device;
|
const OstProto::DeviceGroup *dg;
|
||||||
OstProto::Device *d;
|
|
||||||
|
|
||||||
device = devMgr->device(request->device_id(i).id());
|
dg = devMgr->deviceGroup(request->device_group_id(i).id());
|
||||||
if (!device)
|
if (!dg)
|
||||||
continue; //! \todo(LOW): Partial status of RPC
|
continue; //! \todo(LOW): Partial status of RPC
|
||||||
|
|
||||||
d = response->add_device();
|
response->add_device_group()->CopyFrom(*dg);
|
||||||
device->protoDataCopyInto(*d);
|
|
||||||
}
|
}
|
||||||
portLock[portId]->unlock();
|
portLock[portId]->unlock();
|
||||||
|
|
||||||
@ -677,8 +677,9 @@ _invalid_port:
|
|||||||
done->Run();
|
done->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyService::addDevice(::google::protobuf::RpcController* controller,
|
void MyService::addDeviceGroup(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
::OstProto::Ack* /*response*/,
|
::OstProto::Ack* /*response*/,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
@ -699,16 +700,16 @@ void MyService::addDevice(::google::protobuf::RpcController* controller,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
portLock[portId]->lockForWrite();
|
portLock[portId]->lockForWrite();
|
||||||
for (int i = 0; i < request->device_id_size(); i++)
|
for (int i = 0; i < request->device_group_id_size(); i++)
|
||||||
{
|
{
|
||||||
quint32 id = request->device_id(i).id();
|
quint32 id = request->device_group_id(i).id();
|
||||||
Device *device = devMgr->device(id);
|
const OstProto::DeviceGroup *dg = devMgr->deviceGroup(id);
|
||||||
|
|
||||||
// If device with same id as in request exists already ==> error!!
|
// If device group with same id as in request exists already ==> error!
|
||||||
if (device)
|
if (dg)
|
||||||
continue; //! \todo (LOW): Partial status of RPC
|
continue; //! \todo (LOW): Partial status of RPC
|
||||||
|
|
||||||
devMgr->addDevice(id);
|
devMgr->addDeviceGroup(id);
|
||||||
}
|
}
|
||||||
portLock[portId]->unlock();
|
portLock[portId]->unlock();
|
||||||
|
|
||||||
@ -729,8 +730,9 @@ _exit:
|
|||||||
done->Run();
|
done->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyService::deleteDevice(::google::protobuf::RpcController* controller,
|
void MyService::deleteDeviceGroup(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
::OstProto::Ack* /*response*/,
|
::OstProto::Ack* /*response*/,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
@ -751,8 +753,8 @@ void MyService::deleteDevice(::google::protobuf::RpcController* controller,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
portLock[portId]->lockForWrite();
|
portLock[portId]->lockForWrite();
|
||||||
for (int i = 0; i < request->device_id_size(); i++)
|
for (int i = 0; i < request->device_group_id_size(); i++)
|
||||||
devMgr->deleteDevice(request->device_id(i).id());
|
devMgr->deleteDeviceGroup(request->device_group_id(i).id());
|
||||||
portLock[portId]->unlock();
|
portLock[portId]->unlock();
|
||||||
|
|
||||||
//! \todo (LOW): fill-in response "Ack"????
|
//! \todo (LOW): fill-in response "Ack"????
|
||||||
@ -771,8 +773,9 @@ _exit:
|
|||||||
done->Run();
|
done->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyService::modifyDevice(::google::protobuf::RpcController* controller,
|
void MyService::modifyDeviceGroup(
|
||||||
const ::OstProto::DeviceConfigList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupConfigList* request,
|
||||||
::OstProto::Ack* /*response*/,
|
::OstProto::Ack* /*response*/,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
@ -793,8 +796,8 @@ void MyService::modifyDevice(::google::protobuf::RpcController* controller,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
portLock[portId]->lockForWrite();
|
portLock[portId]->lockForWrite();
|
||||||
for (int i = 0; i < request->device_size(); i++)
|
for (int i = 0; i < request->device_group_size(); i++)
|
||||||
devMgr->modifyDevice(&request->device(i));
|
devMgr->modifyDeviceGroup(&request->device_group(i));
|
||||||
portLock[portId]->unlock();
|
portLock[portId]->unlock();
|
||||||
|
|
||||||
// FIXME: check for overlaps between devices?
|
// FIXME: check for overlaps between devices?
|
||||||
|
@ -105,25 +105,30 @@ public:
|
|||||||
::OstProto::VersionCompatibility* response,
|
::OstProto::VersionCompatibility* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
|
|
||||||
// Device and Protocol Emulation
|
// DeviceGroup and Protocol Emulation
|
||||||
virtual void getDeviceIdList(::google::protobuf::RpcController* controller,
|
virtual void getDeviceGroupIdList(
|
||||||
|
::google::protobuf::RpcController* controller,
|
||||||
const ::OstProto::PortId* request,
|
const ::OstProto::PortId* request,
|
||||||
::OstProto::DeviceIdList* response,
|
::OstProto::DeviceGroupIdList* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
virtual void getDeviceConfig(::google::protobuf::RpcController* controller,
|
virtual void getDeviceGroupConfig(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
::OstProto::DeviceConfigList* response,
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
|
::OstProto::DeviceGroupConfigList* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
virtual void addDevice(::google::protobuf::RpcController* controller,
|
virtual void addDeviceGroup(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
::OstProto::Ack* response,
|
::OstProto::Ack* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
virtual void deleteDevice(::google::protobuf::RpcController* controller,
|
virtual void deleteDeviceGroup(
|
||||||
const ::OstProto::DeviceIdList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupIdList* request,
|
||||||
::OstProto::Ack* response,
|
::OstProto::Ack* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
virtual void modifyDevice(::google::protobuf::RpcController* controller,
|
virtual void modifyDeviceGroup(
|
||||||
const ::OstProto::DeviceConfigList* request,
|
::google::protobuf::RpcController* controller,
|
||||||
|
const ::OstProto::DeviceGroupConfigList* request,
|
||||||
::OstProto::Ack* response,
|
::OstProto::Ack* response,
|
||||||
::google::protobuf::Closure* done);
|
::google::protobuf::Closure* done);
|
||||||
signals:
|
signals:
|
||||||
|
@ -139,54 +139,54 @@ try:
|
|||||||
# configure emulated device(s) on tx/rx ports #
|
# configure emulated device(s) on tx/rx ports #
|
||||||
#---------------------------------------------#
|
#---------------------------------------------#
|
||||||
# delete existing devices, if any, on tx port
|
# delete existing devices, if any, on tx port
|
||||||
did_list = drone.getDeviceIdList(tx_port.port_id[0])
|
dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0])
|
||||||
drone.deleteDevice(did_list)
|
drone.deleteDeviceGroup(dgid_list)
|
||||||
|
|
||||||
# add a emulated device on tx port
|
# add a emulated device on tx port
|
||||||
device_id = ost_pb.DeviceIdList()
|
dgid_list = ost_pb.DeviceGroupIdList()
|
||||||
device_id.port_id.CopyFrom(tx_port.port_id[0])
|
dgid_list.port_id.CopyFrom(tx_port.port_id[0])
|
||||||
device_id.device_id.add().id = 1
|
dgid_list.device_group_id.add().id = 1
|
||||||
log.info('adding tx_device %d' % device_id.device_id[0].id)
|
log.info('adding tx device_group %d' % dgid_list.device_group_id[0].id)
|
||||||
drone.addDevice(device_id)
|
drone.addDeviceGroup(dgid_list)
|
||||||
|
|
||||||
# configure the device
|
# configure the device
|
||||||
device_cfg = ost_pb.DeviceConfigList()
|
devgrp_cfg = ost_pb.DeviceGroupConfigList()
|
||||||
device_cfg.port_id.CopyFrom(tx_port.port_id[0])
|
devgrp_cfg.port_id.CopyFrom(tx_port.port_id[0])
|
||||||
d = device_cfg.device.add()
|
dg = devgrp_cfg.device_group.add()
|
||||||
d.device_id.id = device_id.device_id[0].id
|
dg.device_group_id.id = dgid_list.device_group_id[0].id
|
||||||
d.core.name = "Host1"
|
dg.core.name = "Host1"
|
||||||
d.Extensions[emul.mac].addr = 0x000102030001
|
d = dg.Extensions[emul.device]
|
||||||
ip = d.Extensions[emul.ip4]
|
d.mac.address = 0x000102030001
|
||||||
ip.addr = 0x0a0a0164
|
d.ip4.address = 0x0a0a0164
|
||||||
ip.prefix_length = 24
|
d.ip4.prefix_length = 24
|
||||||
ip.gateway = 0x0a0a0101
|
d.ip4.default_gateway = 0x0a0a0101
|
||||||
|
|
||||||
drone.modifyDevice(device_cfg)
|
drone.modifyDeviceGroup(devgrp_cfg)
|
||||||
|
|
||||||
# delete existing devices, if any, on rx port
|
# delete existing devices, if any, on rx port
|
||||||
did_list = drone.getDeviceIdList(rx_port.port_id[0])
|
dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0])
|
||||||
drone.deleteDevice(did_list)
|
drone.deleteDeviceGroup(dgid_list)
|
||||||
|
|
||||||
# add a emulated device on rx port
|
# add a emulated device on rx port
|
||||||
device_id = ost_pb.DeviceIdList()
|
dgid_list = ost_pb.DeviceGroupIdList()
|
||||||
device_id.port_id.CopyFrom(rx_port.port_id[0])
|
dgid_list.port_id.CopyFrom(rx_port.port_id[0])
|
||||||
device_id.device_id.add().id = 1
|
dgid_list.device_group_id.add().id = 1
|
||||||
log.info('adding rx_device %d' % device_id.device_id[0].id)
|
log.info('adding rx device_group %d' % dgid_list.device_group_id[0].id)
|
||||||
drone.addDevice(device_id)
|
drone.addDeviceGroup(dgid_list)
|
||||||
|
|
||||||
# configure the device
|
# configure the device
|
||||||
device_cfg = ost_pb.DeviceConfigList()
|
devgrp_cfg = ost_pb.DeviceGroupConfigList()
|
||||||
device_cfg.port_id.CopyFrom(rx_port.port_id[0])
|
devgrp_cfg.port_id.CopyFrom(rx_port.port_id[0])
|
||||||
d = device_cfg.device.add()
|
dg = devgrp_cfg.device_group.add()
|
||||||
d.device_id.id = device_id.device_id[0].id
|
dg.device_group_id.id = dgid_list.device_group_id[0].id
|
||||||
d.core.name = "Host2"
|
dg.core.name = "Host1"
|
||||||
d.Extensions[emul.mac].addr = 0x000102030002
|
d = dg.Extensions[emul.device]
|
||||||
ip = d.Extensions[emul.ip4]
|
d.mac.address = 0x000102030002
|
||||||
ip.addr = 0x0a0a0264
|
d.ip4.address = 0x0a0a0264
|
||||||
ip.prefix_length = 24
|
d.ip4.prefix_length = 24
|
||||||
ip.gateway = 0x0a0a0201
|
d.ip4.default_gateway = 0x0a0a0201
|
||||||
|
|
||||||
drone.modifyDevice(device_cfg)
|
drone.modifyDeviceGroup(devgrp_cfg)
|
||||||
|
|
||||||
#--------------------------------------#
|
#--------------------------------------#
|
||||||
# configure traffic stream(s)
|
# configure traffic stream(s)
|
||||||
@ -210,7 +210,7 @@ try:
|
|||||||
s.core.is_enabled = True
|
s.core.is_enabled = True
|
||||||
#s.core.frame_len = 128
|
#s.core.frame_len = 128
|
||||||
s.control.packets_per_sec = 20
|
s.control.packets_per_sec = 20
|
||||||
s.control.num_packets = 100
|
s.control.num_packets = 10
|
||||||
|
|
||||||
# setup stream protocols as mac:eth2:ip4:udp:payload
|
# setup stream protocols as mac:eth2:ip4:udp:payload
|
||||||
p = s.protocol.add()
|
p = s.protocol.add()
|
||||||
@ -280,10 +280,10 @@ try:
|
|||||||
drone.deleteStream(stream_id)
|
drone.deleteStream(stream_id)
|
||||||
|
|
||||||
# delete devices
|
# delete devices
|
||||||
did_list = drone.getDeviceIdList(tx_port.port_id[0])
|
dgid_list = drone.getDeviceGroupIdList(tx_port.port_id[0])
|
||||||
drone.deleteDevice(did_list)
|
drone.deleteDeviceGroup(dgid_list)
|
||||||
did_list = drone.getDeviceIdList(rx_port.port_id[0])
|
dgid_list = drone.getDeviceGroupIdList(rx_port.port_id[0])
|
||||||
drone.deleteDevice(did_list)
|
drone.deleteDeviceGroup(dgid_list)
|
||||||
|
|
||||||
# bye for now
|
# bye for now
|
||||||
drone.disconnect()
|
drone.disconnect()
|
||||||
|
Loading…
Reference in New Issue
Block a user