ia64/xen-unstable

changeset 919:264c48ba4da3

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.
author kaf24@scramble.cl.cam.ac.uk
date Mon Nov 10 16:38:16 2003 +0000 (2003-11-10)
parents 3913078b6947
children e2a517ef1be8 fc5ae656dd1e
files .rootkeys tools/misc/Makefile tools/misc/xen_netwatch.c
line diff
     1.1 --- a/.rootkeys	Mon Nov 10 13:44:15 2003 +0000
     1.2 +++ b/.rootkeys	Mon Nov 10 16:38:16 2003 +0000
     1.3 @@ -190,6 +190,7 @@ 3f870808zS6T6iFhqYPGelroZlVfGQ tools/mis
     1.4  3f8bcf29ulZIC9rC4wM70H_q4s6VPg tools/misc/xen_log.c
     1.5  3f13d81eQ9Vz-h-6RDGFkNR9CRP95g tools/misc/xen_nat_enable
     1.6  3f13d81e6Z6806ihYYUw8GVKNkYnuw tools/misc/xen_nat_enable.README
     1.7 +3fafbef1fJFKCcJLq-ffpauvpM10jQ tools/misc/xen_netwatch.c
     1.8  3f1668d4F29Jsw0aC0bJEIkOBiagiQ tools/misc/xen_read_console.c
     1.9  3f87ba90EUVPQLVOlFG0sW89BCwouQ tools/misc/xen_refresh_dev.c
    1.10  3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
     2.1 --- a/tools/misc/Makefile	Mon Nov 10 13:44:15 2003 +0000
     2.2 +++ b/tools/misc/Makefile	Mon Nov 10 16:38:16 2003 +0000
     2.3 @@ -1,13 +1,13 @@
     2.4  
     2.5 -CC       = gcc
     2.6 -CFLAGS   = -Wall -O3 
     2.7 -CFLAGS  += -I../../xen/include -I../../xenolinux-sparse/include -I../internal
     2.8 +CC        = gcc
     2.9 +CFLAGS    = -Wall -O3 
    2.10 +EXTRA_INC = -I../../xen/include -I../../xenolinux-sparse/include -I../internal
    2.11  
    2.12  HDRS     = $(wildcard *.h)
    2.13  SRCS     = $(wildcard *.c)
    2.14  OBJS     = $(patsubst %.c,%.o,$(SRCS))
    2.15  
    2.16 -TARGETS  = xen_read_console xen_cpuperf xen_refresh_dev
    2.17 +TARGETS  = xen_read_console xen_cpuperf xen_refresh_dev xen_netwatch
    2.18  
    2.19  INSTALL  = $(TARGETS) xen-mkdevnodes xen_nat_enable xen-clone 
    2.20  
    2.21 @@ -25,6 +25,9 @@ clean:
    2.22  	$(RM) *.o $(TARGETS)
    2.23  	$(MAKE) -C miniterm clean	
    2.24  
    2.25 -%: %.c $(HDRS) Makefile
    2.26 +xen_netwatch: %: %.c $(HDRS) Makefile
    2.27  	$(CC) $(CFLAGS) -o $@ $<
    2.28  
    2.29 +%: %.c $(HDRS) Makefile
    2.30 +	$(CC) $(CFLAGS) $(EXTRA_INC) -o $@ $<
    2.31 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/misc/xen_netwatch.c	Mon Nov 10 16:38:16 2003 +0000
     3.3 @@ -0,0 +1,196 @@
     3.4 +/******************************************************************************
     3.5 + * netwatch.c
     3.6 + * 
     3.7 + * Watch for network interfaces needing frobbing.
     3.8 + * 
     3.9 + * Copyright (c) 2003, K A Fraser
    3.10 + */
    3.11 +
    3.12 +#include <asm/types.h>
    3.13 +#include <sys/types.h>
    3.14 +#include <sys/socket.h>
    3.15 +#include <sys/ioctl.h>
    3.16 +#include <sys/resource.h>
    3.17 +#include <sys/time.h>
    3.18 +#include <sys/un.h>
    3.19 +#include <sys/wait.h>
    3.20 +#include <linux/netlink.h>
    3.21 +#include <linux/rtnetlink.h>
    3.22 +#include <linux/if.h>
    3.23 +
    3.24 +#include <errno.h>
    3.25 +#include <signal.h>
    3.26 +#include <stdio.h>
    3.27 +#include <unistd.h>
    3.28 +#include <time.h>
    3.29 +
    3.30 +#define LOG(_f, _a...)                                  \
    3.31 +    do {                                                \
    3.32 +        time_t now = time(NULL);                        \
    3.33 +        char *tstr = ctime(&now);                       \
    3.34 +        char *p = strchr(tstr, '\n'); if (p) *p = '\0'; \
    3.35 +        fprintf(logfd, "%s: " _f "\n", tstr,  ## _a);   \
    3.36 +        fflush(logfd);                                  \
    3.37 +    } while ( 0 )
    3.38 +
    3.39 +#define EXIT do { LOG("Exiting."); return 1; } while ( 0 )
    3.40 +
    3.41 +static void daemonise(void)
    3.42 +{
    3.43 +    int i;
    3.44 +    struct rlimit rlim;
    3.45 +
    3.46 +    /* Close all file handles we inherited from our parent. */
    3.47 +    if ( getrlimit(RLIMIT_NOFILE, &rlim) == 0 )
    3.48 +        for ( i = 0; i < rlim.rlim_cur; i++ )
    3.49 +            close(i);
    3.50 +
    3.51 +    /* Lose the controlling tty. */
    3.52 +    setsid();
    3.53 +}
    3.54 +
    3.55 +void handle_child_death(int dummy)
    3.56 +{
    3.57 +    (void)waitpid(-1, NULL, WNOHANG);
    3.58 +}
    3.59 +
    3.60 +int main(int argc, char **argv)
    3.61 +{
    3.62 +    char *logfile = "/var/xen/netwatch";
    3.63 +    char *scriptfile = "/etc/xen/netwatch";
    3.64 +    FILE *logfd;
    3.65 +    int nlfd, unixfd, bytes;
    3.66 +    int last_index = ~0;
    3.67 +    unsigned int last_flags = ~0;
    3.68 +    char buffer[8192];
    3.69 +    struct sockaddr_nl nladdr;
    3.70 +    struct nlmsghdr *nlmsg;
    3.71 +    struct ifinfomsg *ifi;
    3.72 +    struct ifreq ifr;
    3.73 +    struct sigaction sigchld;
    3.74 +
    3.75 +    /* Ensure that zombie children are reaped. */
    3.76 +    memset(&sigchld, 0, sizeof(sigchld));
    3.77 +    sigchld.sa_handler = handle_child_death;
    3.78 +    sigemptyset(&sigchld.sa_mask);
    3.79 +    sigchld.sa_flags = SA_NOCLDSTOP | SA_RESTART;
    3.80 +    (void)sigaction(SIGCHLD, &sigchld, NULL);
    3.81 +
    3.82 +    /*
    3.83 +     * After child daemonises it can't display errors until it opens the log 
    3.84 +     * file. Since it may be unable to open the log file, we test for that
    3.85 +     * possibility here.
    3.86 +     */
    3.87 +    if ( (logfd = fopen(logfile, "wb")) == NULL )
    3.88 +    {
    3.89 +        fprintf(stderr, "Could not open log file '%s' (%d)\n", logfile, errno);
    3.90 +        fprintf(stderr, "Exiting.\n");
    3.91 +        return 1;
    3.92 +    }
    3.93 +    fclose(logfd);
    3.94 +
    3.95 +    switch ( fork() )
    3.96 +    {
    3.97 +    case 0:
    3.98 +        daemonise();
    3.99 +        break;
   3.100 +    case -1:
   3.101 +        fprintf(stderr, "Could not daemonize. (%d)\n", errno);
   3.102 +        fprintf(stderr, "Exiting.\n");
   3.103 +        return 1;
   3.104 +    default:
   3.105 +        goto out;
   3.106 +    }
   3.107 +
   3.108 +    /* Silent error is forgiveable here, as our parent did a test for us. */
   3.109 +    if ( (logfd = fopen(logfile, "wb")) == NULL )
   3.110 +        return 1;
   3.111 +
   3.112 +    if ( (nlfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1 )
   3.113 +    {
   3.114 +        LOG("Could not open an rtnetlink socket. (%d)\n", errno);
   3.115 +        EXIT;
   3.116 +    }
   3.117 +
   3.118 +    if ( (unixfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1 )
   3.119 +    {
   3.120 +        LOG("Could not open UNIX socket. (%d)\n", errno);
   3.121 +        EXIT;
   3.122 +    }
   3.123 +
   3.124 +    nladdr.nl_family = AF_NETLINK;
   3.125 +    nladdr.nl_pid    = 0;
   3.126 +    nladdr.nl_groups = RTMGRP_LINK;
   3.127 +    if ( bind(nlfd, (struct sockaddr *)&nladdr, sizeof(nladdr)) == -1 )
   3.128 +    {
   3.129 +        LOG("Could not bind to kernel (%d)\n", errno);
   3.130 +        EXIT;
   3.131 +    }
   3.132 +
   3.133 +    for ( ; ; )
   3.134 +    {
   3.135 +        memset(buffer, 0, sizeof(buffer));
   3.136 +
   3.137 +        if ( (bytes = read(nlfd, buffer, sizeof(buffer))) == -1 )
   3.138 +        {
   3.139 +            if ( errno != EINTR )
   3.140 +                LOG("Error when reading from socket (%d)", errno);
   3.141 +            continue;
   3.142 +        }
   3.143 +
   3.144 +        if ( bytes == 0 )
   3.145 +            continue;
   3.146 +
   3.147 +        for ( nlmsg = (struct nlmsghdr *)buffer; 
   3.148 +              !(nlmsg->nlmsg_flags & NLMSG_DONE);
   3.149 +              nlmsg = NLMSG_NEXT(nlmsg, bytes) )
   3.150 +        {
   3.151 +            /* This termination condition works. NLMSG_DONE doesn't always. */
   3.152 +            if ( nlmsg->nlmsg_len == 0 )
   3.153 +                break;
   3.154 +
   3.155 +            if ( nlmsg->nlmsg_type != RTM_NEWLINK )
   3.156 +                continue;
   3.157 +
   3.158 +            ifi = NLMSG_DATA(nlmsg);
   3.159 +
   3.160 +            ifr.ifr_ifindex = ifi->ifi_index;
   3.161 +            if ( ioctl(unixfd, SIOCGIFNAME, &ifr) == -1 )
   3.162 +                continue;
   3.163 +
   3.164 +            if ( !(ifi->ifi_change & IFF_UP) )
   3.165 +                continue;
   3.166 +
   3.167 +            /* Ignore duplicate messages. */
   3.168 +            if ( (last_index == ifr.ifr_ifindex) &&
   3.169 +                 (last_flags == ifi->ifi_flags) )
   3.170 +                continue;
   3.171 +            last_index = ifr.ifr_ifindex;
   3.172 +            last_flags = ifi->ifi_flags;
   3.173 +
   3.174 +            LOG("Network %s event for interface %s",
   3.175 +                (ifi->ifi_flags & IFF_UP) ? "UP" : "DOWN",
   3.176 +                ifr.ifr_name);
   3.177 +
   3.178 +            switch ( fork() )
   3.179 +            {
   3.180 +            case 0:
   3.181 +                execl(scriptfile,
   3.182 +                      ifr.ifr_name, 
   3.183 +                      (ifi->ifi_flags & IFF_UP) ? "up" : "down");
   3.184 +                LOG("Error executing network script '%s %s %s'", 
   3.185 +                    scriptfile, ifr.ifr_name, 
   3.186 +                    (ifi->ifi_flags & IFF_UP) ? "up" : "down");
   3.187 +                return 1;
   3.188 +            case -1:
   3.189 +                LOG("Error forking to exec script");
   3.190 +                break;
   3.191 +            default:
   3.192 +                break;
   3.193 +            }
   3.194 +        }
   3.195 +    }
   3.196 +
   3.197 + out:
   3.198 +    return 0;
   3.199 +}