aboutsummaryrefslogtreecommitdiffstats
path: root/tools/misc
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-11-10 16:38:16 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-11-10 16:38:16 +0000
commit671ef04c764dbe2c4bea2c9fdabf839a23396cc4 (patch)
tree7651eac4f61e6b9b19f5b284df005e20b3e5c03a /tools/misc
parentc00aa14e171953d2f31d3e159e27c4d60786bf86 (diff)
downloadxen-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/Makefile13
-rw-r--r--tools/misc/xen_netwatch.c196
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;
+}