vnetd.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,201 行 · 第 1/3 页

C
1,201
字号
        kfree_skb(skb);        *pskb = NULL;    } else {        *pskb = skb;    }    return (err < 0 ? err : n);}/** Read an skb from the tap device for a vnet and send it. */int vnet_read(Vnet *vnet){    int err;    struct sk_buff *skb = NULL;    err = skb_read(vnet->dev->tapfd, &skb);    if(err < 0) goto exit;    err = vnet_skb_send(skb, &vnet->vnet);  exit:    if(skb) kfree_skb(skb);    return (err < 0 ? err : 0);}/** Transmit an skb to the network. */int _skb_xmit(struct sk_buff *skb, uint32_t saddr){    int err = 0;    int sock;    unsigned char *data;    struct sockaddr_in addr = { .sin_family = AF_INET };    int flags = 0;    if(saddr){        dprintf("> Raw IP send\n");        sock = vnetd->raw_sock;        skb->nh.iph->saddr = saddr;        addr.sin_addr.s_addr = skb->nh.iph->daddr;        // Should be the protocol, but is ignored. See raw(7) man page.        addr.sin_port        = 0;        // Data includes the ip header.        data = (void*)(skb->nh.iph);    } else {                switch(skb->nh.iph->protocol){        case IPPROTO_UDP:            dprintf("> protocol=UDP\n");            sock = vnetd->udp_sock;            // Data comes after the udp header.            data = (void*)(skb->h.uh + 1);            addr.sin_addr.s_addr = skb->nh.iph->daddr;            addr.sin_port        = skb->h.uh->dest;            break;        case IPPROTO_ETHERIP:            dprintf("> protocol=ETHERIP\n");            if(vnetd->etherip_sock < 0){                err = -ENOSYS;                goto exit;            }            sock = vnetd->etherip_sock;            // Data comes after the ip header.            data = (void*)(skb->nh.iph + 1);            addr.sin_addr.s_addr = skb->nh.iph->daddr;            // Should be the protocol, but is ignored. See raw(7) man page.            addr.sin_port        = 0;            break;        default:            err = -ENOSYS;            wprintf("> protocol=%d, %d\n", skb->nh.iph->protocol, skb->protocol);            goto exit;        }    }    dprintf("> sending %d bytes to %s:%d protocol=%d\n",            skb->tail - data,            inet_ntoa(addr.sin_addr),            ntohs(addr.sin_port),            skb->nh.iph->protocol);    err = sendto(sock, data, skb->tail - data, flags,                 (struct sockaddr *)&addr, sizeof(addr));    if(err < 0){        err = -errno;        perror("sendto");    }  exit:        if(err >= 0){        // Caller will assume skb freed if no error.        kfree_skb(skb);        err = 0;    }    dprintf("< err=%d\n", err);    return err;}int varp_open(uint32_t mcaddr, uint16_t port){    return 0;}void varp_close(void){}/** Create a raw socket. * * @param protocol protocol * @param flags flags (VSOCK_*) * @param mcaddr multicast addr used with flag VSOCK_MULTICAST * @param sock return value for the socket */int vnetd_raw_socket(Vnetd *vnetd, int protocol, int flags,                     uint32_t mcaddr, int *sock){    int err;    int bcast = (flags & VSOCK_BROADCAST);    err = *sock = socket(AF_INET, SOCK_RAW, protocol);    if(err < 0){        err = -errno;        perror("socket");        goto exit;    }    if(bcast){        err = setsock_broadcast(*sock, bcast);        if(err < 0) goto exit;    }    if(flags & VSOCK_MULTICAST){        err = setsock_multicast(*sock, INADDR_ANY, mcaddr);        if(err < 0) goto exit;    }    //todo ?? fcntl(*sock, F_SETFL, O_NONBLOCK);  exit:    return err;}int get_dev_address(char *dev, unsigned long *addr){    int err = 0;    int sock = -1;    struct ifreq ifreq = {};    struct sockaddr_in *in_addr;    sock = socket(AF_INET, SOCK_DGRAM, 0);    if(sock < 0){        err = -errno;        goto exit;    }    strncpy(ifreq.ifr_name, dev, IFNAMSIZ);    err = ioctl(sock, SIOCGIFADDR, &ifreq);    if(err){        err = -errno;        goto exit;    }    in_addr = (struct sockaddr_in *) &ifreq.ifr_addr;    *addr = in_addr->sin_addr.s_addr;    //iprintf("> dev=%s addr=%s\n", dev, inet_ntoa(in_addr->sin_addr));  exit:    if(sock >= 0) close(sock);    return err;}int get_intf_address(unsigned long *addr){    int err = 0;    char *devs[] = { "xen-br0", "eth0", "eth1", "eth2", NULL };    char **dev;    for(dev = devs; *dev; dev++){        err = get_dev_address(*dev, addr);        if(err == 0) goto exit;    }    err = -ENOSYS;  exit:    return err;}/** Get our own address. So we can ignore broadcast traffic * we sent ourselves. * * @param addr * @return 0 on success, error code otherwise */int get_self_addr(struct sockaddr_in *addr){    int err = 0;    char hostname[1024] = {};    unsigned long saddr;     err = gethostname(hostname, sizeof(hostname) - 1);    if(err){        err = -errno;        perror("gethostname");        goto exit;    }    err = get_host_address(hostname, &saddr);    if(err) goto exit;    addr->sin_addr.s_addr = saddr;    if(saddr == htonl(INADDR_LOOPBACK)){        err = get_intf_address(&saddr);        if(err) goto exit;    }    addr->sin_addr.s_addr = saddr;    err = 0;  exit:    return err;}static int eval_vnetd_mcaddr(Sxpr exp, IOStream *out, void *data){    int err = 0;    Vnetd *vnetd = data;    Sxpr oaddr = intern("addr");    Sxpr ottl = intern("ttl");    uint32_t addr;    int ttl;    err = child_addr(exp, oaddr, &addr);    if(err < 0) goto exit;    vnetd_set_mcast_addr(vnetd, addr);    if(child_int(exp, ottl, &ttl) == 0){        vnetd->ttl = ttl;    }  exit:    return err;}static int vnetd_eval_io(Vnetd *vnetd, Parser *parser, SxprEval *defs,                         IOStream *in, IOStream *out){    int err = 0;    char buf[1024];    int k, n = sizeof(buf) - 1;    for( ; ; ){        k = IOStream_read(in, buf, n);        if(k < 0){            err = k;            goto exit;        }        err = Parser_input(parser, buf, k);        if(err < 0) goto exit;        while(Parser_ready(parser)){            Sxpr exp = Parser_get_val(parser);            if(NONEP(exp)) break;            err = vnet_eval_defs(defs, exp, out, vnetd);            if(err) goto exit;        }        if(Parser_at_eof(parser)) break;    }  exit:    return err;}static int vnetd_configure(Vnetd *vnetd, char *file){    int err = 0;    Parser *parser = NULL;        IOStream *io = NULL;    SxprEval defs[] = {        { .name = intern("peer.add"),     .fn = eval_peer_add     },        { .name = intern("varp.mcaddr"),  .fn = eval_vnetd_mcaddr },        { .name = intern("vnet.add"),     .fn = eval_vnet_add     },        { .name = ONONE, .fn = NULL } };    parser = Parser_new();     io = file_stream_fopen(file, "rb");    if(!io){        err = -errno;        goto exit;    }    vnetd_eval_io(vnetd, parser, defs, io, iostdout);  exit:    if(io) IOStream_close(io);    Parser_free(parser);    return err;}#define OPT_MCADDR   'a'#define KEY_MCADDR   "varp_mcaddr"#define DOC_MCADDR   "<addr>\n\t VARP multicast address"#define OPT_FILE     'f'#define KEY_FILE     "file"#define DOC_FILE     "<file>\n\t Configuration file to load"#define OPT_HELP     'h'#define KEY_HELP     "help"#define DOC_HELP     "\n\tprint help"#define OPT_VERSION  'v'#define KEY_VERSION  "version"#define DOC_VERSION  "\n\tprint version"#define OPT_VERBOSE  'V'#define KEY_VERBOSE  "verbose"#define DOC_VERBOSE  "\n\tverbose flag"/** Print a usage message. * Prints to stdout if err is zero, and exits with 0. * Prints to stderr if err is non-zero, and exits with 1. * * @param err error code */static void usage(int err){    FILE *out = (err ? stderr : stdout);    fprintf(out, "Usage: %s [options]\n", PROGRAM);    fprintf(out, "-%c, --%s %s\n", OPT_MCADDR,   KEY_MCADDR,   DOC_MCADDR);    fprintf(out, "-%c, --%s %s\n", OPT_FILE,     KEY_FILE,     DOC_FILE);    fprintf(out, "-%c, --%s %s\n", OPT_VERBOSE,  KEY_VERBOSE,  DOC_VERBOSE);    fprintf(out, "-%c, --%s %s\n", OPT_VERSION,  KEY_VERSION,  DOC_VERSION);    fprintf(out, "-%c, --%s %s\n", OPT_HELP,     KEY_HELP,     DOC_HELP);    exit(err ? 1 : 0);}/** Short options. Options followed by ':' take an argument. */static char *short_opts = (char[]){    OPT_MCADDR,   ':',    OPT_FILE,     ':',    OPT_HELP,    OPT_VERSION,    OPT_VERBOSE,    0 };/** Long options. */static struct option const long_opts[] = {    { KEY_MCADDR,   required_argument, NULL, OPT_MCADDR   },    { KEY_FILE,     required_argument, NULL, OPT_FILE     },    { KEY_HELP,     no_argument,       NULL, OPT_HELP     },    { KEY_VERSION,  no_argument,       NULL, OPT_VERSION  },    { KEY_VERBOSE,  no_argument,       NULL, OPT_VERBOSE  },    { NULL,         0,                 NULL, 0            }};static int vnetd_getopts(Vnetd *vnetd, int argc, char *argv[]){    int err = 0;    int key = 0;    int long_index = 0;    while(1){	key = getopt_long(argc, argv, short_opts, long_opts, &long_index);	if(key == -1) break;	switch(key){        case OPT_MCADDR: {            unsigned long addr;            err = get_inet_addr(optarg, &addr);            if(err) goto exit;            vnetd_set_mcast_addr(vnetd, addr);            break; }        case OPT_FILE:            err = vnetd_configure(vnetd, optarg);            if(err) goto exit;            break;	case OPT_HELP:	    usage(0);	    break;	case OPT_VERBOSE:	    vnetd->verbose = true;	    break;	case OPT_VERSION:            iprintf("> %s %s\n", PROGRAM, VERSION);            exit(0);	    break;	default:	    usage(EINVAL);	    break;	}    }  exit:    return err;}/** Initialise vnetd params. * * @param vnetd vnetd */static int vnetd_init(Vnetd *vnetd, int argc, char *argv[]){    int err = 0;    // Use etherip-in-udp encapsulation.    etherip_in_udp = true;    *vnetd = (Vnetd){};    vnetd->port = htons(VARP_PORT);    vnetd->verbose = false;    vnetd->ttl = 1; // Default multicast ttl.    vnetd->etherip = true;    vnetd->udp_sock = -1;    vnetd->mcast_sock = -1;    vnetd->etherip_sock = -1;    vnetd_set_mcast_addr(vnetd, htonl(VARP_MCAST_ADDR));    vnetd->mcast_addr.sin_port = vnetd->port;    vnetd->unix_path = "/tmp/vnetd";    vnetd_getopts(vnetd, argc, argv);        err = get_self_addr(&vnetd->ucast_addr);    vnetd->ucast_addr.sin_port = vnetd->port;    dprintf("> mcaddr=%s\n", inet_ntoa(vnetd->mcast_addr.sin_addr));    dprintf("> addr  =%s\n", inet_ntoa(vnetd->ucast_addr.sin_addr));    return err;}static void vnet_select(Vnetd *vnetd, SelectSet *set){    HashTable_for_decl(entry);    HashTable_for_each(entry, vnetd->vnet_table){        Vnet *vnet = entry->value;        struct net_device *dev = vnet->dev;        if(!dev) continue;        if(dev->tapfd < 0) continue;        SelectSet_add(set, dev->tapfd, SELECT_READ);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?