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 + -
显示快捷键?