- Packet Transmission is now a separate thread to allow for event processing

- Packet Transmission rate (IPG) is done - need to test. IBG is still pending
- Per port there are two pcap_t handles - one for Rx and one for Tx: since PCAP does not capture loopback packets, transmission by OST happens on Rx Hdl so that they are recieved on the Tx Hdl
- pcap_loop() changed to pcap_dispatch() to be able to work in PCAP/Linux - forgot exactly why :-)
- Removed NIC stats
- Implemented PortStatsFilterDialog ordering of ports
- PortStatsWindow - Tooltip on Port column dispays stats limitations
This commit is contained in:
Srivats P. 2009-02-12 17:07:19 +00:00
parent 0c70668e56
commit 017cb75ae5
9 changed files with 294 additions and 156 deletions

View File

@ -6,7 +6,7 @@
<x>0</x>
<y>0</y>
<width>588</width>
<height>298</height>
<height>320</height>
</rect>
</property>
<property name="windowTitle" >
@ -17,9 +17,21 @@
<layout class="QHBoxLayout" >
<item>
<widget class="QListView" name="lvUnselected" >
<property name="acceptDrops" >
<bool>false</bool>
</property>
<property name="dragEnabled" >
<bool>false</bool>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="movement" >
<enum>QListView::Static</enum>
</property>
</widget>
</item>
<item>
@ -68,6 +80,18 @@
</item>
<item>
<widget class="QListView" name="lvSelected" >
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="dragEnabled" >
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode" >
<bool>false</bool>
</property>
<property name="dragDropMode" >
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
@ -76,50 +100,6 @@
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="toolButton" >
<property name="text" >
<string>U</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_2" >
<property name="text" >
<string>D</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>

View File

@ -4,13 +4,6 @@ PortStatsFilterDialog::PortStatsFilterDialog(QWidget *parent)
{
setupUi(this);
// TODO(MED): Use ExtendedSelection and use "selected" instead of
// "current" for selecting in/out
// TODO(MED): Ensure items are READ-ONLY not editable
// TODO(MED): Enable "double-click" on items
lvUnselected->setSelectionMode(QAbstractItemView::SingleSelection);
lvSelected->setSelectionMode(QAbstractItemView::SingleSelection);
mUnselected.setSortRole(PositionRole);
lvUnselected->setModel(&mUnselected);
@ -37,6 +30,10 @@ QList<uint> PortStatsFilterDialog::getItemList(bool* ok,
item = new QStandardItem(model->headerData(i, orientation).toString());
item->setData(i, PositionRole);
item->setFlags(Qt::ItemIsSelectable
| Qt::ItemIsDragEnabled
//| Qt::ItemIsDropEnabled
| Qt::ItemIsEnabled);
if (initial.contains(i))
mSelected.appendRow(item);
@ -62,6 +59,36 @@ QList<uint> PortStatsFilterDialog::getItemList(bool* ok,
}
void PortStatsFilterDialog::on_tbSelectIn_clicked()
{
QStandardItem *item;
while (lvUnselected->selectionModel()->selectedIndexes().size())
{
item = mUnselected.takeItem(lvUnselected->selectionModel()->
selectedIndexes().at(0).row());
if (mUnselected.removeRow(lvUnselected->selectionModel()->
selectedIndexes().at(0).row()))
mSelected.appendRow(item);
}
}
void PortStatsFilterDialog::on_tbSelectOut_clicked()
{
QStandardItem *item;
while (lvSelected->selectionModel()->selectedIndexes().size())
{
item = mSelected.takeItem(lvSelected->selectionModel()->
selectedIndexes().at(0).row());
if (mSelected.removeRow(lvSelected->selectionModel()->
selectedIndexes().at(0).row()))
{
mUnselected.appendRow(item);
mUnselected.sort(0);
}
}
}
void PortStatsFilterDialog::on_lvUnselected_doubleClicked(const QModelIndex &index)
{
QStandardItem *item;
@ -70,7 +97,7 @@ void PortStatsFilterDialog::on_tbSelectIn_clicked()
mSelected.appendRow(item);
}
void PortStatsFilterDialog::on_tbSelectOut_clicked()
void PortStatsFilterDialog::on_lvSelected_doubleClicked(const QModelIndex &index)
{
QStandardItem *item;

View File

@ -27,6 +27,8 @@ private:
private slots:
void on_tbSelectIn_clicked();
void on_tbSelectOut_clicked();
void on_lvUnselected_doubleClicked(const QModelIndex &index);
void on_lvSelected_doubleClicked(const QModelIndex &index);
};
#endif

View File

@ -105,12 +105,6 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
case e_STAT_FRAME_RECV_RATE:
return stats.rx_pps();
case e_STAT_FRAMES_RCVD_NIC:
return stats.rx_pkts_nic();
case e_STAT_FRAMES_SENT_NIC:
return stats.tx_pkts_nic();
case e_STAT_BYTES_RCVD:
return stats.rx_bytes();
@ -123,12 +117,19 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
case e_STAT_BYTE_RECV_RATE:
return stats.rx_bps();
#if 0
case e_STAT_FRAMES_RCVD_NIC:
return stats.rx_pkts_nic();
case e_STAT_FRAMES_SENT_NIC:
return stats.tx_pkts_nic();
case e_STAT_BYTES_RCVD_NIC:
return stats.rx_bytes_nic();
case e_STAT_BYTES_SENT_NIC:
return stats.tx_bytes_nic();
#endif
default:
qWarning("%s: Unhandled stats id %d\n", __FUNCTION__,
index.row());
@ -142,11 +143,39 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
#ifdef Q_OS_WIN32
// TODO(MED): The limitations should be the server's not the client's!
// Ideally we shd enhance the protocol to convey limitation(s), if any,
// from server to client
if (role == Qt::ToolTipRole)
{
if (orientation == Qt::Horizontal)
{
return QString("<b>Limitation(s)</b>"
"<p><i>Frames/Bytes Receieved</i>: Includes non Ostinato Tx pkts also (Tx by Ostinato are not included)<br>"
"<i>Frames/Bytes Sent</i>: Only Ostinato Tx pkts (Tx by others NOT included)</p>"
"<p>Rx/Tx Rates are derived from the above and hence subject to same limitations</p>"
);
}
else
return QVariant();
}
#endif
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
return QString("Port %1").arg(section);
{
uint portGroupIdx, portIdx;
getDomainIndexes(index(0, section), portGroupIdx, portIdx);
#ifdef Q_OS_WIN32
return QString("Port %1/%2 (*)").arg(portGroupIdx).arg(portIdx);
#else
return QString("Port %1/%2").arg(portGroupIdx).arg(portIdx);
#endif
}
else
return PortStatName.at(section);
}
@ -212,7 +241,6 @@ void PortStatsModel::when_portListChanged()
void PortStatsModel::on_portStatsUpdate(int port, void*stats)
{
// FIXME(MED): update only the changed port not all
QModelIndex topLeft = index(port, 0, QModelIndex());
QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex());

View File

@ -9,14 +9,16 @@ typedef enum {
e_STAT_FRAMES_SENT,
e_STAT_FRAME_SEND_RATE,
e_STAT_FRAME_RECV_RATE,
e_STAT_FRAMES_RCVD_NIC,
e_STAT_FRAMES_SENT_NIC,
e_STAT_BYTES_RCVD,
e_STAT_BYTES_SENT,
e_STAT_BYTE_SEND_RATE,
e_STAT_BYTE_RECV_RATE,
#if 0
e_STAT_FRAMES_RCVD_NIC,
e_STAT_FRAMES_SENT_NIC,
e_STAT_BYTES_RCVD_NIC,
e_STAT_BYTES_SENT_NIC,
#endif
e_STAT_MAX
} PortStat;
@ -25,14 +27,16 @@ static QStringList PortStatName = (QStringList()
<< "Frames Sent"
<< "Frame Send Rate (fps)"
<< "Frame Receive Rate (fps)"
<< "Frames Received (NIC)"
<< "Frames Sent (NIC)"
<< "Bytes Received"
<< "Bytes Sent"
<< "Byte Send Rate (Bps)"
<< "Byte Receive Rate (Bps)"
#if 0
<< "Frames Received (NIC)"
<< "Frames Sent (NIC)"
<< "Bytes Received (NIC)"
<< "Bytes Sent (NIC)"
#endif
);
class PortGroupList;

View File

@ -13,11 +13,11 @@ PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
this->pgl = pgl;
model = pgl->getPortStatsModel();
tvPortStats->setModel(model);
tvPortStats->horizontalHeader()->setMovable(true);
tvPortStats->verticalHeader()->setHighlightSections(false);
tvPortStats->verticalHeader()->setDefaultSectionSize(
tvPortStats->verticalHeader()->minimumSectionSize());
}
PortStatsWindow::~PortStatsWindow()
@ -109,7 +109,17 @@ void PortStatsWindow::on_tbFilter_clicked()
newColumns = dialog.getItemList(&ok, model, Qt::Horizontal, currentColumns);
if(ok)
if (ok)
{
// hide/show sections first ...
for(int i = 0; i < model->columnCount(); i++)
tvPortStats->setColumnHidden(i, !newColumns.contains(i));
// ... then for the 'shown' columns, set the visual index
for(int i = 0; i < newColumns.size(); i++)
{
tvPortStats->horizontalHeader()->moveSection(tvPortStats->
horizontalHeader()->visualIndex(newColumns.at(i)), i);
}
}
}

View File

@ -15,9 +15,6 @@
<layout class="QVBoxLayout" >
<item>
<widget class="QFrame" name="frame" >
<property name="toolTip" >
<string>Clear All</string>
</property>
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
@ -28,7 +25,7 @@
<item>
<widget class="QToolButton" name="tbStartTransmit" >
<property name="toolTip" >
<string>Clear All</string>
<string>Start Tx</string>
</property>
<property name="statusTip" >
<string>Starts transmit on selected port(s)</string>
@ -44,7 +41,7 @@
<item>
<widget class="QToolButton" name="tbStopTransmit" >
<property name="toolTip" >
<string>Clear All</string>
<string>Stop Tx</string>
</property>
<property name="statusTip" >
<string>Stops transmit on selected port(s)</string>
@ -60,7 +57,7 @@
<item>
<widget class="QToolButton" name="tbClear" >
<property name="toolTip" >
<string>Clear All</string>
<string>Clear Selected Port Stats</string>
</property>
<property name="statusTip" >
<string>Clears statistics of the selected port(s)</string>
@ -73,7 +70,7 @@
<item>
<widget class="QToolButton" name="tbClearAll" >
<property name="toolTip" >
<string>Clear All</string>
<string>Clear All Ports Stats</string>
</property>
<property name="statusTip" >
<string>Clears statistics of all ports</string>
@ -86,7 +83,7 @@
<item>
<widget class="QToolButton" name="tbStartCapture" >
<property name="toolTip" >
<string>Clear All</string>
<string>Start Capture</string>
</property>
<property name="statusTip" >
<string>Captures packets on the selected port(s)</string>
@ -102,7 +99,7 @@
<item>
<widget class="QToolButton" name="tbStopCapture" >
<property name="toolTip" >
<string>Clear All</string>
<string>Stop Capture</string>
</property>
<property name="statusTip" >
<string>End capture on selecteed port(s)</string>
@ -118,7 +115,7 @@
<item>
<widget class="QToolButton" name="tbViewCapture" >
<property name="toolTip" >
<string>Clear All</string>
<string>View Capture Buffer</string>
</property>
<property name="statusTip" >
<string>View captured packets on selected port(s)</string>
@ -133,9 +130,6 @@
</item>
<item>
<widget class="Line" name="line" >
<property name="toolTip" >
<string>Clear All</string>
</property>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
@ -143,9 +137,6 @@
</item>
<item>
<spacer>
<property name="toolTip" >
<string>Clear All</string>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
@ -159,9 +150,6 @@
</item>
<item>
<widget class="QToolButton" name="tbFilter" >
<property name="toolTip" >
<string>Clear All</string>
</property>
<property name="statusTip" >
<string>Select which ports to view</string>
</property>
@ -177,11 +165,7 @@
</widget>
</item>
<item>
<widget class="QTableView" name="tvPortStats" >
<property name="toolTip" >
<string>Clear All</string>
</property>
</widget>
<widget class="QTableView" name="tvPortStats" />
</item>
</layout>
</widget>

View File

@ -4,7 +4,7 @@
#include <qglobal.h>
#include <qendian.h>
#ifdef Q_OS_WIN32
#if 0
#include <pcap-int.h>
#include <Ntddndis.h>
#endif
@ -482,7 +482,7 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n)
// ------------------ PortInfo --------------------
//
PortInfo::PortInfo(uint id, pcap_if_t *dev)
: monitorRx(this), monitorTx(this)
: monitorRx(this), monitorTx(this), transmitter(this)
{
char errbuf[PCAP_ERRBUF_SIZE];
@ -501,10 +501,12 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
dev->name, pcap_geterr(devHandleRx));
}
#if 0
if (pcap_setdirection(devHandleRx, PCAP_D_IN)<0)
{
qDebug("[%s] Error setting direction inbound only\n", dev->name);
}
#endif
/* By default, put the interface in statistics mode */
if (pcap_setmode(devHandleRx, MODE_STAT)<0)
@ -520,10 +522,12 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
dev->name, pcap_geterr(devHandleTx));
}
#if 0
if (pcap_setdirection(devHandleTx, PCAP_D_OUT)<0)
{
qDebug("[%s] Error setting direction outbound only\n", dev->name);
}
#endif
/* By default, put the interface in statistics mode */
if (pcap_setmode(devHandleTx, MODE_STAT)<0)
@ -534,14 +538,15 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
d.mutable_port_id()->set_id(id);
#ifdef Q_OS_WIN32
d.set_name(QString("if%1").arg(id).toAscii().constData());
d.set_name(QString("if%1 ").arg(id).toAscii().constData());
#else
if (dev->name)
d.set_name(dev->name);
else
d.set_name(QString("if%1").arg(id).toAscii().constData());
d.set_name(QString("if%1 ").arg(id).toAscii().constData());
#endif
d.set_name(d.name()+pcap_datalink_val_to_name(pcap_datalink(devHandleRx)));
d.set_name(d.name()+"{"+
pcap_datalink_val_to_name(pcap_datalink(devHandleRx))+"}");
if (dev->description)
d.set_description(dev->description);
@ -586,6 +591,7 @@ void PortInfo::update()
if (streamList[i].d.core().is_enabled())
{
int numPackets, numBursts;
long ipg;
switch (streamList[i].d.control().unit())
{
@ -596,6 +602,8 @@ void PortInfo::update()
case OstProto::StreamControl::e_su_packets:
numBursts = 1;
numPackets = streamList[i].d.control().num_packets();
ipg = 1000000/streamList[i].d.control().packets_per_sec();
qDebug("ipg = %ld\n", ipg);
break;
default:
qWarning("Unhandled stream control unit %d",
@ -603,9 +611,11 @@ void PortInfo::update()
continue;
}
pktHdr.ts.tv_sec = 0;
pktHdr.ts.tv_usec = 0;
for (int j = 0; j < numBursts; j++)
{
// FIXME(HI): IBG rate (bursts_per_sec)
for (int k = 0; k < numPackets; k++)
{
int len;
@ -615,7 +625,12 @@ void PortInfo::update()
if (len > 0)
{
pktHdr.caplen = pktHdr.len = len;
pktHdr.ts.tv_sec = pktHdr.ts.tv_usec = 0; // FIXME(HI)
pktHdr.ts.tv_usec += ipg;
if (pktHdr.ts.tv_usec > 1000000)
{
pktHdr.ts.tv_sec++;
pktHdr.ts.tv_usec -= 1000000;
}
if (-1 == pcap_sendqueue_queue(sendQueue, &pktHdr,
(u_char*) pktBuf))
@ -636,49 +651,7 @@ void PortInfo::update()
void PortInfo::startTransmit()
{
uint bytes, pkts;
// TODO(HI): Stream Mode - one pass/continuous
// NOTE: Transmit on the Rx Handle so that we can receive it back
// on the Tx Handle to do stats
bytes = pcap_sendqueue_transmit(devHandleRx, sendQueue, false);
if (bytes < sendQueue->len)
{
qDebug("port %d: sent (%d/%d) error %s. TxStats may be inconsistent",
id(), bytes, sendQueue->len, pcap_geterr(devHandleTx));
// parse sendqueue using 'bytes' to get actual pkts sent
#if 0
// FIXME(LOW): Get this working
pkts = qUpperBound(pcapExtra.sendQueueCumLen, bytes);
#else
for (int i = 0; i < pcapExtra.sendQueueCumLen.size(); i++)
{
if (pcapExtra.sendQueueCumLen.at(i) > bytes)
{
pkts = i;
break;
}
}
#endif
}
else
{
qDebug("port %d: sent (%d/%d) bytes\n", id(), bytes, sendQueue->len);
pkts = pcapExtra.sendQueueCumLen.size();
}
// pcap_sendqueue_transmit() returned 'bytes' includes size of pcap_pkthdr
// - adjust for it
if (bytes)
bytes -= pkts * sizeof(pcap_pkthdr);
#ifdef Q_OS_WIN32
// Update pcapExtra counters - port TxStats will be updated in the
// 'stats callback' function so that both Rx and Tx stats are updated
// together
pcapExtra.txPkts += pkts;
pcapExtra.txBytes += bytes;
#endif
transmitter.start();
}
void PortInfo::stopTransmit()
@ -750,6 +723,11 @@ void PortInfo::PortMonitorRx::callbackRx(u_char *state,
pkts = *((quint64*)(pkt_data + 0));
bytes = *((quint64*)(pkt_data + 8));
#if 0
if (port->id() == 2)
qDebug("# %llu", pkts);
#endif
// Note: PCAP reported bytes includes ETH_FRAME_HDR_SIZE - adjust for it
bytes -= pkts * ETH_FRAME_HDR_SIZE;
@ -777,7 +755,7 @@ void PortInfo::PortMonitorRx::callbackRx(u_char *state,
#endif
// Retreive NIC stats
#ifdef Q_OS_WIN32
#if 0
port->monitorRx.oidData->Oid = OID_GEN_RCV_OK;
if (PacketRequest(port->devHandleRx->adapter, 0, port->monitorRx.oidData))
{
@ -799,20 +777,28 @@ void PortInfo::PortMonitorTx::callbackTx(u_char *state,
quint64 pkts;
quint64 bytes;
#if 0
// Update RxStats and RxRates using PCAP data
pkts = *((quint64*)(pkt_data + 0));
bytes = *((quint64*)(pkt_data + 8));
#if 0
if (port->id() == 2)
qDebug("@ %llu", pkts);
#endif
// Note: PCAP reported bytes includes ETH_FRAME_HDR_SIZE - adjust for it
bytes -= pkts * ETH_FRAME_HDR_SIZE;
usec = (header->ts.tv_sec - port->lastTs.tv_sec) * 1000000 +
(header->ts.tv_usec - port->lastTs.tv_usec);
port->stats.rxPps = (pkts * 1000000) / usec;
port->stats.rxBps = (bytes * 1000000) / usec;
usec = (header->ts.tv_sec - port->lastTsTx.tv_sec) * 1000000 +
(header->ts.tv_usec - port->lastTsTx.tv_usec);
port->stats.txPps = (pkts * 1000000) / usec;
port->stats.txBps = (bytes * 1000000) / usec;
port->stats.rxPkts += pkts;
port->stats.rxBytes += bytes;
port->stats.txPkts += pkts;
port->stats.txBytes += bytes;
#endif
// Since WinPCAP (due to NDIS limitation) cannot distinguish between
// rx/tx packets, pcap stats are not of much use - for the tx stats
@ -822,8 +808,8 @@ void PortInfo::PortMonitorTx::callbackTx(u_char *state,
bytes = port->pcapExtra.txBytes - port->stats.txBytes;
// Use the pcap timestamp for rate calculation though
usec = (header->ts.tv_sec - port->lastTs.tv_sec) * 1000000 +
(header->ts.tv_usec - port->lastTs.tv_usec);
usec = (header->ts.tv_sec - port->lastTsTx.tv_sec) * 1000000 +
(header->ts.tv_usec - port->lastTsTx.tv_usec);
port->stats.txPps = (pkts * 1000000) / usec;
port->stats.txBps = (bytes * 1000000) / usec;
@ -846,7 +832,7 @@ void PortInfo::PortMonitorTx::callbackTx(u_char *state,
#endif
// Retreive NIC stats
#ifdef Q_OS_WIN32
#if 0
port->monitorTx.oidData->Oid = OID_GEN_XMIT_OK;
if (PacketRequest(port->devHandleTx->adapter, 0, port->monitorTx.oidData))
{
@ -926,7 +912,7 @@ void PortInfo::PortMonitorRx::run()
int ret;
qDebug("before pcap_loop rx \n");
#if 1
/* Start the main loop */
ret = pcap_loop(port->devHandleRx, -1,
&PortInfo::PortMonitorRx::callbackRx, (u_char*) port);
@ -945,6 +931,28 @@ void PortInfo::PortMonitorRx::run()
default:
qDebug("Unknown return value from pcap_loop()\n");
}
#else
while (1)
{
/* Start the main loop */
ret = pcap_dispatch(port->devHandleRx, -1,
&PortInfo::PortMonitorRx::callbackRx, (u_char*) port);
switch(ret)
{
case -1:
qDebug("Unsolicited (error) return from pcap_loop() %s\n",
pcap_geterr(port->devHandleRx));
break;
case -2:
qDebug("Solicited return from pcap_loop()\n");
break;
default:
//qDebug("%d pkts rcvd\n", ret);
break;
}
}
#endif
}
void PortInfo::PortMonitorTx::run()
@ -952,7 +960,7 @@ void PortInfo::PortMonitorTx::run()
int ret;
qDebug("before pcap_loopTx\n");
#if 1
/* Start the main loop */
ret = pcap_loop(port->devHandleTx, -1,
&PortInfo::PortMonitorTx::callbackTx, (u_char*) port);
@ -971,6 +979,84 @@ void PortInfo::PortMonitorTx::run()
default:
qDebug("Unknown return value from pcap_loop()\n");
}
#else
while (1)
{
/* Start the main loop */
ret = pcap_dispatch(port->devHandleTx, -1,
&PortInfo::PortMonitorTx::callbackTx, (u_char*) port);
switch(ret)
{
case -1:
qDebug("Unsolicited (error) return from pcap_loop() %s\n",
pcap_geterr(port->devHandleTx));
break;
case -2:
qDebug("Solicited return from pcap_loop()\n");
break;
default:
//qDebug("%d pkts rcvd\n", ret);
break;
}
}
#endif
}
/*--------------- PortTransmitter ---------------*/
PortInfo::PortTransmitter::PortTransmitter(PortInfo *port)
{
this->port = port;
}
void PortInfo::PortTransmitter::run()
{
uint bytes, pkts;
// TODO(HI): Stream Mode - one pass/continuous
// NOTE: Transmit on the Rx Handle so that we can receive it back
// on the Tx Handle to do stats
bytes = pcap_sendqueue_transmit(port->devHandleRx, port->sendQueue, true);
if (bytes < port->sendQueue->len)
{
qDebug("port %d: sent (%d/%d) error %s. TxStats may be inconsistent",
port->id(), bytes, port->sendQueue->len,
pcap_geterr(port->devHandleTx));
// parse sendqueue using 'bytes' to get actual pkts sent
#if 0
// FIXME(LOW): Get this working
pkts = qUpperBound(pcapExtra.sendQueueCumLen, bytes);
#else
for (int i = 0; i < port->pcapExtra.sendQueueCumLen.size(); i++)
{
if (port->pcapExtra.sendQueueCumLen.at(i) > bytes)
{
pkts = i;
break;
}
}
#endif
}
else
{
qDebug("port %d: sent (%d/%d) bytes\n", port->id(), bytes,
port->sendQueue->len);
pkts = port->pcapExtra.sendQueueCumLen.size();
}
// pcap_sendqueue_transmit() returned 'bytes' includes size of pcap_pkthdr
// - adjust for it
if (bytes)
bytes -= pkts * sizeof(pcap_pkthdr);
#ifdef Q_OS_WIN32
// Update pcapExtra counters - port TxStats will be updated in the
// 'stats callback' function so that both Rx and Tx stats are updated
// together
port->pcapExtra.txPkts += pkts;
port->pcapExtra.txBytes += bytes;
#endif
}
/*--------------- MyService ---------------*/
@ -1369,6 +1455,11 @@ const ::OstProto::PortIdList* request,
s = response->add_port_stats();
s->mutable_port_id()->set_id(request->port_id(i).id());
if (portidx == 2)
{
qDebug("<%llu", portInfo[portidx]->epochStats.rxPkts);
qDebug(">%llu", portInfo[portidx]->stats.rxPkts);
}
s->set_rx_pkts(portInfo[portidx]->stats.rxPkts -
portInfo[portidx]->epochStats.rxPkts);
s->set_rx_bytes(portInfo[portidx]->stats.rxBytes -

View File

@ -82,6 +82,17 @@ class PortInfo
const struct pcap_pkthdr *header, const u_char *pkt_data);
void run();
};
class PortTransmitter: public QThread
{
friend class PortInfo;
PortInfo *port;
public:
PortTransmitter(PortInfo *port);
void run();
};
OstProto::Port d;
@ -111,7 +122,7 @@ class PortInfo
//! Used to track num of packets (and their sizes) in the
// send queue. Also used to find out actual num of pkts sent
// in case of partial send in pcap_sendqueue_transmit()
QList<uint> sendQueueCumLen;
QList<uint> sendQueueCumLen;
//! PCAP doesn't do any tx stats
quint64 txPkts;
@ -121,11 +132,12 @@ class PortInfo
pcap_if_t *dev;
pcap_t *devHandleRx;
pcap_t *devHandleTx;
pcap_send_queue *sendQueue;
pcap_send_queue* sendQueue;
bool isSendQueueDirty;
PcapExtra pcapExtra;
PortMonitorRx monitorRx;
PortMonitorTx monitorTx;
PortTransmitter transmitter;
struct PortStats epochStats;
struct PortStats stats;