diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-11-10 16:38:16 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-11-10 16:38:16 +0000 |
commit | 671ef04c764dbe2c4bea2c9fdabf839a23396cc4 (patch) | |
tree | 7651eac4f61e6b9b19f5b284df005e20b3e5c03a /tools/misc | |
parent | c00aa14e171953d2f31d3e159e27c4d60786bf86 (diff) | |
download | xen-671ef04c764dbe2c4bea2c9fdabf839a23396cc4.tar.gz xen-671ef04c764dbe2c4bea2c9fdabf839a23396cc4.tar.bz2 xen-671ef04c764dbe2c4bea2c9fdabf839a23396cc4.zip |
bitkeeper revision 1.582.1.1 (3fafbef8y8bKbMkHy5KldiazAvehBA)
xen_netwatch.c:
new file
Makefile:
New utility for watching network interfaces coming up and going down, and calling a configure script.
Diffstat (limited to 'tools/misc')
-rw-r--r-- | tools/misc/Makefile | 13 | ||||
-rw-r--r-- | tools/misc/xen_netwatch.c | 196 |
2 files changed, 204 insertions, 5 deletions
diff --git a/tools/misc/Makefile b/tools/misc/Makefile index c21ae540de..1eda792f69 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -1,13 +1,13 @@ -CC = gcc -CFLAGS = -Wall -O3 -CFLAGS += -I../../xen/include -I../../xenolinux-sparse/include -I../internal +CC = gcc +CFLAGS = -Wall -O3 +EXTRA_INC = -I../../xen/include -I../../xenolinux-sparse/include -I../internal HDRS = $(wildcard *.h) SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) -TARGETS = xen_read_console xen_cpuperf xen_refresh_dev +TARGETS = xen_read_console xen_cpuperf xen_refresh_dev xen_netwatch INSTALL = $(TARGETS) xen-mkdevnodes xen_nat_enable xen-clone @@ -25,6 +25,9 @@ clean: $(RM) *.o $(TARGETS) $(MAKE) -C miniterm clean -%: %.c $(HDRS) Makefile +xen_netwatch: %: %.c $(HDRS) Makefile $(CC) $(CFLAGS) -o $@ $< +%: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) $(EXTRA_INC) -o $@ $< + diff --git a/tools/misc/xen_netwatch.c b/tools/misc/xen_netwatch.c new file mode 100644 index 0000000000..b4aac6da1b --- /dev/null +++ b/tools/misc/xen_netwatch.c @@ -0,0 +1,196 @@ +/****************************************************************************** + * netwatch.c + * + * Watch for network interfaces needing frobbing. + * + * Copyright (c) 2003, K A Fraser + */ + +#include <asm/types.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/resource.h> +#include <sys/time.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/if.h> + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> + +#define LOG(_f, _a...) \ + do { \ + time_t now = time(NULL); \ + char *tstr = ctime(&now); \ + char *p = strchr(tstr, '\n'); if (p) *p = '\0'; \ + fprintf(logfd, "%s: " _f "\n", tstr, ## _a); \ + fflush(logfd); \ + } while ( 0 ) + +#define EXIT do { LOG("Exiting."); return 1; } while ( 0 ) + +static void daemonise(void) +{ + int i; + struct rlimit rlim; + + /* Close all file handles we inherited from our parent. */ + if ( getrlimit(RLIMIT_NOFILE, &rlim) == 0 ) + for ( i = 0; i < rlim.rlim_cur; i++ ) + close(i); + + /* Lose the controlling tty. */ + setsid(); +} + +void handle_child_death(int dummy) +{ + (void)waitpid(-1, NULL, WNOHANG); +} + +int main(int argc, char **argv) +{ + char *logfile = "/var/xen/netwatch"; + char *scriptfile = "/etc/xen/netwatch"; + FILE *logfd; + int nlfd, unixfd, bytes; + int last_index = ~0; + unsigned int last_flags = ~0; + char buffer[8192]; + struct sockaddr_nl nladdr; + struct nlmsghdr *nlmsg; + struct ifinfomsg *ifi; + struct ifreq ifr; + struct sigaction sigchld; + + /* Ensure that zombie children are reaped. */ + memset(&sigchld, 0, sizeof(sigchld)); + sigchld.sa_handler = handle_child_death; + sigemptyset(&sigchld.sa_mask); + sigchld.sa_flags = SA_NOCLDSTOP | SA_RESTART; + (void)sigaction(SIGCHLD, &sigchld, NULL); + + /* + * After child daemonises it can't display errors until it opens the log + * file. Since it may be unable to open the log file, we test for that + * possibility here. + */ + if ( (logfd = fopen(logfile, "wb")) == NULL ) + { + fprintf(stderr, "Could not open log file '%s' (%d)\n", logfile, errno); + fprintf(stderr, "Exiting.\n"); + return 1; + } + fclose(logfd); + + switch ( fork() ) + { + case 0: + daemonise(); + break; + case -1: + fprintf(stderr, "Could not daemonize. (%d)\n", errno); + fprintf(stderr, "Exiting.\n"); + return 1; + default: + goto out; + } + + /* Silent error is forgiveable here, as our parent did a test for us. */ + if ( (logfd = fopen(logfile, "wb")) == NULL ) + return 1; + + if ( (nlfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1 ) + { + LOG("Could not open an rtnetlink socket. (%d)\n", errno); + EXIT; + } + + if ( (unixfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1 ) + { + LOG("Could not open UNIX socket. (%d)\n", errno); + EXIT; + } + + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = RTMGRP_LINK; + if ( bind(nlfd, (struct sockaddr *)&nladdr, sizeof(nladdr)) == -1 ) + { + LOG("Could not bind to kernel (%d)\n", errno); + EXIT; + } + + for ( ; ; ) + { + memset(buffer, 0, sizeof(buffer)); + + if ( (bytes = read(nlfd, buffer, sizeof(buffer))) == -1 ) + { + if ( errno != EINTR ) + LOG("Error when reading from socket (%d)", errno); + continue; + } + + if ( bytes == 0 ) + continue; + + for ( nlmsg = (struct nlmsghdr *)buffer; + !(nlmsg->nlmsg_flags & NLMSG_DONE); + nlmsg = NLMSG_NEXT(nlmsg, bytes) ) + { + /* This termination condition works. NLMSG_DONE doesn't always. */ + if ( nlmsg->nlmsg_len == 0 ) + break; + + if ( nlmsg->nlmsg_type != RTM_NEWLINK ) + continue; + + ifi = NLMSG_DATA(nlmsg); + + ifr.ifr_ifindex = ifi->ifi_index; + if ( ioctl(unixfd, SIOCGIFNAME, &ifr) == -1 ) + continue; + + if ( !(ifi->ifi_change & IFF_UP) ) + continue; + + /* Ignore duplicate messages. */ + if ( (last_index == ifr.ifr_ifindex) && + (last_flags == ifi->ifi_flags) ) + continue; + last_index = ifr.ifr_ifindex; + last_flags = ifi->ifi_flags; + + LOG("Network %s event for interface %s", + (ifi->ifi_flags & IFF_UP) ? "UP" : "DOWN", + ifr.ifr_name); + + switch ( fork() ) + { + case 0: + execl(scriptfile, + ifr.ifr_name, + (ifi->ifi_flags & IFF_UP) ? "up" : "down"); + LOG("Error executing network script '%s %s %s'", + scriptfile, ifr.ifr_name, + (ifi->ifi_flags & IFF_UP) ? "up" : "down"); + return 1; + case -1: + LOG("Error forking to exec script"); + break; + default: + break; + } + } + } + + out: + return 0; +} |