PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : eth0: Link is down detektieren



f0rtex
10-05-2006, 07:12
Hi folks,

Ich stehe vor folgender Aufgabe: Ich habe mehrere TCP/IP-Verbindungen, über die sporadisch Daten gesendet werden. Bricht ein Client die Verbindung zum Server ab, so kann ich dies detektieren. (read = 0)

Zieht jedoch jemand das Netzwerkkabel aus, bleibt meine Verbindung bis zum nächsten read bestehen. Der Kernel merk jedoch sofort, dass der Link down ist.


[4297696.224000] tg3: eth0: Link is down.
[4297704.237000] tg3: eth0: Link is up at 100 Mbps, full duplex.
[4297704.237000] tg3: eth0: Flow control is on for TX and on for RX.


Besteht die Möglichkeit, dass meine Applikation ein Event (Signal?) erhält, dass der Link down ist?

Besten Dank :)

Grüsse
f0rtex

f0rtex
10-05-2006, 11:59
Meine Ansätze bis jetzt:

1. Den Kernel mich infromieren lassen, dass sich /sys/class/net/eth0/carrier geändert hat:



#include <iostream>

extern "C"
{
#include <fcntl.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
}

using namespace std;

static volatile int event_fd;

static void handler(int sig, siginfo_t *si, void *data)
{
event_fd = si->si_fd;
}

int main(void)
{
struct sigaction act;
int fd;

act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN + 1, &act, NULL);

if ((fd = open("/sys/class/net/eth0", O_RDONLY)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
cout << "fd: " << fd << endl;

fcntl(fd, F_SETSIG, SIGRTMIN + 1);
fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_ACCESS|DN_RENAME|DN_ATTRIB| DN_MULTISHOT);

while (1)
{
pause();
cout << "eth0 changed" << endl;
}
close(fd);
}


Funktioniert leider nur, wenn ich auf die Datei zugreife (cat, touch...).
Wieso ändert der Kernel den timestamp der Datei nicht, sobald er diese ändert?

2. Mittels ioctl den Status erfragen.



#include <iostream>

extern "C"
{
#include <fcntl.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
}

using namespace std;

int main(void)
{
int fd;
struct ifreq ifr;
struct ethtool_value edata;

fd = socket(AF_INET, SOCK_DGRAM, 0);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name)-1);
edata.cmd = ETHTOOL_GLINK;
ifr.ifr_data = (caddr_t) &edata;


while(1)
{
if(ioctl(fd, SIOCETHTOOL, &ifr) == -1)
{
perror("ETHTOOL_GLINK");
return -1;
}

string foo = edata.data ? "up": "down";
cout << foo << endl;
sleep(1);
}
close(fd);
return 0;
}


Bei dieser Lösung gefällt mir nicht, dass ich das IF pollen müsste. Dazu kommt noch, dass ich root-Rechte benötige.

Hat jemand einen hinweis, wie ich das (möglichst ohne root) mittels asynchrones Event lösen könnte?


Any hints?

f0rtex
16-05-2006, 06:24
Also und hier die Lösung welche nicht die ethtools voraussetzt.
Ich habe das so gelöst, dass ein Thread den Status pollt und jeweils ein Signal auslöst, wenn das IF down ist.



static void *IfMonitoring(void *arg)
{
int fd;
struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name)-1);
fd = socket(AF_INET, SOCK_DGRAM, 0);

while(1)
{
if (ioctl(fd, SIOCGIFFLAGS, &ifr))
{
std::cerr << "Could not determin LINK-Status" << std::endl;
perror("SIOCGIFFFLAGS");
close(fd);
raise(SIGINT);
}

if ((ifr.ifr_flags & IFF_UP) && !(ifr.ifr_flags & IFF_RUNNING))
{
std::cerr << "Interface eth0 down! " << std::endl;
raise(SIGUSR1);
}
sleep(2);
}
}


Grüsse
f0rtex