Create a Tx Ttag tracker thread
For now we are just debug printing timestamp with T-TagId and GUID. We need to store this tuple and compare when we Rx the same - this will be in a upcoming commit.
This commit is contained in:
parent
f1cfaa6e89
commit
682d0cc5c9
@ -241,3 +241,25 @@ bool SignProtocol::packetGuid(const uchar *pkt, int pktLen, uint *guid)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SignProtocol::packetTtagId(const uchar *pkt, int pktLen, uint *ttagId, uint *guid)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
const uchar *p = pkt + pktLen - sizeof(kSignMagic);
|
||||||
|
quint32 magic = qFromBigEndian<quint32>(p);
|
||||||
|
if (magic != kSignMagic)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*guid = 0xffffffff; // invalid GUID
|
||||||
|
p--;
|
||||||
|
while (*p != kTypeLenEnd) {
|
||||||
|
if (*p == kTypeLenTtag) {
|
||||||
|
*ttagId = *(p - 1);
|
||||||
|
ret = true;
|
||||||
|
} else if (*p == kTypeLenGuid) {
|
||||||
|
*guid = qFromBigEndian<quint32>(p - 3) >> 8;
|
||||||
|
}
|
||||||
|
p -= 1 + (*p >> 5); // move to next TLV
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -86,6 +86,7 @@ public:
|
|||||||
|
|
||||||
static quint32 magic();
|
static quint32 magic();
|
||||||
static bool packetGuid(const uchar *pkt, int pktLen, uint *guid);
|
static bool packetGuid(const uchar *pkt, int pktLen, uint *guid);
|
||||||
|
static bool packetTtagId(const uchar *pkt, int pktLen, uint *ttagId, uint *guid);
|
||||||
|
|
||||||
static const quint32 kMaxGuid = 0x00ffffff;
|
static const quint32 kMaxGuid = 0x00ffffff;
|
||||||
static const quint8 kTypeLenTtagPlaceholder = 0x22;
|
static const quint8 kTypeLenTtagPlaceholder = 0x22;
|
||||||
|
@ -56,6 +56,7 @@ SOURCES += \
|
|||||||
pcaprxstats.cpp \
|
pcaprxstats.cpp \
|
||||||
pcaptxstats.cpp \
|
pcaptxstats.cpp \
|
||||||
pcaptxthread.cpp \
|
pcaptxthread.cpp \
|
||||||
|
pcaptxttagstats.cpp \
|
||||||
bsdhostdevice.cpp \
|
bsdhostdevice.cpp \
|
||||||
bsdport.cpp \
|
bsdport.cpp \
|
||||||
linuxhostdevice.cpp \
|
linuxhostdevice.cpp \
|
||||||
|
@ -34,6 +34,7 @@ PcapPort::PcapPort(int id, const char *device)
|
|||||||
transmitter_ = new PcapTransmitter(device, streamStats_);
|
transmitter_ = new PcapTransmitter(device, streamStats_);
|
||||||
capturer_ = new PortCapturer(device);
|
capturer_ = new PortCapturer(device);
|
||||||
emulXcvr_ = new EmulationTransceiver(device, deviceManager_);
|
emulXcvr_ = new EmulationTransceiver(device, deviceManager_);
|
||||||
|
txTtagStatsPoller_ = new PcapTxTtagStats(device, id);
|
||||||
rxStatsPoller_ = new PcapRxStats(device, streamStats_, id);
|
rxStatsPoller_ = new PcapRxStats(device, streamStats_, id);
|
||||||
|
|
||||||
if (!monitorRx_->handle() || !monitorTx_->handle())
|
if (!monitorRx_->handle() || !monitorTx_->handle())
|
||||||
@ -85,6 +86,9 @@ PcapPort::~PcapPort()
|
|||||||
if (monitorTx_)
|
if (monitorTx_)
|
||||||
monitorTx_->stop();
|
monitorTx_->stop();
|
||||||
|
|
||||||
|
txTtagStatsPoller_->stop();
|
||||||
|
delete txTtagStatsPoller_;
|
||||||
|
|
||||||
rxStatsPoller_->stop();
|
rxStatsPoller_->stop();
|
||||||
delete rxStatsPoller_;
|
delete rxStatsPoller_;
|
||||||
|
|
||||||
@ -145,8 +149,10 @@ bool PcapPort::setRateAccuracy(AbstractPort::Accuracy accuracy)
|
|||||||
void PcapPort::updateStreamStats()
|
void PcapPort::updateStreamStats()
|
||||||
{
|
{
|
||||||
// XXX: PcapTxThread already does this at the end of transmit; we
|
// XXX: PcapTxThread already does this at the end of transmit; we
|
||||||
// just dump rx stats poller debug stats here
|
// just dump tx/rx stats poller debug stats here
|
||||||
|
|
||||||
|
qDebug("port %d txTtagStatsPoller: %s",
|
||||||
|
id(), qUtf8Printable(txTtagStatsPoller_->debugStats()));
|
||||||
qDebug("port %d rxStatsPoller: %s",
|
qDebug("port %d rxStatsPoller: %s",
|
||||||
id(), qUtf8Printable(rxStatsPoller_->debugStats()));
|
id(), qUtf8Printable(rxStatsPoller_->debugStats()));
|
||||||
}
|
}
|
||||||
@ -170,6 +176,8 @@ bool PcapPort::startStreamStatsTracking()
|
|||||||
{
|
{
|
||||||
if (!transmitter_->setStreamStatsTracking(true))
|
if (!transmitter_->setStreamStatsTracking(true))
|
||||||
goto _tx_fail;
|
goto _tx_fail;
|
||||||
|
if (!txTtagStatsPoller_->start())
|
||||||
|
goto _tx_ttag_fail;
|
||||||
if (!rxStatsPoller_->start())
|
if (!rxStatsPoller_->start())
|
||||||
goto _rx_fail;
|
goto _rx_fail;
|
||||||
/*
|
/*
|
||||||
@ -183,22 +191,28 @@ bool PcapPort::startStreamStatsTracking()
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
_rx_fail:
|
_rx_fail:
|
||||||
|
txTtagStatsPoller_->stop();
|
||||||
|
_tx_ttag_fail:
|
||||||
transmitter_->setStreamStatsTracking(false);
|
transmitter_->setStreamStatsTracking(false);
|
||||||
_tx_fail:
|
_tx_fail:
|
||||||
qWarning("failed to start stream stats tracking");
|
qWarning("failed to start stream stats tracking");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: stop everything possible, don't revert in case of error
|
||||||
bool PcapPort::stopStreamStatsTracking()
|
bool PcapPort::stopStreamStatsTracking()
|
||||||
{
|
{
|
||||||
if (!transmitter_->setStreamStatsTracking(false))
|
if (!transmitter_->setStreamStatsTracking(false))
|
||||||
goto _tx_fail;
|
goto _tx_fail;
|
||||||
|
if (!txTtagStatsPoller_->stop())
|
||||||
|
goto _tx_ttag_fail;
|
||||||
if (!rxStatsPoller_->stop())
|
if (!rxStatsPoller_->stop())
|
||||||
goto _rx_fail;
|
goto _rx_fail;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
_rx_fail:
|
_rx_fail:
|
||||||
transmitter_->setStreamStatsTracking(true);
|
_tx_ttag_fail:
|
||||||
|
transmitter_->setStreamStatsTracking(true); // FIXME: needed?
|
||||||
_tx_fail:
|
_tx_fail:
|
||||||
qWarning("failed to stop stream stats tracking");
|
qWarning("failed to stop stream stats tracking");
|
||||||
return false;
|
return false;
|
||||||
|
@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "abstractport.h"
|
#include "abstractport.h"
|
||||||
#include "pcapextra.h"
|
#include "pcapextra.h"
|
||||||
#include "pcaprxstats.h"
|
#include "pcaprxstats.h"
|
||||||
|
#include "pcaptxttagstats.h"
|
||||||
#include "pcapsession.h"
|
#include "pcapsession.h"
|
||||||
#include "pcaptransmitter.h"
|
#include "pcaptransmitter.h"
|
||||||
|
|
||||||
@ -177,6 +178,7 @@ private:
|
|||||||
PcapTransmitter *transmitter_;
|
PcapTransmitter *transmitter_;
|
||||||
PortCapturer *capturer_;
|
PortCapturer *capturer_;
|
||||||
EmulationTransceiver *emulXcvr_;
|
EmulationTransceiver *emulXcvr_;
|
||||||
|
PcapTxTtagStats *txTtagStatsPoller_;
|
||||||
PcapRxStats *rxStatsPoller_;
|
PcapRxStats *rxStatsPoller_;
|
||||||
|
|
||||||
static pcap_if_t *deviceList_;
|
static pcap_if_t *deviceList_;
|
||||||
|
234
server/pcaptxttagstats.cpp
Normal file
234
server/pcaptxttagstats.cpp
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2023 Srivats P.
|
||||||
|
|
||||||
|
This file is part of "Ostinato"
|
||||||
|
|
||||||
|
This is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pcaptxttagstats.h"
|
||||||
|
|
||||||
|
#include "pcapextra.h"
|
||||||
|
#include "../common/sign.h"
|
||||||
|
|
||||||
|
#define Xnotify qWarning // FIXME
|
||||||
|
|
||||||
|
PcapTxTtagStats::PcapTxTtagStats(const char *device, int id)
|
||||||
|
: id_(id)
|
||||||
|
{
|
||||||
|
setObjectName(QString("TxTtagStats:%1").arg(device));
|
||||||
|
device_ = QString::fromLatin1(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PcapTxTtagStats::run()
|
||||||
|
{
|
||||||
|
int flags = PCAP_OPENFLAG_PROMISCUOUS;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||||
|
struct bpf_program bpf;
|
||||||
|
const int optimize = 1;
|
||||||
|
QString capture_filter = QString("(ether[len - 5:5] == 0x%1%2)")
|
||||||
|
.arg(SignProtocol::kTypeLenTtag, 0, BASE_HEX)
|
||||||
|
.arg(SignProtocol::magic(), 0, BASE_HEX);
|
||||||
|
|
||||||
|
qDebug("In %s", __PRETTY_FUNCTION__);
|
||||||
|
qDebug("pcap-filter: %s", qPrintable(capture_filter));
|
||||||
|
|
||||||
|
handle_ = pcap_open_live(qPrintable(device_), 65535,
|
||||||
|
flags, 100 /* ms */, errbuf);
|
||||||
|
if (!handle_) {
|
||||||
|
if (flags && QString(errbuf).contains("promiscuous")) {
|
||||||
|
Xnotify("Unable to set promiscuous mode on <%s> - "
|
||||||
|
"stream stats time tracking will not work", qPrintable(device_));
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Xnotify("Unable to open <%s> [%s] - stream stats rx will not work",
|
||||||
|
qPrintable(device_), errbuf);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
// pcap_setdirection() API is not supported in Windows.
|
||||||
|
// NOTE: WinPcap 4.1.1 and above exports a dummy API that returns -1
|
||||||
|
// but since we would like to work with previous versions of WinPcap
|
||||||
|
// also, we assume the API does not exist
|
||||||
|
isDirectional_ = false;
|
||||||
|
#else
|
||||||
|
if (pcap_setdirection(handle_, PCAP_D_OUT) < 0) {
|
||||||
|
qDebug("TxTtagStats: Error setting OUT direction %s: %s\n",
|
||||||
|
qPrintable(device_), pcap_geterr(handle_));
|
||||||
|
isDirectional_ = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pcap_compile(handle_, &bpf, qPrintable(capture_filter),
|
||||||
|
optimize, 0) < 0) {
|
||||||
|
qWarning("%s: error compiling filter: %s", qPrintable(device_),
|
||||||
|
pcap_geterr(handle_));
|
||||||
|
goto _skip_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcap_setfilter(handle_, &bpf) < 0) {
|
||||||
|
qWarning("%s: error setting filter: %s", qPrintable(device_),
|
||||||
|
pcap_geterr(handle_));
|
||||||
|
goto _skip_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
_skip_filter:
|
||||||
|
PcapSession::preRun();
|
||||||
|
state_ = kRunning;
|
||||||
|
while (1) {
|
||||||
|
int ret;
|
||||||
|
struct pcap_pkthdr *hdr;
|
||||||
|
const uchar *data;
|
||||||
|
|
||||||
|
ret = pcap_next_ex(handle_, &hdr, &data);
|
||||||
|
switch (ret) {
|
||||||
|
case 1: {
|
||||||
|
uint ttagId;
|
||||||
|
uint guid;
|
||||||
|
if (SignProtocol::packetTtagId(data, hdr->caplen,
|
||||||
|
&ttagId, &guid)) {
|
||||||
|
// TODO: store packet timestamp with ttag/guid
|
||||||
|
qDebug("XXXXX %ld:%ld ttag %u guid %u",
|
||||||
|
hdr->ts.tv_sec, hdr->ts.tv_usec, ttagId, guid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0:
|
||||||
|
// timeout: just go back to the loop
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
qWarning("%s: error reading packet (%d): %s",
|
||||||
|
__PRETTY_FUNCTION__, ret, pcap_geterr(handle_));
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
qDebug("%s: Loop/signal break or some other error",
|
||||||
|
__PRETTY_FUNCTION__);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qWarning("%s: Unexpected return value %d",
|
||||||
|
__PRETTY_FUNCTION__, ret);
|
||||||
|
stop_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop_) {
|
||||||
|
qDebug("user requested txTtagStats stop");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PcapSession::postRun();
|
||||||
|
pcap_close(handle_);
|
||||||
|
handle_ = NULL;
|
||||||
|
stop_ = false;
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
state_ = kFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PcapTxTtagStats::start()
|
||||||
|
{
|
||||||
|
if (state_ == kRunning) {
|
||||||
|
qWarning("TxTtagStats start requested but is already running!");
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_ = kNotStarted;
|
||||||
|
PcapSession::start();
|
||||||
|
|
||||||
|
while (state_ == kNotStarted)
|
||||||
|
QThread::msleep(10);
|
||||||
|
_exit:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PcapTxTtagStats::stop()
|
||||||
|
{
|
||||||
|
if (state_ == kRunning) {
|
||||||
|
stop_ = true;
|
||||||
|
PcapSession::stop(handle_);
|
||||||
|
while (state_ == kRunning)
|
||||||
|
QThread::msleep(10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
qWarning("TxTtagStats stop requested but is not running!");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PcapTxTtagStats::isRunning()
|
||||||
|
{
|
||||||
|
return (state_ == kRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PcapTxTtagStats::isDirectional()
|
||||||
|
{
|
||||||
|
return isDirectional_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: move to PcapSession
|
||||||
|
// XXX: Implemented as reset on read
|
||||||
|
QString PcapTxTtagStats::debugStats()
|
||||||
|
{
|
||||||
|
QString dbgStats;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
static_assert(sizeof(struct pcap_stat) == 6*sizeof(uint),
|
||||||
|
"pcap_stat has less or more than 6 values");
|
||||||
|
int size;
|
||||||
|
struct pcap_stat incPcapStats;
|
||||||
|
struct pcap_stat *pcapStats = pcap_stats_ex(handle_, &size);
|
||||||
|
if (pcapStats && (uint(size) >= 6*sizeof(uint))) {
|
||||||
|
incPcapStats.ps_recv = pcapStats->ps_recv - lastPcapStats_.ps_recv;
|
||||||
|
incPcapStats.ps_drop = pcapStats->ps_drop - lastPcapStats_.ps_drop;
|
||||||
|
incPcapStats.ps_ifdrop = pcapStats->ps_ifdrop - lastPcapStats_.ps_ifdrop;
|
||||||
|
incPcapStats.ps_capt = pcapStats->ps_capt - lastPcapStats_.ps_capt;
|
||||||
|
incPcapStats.ps_sent = pcapStats->ps_sent - lastPcapStats_.ps_sent;
|
||||||
|
incPcapStats.ps_netdrop = pcapStats->ps_netdrop - lastPcapStats_.ps_netdrop;
|
||||||
|
dbgStats = QString("recv: %1 drop: %2 ifdrop: %3 "
|
||||||
|
"capt: %4 sent: %5 netdrop: %6")
|
||||||
|
.arg(incPcapStats.ps_recv)
|
||||||
|
.arg(incPcapStats.ps_drop)
|
||||||
|
.arg(incPcapStats.ps_ifdrop)
|
||||||
|
.arg(incPcapStats.ps_capt)
|
||||||
|
.arg(incPcapStats.ps_sent)
|
||||||
|
.arg(incPcapStats.ps_netdrop);
|
||||||
|
lastPcapStats_ = *pcapStats;
|
||||||
|
} else {
|
||||||
|
dbgStats = QString("error reading pcap stats: %1")
|
||||||
|
.arg(pcap_geterr(handle_));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct pcap_stat pcapStats;
|
||||||
|
struct pcap_stat incPcapStats;
|
||||||
|
|
||||||
|
int ret = pcap_stats(handle_, &pcapStats);
|
||||||
|
if (ret == 0) {
|
||||||
|
incPcapStats.ps_recv = pcapStats.ps_recv - lastPcapStats_.ps_recv;
|
||||||
|
incPcapStats.ps_drop = pcapStats.ps_drop - lastPcapStats_.ps_drop;
|
||||||
|
incPcapStats.ps_ifdrop = pcapStats.ps_ifdrop - lastPcapStats_.ps_ifdrop;
|
||||||
|
dbgStats = QString("recv: %1 drop: %2 ifdrop: %3")
|
||||||
|
.arg(incPcapStats.ps_recv)
|
||||||
|
.arg(incPcapStats.ps_drop)
|
||||||
|
.arg(incPcapStats.ps_ifdrop);
|
||||||
|
lastPcapStats_ = pcapStats;
|
||||||
|
} else {
|
||||||
|
dbgStats = QString("error reading pcap stats: %1")
|
||||||
|
.arg(pcap_geterr(handle_));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return dbgStats;
|
||||||
|
}
|
55
server/pcaptxttagstats.h
Normal file
55
server/pcaptxttagstats.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2023 Srivats P.
|
||||||
|
|
||||||
|
This file is part of "Ostinato"
|
||||||
|
|
||||||
|
This is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PCAP_TX_TTAG_H
|
||||||
|
#define _PCAP_TX_TTAG_H
|
||||||
|
|
||||||
|
#include "pcapsession.h"
|
||||||
|
|
||||||
|
class PcapTxTtagStats: public PcapSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PcapTxTtagStats(const char *device, int id);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
bool start();
|
||||||
|
bool stop();
|
||||||
|
bool isRunning();
|
||||||
|
bool isDirectional();
|
||||||
|
|
||||||
|
QString debugStats();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum State {
|
||||||
|
kNotStarted,
|
||||||
|
kRunning,
|
||||||
|
kFinished
|
||||||
|
};
|
||||||
|
|
||||||
|
QString device_;
|
||||||
|
bool isDirectional_{true};
|
||||||
|
pcap_t *handle_{nullptr};
|
||||||
|
volatile State state_{kNotStarted};
|
||||||
|
volatile bool stop_{false};
|
||||||
|
|
||||||
|
int id_; // FIXME: needed?
|
||||||
|
struct pcap_stat lastPcapStats_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user