Merge branch 'master' of https://github.com/pstavirs/ostinato into emul

Conflicts:
	server/pcapport.cpp
This commit is contained in:
Srivats P 2015-12-01 21:00:41 +05:30
commit c022290da1
21 changed files with 400 additions and 41 deletions

View File

@ -6,7 +6,7 @@ Ostinato is an open-source, cross-platform network packet crafter/traffic genera
Ostinato aims to be "Wireshark in Reverse" and become complementary to Wireshark. Ostinato aims to be "Wireshark in Reverse" and become complementary to Wireshark.
License: GPLv3+ (see COPYING) License: GPLv3+ (see [COPYING](https://raw.githubusercontent.com/pstavirs/ostinato/master/COPYING))
For more information visit http://ostinato.org. For more information visit http://ostinato.org.

View File

@ -37,7 +37,7 @@ extern char *version;
quint32 PortGroup::mPortGroupAllocId = 0; quint32 PortGroup::mPortGroupAllocId = 0;
PortGroup::PortGroup(QHostAddress ip, quint16 port) PortGroup::PortGroup(QString serverName, quint16 port)
{ {
// Allocate an id for self // Allocate an id for self
mPortGroupId = PortGroup::mPortGroupAllocId++; mPortGroupId = PortGroup::mPortGroupAllocId++;
@ -57,7 +57,7 @@ PortGroup::PortGroup(QHostAddress ip, quint16 port)
connect(reconnectTimer, SIGNAL(timeout()), connect(reconnectTimer, SIGNAL(timeout()),
this, SLOT(on_reconnectTimer_timeout())); this, SLOT(on_reconnectTimer_timeout()));
rpcChannel = new PbRpcChannel(ip, port, rpcChannel = new PbRpcChannel(serverName, port,
OstProto::Notification::default_instance()); OstProto::Notification::default_instance());
serviceStub = new OstProto::OstService::Stub(rpcChannel); serviceStub = new OstProto::OstService::Stub(rpcChannel);
@ -272,7 +272,7 @@ void PortGroup::when_portListChanged(quint32 /*portGroupId*/)
"For more information see " "For more information see "
"http://code.google.com/p/ostinato/wiki/FAQ#" "http://code.google.com/p/ostinato/wiki/FAQ#"
"Q._Port_group_has_no_interfaces") "Q._Port_group_has_no_interfaces")
.arg(serverAddress().toString()) .arg(serverName())
.arg(int(serverPort()))); .arg(int(serverPort())));
} }
} }

View File

@ -66,7 +66,7 @@ public: // FIXME(HIGH): member access
QList<Port*> mPorts; QList<Port*> mPorts;
public: public:
PortGroup(QHostAddress ip = QHostAddress::LocalHost, PortGroup(QString serverName = "127.0.0.1",
quint16 port = DEFAULT_SERVER_PORT); quint16 port = DEFAULT_SERVER_PORT);
~PortGroup(); ~PortGroup();
@ -75,10 +75,10 @@ public:
compat = kUnknown; compat = kUnknown;
rpcChannel->establish(); rpcChannel->establish();
} }
void connectToHost(QHostAddress ip, quint16 port) { void connectToHost(QString serverName, quint16 port) {
reconnect = true; reconnect = true;
compat = kUnknown; compat = kUnknown;
rpcChannel->establish(ip, port); rpcChannel->establish(serverName, port);
} }
void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); } void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); }
@ -88,8 +88,8 @@ public:
const QString& userAlias() const { return mUserAlias; } const QString& userAlias() const { return mUserAlias; }
void setUserAlias(QString alias) { mUserAlias = alias; }; void setUserAlias(QString alias) { mUserAlias = alias; };
const QHostAddress& serverAddress() const const QString serverName() const
{ return rpcChannel->serverAddress(); } { return rpcChannel->serverName(); }
quint16 serverPort() const quint16 serverPort() const
{ return rpcChannel->serverPort(); } { return rpcChannel->serverPort(); }
QAbstractSocket::SocketState state() const { QAbstractSocket::SocketState state() const {

View File

@ -121,10 +121,10 @@ QVariant PortModel::data(const QModelIndex &index, int role) const
if ((role == Qt::DisplayRole)) if ((role == Qt::DisplayRole))
{ {
DBG0("Exit PortModel data 1\n"); DBG0("Exit PortModel data 1\n");
return QString("Port Group %1: %2 [%3:%4] (%5)"). return QString("Port Group %1: %2 [%3]:%4 (%5)").
arg(pgl->mPortGroups.at(index.row())->id()). arg(pgl->mPortGroups.at(index.row())->id()).
arg(pgl->mPortGroups.at(index.row())->userAlias()). arg(pgl->mPortGroups.at(index.row())->userAlias()).
arg(pgl->mPortGroups.at(index.row())->serverAddress().toString()). arg(pgl->mPortGroups.at(index.row())->serverName()).
arg(pgl->mPortGroups.at(index.row())->serverPort()). arg(pgl->mPortGroups.at(index.row())->serverPort()).
arg(pgl->mPortGroups.value(index.row())->numPorts()); arg(pgl->mPortGroups.value(index.row())->numPorts());
} }

View File

@ -503,15 +503,29 @@ void PortsWindow::on_actionNew_Port_Group_triggered()
{ {
bool ok; bool ok;
QString text = QInputDialog::getText(this, QString text = QInputDialog::getText(this,
"Add Port Group", "Port Group Address (IP[:Port])", "Add Port Group", "Port Group Address (HostName[:Port])",
QLineEdit::Normal, lastNewPortGroup, &ok); QLineEdit::Normal, lastNewPortGroup, &ok);
if (ok) if (ok)
{ {
QStringList addr = text.split(":"); QStringList addr = text.split(":");
if (addr.size() == 1) // Port unspecified quint16 port = DEFAULT_SERVER_PORT;
addr.append(QString().setNum(DEFAULT_SERVER_PORT));
PortGroup *pg = new PortGroup(QHostAddress(addr[0]),addr[1].toUShort()); if (addr.size() > 2) { // IPv6 Address
// IPv6 addresses with port number SHOULD be specified as
// [2001:db8::1]:80 (RFC5952 Sec6) to avoid ambiguity due to ':'
addr = text.split("]:");
if (addr.size() > 1)
port = addr[1].toUShort();
}
else if (addr.size() == 2) // Hostname/IPv4 + Port specified
port = addr[1].toUShort();
// Play nice and remove square brackets irrespective of addr type
addr[0].remove(QChar('['));
addr[0].remove(QChar(']'));
PortGroup *pg = new PortGroup(addr[0], port);
plm->addPortGroup(*pg); plm->addPortGroup(*pg);
lastNewPortGroup = text; lastNewPortGroup = text;
} }

View File

@ -447,6 +447,27 @@ _exit:
return true; return true;
} }
int StreamBase::frameSizeVariableCount() const
{
int count = 1;
switch(lenMode())
{
case OstProto::StreamCore::e_fl_fixed:
break;
case OstProto::StreamCore::e_fl_inc:
case OstProto::StreamCore::e_fl_dec:
case OstProto::StreamCore::e_fl_random:
count = frameLenMax() - frameLenMin() + 1;
break;
default:
qWarning("%s: Unhandled len mode %d", __FUNCTION__, lenMode());
break;
}
return count;
}
int StreamBase::frameVariableCount() const int StreamBase::frameVariableCount() const
{ {
ProtocolListIterator *iter; ProtocolListIterator *iter;
@ -469,7 +490,7 @@ int StreamBase::frameVariableCount() const
} }
delete iter; delete iter;
return frameCount; return AbstractProtocol::lcm(frameCount, frameSizeVariableCount());
} }
// frameProtocolLength() returns the sum of all the individual protocol sizes // frameProtocolLength() returns the sum of all the individual protocol sizes

View File

@ -131,6 +131,7 @@ public:
bool isFrameVariable() const; bool isFrameVariable() const;
bool isFrameSizeVariable() const; bool isFrameSizeVariable() const;
int frameSizeVariableCount() const;
int frameVariableCount() const; int frameVariableCount() const;
int frameProtocolLength(int frameIndex) const; int frameProtocolLength(int frameIndex) const;
int frameCount() const; int frameCount() const;

View File

@ -25,7 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
static uchar msgBuf[4096]; static uchar msgBuf[4096];
PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port, PbRpcChannel::PbRpcChannel(QString serverName, quint16 port,
const ::google::protobuf::Message &notifProto) const ::google::protobuf::Message &notifProto)
: notifPrototype(notifProto) : notifPrototype(notifProto)
{ {
@ -36,7 +36,7 @@ PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port,
done = NULL; done = NULL;
response = NULL; response = NULL;
mServerAddress = ip; mServerHost = serverName;
mServerPort = port; mServerPort = port;
mpSocket = new QTcpSocket(this); mpSocket = new QTcpSocket(this);
@ -75,12 +75,12 @@ void PbRpcChannel::establish()
{ {
qDebug("In %s", __FUNCTION__); qDebug("In %s", __FUNCTION__);
mpSocket->connectToHost(mServerAddress, mServerPort); mpSocket->connectToHost(mServerHost, mServerPort);
} }
void PbRpcChannel::establish(QHostAddress ip, quint16 port) void PbRpcChannel::establish(QString serverName, quint16 port)
{ {
mServerAddress = ip; mServerHost = serverName;
mServerPort = port; mServerPort = port;
establish(); establish();
} }

View File

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifndef _PB_RPC_CHANNEL_H #ifndef _PB_RPC_CHANNEL_H
#define _PB_RPC_CHANNEL_H #define _PB_RPC_CHANNEL_H
#include <QString>
#include <QTcpServer> #include <QTcpServer>
#include <QTcpSocket> #include <QTcpSocket>
@ -64,7 +65,7 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
const ::google::protobuf::Message &notifPrototype; const ::google::protobuf::Message &notifPrototype;
::google::protobuf::Message *notif; ::google::protobuf::Message *notif;
QHostAddress mServerAddress; QString mServerHost;
quint16 mServerPort; quint16 mServerPort;
QTcpSocket *mpSocket; QTcpSocket *mpSocket;
@ -72,15 +73,18 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream; ::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
public: public:
PbRpcChannel(QHostAddress ip, quint16 port, PbRpcChannel(QString serverName, quint16 port,
const ::google::protobuf::Message &notifProto); const ::google::protobuf::Message &notifProto);
~PbRpcChannel(); ~PbRpcChannel();
void establish(); void establish();
void establish(QHostAddress ip, quint16 port); void establish(QString serverName, quint16 port);
void tearDown(); void tearDown();
const QHostAddress& serverAddress() const { return mServerAddress; } const QString serverName() const
{
return mpSocket->peerName();
}
quint16 serverPort() const { return mServerPort; } quint16 serverPort() const { return mServerPort; }
QAbstractSocket::SocketState state() const QAbstractSocket::SocketState state() const

View File

@ -43,13 +43,14 @@ RpcServer::~RpcServer()
} }
bool RpcServer::registerService(::google::protobuf::Service *service, bool RpcServer::registerService(::google::protobuf::Service *service,
quint16 tcpPortNum) QHostAddress address, quint16 tcpPortNum)
{ {
this->service = service; this->service = service;
if (!listen(QHostAddress::Any, tcpPortNum)) if (!listen(address, tcpPortNum))
{ {
qDebug("Unable to start the server: %s", qDebug("Unable to start the server on <%s>: %s",
qPrintable(address.toString()),
errorString().toAscii().constData()); errorString().toAscii().constData());
return false; return false;
} }

View File

@ -41,7 +41,7 @@ public:
virtual ~RpcServer(); virtual ~RpcServer();
bool registerService(::google::protobuf::Service *service, bool registerService(::google::protobuf::Service *service,
quint16 tcpPortNum); QHostAddress address, quint16 tcpPortNum);
signals: signals:
void notifyClients(int notifType, SharedProtobufMessage notifData); void notifyClients(int notifType, SharedProtobufMessage notifData);

View File

@ -45,6 +45,7 @@ AbstractPort::AbstractPort(int id, const char *device)
data_.set_is_exclusive_control(false); data_.set_is_exclusive_control(false);
isSendQueueDirty_ = false; isSendQueueDirty_ = false;
rateAccuracy_ = kHighAccuracy;
linkState_ = OstProto::LinkStateUnknown; linkState_ = OstProto::LinkStateUnknown;
minPacketSetSize_ = 1; minPacketSetSize_ = 1;
@ -154,6 +155,17 @@ void AbstractPort::addNote(QString note)
data_.set_notes(notes.toStdString()); data_.set_notes(notes.toStdString());
} }
AbstractPort::Accuracy AbstractPort::rateAccuracy()
{
return rateAccuracy_;
}
bool AbstractPort::setRateAccuracy(Accuracy accuracy)
{
rateAccuracy_ = accuracy;
return true;
}
void AbstractPort::updatePacketList() void AbstractPort::updatePacketList()
{ {
switch(data_.transmit_mode()) switch(data_.transmit_mode())

View File

@ -54,6 +54,13 @@ public:
quint64 txBps; quint64 txBps;
}; };
enum Accuracy
{
kHighAccuracy,
kMediumAccuracy,
kLowAccuracy,
};
AbstractPort(int id, const char *device); AbstractPort(int id, const char *device);
virtual ~AbstractPort(); virtual ~AbstractPort();
@ -80,6 +87,9 @@ public:
bool isDirty() { return isSendQueueDirty_; } bool isDirty() { return isSendQueueDirty_; }
void setDirty() { isSendQueueDirty_ = true; } void setDirty() { isSendQueueDirty_ = true; }
Accuracy rateAccuracy();
virtual bool setRateAccuracy(Accuracy accuracy);
virtual void clearPacketList() = 0; virtual void clearPacketList() = 0;
virtual void loopNextPacketSet(qint64 size, qint64 repeats, virtual void loopNextPacketSet(qint64 size, qint64 repeats,
long repeatDelaySec, long repeatDelayNsec) = 0; long repeatDelaySec, long repeatDelayNsec) = 0;
@ -122,6 +132,7 @@ protected:
OstProto::Port data_; OstProto::Port data_;
OstProto::LinkState linkState_; OstProto::LinkState linkState_;
ulong minPacketSetSize_; ulong minPacketSetSize_;
Accuracy rateAccuracy_;
quint64 maxStatsValue_; quint64 maxStatsValue_;
struct PortStats stats_; struct PortStats stats_;

View File

@ -19,8 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "drone.h" #include "drone.h"
#include "rpcserver.h"
#include "myservice.h" #include "myservice.h"
#include "rpcserver.h"
#include "settings.h"
#include <QMetaType> #include <QMetaType>
@ -43,11 +44,21 @@ Drone::~Drone()
bool Drone::init() bool Drone::init()
{ {
QString addr = appSettings->value(kRpcServerAddress).toString();
QHostAddress address = addr.isEmpty() ?
QHostAddress::Any : QHostAddress(addr);
Q_ASSERT(rpcServer); Q_ASSERT(rpcServer);
qRegisterMetaType<SharedProtobufMessage>("SharedProtobufMessage"); qRegisterMetaType<SharedProtobufMessage>("SharedProtobufMessage");
if (!rpcServer->registerService(service, myport ? myport : 7878)) if (address.isNull()) {
qWarning("Invalid RpcServer Address <%s> specified. Using 'Any'",
qPrintable(addr));
address = QHostAddress::Any;
}
if (!rpcServer->registerService(service, address, myport ? myport : 7878))
{ {
//qCritical(qPrintable(rpcServer->errorString())); //qCritical(qPrintable(rpcServer->errorString()));
return false; return false;

View File

@ -172,6 +172,15 @@ void PcapPort::updateNotes()
arg(notes).toStdString()); arg(notes).toStdString());
} }
bool PcapPort::setRateAccuracy(AbstractPort::Accuracy accuracy)
{
if (transmitter_->setRateAccuracy(accuracy)) {
AbstractPort::setRateAccuracy(accuracy);
return true;
}
return false;
}
void PcapPort::startDeviceEmulation() void PcapPort::startDeviceEmulation()
{ {
emulXcvr_->start(); emulXcvr_->start();
@ -187,7 +196,6 @@ int PcapPort::sendEmulationPacket(PacketBuffer *pktBuf)
return emulXcvr_->transmitPacket(pktBuf); return emulXcvr_->transmitPacket(pktBuf);
} }
/* /*
* ------------------------------------------------------------------- * * ------------------------------------------------------------------- *
* Port Monitor * Port Monitor
@ -350,7 +358,7 @@ PcapPort::PortTransmitter::PortTransmitter(const char *device)
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
LARGE_INTEGER freq; LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq)) if (QueryPerformanceFrequency(&freq))
gTicksFreq = ticksFreq_ = freq.QuadPart; gTicksFreq = freq.QuadPart;
else else
Q_ASSERT_X(false, "PortTransmitter::PortTransmitter", Q_ASSERT_X(false, "PortTransmitter::PortTransmitter",
"This Win32 platform does not support performance counter"); "This Win32 platform does not support performance counter");
@ -383,6 +391,26 @@ PcapPort::PortTransmitter::~PortTransmitter()
pcap_close(handle_); pcap_close(handle_);
} }
bool PcapPort::PortTransmitter::setRateAccuracy(
AbstractPort::Accuracy accuracy)
{
switch (accuracy) {
case kHighAccuracy:
udelayFn_ = udelay;
qWarning("%s: rate accuracy set to High - busy wait", __FUNCTION__);
break;
case kLowAccuracy:
udelayFn_ = QThread::usleep;
qWarning("%s: rate accuracy set to Low - usleep", __FUNCTION__);
break;
default:
qWarning("%s: unsupported rate accuracy value %d", __FUNCTION__,
accuracy);
return false;
}
return true;
}
void PcapPort::PortTransmitter::clearPacketList() void PcapPort::PortTransmitter::clearPacketList()
{ {
Q_ASSERT(!isRunning()); Q_ASSERT(!isRunning());
@ -585,7 +613,7 @@ _restart:
long usecs = seq->usecDelay_ + overHead; long usecs = seq->usecDelay_ + overHead;
if (usecs > 0) if (usecs > 0)
{ {
udelay(usecs); (*udelayFn_)(usecs);
overHead = 0; overHead = 0;
} }
else else
@ -611,7 +639,7 @@ _restart:
if (usecs > 0) if (usecs > 0)
{ {
udelay(usecs); (*udelayFn_)(usecs);
overHead = 0; overHead = 0;
} }
else else
@ -687,7 +715,7 @@ int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p,
usec += overHead; usec += overHead;
if (usec > 0) if (usec > 0)
{ {
udelay(usec); (*udelayFn_)(usec);
overHead = 0; overHead = 0;
} }
else else
@ -716,14 +744,14 @@ int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p,
return 0; return 0;
} }
void PcapPort::PortTransmitter::udelay(long usec) void PcapPort::PortTransmitter::udelay(unsigned long usec)
{ {
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
LARGE_INTEGER tgtTicks; LARGE_INTEGER tgtTicks;
LARGE_INTEGER curTicks; LARGE_INTEGER curTicks;
QueryPerformanceCounter(&curTicks); QueryPerformanceCounter(&curTicks);
tgtTicks.QuadPart = curTicks.QuadPart + (usec*ticksFreq_)/1000000; tgtTicks.QuadPart = curTicks.QuadPart + (usec*gTicksFreq)/1000000;
while (curTicks.QuadPart < tgtTicks.QuadPart) while (curTicks.QuadPart < tgtTicks.QuadPart)
QueryPerformanceCounter(&curTicks); QueryPerformanceCounter(&curTicks);

View File

@ -38,6 +38,8 @@ public:
virtual bool hasExclusiveControl() { return false; } virtual bool hasExclusiveControl() { return false; }
virtual bool setExclusiveControl(bool /*exclusive*/) { return false; } virtual bool setExclusiveControl(bool /*exclusive*/) { return false; }
virtual bool setRateAccuracy(AbstractPort::Accuracy accuracy);
virtual void clearPacketList() { virtual void clearPacketList() {
transmitter_->clearPacketList(); transmitter_->clearPacketList();
setPacketListLoopMode(false, 0, 0); setPacketListLoopMode(false, 0, 0);
@ -106,6 +108,9 @@ protected:
public: public:
PortTransmitter(const char *device); PortTransmitter(const char *device);
~PortTransmitter(); ~PortTransmitter();
bool setRateAccuracy(AbstractPort::Accuracy accuracy);
void clearPacketList(); void clearPacketList();
void loopNextPacketSet(qint64 size, qint64 repeats, void loopNextPacketSet(qint64 size, qint64 repeats,
long repeatDelaySec, long repeatDelayNsec); long repeatDelaySec, long repeatDelayNsec);
@ -176,11 +181,10 @@ protected:
long usecDelay_; long usecDelay_;
}; };
void udelay(long usec); static void udelay(unsigned long usec);
int sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead, int sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead,
int sync); int sync);
quint64 ticksFreq_;
QList<PacketSequence*> packetSequenceList_; QList<PacketSequence*> packetSequenceList_;
PacketSequence *currentPacketSequence_; PacketSequence *currentPacketSequence_;
int repeatSequenceStart_; int repeatSequenceStart_;
@ -190,6 +194,8 @@ protected:
int returnToQIdx_; int returnToQIdx_;
quint64 loopDelay_; quint64 loopDelay_;
void (*udelayFn_)(unsigned long);
bool usingInternalStats_; bool usingInternalStats_;
AbstractPort::PortStats *stats_; AbstractPort::PortStats *stats_;
bool usingInternalHandle_; bool usingInternalHandle_;

View File

@ -36,12 +36,15 @@ PortManager::PortManager()
pcap_if_t *deviceList; pcap_if_t *deviceList;
pcap_if_t *device; pcap_if_t *device;
char errbuf[PCAP_ERRBUF_SIZE]; char errbuf[PCAP_ERRBUF_SIZE];
AbstractPort::Accuracy txRateAccuracy;
qDebug("Retrieving the device list from the local machine\n"); qDebug("Retrieving the device list from the local machine\n");
if (pcap_findalldevs(&deviceList, errbuf) == -1) if (pcap_findalldevs(&deviceList, errbuf) == -1)
qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf); qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf);
txRateAccuracy = rateAccuracy();
for(device = deviceList, i = 0; device != NULL; device = device->next, i++) for(device = deviceList, i = 0; device != NULL; device = device->next, i++)
{ {
AbstractPort *port; AbstractPort *port;
@ -81,6 +84,9 @@ PortManager::PortManager()
continue; continue;
} }
if (!port->setRateAccuracy(txRateAccuracy))
qWarning("failed to set rateAccuracy (%d)", txRateAccuracy);
portList_.append(port); portList_.append(port);
} }
@ -106,6 +112,21 @@ PortManager* PortManager::instance()
return instance_; return instance_;
} }
AbstractPort::Accuracy PortManager::rateAccuracy()
{
QString rateAccuracy = appSettings->value(kRateAccuracyKey,
kRateAccuracyDefaultValue).toString();
if (rateAccuracy == "High")
return AbstractPort::kHighAccuracy;
else if (rateAccuracy == "Low")
return AbstractPort::kLowAccuracy;
else
qWarning("Unsupported RateAccuracy setting - %s",
qPrintable(rateAccuracy));
return AbstractPort::kHighAccuracy;
}
bool PortManager::filterAcceptsPort(const char *name) bool PortManager::filterAcceptsPort(const char *name)
{ {
QRegExp pattern; QRegExp pattern;

View File

@ -35,6 +35,7 @@ public:
static PortManager* instance(); static PortManager* instance();
private: private:
AbstractPort::Accuracy rateAccuracy();
bool filterAcceptsPort(const char *name); bool filterAcceptsPort(const char *name);
private: private:

View File

@ -25,6 +25,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
extern QSettings *appSettings; extern QSettings *appSettings;
//
// General Section Keys
//
const QString kRateAccuracyKey("RateAccuracy");
const QString kRateAccuracyDefaultValue("High");
//
// RpcServer Section Keys
//
const QString kRpcServerAddress("RpcServer/Address");
// //
// PortList Section Keys // PortList Section Keys
// //

214
test/pktlentest.py Normal file
View File

@ -0,0 +1,214 @@
#! /usr/bin/env python
# standard modules
import logging
import os
import pytest
import subprocess
import sys
import time
from harness import extract_column
sys.path.insert(1, '../binding')
from core import ost_pb, DroneProxy
from rpc import RpcError
#from protocols.mac_pb2 import mac
#from protocols.payload_pb2 import payload, Payload
# initialize defaults
host_name = '127.0.0.1'
tx_number = -1
rx_number = -1
if sys.platform == 'win32':
tshark = r'C:\Program Files\Wireshark\tshark.exe'
else:
tshark = 'tshark'
fmt = 'column.format:"Packet#","%m","Time","%t","Source","%uns","Destination","%und","Protocol","%p","Size","%L","Info","%i","Expert","%a"'
fmt_col = 7 # col# in fmt for Size/PktLength
# setup protocol number dictionary
proto_number = {}
proto_number['mac'] = ost_pb.Protocol.kMacFieldNumber
proto_number['eth2'] = ost_pb.Protocol.kEth2FieldNumber
proto_number['ip4'] = ost_pb.Protocol.kIp4FieldNumber
proto_number['udp'] = ost_pb.Protocol.kUdpFieldNumber
proto_number['payload'] = ost_pb.Protocol.kPayloadFieldNumber
# setup logging
log = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
print('')
print('This test uses the following topology -')
print('')
print(' +-------+ ')
print(' | |Tx--->----+')
print(' | Drone | |')
print(' | |Rx---<----+')
print(' +-------+ ')
print('')
print('A loopback port is used as both the Tx and Rx ports')
print('')
@pytest.fixture(scope='module')
def drone(request):
"""Baseline Configuration for all testcases in this module"""
dut = DroneProxy(host_name)
log.info('connecting to drone(%s:%d)' % (dut.hostName(), dut.portNumber()))
dut.connect()
def fin():
dut.disconnect()
request.addfinalizer(fin)
return dut
@pytest.fixture(scope='module')
def ports(request, drone):
# retreive port id list
log.info('retreiving port list')
port_id_list = drone.getPortIdList()
# retreive port config list
log.info('retreiving port config for all ports')
port_config_list = drone.getPortConfig(port_id_list)
if len(port_config_list.port) == 0:
log.warning('drone has no ports!')
sys.exit(1)
# iterate port list to find a loopback port to use as the tx/rx port id
print('Port List')
print('---------')
for port in port_config_list.port:
print('%d.%s (%s)' % (port.port_id.id, port.name, port.description))
# use a loopback port as default tx/rx port
if ('lo' in port.name or 'loopback' in port.description.lower()):
tx_number = port.port_id.id
rx_number = port.port_id.id
if tx_number < 0 or rx_number < 0:
log.warning('loopback port not found')
sys.exit(1)
print('Using port %d as tx/rx port(s)' % tx_number)
ports.tx = ost_pb.PortIdList()
ports.tx.port_id.add().id = tx_number;
ports.rx = ost_pb.PortIdList()
ports.rx.port_id.add().id = rx_number;
# delete existing streams, if any, on tx port
sid_list = drone.getStreamIdList(ports.tx.port_id[0])
drone.deleteStream(sid_list)
return ports
protolist=['mac eth2 ip4 udp payload', 'mac eth2 ip4 udp']
@pytest.fixture(scope='module', params=protolist)
def stream(request, drone, ports):
global proto_number
# add a stream
stream_id = ost_pb.StreamIdList()
stream_id.port_id.CopyFrom(ports.tx.port_id[0])
stream_id.stream_id.add().id = 1
log.info('adding tx_stream %d' % stream_id.stream_id[0].id)
drone.addStream(stream_id)
# configure the stream
stream_cfg = ost_pb.StreamConfigList()
stream_cfg.port_id.CopyFrom(ports.tx.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 = 100
s.control.num_packets = 10
# setup stream protocols as mac:eth2:ip:udp:payload
s.ClearField("protocol")
protos = request.param.split()
for p in protos:
s.protocol.add().protocol_id.id = proto_number[p]
def fin():
# delete streams
log.info('deleting tx_stream %d' % stream_id.stream_id[0].id)
drone.deleteStream(stream_id)
request.addfinalizer(fin)
return stream_cfg
@pytest.mark.parametrize("mode", [
ost_pb.StreamCore.e_fl_inc,
ost_pb.StreamCore.e_fl_dec,
ost_pb.StreamCore.e_fl_random
])
def test_packet_length(drone, ports, stream, mode):
""" Test random length packets """
min_pkt_len = 100
max_pkt_len = 1000
stream.stream[0].core.len_mode = mode
stream.stream[0].core.frame_len_min = min_pkt_len
stream.stream[0].core.frame_len_max = max_pkt_len
log.info('configuring tx_stream %d' % stream.stream[0].stream_id.id)
drone.modifyStream(stream)
# clear tx/rx stats
log.info('clearing tx/rx stats')
drone.clearStats(ports.tx)
drone.clearStats(ports.rx)
try:
drone.startCapture(ports.rx)
drone.startTransmit(ports.tx)
log.info('waiting for transmit to finish ...')
time.sleep(3)
drone.stopTransmit(ports.tx)
drone.stopCapture(ports.rx)
log.info('getting Rx capture buffer')
buff = drone.getCaptureBuffer(ports.rx.port_id[0])
drone.saveCaptureBuffer(buff, 'capture.pcap')
log.info('dumping Rx capture buffer')
cap_pkts = subprocess.check_output([tshark, '-n', '-r', 'capture.pcap',
'-R', 'udp'])
cap_pkts = subprocess.check_output([tshark, '-n', '-r', 'capture.pcap',
'-R', 'udp', '-o', fmt])
print(cap_pkts)
result = extract_column(cap_pkts, fmt_col)
diffSum = 0
for i in range(len(result)):
l = int(result[i]) + 4 # add FCS to length
assert (l >= min_pkt_len) and (l <= max_pkt_len)
# check current packet length to last
if (i > 0):
ll = int(result[i-1]) + 4
if mode == ost_pb.StreamCore.e_fl_inc:
assert l == (ll+1)
elif mode == ost_pb.StreamCore.e_fl_dec:
assert l == (ll-1)
elif mode == ost_pb.StreamCore.e_fl_random:
diffSum += (l-ll)
# TODO: find a better way to check for randomness
if mode == ost_pb.StreamCore.e_fl_random:
assert (diffSum % (len(result) - 1)) != 0
os.remove('capture.pcap')
except RpcError as e:
raise
finally:
drone.stopTransmit(ports.tx)

3
test/pytest.ini Normal file
View File

@ -0,0 +1,3 @@
[pytest]
; change file glob pattern after converting old test files to pytest
python_files=pktlentest.py