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

📄 polldevice.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * polldevice.{cc,hh} -- element steals packets from Linux devices by polling. * Benjie Chen, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2000 Mazu Networks, Inc. * Copyright (c) 2001 International Computer Science Institute * Copyright (c) 2004 Regents of the University of California * * 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/glue.hh>#include "polldevice.hh"#include "fromdevice.hh"#include "todevice.hh"#include <click/error.hh>#include <click/confparse.hh>#include <click/router.hh>#include <click/skbmgr.hh>#include <click/standard/scheduleinfo.hh>#include <click/cxxprotect.h>CLICK_CXX_PROTECT#include <linux/netdevice.h>#if __i386__#include <asm/msr.h>#endifCLICK_CXX_UNPROTECT#include <click/cxxunprotect.h>/* for hot-swapping */static AnyDeviceMap poll_device_map;static struct notifier_block device_notifier;extern "C" {static int device_notifier_hook(struct notifier_block *nb, unsigned long val, void *v);}voidPollDevice::static_initialize(){    poll_device_map.initialize();    device_notifier.notifier_call = device_notifier_hook;    device_notifier.priority = 1;    device_notifier.next = 0;    register_netdevice_notifier(&device_notifier);}voidPollDevice::static_cleanup(){    unregister_netdevice_notifier(&device_notifier);}PollDevice::PollDevice(){    add_output();}PollDevice::~PollDevice(){}intPollDevice::configure(Vector<String> &conf, ErrorHandler *errh){    _burst = 8;    bool promisc = false;    bool allow_nonexistent = false;    if (cp_va_parse(conf, this, errh,		    cpString, "device name", &_devname,		    cpOptional,		    cpBool, "enter promiscuous mode?", &promisc,		    cpUnsigned, "burst size", &_burst,		    cpKeywords,		    "PROMISC", cpBool, "enter promiscuous mode?", &promisc,		    "PROMISCUOUS", cpBool, "enter promiscuous mode?", &promisc,		    "BURST", cpUnsigned, "burst size", &_burst,		    "ALLOW_NONEXISTENT", cpBool, "allow nonexistent device?", &allow_nonexistent,		    cpEnd) < 0)	return -1;    if (promisc)	set_promisc();    #if HAVE_LINUX_POLLING    if (find_device(allow_nonexistent, &poll_device_map, errh) < 0)	return -1;    if (_dev && (!_dev->poll_on || _dev->polling < 0))	return errh->error("device '%s' not pollable, use FromDevice instead", _devname.cc());#endif    return 0;}/* * Use Linux interface for polling, added by us, in include/linux/netdevice.h, * to poll devices. */intPollDevice::initialize(ErrorHandler *errh){#if HAVE_LINUX_POLLING    // check for duplicate readers    if (ifindex() >= 0) {	void *&used = router()->force_attachment("device_reader_" + String(ifindex()));	if (used)	    return errh->error("duplicate reader for device '%s'", _devname.cc());	used = this;	if (!router()->attachment("device_writer_" + String(ifindex())))	    errh->warning("no ToDevice(%s) in configuration\n(\Generally, you will get bad performance from PollDevice unless\n\you include a ToDevice for the same device. Try adding\n\'Idle -> ToDevice(%s)' to your configuration.)", _devname.c_str(), _devname.c_str());    }    if (_dev && !_dev->polling) {	/* turn off interrupt if interrupts weren't already off */	_dev->poll_on(_dev);	if (_dev->polling != 2)	    return errh->error("PollDevice detected wrong version of polling patch");    }    ScheduleInfo::initialize_task(this, &_task, _dev != 0, errh);#ifdef HAVE_STRIDE_SCHED    // user specifies max number of tickets; we start with default    _max_tickets = _task.tickets();    _task.set_tickets(Task::DEFAULT_TICKETS);#endif    reset_counts();    #else    errh->warning("can't get packets: not compiled with polling extensions");#endif    return 0;}voidPollDevice::reset_counts(){  _npackets = 0;#if CLICK_DEVICE_STATS  _activations = 0;  _empty_polls = 0;  _time_poll = 0;  _time_refill = 0;  _time_allocskb = 0;  _perfcnt1_poll = 0;  _perfcnt1_refill = 0;  _perfcnt1_allocskb = 0;  _perfcnt1_pushing = 0;  _perfcnt2_poll = 0;  _perfcnt2_refill = 0;  _perfcnt2_allocskb = 0;  _perfcnt2_pushing = 0;#endif#if CLICK_DEVICE_THESIS_STATS || CLICK_DEVICE_STATS  _push_cycles = 0;#endif  _buffers_reused = 0;}voidPollDevice::cleanup(CleanupStage){#if HAVE_LINUX_POLLING    net_device *had_dev = _dev;    // call clear_device first so we can check poll_device_map for    // other users    clear_device(&poll_device_map);    if (had_dev && had_dev->polling > 0 && !poll_device_map.lookup(had_dev, 0))	had_dev->poll_off(had_dev);#endif}boolPollDevice::run_task(){#if HAVE_LINUX_POLLING  struct sk_buff *skb_list, *skb;  int got=0;# if CLICK_DEVICE_STATS  uint64_t time_now;  unsigned low00, low10;# endif  SET_STATS(low00, low10, time_now);  got = _burst;  skb_list = _dev->rx_poll(_dev, &got);# if CLICK_DEVICE_STATS  if (got > 0 || _activations > 0) {    GET_STATS_RESET(low00, low10, time_now, 		    _perfcnt1_poll, _perfcnt2_poll, _time_poll);    if (got == 0)       _empty_polls++;    else       _activations++;  }# endif  int nskbs = got;  if (got == 0)    nskbs = _dev->rx_refill(_dev, 0);  if (nskbs > 0) {    /*     * Extra 16 bytes in the SKB for eepro100 RxFD -- perhaps there     * should be some callback to the device driver to query for the     * desired packet size.     */    struct sk_buff *new_skbs = skbmgr_allocate_skbs(0, 1536+16, &nskbs);# if CLICK_DEVICE_STATS    if (_activations > 0)      GET_STATS_RESET(low00, low10, time_now, 	              _perfcnt1_allocskb, _perfcnt2_allocskb, _time_allocskb);# endif    nskbs = _dev->rx_refill(_dev, &new_skbs);# if CLICK_DEVICE_STATS    if (_activations > 0)       GET_STATS_RESET(low00, low10, time_now, 	              _perfcnt1_refill, _perfcnt2_refill, _time_refill);# endif    if (new_skbs) {	for (struct sk_buff *skb = new_skbs; skb; skb = skb->next)	    _buffers_reused++;	skbmgr_recycle_skbs(new_skbs);    }  }  for (int i = 0; i < got; i++) {    skb = skb_list;    skb_list = skb_list->next;    skb->next = NULL;     if (skb_list) {      // prefetch annotation area, and first 2 cache      // lines that contain ethernet and ip headers.# if __i386__ && HAVE_INTEL_CPU      asm volatile("prefetcht0 %0" : : "m" (skb_list->cb[0]));      // asm volatile("prefetcht0 %0" : : "m" (*(skb_list->data)));      asm volatile("prefetcht0 %0" : : "m" (*(skb_list->data+32)));# endif    }    /* Retrieve the ether header. */    skb_push(skb, 14);    if (skb->pkt_type == PACKET_HOST)      skb->pkt_type |= PACKET_CLEAN;    Packet *p = Packet::make(skb);    # ifndef CLICK_WARP9    p->timestamp_anno().set_now();# endif    _npackets++;# if CLICK_DEVICE_THESIS_STATS && !CLICK_DEVICE_STATS    uint64_t before_push_cycles = click_get_cycles();# endif    output(0).push(p);# if CLICK_DEVICE_THESIS_STATS && !CLICK_DEVICE_STATS    _push_cycles += click_get_cycles() - before_push_cycles - CLICK_CYCLE_COMPENSATION;# endif  }# if CLICK_DEVICE_STATS  if (_activations > 0) {    GET_STATS_RESET(low00, low10, time_now, 	            _perfcnt1_pushing, _perfcnt2_pushing, _push_cycles);#  if _DEV_OVRN_STATS_    if ((_activations % 1024) == 0)	_dev->get_stats(_dev);#  endif  }# endif  adjust_tickets(got);  _task.fast_reschedule();  return got > 0;#else  return false;#endif /* HAVE_LINUX_POLLING */}voidPollDevice::change_device(net_device *dev){#if HAVE_LINUX_POLLING    if (_dev == dev)		// no op	return;        _task.strong_unschedule();        if (dev && (!dev->poll_on || dev->polling < 0)) {	click_chatter("%s: device '%s' does not support polling", declaration().cc(), _devname.cc());	dev = 0;    }        if (_dev)	_dev->poll_off(_dev);    set_device(dev, &poll_device_map);        if (_dev && !_dev->polling)	_dev->poll_on(_dev);    if (_dev)	_task.strong_reschedule();#else    (void) dev;#endif /* HAVE_LINUX_POLLING */}extern "C" {static intdevice_notifier_hook(struct notifier_block *nb, unsigned long flags, void *v){#ifdef NETDEV_GOING_DOWN    if (flags == NETDEV_GOING_DOWN)	flags = NETDEV_DOWN;#endif    if (flags == NETDEV_DOWN || flags == NETDEV_UP) {	bool down = (flags == NETDEV_DOWN);	net_device *dev = (net_device *)v;	Vector<AnyDevice *> es;	poll_device_map.lookup_all(dev, down, es);	for (int i = 0; i < es.size(); i++)	    ((PollDevice *)(es[i]))->change_device(down ? 0 : dev);    }    return 0;}}static StringPollDevice_read_calls(Element *f, void *){  PollDevice *kw = (PollDevice *)f;  return    String(kw->_npackets) + " packets received\n" +    String(kw->_buffers_reused) + " buffers reused\n" +#if CLICK_DEVICE_STATS    String(kw->_time_poll) + " cycles poll\n" +    String(kw->_time_refill) + " cycles refill\n" +    String(kw->_time_allocskb) + " cycles allocskb\n" +    String(kw->_push_cycles) + " cycles pushing\n" +    String(kw->_perfcnt1_poll) + " perfctr1 poll\n" +    String(kw->_perfcnt1_refill) + " perfctr1 refill\n" +    String(kw->_perfcnt1_allocskb) + " perfctr1 allocskb\n" +    String(kw->_perfcnt1_pushing) + " perfctr1 pushing\n" +    String(kw->_perfcnt2_poll) + " perfctr2 poll\n" +    String(kw->_perfcnt2_refill) + " perfctr2 refill\n" +    String(kw->_perfcnt2_allocskb) + " perfctr2 allocskb\n" +    String(kw->_perfcnt2_pushing) + " perfctr2 pushing\n" +    String(kw->_empty_polls) + " empty polls\n" +    String(kw->_activations) + " activations\n";#else    String();#endif}static StringPollDevice_read_stats(Element *e, void *thunk){  PollDevice *pd = (PollDevice *)e;  switch (reinterpret_cast<intptr_t>(thunk)) {   case 0:    return String(pd->_npackets) + "\n";#if CLICK_DEVICE_THESIS_STATS || CLICK_DEVICE_STATS   case 1:    return String(pd->_push_cycles) + "\n";#endif#if CLICK_DEVICE_STATS   case 2:    return String(pd->_time_poll) + "\n";   case 3:    return String(pd->_time_refill) + "\n";#endif   case 4:    return String(pd->_buffers_reused) + "\n";   default:    return String();  }}static intPollDevice_write_stats(const String &, Element *e, void *, ErrorHandler *){  PollDevice *pd = (PollDevice *)e;  pd->reset_counts();  return 0;}voidPollDevice::add_handlers(){  add_read_handler("calls", PollDevice_read_calls, 0);  add_read_handler("count", PollDevice_read_stats, 0);  // XXX deprecated  add_read_handler("packets", PollDevice_read_stats, 0);#if CLICK_DEVICE_THESIS_STATS || CLICK_DEVICE_STATS  add_read_handler("push_cycles", PollDevice_read_stats, (void *)1);#endif#if CLICK_DEVICE_STATS  add_read_handler("poll_cycles", PollDevice_read_stats, (void *)2);  add_read_handler("refill_dma_cycles", PollDevice_read_stats, (void *)3);#endif  add_write_handler("reset_counts", PollDevice_write_stats, 0);  add_read_handler("buffers_reused", PollDevice_read_stats, (void *)4);  add_task_handlers(&_task);}ELEMENT_REQUIRES(AnyDevice linuxmodule)EXPORT_ELEMENT(PollDevice)

⌨️ 快捷键说明

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