⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kerneltap.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
// -*- c-basic-offset: 4 -*-/* * kerneltap.{cc,hh} -- element accesses network via /dev/tap device * Robert Morris, Douglas S. J. De Couto, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "kerneltap.hh"#include <click/error.hh>#include <click/bitvector.hh>#include <click/confparse.hh>#include <click/straccum.hh>#include <click/glue.hh>#include <clicknet/ether.h>#include <click/standard/scheduleinfo.hh>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <arpa/inet.h>#if defined(__linux__) && defined(HAVE_LINUX_IF_TUN_H)# define KERNELTUN_LINUX 1#elif defined(HAVE_NET_IF_TUN_H)# define KERNELTUN_NET 1#elif defined(__APPLE__)# define KERNELTUN_OSX 1 // assume tun driver installed from http://chrisp.de/en/projects/tunnel.html// this driver doesn't produce or expect packets with an address family prepended#endif#include <net/if.h>#if HAVE_NET_IF_TUN_H# include <net/if_tun.h>#elif HAVE_LINUX_IF_TUN_H# include <linux/if_tun.h>#endifCLICK_DECLSKernelTap::KernelTap()  : Element(1, 1), _fd(-1), _task(this),    _macaddr((const unsigned char *)"\000\001\002\003\004\005"),    _ignore_q_errs(false), _printed_write_err(false), _printed_read_err(false){}KernelTap::~KernelTap(){}intKernelTap::configure(Vector<String> &conf, ErrorHandler *errh){    _gw = IPAddress();    _headroom = Packet::DEFAULT_HEADROOM;    _mtu_out = DEFAULT_MTU;    if (cp_va_parse(conf, this, errh,		    cpIPPrefix, "network address", &_near, &_mask,		    cpOptional,		    cpKeywords,		    "HEADROOM", cpUnsigned, "default headroom for generated packets", &_headroom,		    "ETHER", cpEthernetAddress, "fake device Ethernet address", &_macaddr,		    "IGNORE_QUEUE_OVERFLOWS", cpBool, "ignore queue overflow errors?", &_ignore_q_errs,		    "MTU", cpInteger, "MTU", &_mtu_out,		    cpEnd) < 0)	return -1;    if (_gw) { // then it was set to non-zero by arg	// check net part matches 	unsigned int g = _gw.in_addr().s_addr;	unsigned int m = _mask.in_addr().s_addr;	unsigned int n = _near.in_addr().s_addr;	if ((g & m) != (n & m)) {	    _gw = 0;	    errh->warning("not setting up default route\n(network address and gateway are on different networks)");	}    }    return 0;}#if KERNELTUN_LINUXintKernelTap::try_linux_universal(ErrorHandler *errh){    int fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);    if (fd < 0)	return -errno;    struct ifreq ifr;    memset(&ifr, 0, sizeof(ifr));    ifr.ifr_flags = IFF_TAP;    int err = ioctl(fd, TUNSETIFF, (void *)&ifr);    if (err < 0) {	errh->warning("Linux universal tun failed: %s", strerror(errno));	close(fd);	return -errno;    }    _dev_name = ifr.ifr_name;    _type = LINUX_UNIVERSAL;    _fd = fd;    return 0;}#endifintKernelTap::try_tun(const String &dev_name, ErrorHandler *){    String filename = "/dev/" + dev_name;    int fd = open(filename.cc(), O_RDWR | O_NONBLOCK);    if (fd < 0)	return -errno;    _dev_name = dev_name;    _fd = fd;    return 0;}/* * Find an available kernel tap, or report error if none are available. * Does not set up the tap. * On success, _dev_name, _type, and _fd are valid. */intKernelTap::alloc_tun(ErrorHandler *errh){#if !KERNELTUN_LINUX && !KERNELTUN_NET && !KERNELTUN_OSX    return errh->error("KernelTap is not yet supported on this system.\n(Please report this message to click@pdos.lcs.mit.edu.)");#endif    int error, saved_error = 0;    String saved_device, saved_message;    StringAccum tried;    #if KERNELTUN_LINUX    _type = LINUX_UNIVERSAL;    if ((error = try_linux_universal(errh)) >= 0)	return error;    else if (!saved_error || error != -ENOENT) {	saved_error = error, saved_device = "net/tun";	if (error == -ENODEV)	    saved_message = "\n(Perhaps you need to enable tun in your kernel or load the `tun' module.)";    }    tried << "/dev/net/tun, ";#endif#ifdef __linux__    _type = LINUX_ETHERTAP;    String dev_prefix = "tap";#elif defined(KERNELTUN_OSX)    _type = OSX_TUN;    String dev_prefix = "tun";#else    _type = BSD_TUN;    String dev_prefix = "tun";#endif    for (int i = 0; i < 6; i++) {	if ((error = try_tun(dev_prefix + String(i), errh)) >= 0)	    return error;	else if (!saved_error || error != -ENOENT)	    saved_error = error, saved_device = dev_prefix + String(i), saved_message = String();	tried << "/dev/" << dev_prefix << i << ", ";    }        if (saved_error == -ENOENT) {	tried.pop_back(2);	return errh->error("could not find a tap device\n(checked %s)\nYou may need to enable tap support in your kernel.", tried.cc());    } else	return errh->error("could not allocate device /dev/%s: %s%s", saved_device.cc(), strerror(-saved_error), saved_message.cc());}intKernelTap::setup_tun(struct in_addr near, struct in_addr mask, ErrorHandler *errh){    char tmp[512], tmp0[64], tmp1[64];// #if defined(__OpenBSD__)  && !defined(TUNSIFMODE)//     /* see OpenBSD bug: http://cvs.openbsd.org/cgi-bin/wwwgnats.pl/full/782 */// #define       TUNSIFMODE      _IOW('t', 88, int)// #endif#if defined(TUNSIFMODE) || defined(__FreeBSD__)    {	int mode = IFF_BROADCAST;	if (ioctl(_fd, TUNSIFMODE, &mode) != 0)	    return errh->error("TUNSIFMODE failed: %s", strerror(errno));    }#endif#if defined(__OpenBSD__)    {	struct tuninfo ti;	memset(&ti, 0, sizeof(struct tuninfo));	if (ioctl(_fd, TUNGIFINFO, &ti) != 0)	    return errh->error("TUNGIFINFO failed: %s", strerror(errno));	ti.flags &= IFF_BROADCAST;	if (ioctl(_fd, TUNSIFINFO, &ti) != 0)	    return errh->error("TUNSIFINFO failed: %s", strerror(errno));    }#endif        if (_macaddr) {	sprintf(tmp, "/sbin/ifconfig %s hw ether %s", _dev_name.cc(),		_macaddr.s().cc());	if (system(tmp) != 0) {	    errh->error("%s: %s", tmp, strerror(errno));	}		sprintf(tmp, "/sbin/ifconfig %s arp", _dev_name.cc());	if (system(tmp) != 0) 	    return errh->error("%s: %s", tmp, strerror(errno));    }    #if defined(TUNSIFHEAD) || defined(__FreeBSD__)    // Each read/write prefixed with a 32-bit address family,    // just as in OpenBSD.    int yes = 1;    if (ioctl(_fd, TUNSIFHEAD, &yes) != 0)	return errh->error("TUNSIFHEAD failed: %s", strerror(errno));#endif            strcpy(tmp0, inet_ntoa(near));    strcpy(tmp1, inet_ntoa(mask));    sprintf(tmp, "/sbin/ifconfig %s %s netmask %s up 2>/dev/null", _dev_name.cc(), tmp0, tmp1);    if (system(tmp) != 0) {# if defined(__linux__)	// Is Ethertap available? If it is moduleified, then it might not be.	// beside the ethertap module, you may also need the netlink_dev	// module to be loaded.	return errh->error("%s: `%s' failed\n(Perhaps Ethertap is in a kernel module that you haven't loaded yet?)", _dev_name.cc(), tmp);# else	return errh->error("%s: `%s' failed", _dev_name.cc(), tmp);# endif    }        if (_gw) {#if defined(__linux__)	sprintf(tmp, "/sbin/route -n add default gw %s", _gw.s().cc());#elif defined(__FreeBSD__) || defined(__OpenBSD__)	sprintf(tmp, "/sbin/route -n add default %s", _gw.s().cc());#endif	if (system(tmp) != 0)	    return errh->error("%s: %s", tmp, strerror(errno));    }        // calculate maximum packet size needed to receive data from    // tun/tap.    if (_type == LINUX_UNIVERSAL)	_mtu_in = _mtu_out + 4;    else if (_type == BSD_TUN)	_mtu_in = _mtu_out + 4;    else if (_type == OSX_TUN)	_mtu_in = _mtu_out + 4; // + 0?    else /* _type == LINUX_ETHERTAP */	_mtu_in = _mtu_out + 16;    return 0;}voidKernelTap::dealloc_tun(){    String cmd = "/sbin/ifconfig " + _dev_name + " down";    if (system(cmd.cc()) != 0) 	click_chatter("%s: failed: %s", id().cc(), cmd.cc());}intKernelTap::initialize(ErrorHandler *errh){    if (alloc_tun(errh) < 0)	return -1;    if (setup_tun(_near, _mask, errh) < 0)	return -1;  if (input_is_pull(0))    ScheduleInfo::join_scheduler(this, &_task, errh);  add_select(_fd, SELECT_READ);  return 0;}voidKernelTap::cleanup(CleanupStage){    if (_fd >= 0) {	close(_fd);	remove_select(_fd, SELECT_READ);	if (_type != LINUX_UNIVERSAL)	    dealloc_tun();    }}voidKernelTap::selected(int fd){    if (fd != _fd)	return;    WritablePacket *p = Packet::make(_headroom, 0, _mtu_in, 0);    if (!p) {	click_chatter("out of memory!");	return;    }        int cc = read(_fd, p->data(), _mtu_in);    if (cc > 0) {	p->take(_mtu_in - cc);		if (_type == LINUX_UNIVERSAL) {	    // 2-byte padding followed by an Ethernet type	    p->pull(4);	} else if (_type == BSD_TUN) {	    // 4-byte address family followed by IP header	    p->pull(4);	} else if (_type == OSX_TUN) {	} else { /* _type == LINUX_ETHERTAP */	    p->pull(2);	}		p->timestamp_anno().set_now();	output(0).push(p);    } else {	if (!_ignore_q_errs || !_printed_read_err || (errno != ENOBUFS)) {	    _printed_read_err = true;	    perror("KernelTap read");	}    }}boolKernelTap::run_task(){    Packet *p = input(0).pull();    if (p)	push(0, p);     _task.fast_reschedule();    return p != 0;}voidKernelTap::push(int, Packet *p){    // Every packet has a 14-byte Ethernet header.    // Extract the packet type, then ignore the Ether header.    const click_ip *iph = p->ip_header();    click_ether *e = (click_ether *) p->data();        if (!iph) {	click_chatter("KernelTap(%s): no network header", _dev_name.cc());	p->kill();    }    if (p->length() < sizeof(*e)){	click_chatter("KernelTap(%s): packet too small", _dev_name.c_str());	p->kill();	return;    }    WritablePacket *q;    if (_type == LINUX_UNIVERSAL) {	// 2-byte padding followed by an Ethernet type	uint32_t ethertype = (iph->ip_v == 4 ? htonl(ETHERTYPE_IP) : htonl(ETHERTYPE_IP6));	if ((q = p->push(4)))	    *(uint32_t *)(q->data()) = ethertype;    } else if (_type == BSD_TUN) { 	uint32_t af = (iph->ip_v == 4 ? htonl(AF_INET) : htonl(AF_INET6));	if ((q = p->push(4)))	    *(uint32_t *)(q->data()) = af;    } else if (_type == OSX_TUN) {	// send raw IP	q = p->uniqueify();    } else { /* _type == LINUX_ETHERTAP */	q = p->push(2);    }        if (q) {	int w = write(_fd, q->data(), q->length());	if (w != (int) q->length() && (errno != ENOBUFS || !_ignore_q_errs || !_printed_write_err)) {	    _printed_write_err = true;	    click_chatter("KernelTap(%s): write failed: %s", _dev_name.cc(), strerror(errno));	}	q->kill();    } else	click_chatter("%{element}: out of memory", this);}StringKernelTap::print_dev_name(Element *e, void *) {  KernelTap *kt = (KernelTap *) e;  return kt->_dev_name;}voidKernelTap::add_handlers(){  if (input_is_pull(0))    add_task_handlers(&_task);  add_read_handler("dev_name", print_dev_name, 0);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel)EXPORT_ELEMENT(KernelTap)

⌨️ 快捷键说明

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