BSD specific interface stats and error stats, including link state
Update issue 28
This commit is contained in:
parent
88cb294567
commit
5f99e9456c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
Copyright (C) 2010-2012 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
@ -121,6 +121,24 @@ bool AbstractPort::deleteStream(int streamId)
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractPort::addNote(QString note)
|
||||
{
|
||||
QString notes = QString::fromStdString(data_.notes());
|
||||
|
||||
note.prepend("<li>");
|
||||
note.append("</li>");
|
||||
|
||||
if (notes.isEmpty())
|
||||
notes="<b>Limitation(s)</b><ul>";
|
||||
else
|
||||
notes.remove("</ul>");
|
||||
|
||||
notes.append(note);
|
||||
notes.append("</ul>");
|
||||
|
||||
data_.set_notes(notes.toStdString());
|
||||
}
|
||||
|
||||
void AbstractPort::updatePacketList()
|
||||
{
|
||||
switch(data_.transmit_mode())
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
Copyright (C) 2010-2012 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
@ -97,6 +97,8 @@ public:
|
||||
void resetStats() { epochStats_ = stats_; }
|
||||
|
||||
protected:
|
||||
void addNote(QString note);
|
||||
|
||||
void updatePacketListSequential();
|
||||
void updatePacketListInterleaved();
|
||||
|
||||
|
327
server/bsdport.cpp
Normal file
327
server/bsdport.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
Copyright (C) 2012 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 "bsdport.h"
|
||||
|
||||
#ifdef Q_OS_BSD4
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QTime>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/route.h>
|
||||
|
||||
QList<BsdPort*> BsdPort::allPorts_;
|
||||
BsdPort::StatsMonitor *BsdPort::monitor_;
|
||||
|
||||
BsdPort::BsdPort(int id, const char *device)
|
||||
: PcapPort(id, device)
|
||||
{
|
||||
isPromisc_ = true;
|
||||
clearPromisc_ = false;
|
||||
|
||||
// We don't need per port Rx/Tx monitors for Bsd
|
||||
delete monitorRx_;
|
||||
delete monitorTx_;
|
||||
monitorRx_ = monitorTx_ = NULL;
|
||||
|
||||
// We have one monitor for both Rx/Tx of all ports
|
||||
if (!monitor_)
|
||||
monitor_ = new StatsMonitor();
|
||||
|
||||
data_.set_is_exclusive_control(hasExclusiveControl());
|
||||
minPacketSetSize_ = 16;
|
||||
|
||||
qDebug("adding dev to all ports list <%s>", device);
|
||||
allPorts_.append(this);
|
||||
}
|
||||
|
||||
BsdPort::~BsdPort()
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (monitor_->isRunning())
|
||||
{
|
||||
monitor_->stop();
|
||||
monitor_->wait();
|
||||
}
|
||||
|
||||
if (clearPromisc_)
|
||||
{
|
||||
int sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name(), sizeof(ifr.ifr_name));
|
||||
|
||||
if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1)
|
||||
{
|
||||
short promisc = IFF_PPROMISC >> 16;
|
||||
|
||||
if (ifr.ifr_flagshigh & promisc)
|
||||
{
|
||||
ifr.ifr_flagshigh &= ~promisc;
|
||||
if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1)
|
||||
qDebug("Failed clearing promisc flag. SIOCSIFFLAGS failed: %s",
|
||||
strerror(errno));
|
||||
else
|
||||
qDebug("Cleared promisc successfully");
|
||||
}
|
||||
else
|
||||
qDebug("clear_promisc is set but IFF_PPROMISC is not?");
|
||||
}
|
||||
else
|
||||
qDebug("Failed clearing promisc flag. SIOCGIFFLAGS failed: %s",
|
||||
strerror(errno));
|
||||
|
||||
close(sd);
|
||||
}
|
||||
}
|
||||
|
||||
void BsdPort::init()
|
||||
{
|
||||
if (!monitor_->isRunning())
|
||||
monitor_->start();
|
||||
|
||||
monitor_->waitForSetupFinished();
|
||||
|
||||
if (!isPromisc_)
|
||||
addNote("Non Promiscuous Mode");
|
||||
}
|
||||
|
||||
bool BsdPort::hasExclusiveControl()
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BsdPort::setExclusiveControl(bool /*exclusive*/)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
BsdPort::StatsMonitor::StatsMonitor()
|
||||
: QThread()
|
||||
{
|
||||
stop_ = false;
|
||||
setupDone_ = false;
|
||||
}
|
||||
|
||||
void BsdPort::StatsMonitor::run()
|
||||
{
|
||||
int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
|
||||
const int mibLen = sizeof(mib)/sizeof(mib[0]);
|
||||
QHash<uint, PortStats*> portStats;
|
||||
QHash<uint, OstProto::LinkState*> linkState;
|
||||
int sd;
|
||||
QByteArray buf;
|
||||
size_t len;
|
||||
char *p, *end;
|
||||
int count;
|
||||
struct ifreq ifr;
|
||||
|
||||
//
|
||||
// We first setup stuff before we start polling for stats
|
||||
//
|
||||
if (sysctl(mib, mibLen, NULL, &len, NULL, 0) < 0)
|
||||
{
|
||||
qWarning("sysctl NET_RT_IFLIST(1) failed (%s)\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("sysctl mib returns reqd len = %d\n", len);
|
||||
len *= 2; // for extra room, just in case!
|
||||
buf.fill('\0', len);
|
||||
if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0)
|
||||
{
|
||||
qWarning("sysctl NET_RT_IFLIST(2) failed(%s)\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
Q_ASSERT(sd >= 0);
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
//
|
||||
// Populate the port stats hash table
|
||||
//
|
||||
p = buf.data();
|
||||
end = p + len;
|
||||
count = 0;
|
||||
while (p < end)
|
||||
{
|
||||
struct if_msghdr *ifm = (struct if_msghdr*) p;
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl*) (ifm + 1);
|
||||
|
||||
if (ifm->ifm_type == RTM_IFINFO)
|
||||
{
|
||||
char ifname[1024];
|
||||
|
||||
strncpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
|
||||
ifname[sdl->sdl_nlen] = 0;
|
||||
|
||||
qDebug("if: %s(%d, %d)", ifname, ifm->ifm_index, sdl->sdl_index);
|
||||
foreach(BsdPort* port, allPorts_)
|
||||
{
|
||||
if (strncmp(port->name(), sdl->sdl_data, sdl->sdl_nlen) == 0)
|
||||
{
|
||||
Q_ASSERT(ifm->ifm_index == sdl->sdl_index);
|
||||
portStats[uint(ifm->ifm_index)] = &(port->stats_);
|
||||
linkState[uint(ifm->ifm_index)] = &(port->linkState_);
|
||||
|
||||
// Set promisc mode, if not already set
|
||||
strncpy(ifr.ifr_name, port->name(), sizeof(ifr.ifr_name));
|
||||
if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1)
|
||||
{
|
||||
short promisc = IFF_PPROMISC >> 16;
|
||||
|
||||
if ((ifr.ifr_flagshigh & promisc) == 0)
|
||||
{
|
||||
ifr.ifr_flagshigh |= promisc;
|
||||
if (ioctl(sd, SIOCSIFFLAGS, &ifr) != -1)
|
||||
{
|
||||
qDebug("%s: set promisc successful",
|
||||
port->name());
|
||||
port->clearPromisc_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
port->isPromisc_ = false;
|
||||
qDebug("%s: failed to set promisc; "
|
||||
"SIOCSIFFLAGS failed (%s)",
|
||||
port->name(), strerror(errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
qDebug("%s: promisc already set", port->name());
|
||||
}
|
||||
else
|
||||
{
|
||||
port->isPromisc_ = false;
|
||||
qDebug("%s: failed to set promisc; SIOCGIFFLAGS failed (%s)",
|
||||
port->name(), strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
p += ifm->ifm_msglen;
|
||||
}
|
||||
|
||||
qDebug("port count = %d\n", count);
|
||||
if (count <= 0)
|
||||
{
|
||||
qWarning("no ports in NET_RT_IFLIST - no stats will be available");
|
||||
return;
|
||||
}
|
||||
|
||||
close(sd);
|
||||
|
||||
qDebug("stats for %d ports setup", count);
|
||||
setupDone_ = true;
|
||||
|
||||
//
|
||||
// We are all set - Let's start polling for stats!
|
||||
//
|
||||
while (!stop_)
|
||||
{
|
||||
if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0)
|
||||
{
|
||||
qWarning("sysctl NET_RT_IFLIST(3) failed(%s)\n", strerror(errno));
|
||||
goto _try_later;
|
||||
}
|
||||
|
||||
p = buf.data();
|
||||
end = p + len;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
struct if_msghdr *ifm = (struct if_msghdr*) p;
|
||||
AbstractPort::PortStats *stats;
|
||||
|
||||
if (ifm->ifm_type != RTM_IFINFO)
|
||||
goto _next;
|
||||
|
||||
stats = portStats[ifm->ifm_index];
|
||||
if (stats)
|
||||
{
|
||||
struct if_data *ifd = &(ifm->ifm_data);
|
||||
OstProto::LinkState *state = linkState[ifm->ifm_index];
|
||||
|
||||
Q_ASSERT(state);
|
||||
*state = (OstProto::LinkState) ifd->ifi_link_state;
|
||||
|
||||
stats->rxPps = (ifd->ifi_ipackets + ifd->ifi_noproto
|
||||
- stats->rxPkts) /kRefreshFreq_;
|
||||
stats->rxBps = (ifd->ifi_ibytes - stats->rxBytes)
|
||||
/kRefreshFreq_;
|
||||
stats->rxPkts = ifd->ifi_ipackets + ifd->ifi_noproto;
|
||||
stats->rxBytes = ifd->ifi_ibytes;
|
||||
stats->txPps = (ifd->ifi_opackets - stats->txPkts)
|
||||
/kRefreshFreq_;
|
||||
stats->txBps = (ifd->ifi_obytes - stats->txBytes)
|
||||
/kRefreshFreq_;
|
||||
stats->txPkts = ifd->ifi_opackets;
|
||||
stats->txBytes = ifd->ifi_obytes;
|
||||
|
||||
stats->rxDrops = ifd->ifi_iqdrops;
|
||||
stats->rxErrors = ifd->ifi_ierrors;
|
||||
}
|
||||
_next:
|
||||
p += ifm->ifm_msglen;
|
||||
}
|
||||
_try_later:
|
||||
QThread::sleep(kRefreshFreq_);
|
||||
}
|
||||
|
||||
portStats.clear();
|
||||
linkState.clear();
|
||||
}
|
||||
|
||||
void BsdPort::StatsMonitor::stop()
|
||||
{
|
||||
stop_ = true;
|
||||
}
|
||||
|
||||
bool BsdPort::StatsMonitor::waitForSetupFinished(int msecs)
|
||||
{
|
||||
QTime t;
|
||||
|
||||
t.start();
|
||||
while (!setupDone_)
|
||||
{
|
||||
if (t.elapsed() > msecs)
|
||||
return false;
|
||||
|
||||
QThread::msleep(10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
61
server/bsdport.h
Normal file
61
server/bsdport.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2012 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 _SERVER_BSD_PORT_H
|
||||
#define _SERVER_BSD_PORT_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_BSD4
|
||||
|
||||
#include "pcapport.h"
|
||||
|
||||
class BsdPort : public PcapPort
|
||||
{
|
||||
public:
|
||||
BsdPort(int id, const char *device);
|
||||
~BsdPort();
|
||||
|
||||
void init();
|
||||
|
||||
virtual bool hasExclusiveControl();
|
||||
virtual bool setExclusiveControl(bool exclusive);
|
||||
|
||||
protected:
|
||||
class StatsMonitor: public QThread
|
||||
{
|
||||
public:
|
||||
StatsMonitor();
|
||||
void run();
|
||||
void stop();
|
||||
bool waitForSetupFinished(int msecs = 10000);
|
||||
private:
|
||||
static const int kRefreshFreq_ = 1; // in seconds
|
||||
bool stop_;
|
||||
bool setupDone_;
|
||||
};
|
||||
|
||||
bool isPromisc_;
|
||||
bool clearPromisc_;
|
||||
static QList<BsdPort*> allPorts_;
|
||||
static StatsMonitor *monitor_; // rx/tx stats for ALL ports
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
@ -36,6 +36,7 @@ SOURCES += \
|
||||
portmanager.cpp \
|
||||
abstractport.cpp \
|
||||
pcapport.cpp \
|
||||
bsdport.cpp \
|
||||
linuxport.cpp \
|
||||
winpcapport.cpp
|
||||
SOURCES += myservice.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
Copyright (C) 2010-2012 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include <QtGlobal>
|
||||
#include <pcap.h>
|
||||
|
||||
#include "bsdport.h"
|
||||
#include "linuxport.h"
|
||||
#include "pcapport.h"
|
||||
#include "winpcapport.h"
|
||||
@ -52,6 +53,8 @@ PortManager::PortManager()
|
||||
port = new WinPcapPort(i, device->name);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
port = new LinuxPort(i, device->name);
|
||||
#elif defined(Q_OS_BSD4)
|
||||
port = new BsdPort(i, device->name);
|
||||
#else
|
||||
port = new PcapPort(i, device->name);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user