📄 fromhost.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromhost.{cc,hh} -- receives packets from Linux * Max Poletto, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2000 Mazu Networks, Inc. * Copyright (c) 2001-2003 International Computer Science Institute * * 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 <click/router.hh>#include "fromhost.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/standard/scheduleinfo.hh>#include <click/cxxprotect.h>CLICK_CXX_PROTECT#include <asm/types.h>#include <asm/uaccess.h>#include <linux/ip.h>#include <linux/inetdevice.h>#include <net/route.h>CLICK_CXX_UNPROTECT#include <click/cxxunprotect.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)# define netif_start_queue(dev) do { dev->start=1; dev->tbusy=0; } while (0)# define netif_stop_queue(dev) do { dev->tbusy=1; } while (0)# define netif_wake_queue(dev) do { dev->tbusy=0; } while (0)#endifstatic int fl_open(net_device *);static int fl_close(net_device *);static net_device_stats *fl_stats(net_device *);static void fl_wakeup(Timer *, void *);static int from_linux_count;static AnyDeviceMap fromlinux_map;voidFromHost::static_initialize(){ fromlinux_map.initialize();}FromHost::FromHost() : _macaddr((const unsigned char *)"\000\001\002\003\004\005"), _task(this), _wakeup_timer(fl_wakeup, this), _queue(0){ add_output(); memset(&_stats, 0, sizeof(_stats));}FromHost::~FromHost(){}net_device *FromHost::new_device(const char *name){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) read_lock(&dev_base_lock);#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) net_device *dev = alloc_netdev(0, name, ether_setup);#else int errcode; net_device *dev = dev_alloc(name, &errcode);#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) read_unlock(&dev_base_lock);#endif if (!dev) return 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) // need to zero out the dev structure char *nameptr = dev->name; memset(dev, 0, sizeof(*dev)); dev->name = nameptr;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) ether_setup(dev);#endif dev->open = fl_open; dev->stop = fl_close; dev->hard_start_xmit = fl_tx; dev->get_stats = fl_stats; return dev;}intFromHost::configure(Vector<String> &conf, ErrorHandler *errh){ if (cp_va_parse(conf, this, errh, cpString, "device name", &_devname, cpIPPrefix, "destination IP prefix", &_destaddr, &_destmask, cpKeywords, "ETHER", cpEthernetAddress, "fake device Ethernet address", &_macaddr, cpEnd) < 0) return -1; if (_devname.length() > IFNAMSIZ - 1) return errh->error("device name '%s' too long", _devname.cc()); // check for duplicate element void *&used = router()->force_attachment("FromHost_" + _devname); if (used) return errh->error("duplicate FromHost for device '%s'", _devname.cc()); used = this; // check for existing device _dev = dev_get_by_name(_devname.cc()); if (_dev) { if (_dev->open != fl_open) { dev_put(_dev); _dev = 0; return errh->error("device '%s' already exists", _devname.cc()); } else { fromlinux_map.insert(this); return 0; } } // if not found, create new device int res; _dev = new_device(_devname.c_str()); if (!_dev) return errh->error("out of memory!", res, _devname.c_str()); else if ((res = register_netdev(_dev)) < 0) { kfree(_dev); _dev = 0; return errh->error("error %d registering device '%s'", res, _devname.c_str()); } dev_hold(_dev); fromlinux_map.insert(this); return 0;}#if 0 /* Why was this code here? */static voiddev_locks(int up){# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) if (up > 0) rtnl_lock(); else rtnl_unlock();# endif}#endifintFromHost::set_device_addresses(ErrorHandler *errh){ int res; struct ifreq ifr; strncpy(ifr.ifr_name, _dev->name, IFNAMSIZ); struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; mm_segment_t oldfs = get_fs(); set_fs(get_ds()); ifr.ifr_hwaddr.sa_family = _dev->type; memcpy(ifr.ifr_hwaddr.sa_data, _macaddr.data(), 6); if ((res = dev_ioctl(SIOCSIFHWADDR, &ifr)) < 0) errh->error("error %d setting hardware address for device '%s'", res, _devname.cc()); sin->sin_family = AF_INET; sin->sin_addr = _destaddr; if (res >= 0 && (res = devinet_ioctl(SIOCSIFADDR, &ifr)) < 0) errh->error("error %d setting address for device '%s'", res, _devname.cc()); sin->sin_addr = _destmask; if (res >= 0 && (res = devinet_ioctl(SIOCSIFNETMASK, &ifr)) < 0) errh->error("error %d setting netmask for device '%s'", res, _devname.cc()); set_fs(oldfs); return res;}static intdev_updown(net_device *dev, int up, ErrorHandler *errh){ struct ifreq ifr; strncpy(ifr.ifr_name, dev->name, IFNAMSIZ); uint32_t flags = IFF_UP | IFF_RUNNING; int res; mm_segment_t oldfs = get_fs(); set_fs(get_ds()); (void) dev_ioctl(SIOCGIFFLAGS, &ifr); ifr.ifr_flags = (up > 0 ? ifr.ifr_flags | flags : ifr.ifr_flags & ~flags); if ((res = dev_ioctl(SIOCSIFFLAGS, &ifr)) < 0 && errh) errh->error("error %d bringing %s device '%s'", res, (up > 0 ? "up" : "down"), dev->name); set_fs(oldfs); return res;}intFromHost::initialize(ErrorHandler *errh){ ScheduleInfo::initialize_task(this, &_task, _dev != 0, errh); _nonfull_signal = Notifier::downstream_nonfull_signal(this, 0, &_task); if (_dev->flags & IFF_UP) { _wakeup_timer.initialize(this); _wakeup_timer.schedule_now(); return 0; } else if (set_device_addresses(errh) < 0) return -1; else return dev_updown(_dev, 1, errh);}voidFromHost::cleanup(CleanupStage){ fromlinux_map.remove(this); if (_queue) { _queue->kill(); _queue = 0; } if (_dev) { dev_put(_dev); if (fromlinux_map.lookup(_dev, 0)) _dev = 0; // do not free device; still in use else { if (_dev->flags & IFF_UP) dev_updown(_dev, -1, 0); unregister_netdev(_dev); kfree(_dev); _dev = 0; } }}static voidfl_wakeup(Timer *, void *thunk){ FromHost *fl = (FromHost *)thunk; PrefixErrorHandler errh(ErrorHandler::default_handler(), fl->declaration() + ": "); net_device *dev = fl->device(); if (dev->flags & IFF_UP) dev_updown(dev, -1, &errh); fl->set_device_addresses(&errh); dev_updown(dev, 1, &errh);}/* * Device callbacks */static intfl_open(net_device *dev){ netif_start_queue(dev); return 0;}static intfl_close(net_device *dev){ netif_stop_queue(dev); return 0;}intFromHost::fl_tx(struct sk_buff *skb, net_device *dev){ /* 8.May.2003 - Doug and company had crashes with FromHost configurations. We eventually figured out this was because fl_tx was called at interrupt time -- at bottom-half time, to be exact -- and then pushed a packet through the configuration. Whoops: if Click was interrupted, and during the bottom-half FromHost emitted a packet into Click, DISASTER -- we assume that, when running single-threaded, at most one Click thread is active at a time; so there were race conditions, particularly with the task list. The solution is a single-packet-long queue in FromHost. fl_tx puts a packet onto the queue, a regular Click Task takes the packet off the queue. We could have implemented a larger queue, but why bother? Linux already maintains a queue for the device. */ if (FromHost *fl = (FromHost *)fromlinux_map.lookup(dev, 0)) if (!fl->_queue) { fl->_queue = Packet::make(skb); netif_stop_queue(dev); fl->_stats.tx_packets++; fl->_stats.tx_bytes += fl->_queue->length(); fl->_task.reschedule(); return 0; } return -1;}static net_device_stats *fl_stats(net_device *dev){ if (FromHost *fl = (FromHost *)fromlinux_map.lookup(dev, 0)) return fl->stats(); return 0;}boolFromHost::run_task(){ if (!_nonfull_signal) return false; else if (Packet *p = _queue) { _queue = 0; netif_wake_queue(_dev); output(0).push(p); return true; } else return false;}ELEMENT_REQUIRES(AnyDevice linuxmodule)EXPORT_ELEMENT(FromHost)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -