From ae76f68c1bae0a19adb6f22937f6b2cf4f7911d5 Mon Sep 17 00:00:00 2001 From: Eddie Kohler Date: Wed, 27 Jan 2010 17:13:08 -0800 Subject: [PATCH] Linuxmodule FromDevice: Work in unmodified kernels (--enable-fixincludes). This code makes use of existing hooks for Ethernet bridging, and will only work if your kernel was compiled with CONFIG_BRIDGE or CONFIG_BRIDGE_MODULE. It replaces the bridge hook with Click code. When using Click, it's probably safest to use CONFIG_BRIDGE_MODULE and then not actually load the module. Required some refactoring, which simplified the code. ToDevice also compiles in unmodified kernels, but haven't tested yet if it runs. --- elements/linuxmodule/anydevice.cc | 102 +++++++++++++----------- elements/linuxmodule/anydevice.hh | 31 ++++++-- elements/linuxmodule/fromdevice.cc | 73 ++++++++++++++--- elements/linuxmodule/fromhost.cc | 2 +- elements/linuxmodule/polldevice.cc | 18 +++-- elements/linuxmodule/todevice.cc | 122 +++++++++++++++++++---------- elements/linuxmodule/todevice.hh | 10 ++- elements/linuxmodule/tohost.cc | 14 ++-- 8 files changed, 247 insertions(+), 125 deletions(-) diff --git a/elements/linuxmodule/anydevice.cc b/elements/linuxmodule/anydevice.cc index bc67d3a6bd..176fe97018 100644 --- a/elements/linuxmodule/anydevice.cc +++ b/elements/linuxmodule/anydevice.cc @@ -108,48 +108,63 @@ AnyDevice::alter_promiscuity(int delta) #endif } -int -AnyDevice::find_device(AnyDeviceMap *adm, ErrorHandler *errh) +void +AnyDevice::alter_from_device(int delta) { - _dev = get_by_name(_devname.c_str()); - _devname_exists = (bool) _dev; - if (!_dev) - _dev = get_by_ether_address(_devname, this); - - if (!_dev && !_allow_nonexistent) - return errh->error("unknown device '%s'", _devname.c_str()); - else if (!_dev && !_quiet) - errh->warning("unknown device '%s'", _devname.c_str()); - else if (_dev && !(_dev->flags & IFF_UP)) { - if (!_quiet) - errh->warning("device '%s' is down", _devname.c_str()); - dev_put(_dev); - _dev = 0; +#if !HAVE_CLICK_KERNEL && (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) + fake_bridge *fb = reinterpret_cast(_dev->br_port); + if (fb && fb->magic != fake_bridge::click_magic) { + printk("<1>%s: appears to be owned by the bridge module!", _devname.c_str()); + return; } - if (_dev && _promisc) - alter_promiscuity(1); -#if HAVE_NET_ENABLE_TIMESTAMP - if (_dev && _timestamp) - net_enable_timestamp(); + if (delta < 0 && fb && atomic_dec_and_test(&fb->refcount)) { + delete fb; + rcu_assign_pointer(_dev->br_port, NULL); + } else if (delta > 0 && fb) + atomic_inc(&fb->refcount); + else if (delta > 0) { + fb = new fake_bridge; + fb->magic = fake_bridge::click_magic; + atomic_set(&fb->refcount, 1); + rcu_assign_pointer(_dev->br_port, reinterpret_cast(fb)); + } +#else + (void) delta; #endif - _carrier_ok = (_dev && netif_carrier_ok(_dev)); - if (adm) - adm->insert(this, false); +} - return 0; +net_device * +AnyDevice::lookup_device(ErrorHandler *errh) +{ + net_device *dev = get_by_name(_devname.c_str()); + _devname_exists = (bool) dev; + if (!dev) + dev = get_by_ether_address(_devname, this); + + if (!dev && !_allow_nonexistent) + errh->error("unknown device %<%s%>", _devname.c_str()); + else if (!dev && !_quiet) + errh->warning("unknown device %<%s%>", _devname.c_str()); + else if (dev && !(dev->flags & IFF_UP)) { + if (!_quiet) + errh->warning("device %<%s%> is down", _devname.c_str()); + dev_put(dev); + dev = 0; + } + return dev; } void -AnyDevice::set_device(net_device *dev, AnyDeviceMap *adm, bool locked) +AnyDevice::set_device(net_device *dev, AnyDeviceMap *adm, int flags) { if (_dev == dev) { // no device change == carrier sense only bool carrier_ok = (_dev && netif_carrier_ok(_dev)); if (carrier_ok != _carrier_ok) { _carrier_ok = carrier_ok; - if (_down_call && !_carrier_ok) + if (_down_call && !_carrier_ok && (flags & anydev_change)) _down_call->call_write(ErrorHandler::default_handler()); - if (_up_call && _carrier_ok) + if (_up_call && _carrier_ok && (flags & anydev_change)) _up_call->call_write(ErrorHandler::default_handler()); } return; @@ -157,28 +172,19 @@ AnyDevice::set_device(net_device *dev, AnyDeviceMap *adm, bool locked) // call going-down notifiers if (_dev) { - if (_down_call && _carrier_ok) + if (_down_call && _carrier_ok && (flags & anydev_change)) _down_call->call_write(ErrorHandler::default_handler()); if (!_down_call && !_quiet) - click_chatter("%s: device '%s' went down", declaration().c_str(), _devname.c_str()); + click_chatter("%s: device %<%s%> went down", declaration().c_str(), _devname.c_str()); } - if (_dev && _promisc) - alter_promiscuity(-1); -#if HAVE_NET_ENABLE_TIMESTAMP - if (_dev && _timestamp) - net_disable_timestamp(); -#endif + clear_device(adm, flags); - if (adm && _in_map) - adm->remove(this, locked); - if (_dev) - dev_put(_dev); _dev = dev; - if (_dev) + if (_dev && (flags & anydev_change)) dev_hold(_dev); if (adm) - adm->insert(this, locked); + adm->insert(this, flags & anydev_change); if (_dev && _promisc) alter_promiscuity(1); @@ -186,19 +192,21 @@ AnyDevice::set_device(net_device *dev, AnyDeviceMap *adm, bool locked) if (_dev && _timestamp) net_enable_timestamp(); #endif + if (_dev && (flags & anydev_from_device)) + alter_from_device(1); _carrier_ok = (_dev && netif_carrier_ok(_dev)); // call going-up notifiers - if (_dev) { + if (_dev && (flags & anydev_change)) { if (_up_call && _carrier_ok) _up_call->call_write(ErrorHandler::default_handler()); if (!_up_call && !_quiet) - click_chatter("%s: device '%s' came up", declaration().c_str(), _devname.c_str()); + click_chatter("%s: device %<%s%> came up", declaration().c_str(), _devname.c_str()); } } void -AnyDevice::clear_device(AnyDeviceMap *adm) +AnyDevice::clear_device(AnyDeviceMap *adm, int flags) { if (_dev && _promisc) alter_promiscuity(-1); @@ -206,8 +214,10 @@ AnyDevice::clear_device(AnyDeviceMap *adm) if (_dev && _timestamp) net_disable_timestamp(); #endif + if (_dev && (flags & anydev_from_device)) + alter_from_device(-1); if (adm && _in_map) - adm->remove(this, false); + adm->remove(this, flags & anydev_change); if (_dev) dev_put(_dev); _dev = 0; diff --git a/elements/linuxmodule/anydevice.hh b/elements/linuxmodule/anydevice.hh index 3f6f1a908c..c99fd40576 100644 --- a/elements/linuxmodule/anydevice.hh +++ b/elements/linuxmodule/anydevice.hh @@ -84,6 +84,7 @@ class AnyDevice : public Element { public: net_device *device() const { return _dev; } int ifindex() const { return _dev ? _dev->ifindex : -1; } + bool allow_nonexistent() const { return _allow_nonexistent; } bool promisc() const { return _promisc; } bool timestamp() const { return _timestamp; } @@ -91,9 +92,13 @@ class AnyDevice : public Element { public: bool is_reader); int initialize_keywords(ErrorHandler *errh); - int find_device(AnyDeviceMap *, ErrorHandler *); - void set_device(net_device *, AnyDeviceMap *, bool locked = false); - void clear_device(AnyDeviceMap *); + net_device *lookup_device(ErrorHandler *errh); + enum { + anydev_change = 1, + anydev_from_device = 2 + }; + void set_device(net_device *dev, AnyDeviceMap *map, int flags); + void clear_device(AnyDeviceMap *map, int flags); static inline net_device *get_by_name(const char *name) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) @@ -105,6 +110,15 @@ class AnyDevice : public Element { public: static net_device *get_by_ether_address(const String &name, Element *context); + // used for FromDevice + struct fake_bridge { + int magic; + atomic_t refcount; + enum { + click_magic = 0x817A10A7 + }; + }; + protected: String _devname; @@ -124,6 +138,7 @@ class AnyDevice : public Element { public: HandlerCall *_down_call; void alter_promiscuity(int delta); + void alter_from_device(int delta); friend class AnyDeviceMap; @@ -178,11 +193,11 @@ class AnyDeviceMap { public: void initialize(); inline void lock(bool write, unsigned long &flags); inline void unlock(bool write, unsigned long flags); - inline AnyDevice *lookup(net_device *, AnyDevice *) const; - AnyDevice *lookup_unknown(net_device *, AnyDevice *) const; - int lookup_all(net_device *, bool known, AnyDevice **dev_store, int ndev) const; - void insert(AnyDevice *, bool locked); - void remove(AnyDevice *, bool locked); + inline AnyDevice *lookup(net_device *dev, AnyDevice *last) const; + AnyDevice *lookup_unknown(net_device *dev, AnyDevice *last) const; + int lookup_all(net_device *dev, bool known, AnyDevice **develt_store, int ndev) const; + void insert(AnyDevice *develt, bool locked); + void remove(AnyDevice *develt, bool locked); private: diff --git a/elements/linuxmodule/fromdevice.cc b/elements/linuxmodule/fromdevice.cc index a9632a4ac3..f9daf791b2 100644 --- a/elements/linuxmodule/fromdevice.cc +++ b/elements/linuxmodule/fromdevice.cc @@ -33,14 +33,30 @@ static AnyDeviceMap from_device_map; static int registered_readers; -#ifdef HAVE_CLICK_KERNEL +#if HAVE_CLICK_KERNEL static struct notifier_block packet_notifier; #endif static struct notifier_block device_notifier; +#if !HAVE_CLICK_KERNEL && (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) +# define CLICK_FROMDEVICE_USE_BRIDGE 1 +#endif + +#if CLICK_FROMDEVICE_USE_BRIDGE +# include +CLICK_CXX_PROTECT +# include +CLICK_CXX_UNPROTECT +# include +#endif + + extern "C" { -#ifdef HAVE_CLICK_KERNEL +#if HAVE_CLICK_KERNEL static int packet_notifier_hook(struct notifier_block *nb, unsigned long val, void *v); +#elif CLICK_FROMDEVICE_USE_BRIDGE +static struct sk_buff *click_br_handle_frame_hook(struct net_bridge_port *p, struct sk_buff *skb); +static struct sk_buff *(*real_br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb); #endif static int device_notifier_hook(struct notifier_block *nb, unsigned long val, void *v); } @@ -49,7 +65,7 @@ void FromDevice::static_initialize() { from_device_map.initialize(); -#ifdef HAVE_CLICK_KERNEL +#if HAVE_CLICK_KERNEL packet_notifier.notifier_call = packet_notifier_hook; packet_notifier.priority = 1; packet_notifier.next = 0; @@ -63,9 +79,12 @@ FromDevice::static_initialize() void FromDevice::static_cleanup() { -#ifdef HAVE_CLICK_KERNEL +#if HAVE_CLICK_KERNEL if (registered_readers) unregister_net_in(&packet_notifier); +#elif CLICK_FROMDEVICE_USE_BRIDGE + if (br_handle_frame_hook == click_br_handle_frame_hook) + br_handle_frame_hook = real_br_handle_frame_hook; #endif unregister_netdevice_notifier(&device_notifier); } @@ -106,7 +125,10 @@ FromDevice::configure(Vector &conf, ErrorHandler *errh) // make queue look full so packets sent to us are ignored _head = _tail = _capacity = 0; - return find_device(&from_device_map, errh); + int before = errh->nerrors(); + net_device *dev = lookup_device(errh); + set_device(dev, &from_device_map, anydev_from_device); + return errh->nerrors() == before ? 0 : -1; } /* @@ -127,15 +149,18 @@ FromDevice::initialize(ErrorHandler *errh) used = this; } - if (!registered_readers) { -#ifdef HAVE_CLICK_KERNEL + if (registered_readers == 0) { +#if HAVE_CLICK_KERNEL packet_notifier.next = 0; register_net_in(&packet_notifier); +#elif CLICK_FROMDEVICE_USE_BRIDGE + real_br_handle_frame_hook = br_handle_frame_hook; + br_handle_frame_hook = click_br_handle_frame_hook; #else errh->warning("can't get packets: not compiled for a Click kernel"); #endif } - registered_readers++; + ++registered_readers; reset_counts(); @@ -156,14 +181,17 @@ void FromDevice::cleanup(CleanupStage stage) { if (stage >= CLEANUP_INITIALIZED) { - registered_readers--; -#ifdef HAVE_CLICK_KERNEL + --registered_readers; +#if HAVE_CLICK_KERNEL if (registered_readers == 0) unregister_net_in(&packet_notifier); +#elif CLICK_FROMDEVICE_USE_BRIDGE + if (registered_readers == 0) + br_handle_frame_hook = real_br_handle_frame_hook; #endif } - clear_device(&from_device_map); + clear_device(&from_device_map, anydev_from_device); if (stage >= CLEANUP_INITIALIZED) for (unsigned i = _head; i != _tail; i = next_i(i)) @@ -203,7 +231,7 @@ FromDevice::take_state(Element *e, ErrorHandler *errh) */ extern "C" { -#ifdef HAVE_CLICK_KERNEL +#if HAVE_CLICK_KERNEL static int packet_notifier_hook(struct notifier_block *nb, unsigned long backlog_len, void *v) { @@ -217,6 +245,24 @@ packet_notifier_hook(struct notifier_block *nb, unsigned long backlog_len, void from_device_map.unlock(false, lock_flags); return (stolen ? NOTIFY_STOP_MASK : 0); } +#elif CLICK_FROMDEVICE_USE_BRIDGE +static struct sk_buff * +click_br_handle_frame_hook(struct net_bridge_port *p, struct sk_buff *skb) +{ + int stolen = 0; + FromDevice *fd = 0; + unsigned long lock_flags; + from_device_map.lock(false, lock_flags); + while (stolen == 0 && (fd = (FromDevice *)from_device_map.lookup(skb->dev, fd))) + stolen = fd->got_skb(skb); + from_device_map.unlock(false, lock_flags); + if (stolen) + return 0; + else if (real_br_handle_frame_hook) + return real_br_handle_frame_hook(p, skb); + else + return skb; +} #endif static int @@ -234,7 +280,7 @@ device_notifier_hook(struct notifier_block *nb, unsigned long flags, void *v) AnyDevice *es[8]; int nes = from_device_map.lookup_all(dev, exists, es, 8); for (int i = 0; i < nes; i++) - ((FromDevice*)(es[i]))->set_device(flags == NETDEV_DOWN ? 0 : dev, &from_device_map, true); + ((FromDevice*)(es[i]))->set_device(flags == NETDEV_DOWN ? 0 : dev, &from_device_map, AnyDevice::anydev_change | AnyDevice::anydev_from_device); from_device_map.unlock(true, lock_flags); } return 0; @@ -398,5 +444,6 @@ FromDevice::add_handlers() add_write_handler("reset_counts", write_handler, H_RESET_COUNTS, Handler::BUTTON); } +#undef CLICK_FROMDEVICE_USE_BRIDGE ELEMENT_REQUIRES(AnyDevice linuxmodule) EXPORT_ELEMENT(FromDevice) diff --git a/elements/linuxmodule/fromhost.cc b/elements/linuxmodule/fromhost.cc index c501ef3618..5cff77112d 100644 --- a/elements/linuxmodule/fromhost.cc +++ b/elements/linuxmodule/fromhost.cc @@ -484,5 +484,5 @@ FromHost::add_handlers() add_data_handlers("drops", Handler::OP_READ, &_drops); } -ELEMENT_REQUIRES(AnyDevice linuxmodule) +ELEMENT_REQUIRES(AnyDevice linuxmodule false) EXPORT_ELEMENT(FromHost) diff --git a/elements/linuxmodule/polldevice.cc b/elements/linuxmodule/polldevice.cc index d784ef7bea..7b45c67a2a 100644 --- a/elements/linuxmodule/polldevice.cc +++ b/elements/linuxmodule/polldevice.cc @@ -84,14 +84,16 @@ PollDevice::configure(Vector &conf, ErrorHandler *errh) cpEnd) < 0) return -1; + int before = errh->nerrors(); #if HAVE_LINUX_POLLING - if (find_device(&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.c_str()); + net_device *dev = lookup_device(errh); + if (dev && (!dev->poll_on || dev->polling < 0)) { + dev_put(dev); + return errh->error("device %<%s%> not pollable, use FromDevice instead", _devname.c_str()); + } + set_device(dev, &poll_device_map, 0); #endif - - return 0; + return errh->nerrors() == before ? 0 : -1; } @@ -177,7 +179,7 @@ PollDevice::cleanup(CleanupStage) // call clear_device first so we can check poll_device_map for // other users - clear_device(&poll_device_map); + clear_device(&poll_device_map, 0); unsigned long lock_flags; poll_device_map.lock(false, lock_flags); @@ -324,7 +326,7 @@ PollDevice::change_device(net_device *dev) _dev->poll_off(_dev); } - set_device(dev, &poll_device_map, true); + set_device(dev, &poll_device_map, anydev_change); if (dev_change) { if (_dev && !_dev->polling) diff --git a/elements/linuxmodule/todevice.cc b/elements/linuxmodule/todevice.cc index 8841434ab6..0fbc2d38d1 100644 --- a/elements/linuxmodule/todevice.cc +++ b/elements/linuxmodule/todevice.cc @@ -9,6 +9,7 @@ * Copyright (c) 2000 Mazu Networks, Inc. * Copyright (c) 2001 International Computer Science Institute * Copyright (c) 2005-2007 Regents of the University of California + * Copyright (c) 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,6 +31,7 @@ #include #include #include +#include #include CLICK_CXX_PROTECT @@ -65,7 +67,6 @@ ToDevice::static_initialize() device_notifier.priority = 1; device_notifier.next = 0; register_netdevice_notifier(&device_notifier); - } void @@ -119,14 +120,34 @@ int ToDevice::configure(Vector &conf, ErrorHandler *errh) { _burst = 16; + int tx_queue = 0; if (AnyDevice::configure_keywords(conf, errh, false) < 0 || cp_va_kparse(conf, this, errh, "DEVNAME", cpkP+cpkM, cpString, &_devname, "BURST", cpkP, cpUnsigned, &_burst, "NO_PAD", 0, cpBool, &_no_pad, + "QUEUE", 0, cpInteger, &tx_queue, cpEnd) < 0) return -1; - return find_device(&to_device_map, errh); +#if !HAVE_NETDEV_GET_TX_QUEUE + if (tx_queue != 0) + return errh->error("the kernel only supports QUEUE 0"); +#else + _tx_queue = tx_queue; +#endif + + int before = errh->nerrors(); + net_device *dev = lookup_device(errh); +#if HAVE_NETDEV_GET_TX_QUEUE + if (dev && _tx_queue >= dev->num_tx_queues) { + dev_put(dev); + dev = 0; + if (!allow_nonexistent()) + return errh->error("device %<%s%> has only %d queues", _devname.c_str(), _tx_queue); + } +#endif + set_device(dev, &to_device_map, 0); + return errh->nerrors() == before ? 0 : -1; } int @@ -135,7 +156,7 @@ ToDevice::initialize(ErrorHandler *errh) if (AnyDevice::initialize_keywords(errh) < 0) return -1; -#ifndef HAVE_CLICK_KERNEL +#if !HAVE_CLICK_KERNEL errh->warning("not compiled for a Click kernel"); #endif @@ -212,7 +233,7 @@ ToDevice::cleanup(CleanupStage stage) #endif if (_q) _q->kill(); - clear_device(&to_device_map); + clear_device(&to_device_map, 0); } /* @@ -222,8 +243,14 @@ ToDevice::cleanup(CleanupStage stage) */ #if LINUX_VERSION_CODE < 0x020400 -# define netif_queue_stopped(dev) ((dev)->tbusy) -# define netif_wake_queue(dev) mark_bh(NET_BH) +# define click_netif_tx_queue_stopped(dev, txq) ((dev)->tbusy) +# define click_netif_tx_wake_queue(dev, txq) mark_bh(NET_BH) +#elif HAVE_NETDEV_GET_TX_QUEUE +# define click_netif_tx_queue_stopped(dev, txq) netif_tx_queue_stopped((txq)) +# define click_netif_tx_wake_queue(dev, txq) netif_tx_wake_queue((txq)) +#else +# define click_netif_tx_queue_stopped(dev, txq) netif_queue_stopped((dev)) +# define click_netif_tx_wake_queue(dev, txq) netif_wake_queue((dev)) #endif bool @@ -234,9 +261,10 @@ ToDevice::run_task(Task *) _runs++; + struct netdev_queue *txq = 0; #if LINUX_VERSION_CODE >= 0x020400 # if HAVE_NETDEV_GET_TX_QUEUE - struct netdev_queue *txq = netdev_get_tx_queue(_dev, 0); + txq = netdev_get_tx_queue(_dev, _tx_queue); int ok = spin_trylock_bh(&txq->_xmit_lock); if (likely(ok)) txq->xmit_lock_owner = smp_processor_id(); @@ -279,7 +307,8 @@ ToDevice::run_task(Task *) #endif /* try to send from click */ - while (sent < _burst && (busy = netif_queue_stopped(_dev)) == 0) { + while (sent < _burst + && (busy = click_netif_tx_queue_stopped(_dev, txq)) == 0) { #if CLICK_DEVICE_THESIS_STATS && !CLICK_DEVICE_STATS click_cycles_t before_pull_cycles = click_get_cycles(); #endif @@ -305,7 +334,7 @@ ToDevice::run_task(Task *) GET_STATS_RESET(low00, low10, time_now, _perfcnt1_pull, _perfcnt2_pull, _pull_cycles); - busy = queue_packet(p); + busy = queue_packet(p, txq); GET_STATS_RESET(low00, low10, time_now, _perfcnt1_queue, _perfcnt2_queue, _time_queue); @@ -326,7 +355,7 @@ ToDevice::run_task(Task *) // to call qdisc_restart() ourselves, outside of net_bh(). if (is_polling && !busy && _dev->qdisc->q.qlen) { _dev->tx_eob(_dev); - netif_wake_queue(_dev); + click_netif_tx_wake_queue(_dev, txq); } #endif @@ -415,7 +444,7 @@ ToDevice::run_task(Task *) } int -ToDevice::queue_packet(Packet *p) +ToDevice::queue_packet(Packet *p, struct netdev_queue *txq) { struct sk_buff *skb1 = p->skb(); @@ -446,14 +475,21 @@ ToDevice::queue_packet(Packet *p) int ret; #if HAVE_LINUX_POLLING - if (_dev->polling > 0) + if (_dev->polling > 0) { ret = _dev->tx_queue(_dev, skb1); - else + goto enqueued; + } #endif - { - ret = _dev->hard_start_xmit(skb1, _dev); - _hard_start++; - } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) + // XXX should we call dev_hard_start_xmit??? Probably + ret = _dev->netdev_ops->ndo_start_xmit(skb1, _dev); +#else + ret = _dev->hard_start_xmit(skb1, _dev); +#endif + ++_hard_start; + + enqueued: if (ret != 0) { _q = p; _q_expiry_j = click_jiffies() + queue_timeout; @@ -467,12 +503,16 @@ ToDevice::queue_packet(Packet *p) void ToDevice::change_device(net_device *dev) { +#if HAVE_NETDEV_GET_TX_QUEUE + if (dev && _tx_queue >= dev->num_tx_queues) + dev = 0; +#endif bool dev_change = _dev != dev; if (dev_change) _task.strong_unschedule(); - set_device(dev, &to_device_map, true); + set_device(dev, &to_device_map, anydev_change); if (dev_change && _dev) _task.strong_reschedule(); @@ -507,32 +547,30 @@ String ToDevice::read_calls(Element *e, void *) { ToDevice *td = (ToDevice *)e; - return - String(td->_holds) + " packets held\n" + - String(td->_drops) + " packets dropped\n" + - String(td->_hard_start) + " hard start xmit\n" + - String(td->_busy_returns) + " device busy returns\n" + - String(td->_npackets) + " packets sent\n" + - String(td->_runs) + " calls to run_task()\n" + - String(td->_pulls) + " pulls\n" + + StringAccum sa; + sa << td->_holds << " packets held\n" + << td->_drops << " packets dropped\n" + << td->_hard_start << " hard start xmit\n" + << td->_busy_returns << " device busy returns\n" + << td->_npackets << " packets sent\n" + << td->_runs << " calls to run_task()\n" + << td->_pulls << " pulls\n"; #if CLICK_DEVICE_STATS - String(td->_pull_cycles) + " cycles pull\n" + - String(td->_time_clean) + " cycles clean\n" + - String(td->_time_freeskb) + " cycles freeskb\n" + - String(td->_time_queue) + " cycles queue\n" + - String(td->_perfcnt1_pull) + " perfctr1 pull\n" + - String(td->_perfcnt1_clean) + " perfctr1 clean\n" + - String(td->_perfcnt1_freeskb) + " perfctr1 freeskb\n" + - String(td->_perfcnt1_queue) + " perfctr1 queue\n" + - String(td->_perfcnt2_pull) + " perfctr2 pull\n" + - String(td->_perfcnt2_clean) + " perfctr2 clean\n" + - String(td->_perfcnt2_freeskb) + " perfctr2 freeskb\n" + - String(td->_perfcnt2_queue) + " perfctr2 queue\n" + - String(td->_activations) + " transmit activations\n" -#else - String() + sa << td->_pull_cycles << " cycles pull\n" + << td->_time_clean << " cycles clean\n" + << td->_time_freeskb << " cycles freeskb\n" + << td->_time_queue << " cycles queue\n" + << td->_perfcnt1_pull << " perfctr1 pull\n" + << td->_perfcnt1_clean << " perfctr1 clean\n" + << td->_perfcnt1_freeskb << " perfctr1 freeskb\n" + << td->_perfcnt1_queue << " perfctr1 queue\n" + << td->_perfcnt2_pull << " perfctr2 pull\n" + << td->_perfcnt2_clean << " perfctr2 clean\n" + << td->_perfcnt2_freeskb << " perfctr2 freeskb\n" + << td->_perfcnt2_queue << " perfctr2 queue\n" + << td->_activations << " transmit activations\n"; #endif - ; + return sa.take_string(); } int diff --git a/elements/linuxmodule/todevice.hh b/elements/linuxmodule/todevice.hh index 4a26f25575..2f09ecd2d4 100644 --- a/elements/linuxmodule/todevice.hh +++ b/elements/linuxmodule/todevice.hh @@ -38,6 +38,10 @@ Unsigned integer. Same as the BURST argument. Boolean. If true, then suppress device up/down messages. Default is false. +=item QUEUE + +Integer. The transmit queue to send to. Default is 0. + =item ALLOW_NONEXISTENT Allow nonexistent devices. If true, and no device named DEVNAME exists when @@ -103,6 +107,7 @@ Resets counters to zero when written. #include "elements/linuxmodule/anydevice.hh" #include +struct netdev_queue; class ToDevice : public AnyTaskDevice { public: @@ -141,6 +146,9 @@ class ToDevice : public AnyTaskDevice { public: queue_timeout = CLICK_HZ / 4 }; +#if HAVE_NETDEV_GET_TX_QUEUE + int _tx_queue; +#endif Packet *_q; click_jiffies_t _q_expiry_j; unsigned _burst; @@ -175,7 +183,7 @@ class ToDevice : public AnyTaskDevice { public: uint32_t _busy_returns; uint32_t _too_short; - int queue_packet(Packet *p); + int queue_packet(Packet *p, struct netdev_queue *txq); static String read_calls(Element *e, void *user_data); static int write_handler(const String &str, Element *e, void *user_data, ErrorHandler *errh); diff --git a/elements/linuxmodule/tohost.cc b/elements/linuxmodule/tohost.cc index 5fb64874f2..e856d78be8 100644 --- a/elements/linuxmodule/tohost.cc +++ b/elements/linuxmodule/tohost.cc @@ -96,16 +96,18 @@ ToHost::initialize(ErrorHandler *errh) // Avoid warnings about "device down" with FromHost devices -- FromHost // brings up its device during initialize(). - int r; - if (_devname && (r = find_device(&to_host_map, errh)) < 0) - return r; - return 0; + int before = errh->nerrors(); + if (_devname) { + net_device *dev = lookup_device(errh); + set_device(dev, &to_host_map, 0); + } + return errh->nerrors() == before ? 0 : -1; } void ToHost::cleanup(CleanupStage) { - clear_device(&to_host_map); + clear_device(&to_host_map, 0); } extern "C" { @@ -124,7 +126,7 @@ device_notifier_hook(struct notifier_block *nb, unsigned long flags, void *v) AnyDevice *es[8]; int nes = to_host_map.lookup_all(dev, exists, es, 8); for (int i = 0; i < nes; i++) - ((ToHost *)(es[i]))->set_device(flags == NETDEV_DOWN ? 0 : dev, &to_host_map, true); + ((ToHost *)(es[i]))->set_device(flags == NETDEV_DOWN ? 0 : dev, &to_host_map, AnyDevice::anydev_change); to_host_map.unlock(true, lock_flags); } return 0;