cregit-Linux how code gets into the kernel

Release 4.11 net/core/dev.c

Directory: net/core
/*
 *      NET3    Protocol independent device support routines.
 *
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *
 *      Derived from the non IP parts of dev.c 1.0.19
 *              Authors:        Ross Biro
 *                              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *                              Mark Evans, <evansmp@uhura.aston.ac.uk>
 *
 *      Additional Authors:
 *              Florian la Roche <rzsfl@rz.uni-sb.de>
 *              Alan Cox <gw4pts@gw4pts.ampr.org>
 *              David Hinds <dahinds@users.sourceforge.net>
 *              Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
 *              Adam Sulmicki <adam@cfar.umd.edu>
 *              Pekka Riikonen <priikone@poesidon.pspt.fi>
 *
 *      Changes:
 *              D.J. Barrow     :       Fixed bug where dev->refcnt gets set
 *                                      to 2 if register_netdev gets called
 *                                      before net_dev_init & also removed a
 *                                      few lines of code in the process.
 *              Alan Cox        :       device private ioctl copies fields back.
 *              Alan Cox        :       Transmit queue code does relevant
 *                                      stunts to keep the queue safe.
 *              Alan Cox        :       Fixed double lock.
 *              Alan Cox        :       Fixed promisc NULL pointer trap
 *              ????????        :       Support the full private ioctl range
 *              Alan Cox        :       Moved ioctl permission check into
 *                                      drivers
 *              Tim Kordas      :       SIOCADDMULTI/SIOCDELMULTI
 *              Alan Cox        :       100 backlog just doesn't cut it when
 *                                      you start doing multicast video 8)
 *              Alan Cox        :       Rewrote net_bh and list manager.
 *              Alan Cox        :       Fix ETH_P_ALL echoback lengths.
 *              Alan Cox        :       Took out transmit every packet pass
 *                                      Saved a few bytes in the ioctl handler
 *              Alan Cox        :       Network driver sets packet type before
 *                                      calling netif_rx. Saves a function
 *                                      call a packet.
 *              Alan Cox        :       Hashed net_bh()
 *              Richard Kooijman:       Timestamp fixes.
 *              Alan Cox        :       Wrong field in SIOCGIFDSTADDR
 *              Alan Cox        :       Device lock protection.
 *              Alan Cox        :       Fixed nasty side effect of device close
 *                                      changes.
 *              Rudi Cilibrasi  :       Pass the right thing to
 *                                      set_mac_address()
 *              Dave Miller     :       32bit quantity for the device lock to
 *                                      make it work out on a Sparc.
 *              Bjorn Ekwall    :       Added KERNELD hack.
 *              Alan Cox        :       Cleaned up the backlog initialise.
 *              Craig Metz      :       SIOCGIFCONF fix if space for under
 *                                      1 device.
 *          Thomas Bogendoerfer :       Return ENODEV for dev_open, if there
 *                                      is no device open function.
 *              Andi Kleen      :       Fix error reporting for SIOCGIFCONF
 *          Michael Chastain    :       Fix signed/unsigned for SIOCGIFCONF
 *              Cyrus Durgin    :       Cleaned for KMOD
 *              Adam Sulmicki   :       Bug Fix : Network Device Unload
 *                                      A network device unload needs to purge
 *                                      the backlog queue.
 *      Paul Rusty Russell      :       SIOCSIFNAME
 *              Pekka Riikonen  :       Netdev boot-time settings code
 *              Andrew Morton   :       Make unregister_netdevice wait
 *                                      indefinitely on dev->refcnt
 *              J Hadi Salim    :       - Backlog queue sampling
 *                                      - netif_rx() feedback
 */

#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/notifier.h>
#include <linux/skbuff.h>
#include <linux/bpf.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/busy_poll.h>
#include <linux/rtnetlink.h>
#include <linux/stat.h>
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/pkt_sched.h>
#include <net/checksum.h>
#include <net/xfrm.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netpoll.h>
#include <linux/rcupdate.h>
#include <linux/delay.h>
#include <net/iw_handler.h>
#include <asm/current.h>
#include <linux/audit.h>
#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/ctype.h>
#include <linux/if_arp.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <net/mpls.h>
#include <linux/ipv6.h>
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/random.h>
#include <trace/events/napi.h>
#include <trace/events/net.h>
#include <trace/events/skb.h>
#include <linux/pci.h>
#include <linux/inetdevice.h>
#include <linux/cpu_rmap.h>
#include <linux/static_key.h>
#include <linux/hashtable.h>
#include <linux/vmalloc.h>
#include <linux/if_macvlan.h>
#include <linux/errqueue.h>
#include <linux/hrtimer.h>
#include <linux/netfilter_ingress.h>
#include <linux/crash_dump.h>

#include "net-sysfs.h"

/* Instead of increasing this, you should create a hash table. */

#define MAX_GRO_SKBS 8

/* This should be increased if a protocol with a bigger head is added. */

#define GRO_MAX_HEAD (MAX_HEADER + 128)

static DEFINE_SPINLOCK(ptype_lock);
static DEFINE_SPINLOCK(offload_lock);

struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;

struct list_head ptype_all __read_mostly;	
/* Taps */

static struct list_head offload_base __read_mostly;

static int netif_rx_internal(struct sk_buff *skb);
static int call_netdevice_notifiers_info(unsigned long val,
					 struct net_device *dev,
					 struct netdev_notifier_info *info);

/*
 * The @dev_base_head list is protected by @dev_base_lock and the rtnl
 * semaphore.
 *
 * Pure readers hold dev_base_lock for reading, or rcu_read_lock()
 *
 * Writers must hold the rtnl semaphore while they loop through the
 * dev_base_head list, and hold dev_base_lock for writing when they do the
 * actual updates.  This allows pure readers to access the list even
 * while a writer is preparing to update it.
 *
 * To put it another way, dev_base_lock is held for writing only to
 * protect against pure readers; the rtnl semaphore provides the
 * protection against other writers.
 *
 * See, for example usages, register_netdevice() and
 * unregister_netdevice(), which must be called with the rtnl
 * semaphore held.
 */

DEFINE_RWLOCK(dev_base_lock);

EXPORT_SYMBOL(dev_base_lock);

/* protects napi_hash addition/deletion and napi_gen_id */
static DEFINE_SPINLOCK(napi_hash_lock);


static unsigned int napi_gen_id = NR_CPUS;
static DEFINE_READ_MOSTLY_HASHTABLE(napi_hash, 8);


static seqcount_t devnet_rename_seq;


static inline void dev_base_seq_inc(struct net *net) { while (++net->dev_base_seq == 0) ; }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Graf22100.00%1100.00%
Total22100.00%1100.00%


static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) { unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ)); return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)]; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger4180.39%240.00%
Eric W. Biedermann713.73%120.00%
Linus Torvalds23.92%120.00%
Eric Dumazet11.96%120.00%
Total51100.00%5100.00%


static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) { return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)]; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2475.00%133.33%
Eric W. Biedermann721.88%133.33%
Eric Dumazet13.12%133.33%
Total32100.00%3100.00%


static inline void rps_lock(struct softnet_data *sd) { #ifdef CONFIG_RPS spin_lock(&sd->input_pkt_queue.lock); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Changli Gao2592.59%150.00%
Eric Dumazet27.41%150.00%
Total27100.00%2100.00%


static inline void rps_unlock(struct softnet_data *sd) { #ifdef CONFIG_RPS spin_unlock(&sd->input_pkt_queue.lock); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Changli Gao2592.59%150.00%
Eric Dumazet27.41%150.00%
Total27100.00%2100.00%

/* Device list insertion */
static void list_netdevice(struct net_device *dev) { struct net *net = dev_net(dev); ASSERT_RTNL(); write_lock_bh(&dev_base_lock); list_add_tail_rcu(&dev->dev_list, &net->dev_base_head); hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); hlist_add_head_rcu(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); write_unlock_bh(&dev_base_lock); dev_base_seq_inc(net); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann7686.36%114.29%
Thomas Graf55.68%114.29%
Eric Dumazet33.41%342.86%
Hideaki Yoshifuji / 吉藤英明33.41%114.29%
Ding Tianhong11.14%114.29%
Total88100.00%7100.00%

/* Device list removal * caller must respect a RCU grace period before freeing/reusing dev */
static void unlist_netdevice(struct net_device *dev) { ASSERT_RTNL(); /* Unlink dev from the device chain */ write_lock_bh(&dev_base_lock); list_del_rcu(&dev->dev_list); hlist_del_rcu(&dev->name_hlist); hlist_del_rcu(&dev->index_hlist); write_unlock_bh(&dev_base_lock); dev_base_seq_inc(dev_net(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann4881.36%120.00%
Thomas Graf813.56%120.00%
Eric Dumazet35.08%360.00%
Total59100.00%5100.00%

/* * Our notifier list */ static RAW_NOTIFIER_HEAD(netdev_chain); /* * Device drivers call our routines to queue packets here. We empty the * queue in the local softnet handler. */ DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data); EXPORT_PER_CPU_SYMBOL(softnet_data); #ifdef CONFIG_LOCKDEP /* * register_netdevice() inits txq->_xmit_lock and sets lockdep class * according to dev->type */ static const unsigned short netdev_lock_type[] = { ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; static const char *const netdev_lock_name[] = { "_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", "_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", "_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", "_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", "_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", "_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", "_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", "_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", "_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", "_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
static inline unsigned short netdev_lock_pos(unsigned short dev_type) { int i; for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++) if (netdev_lock_type[i] == dev_type) return i; /* the last key is used by default */ return ARRAY_SIZE(netdev_lock_type) - 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jarek Poplawski52100.00%1100.00%
Total52100.00%1100.00%


static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, unsigned short dev_type) { int i; i = netdev_lock_pos(dev_type); lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i], netdev_lock_name[i]); }

Contributors

PersonTokensPropCommitsCommitProp
Jarek Poplawski4097.56%150.00%
David S. Miller12.44%150.00%
Total41100.00%2100.00%


static inline void netdev_set_addr_lockdep_class(struct net_device *dev) { int i; i = netdev_lock_pos(dev->type); lockdep_set_class_and_name(&dev->addr_list_lock, &netdev_addr_lock_key[i], netdev_lock_name[i]); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller43100.00%1100.00%
Total43100.00%1100.00%

#else
static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, unsigned short dev_type) { }

Contributors

PersonTokensPropCommitsCommitProp
Jarek Poplawski1392.86%150.00%
David S. Miller17.14%150.00%
Total14100.00%2100.00%


static inline void netdev_set_addr_lockdep_class(struct net_device *dev) { }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller11100.00%1100.00%
Total11100.00%1100.00%

#endif /******************************************************************************* * * Protocol management and registration routines * *******************************************************************************/ /* * Add a protocol ID to the list. Now that the input handler is * smarter we can dispense with all the messy stuff that used to be * here. * * BEWARE!!! Protocol handlers, mangling input packets, * MUST BE last in hash buckets and checking protocol handlers * MUST start from promiscuous ptype_all chain in net_bh. * It is true now, do not change it. * Explanation follows: if protocol handler, mangling packet, will * be the first on list, it is not able to sense, that packet * is cloned and should be copied-on-write, so that it will * change it and subsequent readers will get broken packet. * --ANK (980803) */
static inline struct list_head *ptype_head(const struct packet_type *pt) { if (pt->type == htons(ETH_P_ALL)) return pt->dev ? &pt->dev->ptype_all : &ptype_all; else return pt->dev ? &pt->dev->ptype_specific : &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK]; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2740.30%555.56%
Salam Noureddine2232.84%111.11%
Eric Dumazet1623.88%111.11%
Pavel Emelyanov11.49%111.11%
Stephen Hemminger11.49%111.11%
Total67100.00%9100.00%

/** * dev_add_pack - add packet handler * @pt: packet type declaration * * Add a protocol handler to the networking stack. The passed &packet_type * is linked into kernel lists and may not be freed until it has been * removed from the kernel lists. * * This call does not sleep therefore it can not * guarantee all CPU's that are in middle of receiving packets * will see the new packet type (until the next received packet). */
void dev_add_pack(struct packet_type *pt) { struct list_head *head = ptype_head(pt); spin_lock(&ptype_lock); list_add_rcu(&pt->list, head); spin_unlock(&ptype_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet2661.90%120.00%
Linus Torvalds (pre-git)819.05%360.00%
Stephen Hemminger819.05%120.00%
Total42100.00%5100.00%

EXPORT_SYMBOL(dev_add_pack); /** * __dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * The packet type might still be in use by receivers * and must not be freed until after all the CPU's have gone * through a quiescent state. */
void __dev_remove_pack(struct packet_type *pt) { struct list_head *head = ptype_head(pt); struct packet_type *pt1; spin_lock(&ptype_lock); list_for_each_entry(pt1, head, list) { if (pt == pt1) { list_del_rcu(&pt->list); goto out; } } pr_warn("dev_remove_pack: %p not found\n", pt); out: spin_unlock(&ptype_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3141.33%660.00%
Stephen Hemminger3040.00%110.00%
Eric Dumazet79.33%110.00%
Arnaldo Carvalho de Melo56.67%110.00%
Joe Perches22.67%110.00%
Total75100.00%10100.00%

EXPORT_SYMBOL(__dev_remove_pack); /** * dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function * returns. * * This call sleeps to guarantee that no CPU is looking at the packet * type after return. */
void dev_remove_pack(struct packet_type *pt) { __dev_remove_pack(pt); synchronize_net(); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger1477.78%133.33%
Arnaldo Carvalho de Melo316.67%133.33%
Linus Torvalds (pre-git)15.56%133.33%
Total18100.00%3100.00%

EXPORT_SYMBOL(dev_remove_pack); /** * dev_add_offload - register offload handlers * @po: protocol offload declaration * * Add protocol offload handlers to the networking stack. The passed * &proto_offload is linked into kernel lists and may not be freed until * it has been removed from the kernel lists. * * This call does not sleep therefore it can not * guarantee all CPU's that are in middle of receiving packets * will see the new offload handlers (until the next received packet). */
void dev_add_offload(struct packet_offload *po) { struct packet_offload *elem; spin_lock(&offload_lock); list_for_each_entry(elem, &offload_base, list) { if (po->priority < elem->priority) break; } list_add_rcu(&po->list, elem->list.prev); spin_unlock(&offload_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich3454.84%150.00%
David S. Miller2845.16%150.00%
Total62100.00%2100.00%

EXPORT_SYMBOL(dev_add_offload); /** * __dev_remove_offload - remove offload handler * @po: packet offload declaration * * Remove a protocol offload handler that was previously added to the * kernel offload handlers by dev_add_offload(). The passed &offload_type * is removed from the kernel lists and can be freed or reused once this * function returns. * * The packet type might still be in use by receivers * and must not be freed until after all the CPU's have gone * through a quiescent state. */
static void __dev_remove_offload(struct packet_offload *po) { struct list_head *head = &offload_base; struct packet_offload *po1; spin_lock(&offload_lock); list_for_each_entry(po1, head, list) { if (po == po1) { list_del_rcu(&po->list); goto out; } } pr_warn("dev_remove_offload: %p not found\n", po); out: spin_unlock(&offload_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich7195.95%133.33%
Eric Dumazet22.70%133.33%
Stephen Hemminger11.35%133.33%
Total74100.00%3100.00%

/** * dev_remove_offload - remove packet offload handler * @po: packet offload declaration * * Remove a packet offload handler that was previously added to the kernel * offload handlers by dev_add_offload(). The passed &offload_type is * removed from the kernel lists and can be freed or reused once this * function returns. * * This call sleeps to guarantee that no CPU is looking at the packet * type after return. */
void dev_remove_offload(struct packet_offload *po) { __dev_remove_offload(po); synchronize_net(); }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich18100.00%1100.00%
Total18100.00%1100.00%

EXPORT_SYMBOL(dev_remove_offload); /****************************************************************************** * * Device Boot-time Settings Routines * ******************************************************************************/ /* Boot time configuration table */ static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; /** * netdev_boot_setup_add - add new setup entry * @name: name of the device * @map: configured settings for the device * * Adds new setup entry to the dev_boot_setup list. The function * returns 0 on error and 1 on success. This is a generic routine to * all netdevices. */
static int netdev_boot_setup_add(char *name, struct ifmap *map) { struct netdev_boot_setup *s; int i; s = dev_boot_setup; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { memset(s[i].name, 0, sizeof(s[i].name)); strlcpy(s[i].name, name, IFNAMSIZ); memcpy(&s[i].map, map, sizeof(s[i].map)); break; } } return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13294.96%125.00%
Arnaldo Carvalho de Melo32.16%125.00%
Wang Chen32.16%125.00%
Adrian Bunk10.72%125.00%
Total139100.00%4100.00%

/** * netdev_boot_setup_check - check boot time settings * @dev: the netdevice * * Check boot time settings for the device. * The found settings are set for the device to be used * later in the device probing. * Returns 0 if no settings found, 1 if they are. */
int netdev_boot_setup_check(struct net_device *dev) { struct netdev_boot_setup *s = dev_boot_setup; int i; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && !strcmp(dev->name, s[i].name)) { dev->irq = s[i].map.irq; dev->base_addr = s[i].map.base_addr; dev->mem_start = s[i].map.mem_start; dev->mem_end = s[i].map.mem_end; return 1; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13397.79%250.00%
Arnaldo Carvalho de Melo21.47%125.00%
Wang Chen10.74%125.00%
Total136100.00%4100.00%

EXPORT_SYMBOL(netdev_boot_setup_check); /** * netdev_boot_base - get address from boot time settings * @prefix: prefix for network device * @unit: id for network device * * Check boot time settings for the base address of device. * The found settings are set for the device to be used * later in the device probing. * Returns 0 if no settings found. */
unsigned long netdev_boot_base(const char *prefix, int unit) { const struct netdev_boot_setup *s = dev_boot_setup; char name[IFNAMSIZ]; int i; sprintf(name, "%s%d", prefix, unit); /* * If device already registered then return base of 1 * to indicate not to probe for this interface */ if (__dev_get_by_name(&init_net, name)) return 1; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) if (!strcmp(name, s[i].name)) return s[i].map.base_addr; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger9496.91%266.67%
Eric W. Biedermann33.09%133.33%
Total97100.00%3100.00%

/* * Saves at boot time configured settings for any netdevice. */
int __init netdev_boot_setup(char *str) { int ints[5]; struct ifmap map; str = get_options(str, ARRAY_SIZE(ints), ints); if (!str || !*str) return 0; /* Save settings */ memset(&map, 0, sizeof(map)); if (ints[0] > 0) map.irq = ints[1]; if (ints[0] > 1) map.base_addr = ints[2]; if (ints[0] > 2) map.mem_start = ints[3]; if (ints[0] > 3) map.mem_end = ints[4]; /* Add new entry to the list */ return netdev_boot_setup_add(str, &map); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14199.30%150.00%
Linus Torvalds10.70%150.00%
Total142100.00%2100.00%

__setup("netdev=", netdev_boot_setup); /******************************************************************************* * * Device Interface Subroutines * *******************************************************************************/ /** * dev_get_iflink - get 'iflink' value of a interface * @dev: targeted interface * * Indicates the ifindex the interface is linked to. * Physical interfaces have the same 'ifindex' and 'iflink' values. */
int dev_get_iflink(const struct net_device *dev) { if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) return dev->netdev_ops->ndo_get_iflink(dev); return dev->ifindex; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Dichtel38100.00%2100.00%
Total38100.00%2100.00%

EXPORT_SYMBOL(dev_get_iflink); /** * dev_fill_metadata_dst - Retrieve tunnel egress information. * @dev: targeted interface * @skb: The packet. * * For better visibility of tunnel traffic OVS needs to retrieve * egress tunnel information for a packet. Following API allows * user to get this info. */
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) { struct ip_tunnel_info *info; if (!dev->netdev_ops || !dev->netdev_ops->ndo_fill_metadata_dst) return -EINVAL; info = skb_tunnel_info_unclone(skb); if (!info) return -ENOMEM; if (unlikely(!(info->mode & IP_TUNNEL_INFO_TX))) return -EINVAL; return dev->netdev_ops->ndo_fill_metadata_dst(dev, skb); }

Contributors

PersonTokensPropCommitsCommitProp
Pravin B Shelar84100.00%1100.00%
Total84100.00%1100.00%

EXPORT_SYMBOL_GPL(dev_fill_metadata_dst); /** * __dev_get_by_name - find a device by its name * @net: the applicable net namespace * @name: name to find * * Find an interface by name. Must be called under RTNL semaphore * or @dev_base_lock. If the name is found a pointer to the device * is returned. If the name is not found then %NULL is returned. The * reference counters are not incremented so the caller must be * careful with locks. */
struct net_device *__dev_get_by_name(struct net *net, const char *name) { struct net_device *dev; struct hlist_head *head = dev_name_hash(net, name); hlist_for_each_entry(dev, head, name_hlist) if (!strncmp(dev->name, name, IFNAMSIZ)) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2946.77%758.33%
Eric Dumazet1625.81%18.33%
Stephen Hemminger812.90%18.33%
Eric W. Biedermann58.06%18.33%
Linus Torvalds34.84%18.33%
Arnaldo Carvalho de Melo11.61%18.33%
Total62100.00%12100.00%

EXPORT_SYMBOL(__dev_get_by_name); /** * dev_get_by_name_rcu - find a device by its name * @net: the applicable net namespace * @name: name to find * * Find an interface by name. * If the name is found a pointer to the device is returned. * If the name is not found then %NULL is returned. * The reference counters are not incremented so the caller must be * careful with locks. The caller must hold RCU lock. */
struct net_device *dev_get_by_name_rcu(struct net *net, const char *name) { struct net_device *dev; struct hlist_head *head = dev_name_hash(net, name); hlist_for_each_entry_rcu(dev, head, name_hlist) if (!strncmp(dev->name, name, IFNAMSIZ)) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet62100.00%1100.00%
Total62100.00%1100.00%

EXPORT_SYMBOL(dev_get_by_name_rcu); /** * dev_get_by_name - find a device by its name * @net: the applicable net namespace * @name: name to find * * Find an interface by name. This can be called from any * context and does its own locking. The returned handle has * the usage count incremented and the caller must use dev_put() to * release it when it is no longer needed. %NULL is returned if no * matching device is found. */
struct net_device *dev_get_by_name(struct net *net, const char *name) { struct net_device *dev; rcu_read_lock(); dev = dev_get_by_name_rcu(net, name); if (dev) dev_hold(dev); rcu_read_unlock(); return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3775.51%360.00%
Eric W. Biedermann714.29%120.00%
Eric Dumazet510.20%120.00%
Total49100.00%5100.00%

EXPORT_SYMBOL(dev_get_by_name); /** * __dev_get_by_index - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns %NULL if the device * is not found or a pointer to the device. The device has not * had its reference counter increased so the caller must be careful * about locking. The caller must hold either the RTNL semaphore * or @dev_base_lock. */
struct net_device *__dev_get_by_index(struct net *net, int ifindex) { struct net_device *dev; struct hlist_head *head = dev_index_hash(net, ifindex); hlist_for_each_entry(dev, head, index_hlist) if (dev->ifindex == ifindex) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2546.30%240.00%
Eric Dumazet1629.63%120.00%
Stephen Hemminger814.81%120.00%
Eric W. Biedermann59.26%120.00%
Total54100.00%5100.00%

EXPORT_SYMBOL(__dev_get_by_index); /** * dev_get_by_index_rcu - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns %NULL if the device * is not found or a pointer to the device. The device has not * had its reference counter increased so the caller must be careful * about locking. The caller must hold RCU lock. */
struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex) { struct net_device *dev; struct hlist_head *head = dev_index_hash(net, ifindex); hlist_for_each_entry_rcu(dev, head, index_hlist) if (dev->ifindex == ifindex) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet54100.00%1100.00%
Total54100.00%1100.00%

EXPORT_SYMBOL(dev_get_by_index_rcu); /** * dev_get_by_index - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device * * Search for an interface by index. Returns NULL if the device * is not found or a pointer to the device. The device returned has * had a reference added and the pointer is safe until the user calls * dev_put to indicate they have finished with it. */
struct net_device *dev_get_by_index(struct net *net, int ifindex) { struct net_device *dev; rcu_read_lock(); dev = dev_get_by_index_rcu(net, ifindex); if (dev) dev_hold(dev); rcu_read_unlock(); return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3574.47%360.00%
Eric W. Biedermann714.89%120.00%
Eric Dumazet510.64%120.00%
Total47100.00%5100.00%

EXPORT_SYMBOL(dev_get_by_index); /** * netdev_get_name - get a netdevice name, knowing its ifindex. * @net: network namespace * @name: a pointer to the buffer where the name will be stored. * @ifindex: the ifindex of the interface to get the name from. * * The use of raw_seqcount_begin() and cond_resched() before * retrying is required as we want to give the writers a chance * to complete when CONFIG_PREEMPT is not set. */
int netdev_get_name(struct net *net, char *name, int ifindex) { struct net_device *dev; unsigned int seq; retry: seq = raw_seqcount_begin(&devnet_rename_seq); rcu_read_lock(); dev = dev_get_by_index_rcu(net, ifindex); if (!dev) { rcu_read_unlock(); return -ENODEV; } strcpy(name, dev->name); rcu_read_unlock(); if (read_seqcount_retry(&devnet_rename_seq, seq)) { cond_resched(); goto retry; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Schichan95100.00%1100.00%
Total95100.00%1100.00%

/** * dev_getbyhwaddr_rcu - find a device by its hardware address * @net: the applicable net namespace * @type: media type of device * @ha: hardware address * * Search for an interface by MAC address. Returns NULL if the device * is not found or a pointer to the device. * The caller must hold RCU or RTNL. * The returned device has not had its ref count increased * and the caller must therefore be careful about locking * */
struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type, const char *ha) { struct net_device *dev; for_each_netdev_rcu(net, dev) if (dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4371.67%337.50%
Pavel Emelyanov610.00%112.50%
Eric W. Biedermann610.00%112.50%
Eric Dumazet35.00%112.50%
Denis V. Lunev11.67%112.50%
Arnaldo Carvalho de Melo11.67%112.50%
Total60100.00%8100.00%

EXPORT_SYMBOL(dev_getbyhwaddr_rcu);
struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev; ASSERT_RTNL(); for_each_netdev(net, dev) if (dev->type == type) return dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Arnaldo Carvalho de Melo2250.00%120.00%
Eric W. Biedermann715.91%120.00%
Pavel Emelyanov715.91%120.00%
Patrick McHardy613.64%120.00%
Christoph Hellwig24.55%120.00%
Total44100.00%5100.00%

EXPORT_SYMBOL(__dev_getfirstbyhwtype);
struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev, *ret = NULL; rcu_read_lock(); for_each_netdev_rcu(net, dev) if (dev->type == type) { dev_hold(dev); ret = dev; break; } rcu_read_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy2236.07%125.00%
Eric Dumazet2236.07%125.00%
Arnaldo Carvalho de Melo1118.03%125.00%
Eric W. Biedermann69.84%125.00%
Total61100.00%4100.00%

EXPORT_SYMBOL(dev_getfirstbyhwtype); /** * __dev_get_by_flags - find any device with given flags * @net: the applicable net namespace * @if_flags: IFF_* values * @mask: bitmask of bits in if_flags to check * * Search for any interface with the given flags. Returns NULL if a device * is not found or a pointer to the device. Must be called inside * rtnl_lock(), and result refcount is unchanged. */
struct net_device *__dev_get_by_flags(struct net *net, unsigned short if_flags, unsigned short mask) { struct net_device *dev, *ret; ASSERT_RTNL(); ret = NULL; for_each_netdev(net, dev) { if (((dev->flags ^ if_flags) & mask) == 0) { ret = dev; break; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David L Stevens3956.52%120.00%
Pavel Emelyanov1521.74%120.00%
Eric W. Biedermann710.14%120.00%
Américo Wang57.25%120.00%
Christoph Hellwig34.35%120.00%
Total69100.00%5100.00%

EXPORT_SYMBOL(__dev_get_by_flags); /** * dev_valid_name - check if name is okay for network device * @name: name string * * Network device names need to be valid file names to * to allow sysfs to work. We also disallow any kind of * whitespace. */
bool dev_valid_name(const char *name) { if (*name == '\0') return false; if (strlen(name) >= IFNAMSIZ) return false; if (!strcmp(name, ".") || !strcmp(name, "..")) return false; while (*name) { if (*name == '/' || *name == ':' || isspace(*name)) return false; name++; } return true; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger4450.57%240.00%
David S. Miller3843.68%240.00%
Matthew Thode55.75%120.00%
Total87100.00%5100.00%

EXPORT_SYMBOL(dev_valid_name); /** * __dev_alloc_name - allocate a name for a device * @net: network namespace to allocate the device name in * @name: name format string * @buf: scratch buffer and result name string * * Passed a format string - eg "lt%d" it will try and find a suitable * id. It scans list of devices to build up a free map, then chooses * the first empty slot. The caller must hold the dev_base or rtnl lock * while allocating the name and adding the device in order to avoid * duplicates. * Limited to bits_per_byte * page size devices (ie 32K on most platforms). * Returns the number of the unit assigned or a negative errno code. */
static int __dev_alloc_name(struct net *net, const char *name, char *buf) { int i = 0; const char *p; const int max_netdevices = 8*PAGE_SIZE; unsigned long *inuse; struct net_device *d; p = strnchr(name, IFNAMSIZ-1, '%'); if (p) { /* * Verify the string as this thing may have come from * the user. There must be either one "%d" and no other "%" * characters. */ if (p[1] != 'd' || strchr(p + 2, '%')) return -EINVAL; /* Use one page as a bit array of possible slots */ inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); if (!inuse) return -ENOMEM; for_each_netdev(net, d) { if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) continue; /* avoid cases where sscanf is not exact inverse of printf */ snprintf(buf, IFNAMSIZ, name, i); if (!strncmp(buf, d->name, IFNAMSIZ)) set_bit(i, inuse); } i = find_first_zero_bit(inuse, max_netdevices); free_page((unsigned long) inuse); } if (buf != name) snprintf(buf, IFNAMSIZ, name, i); if (!__dev_get_by_name(net, buf)) return i; /* It is possible to run out of possible slots * when the name is long and there isn't enough space left * for the digits, or if all bits are used. */ return -ENFILE; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger13256.65%216.67%
Linus Torvalds3916.74%216.67%
Linus Torvalds (pre-git)2812.02%325.00%
Eric W. Biedermann239.87%216.67%
Octavian Purdila62.58%18.33%
Pavel Emelyanov41.72%18.33%
Arnaldo Carvalho de Melo10.43%18.33%
Total233100.00%12100.00%

/** * dev_alloc_name - allocate a name for a device * @dev: device * @name: name format string * * Passed a format string - eg "lt%d" it will try and find a suitable * id. It scans list of devices to build up a free map, then chooses * the first empty slot. The caller must hold the dev_base or rtnl lock * while allocating the name and adding the device in order to avoid * duplicates. * Limited to bits_per_byte * page size devices (ie 32K on most platforms). * Returns the number of the unit assigned or a negative errno code. */
int dev_alloc_name(struct net_device *dev, const char *name) { char buf[IFNAMSIZ]; struct net *net; int ret; BUG_ON(!dev_net(dev)); net = dev_net(dev); ret = __dev_alloc_name(net, name, buf); if (ret >= 0) strlcpy(dev->name, buf, IFNAMSIZ); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann5572.37%120.00%
Linus Torvalds (pre-git)1215.79%240.00%
Hideaki Yoshifuji / 吉藤英明67.89%120.00%
Stephen Hemminger33.95%120.00%
Total76100.00%5100.00%

EXPORT_SYMBOL(dev_alloc_name);
static int dev_alloc_name_ns(struct net *net, struct net_device *dev, const char *name) { char buf[IFNAMSIZ]; int ret; ret = __dev_alloc_name(net, name, buf); if (ret >= 0) strlcpy(dev->name, buf, IFNAMSIZ); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Gao Feng4167.21%133.33%
Octavian Purdila1219.67%133.33%
Daniel Lezcano813.11%133.33%
Total61100.00%3100.00%


static int dev_get_valid_name(struct net *net, struct net_device *dev, const char *name) { BUG_ON(!net); if (!dev_valid_name(name)) return -EINVAL; if (strchr(name, '%')) return dev_alloc_name_ns(net, dev, name); else if (__dev_get_by_name(net, name)) return -EEXIST; else if (dev->name != name) strlcpy(dev->name, name, IFNAMSIZ); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila5962.11%133.33%
Gao Feng2526.32%133.33%
Daniel Lezcano1111.58%133.33%
Total95100.00%3100.00%

/** * dev_change_name - change name of a device * @dev: device * @newname: name (or format string) must be at least IFNAMSIZ * * Change name of a device, can pass format strings "eth%d". * for wildcarding. */
int dev_change_name(struct net_device *dev, const char *newname) { unsigned char old_assign_type; char oldname[IFNAMSIZ]; int err = 0; int ret; struct net *net; ASSERT_RTNL(); BUG_ON(!dev_net(dev)); net = dev_net(dev); if (dev->flags & IFF_UP) return -EBUSY; write_seqcount_begin(&devnet_rename_seq); if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { write_seqcount_end(&devnet_rename_seq); return 0; } memcpy(oldname, dev->name, IFNAMSIZ); err = dev_get_valid_name(net, dev, newname); if (err < 0) { write_seqcount_end(&devnet_rename_seq); return err; } if (oldname[0] && !strchr(oldname, '%')) netdev_info(dev, "renamed from %s\n", oldname); old_assign_type = dev->name_assign_type; dev->name_assign_type = NET_NAME_RENAMED; rollback: ret = device_rename(&dev->dev, dev->name); if (ret) { memcpy(dev->name, oldname, IFNAMSIZ); dev->name_assign_type = old_assign_type; write_seqcount_end(&devnet_rename_seq); return ret; } write_seqcount_end(&devnet_rename_seq); netdev_adjacent_rename_links(dev, oldname); write_lock_bh(&dev_base_lock); hlist_del_rcu(&dev->name_hlist); write_unlock_bh(&dev_base_lock); synchronize_rcu(); write_lock_bh(&dev_base_lock); hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); ret = notifier_to_errno(ret); if (ret) { /* err >= 0 after dev_alloc_name() or stores the first errno */ if (err >= 0) { err = ret; write_seqcount_begin(&devnet_rename_seq); memcpy(dev->name, oldname, IFNAMSIZ); memcpy(oldname, newname, IFNAMSIZ); dev->name_assign_type = old_assign_type; old_assign_type = NET_NAME_RENAMED; goto rollback; } else { pr_err("%s: name change rollback failed: %d\n", dev->name, ret); } } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger11530.26%726.92%
Herbert Xu7319.21%27.69%
Veaceslav Falico4010.53%27.69%
Eric Dumazet3810.00%415.38%
Brian Haley348.95%13.85%
Tom Gundersen328.42%13.85%
Eric W. Biedermann174.47%13.85%
Maneesh Soni164.21%13.85%
Hideaki Yoshifuji / 吉藤英明61.58%13.85%
Joe Perches20.53%13.85%
Gao Feng20.53%13.85%
Greg Kroah-Hartman20.53%13.85%
Daniel Lezcano10.26%13.85%
Octavian Purdila10.26%13.85%
Pavel Emelyanov10.26%13.85%
Total380100.00%26100.00%

/** * dev_set_alias - change ifalias of a device * @dev: device * @alias: name up to IFALIASZ * @len: limit of bytes to copy from info * * Set ifalias for a device, */
int dev_set_alias(struct net_device *dev, const char *alias, size_t len) { char *new_ifalias; ASSERT_RTNL(); if (len >= IFALIASZ) return -EINVAL; if (!len) { kfree(dev->ifalias); dev->ifalias = NULL; return 0; } new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); if (!new_ifalias) return -ENOMEM; dev->ifalias = new_ifalias; strlcpy(dev->ifalias, alias, len+1); return len; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger6966.35%133.33%
Oliver Hartkopp2322.12%133.33%
Alexey Khoroshilov1211.54%133.33%
Total104100.00%3100.00%

/** * netdev_features_change - device changes features * @dev: device to cause notification * * Called to indicate a device has changed features. */
void netdev_features_change(struct net_device *dev) { call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger1694.12%150.00%
Pavel Emelyanov15.88%150.00%
Total17100.00%2100.00%

EXPORT_SYMBOL(netdev_features_change); /** * netdev_state_change - device changes state * @dev: device to cause notification * * Called to indicate a device has changed state. This function calls * the notifier chains for netdev_chain and sends a NEWLINK message * to the routing socket. */
void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { struct netdev_notifier_change_info change_info; change_info.flags_changed = 0; call_netdevice_notifiers_info(NETDEV_CHANGE, dev, &change_info.info); rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3566.04%360.00%
Loic Prylli1630.19%120.00%
Alexei Starovoitov23.77%120.00%
Total53100.00%5100.00%

EXPORT_SYMBOL(netdev_state_change); /** * netdev_notify_peers - notify network peers about existence of @dev * @dev: network device * * Generate traffic such that interested network peers are aware of * @dev, such as by generating a gratuitous ARP. This may be used when * a device wants to inform the rest of the network about some sort of * reconfiguration such as a failover event or virtual machine * migration. */
void netdev_notify_peers(struct net_device *dev) { rtnl_lock(); call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev); call_netdevice_notifiers(NETDEV_RESEND_IGMP, dev); rtnl_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Or Gerlitz1343.33%133.33%
Américo Wang1033.33%133.33%
Vlad Yasevich723.33%133.33%
Total30100.00%3100.00%

EXPORT_SYMBOL(netdev_notify_peers);
static int __dev_open(struct net_device *dev) { const struct net_device_ops *ops = dev->netdev_ops; int ret; ASSERT_RTNL(); if (!netif_device_present(dev)) return -ENODEV; /* Block netpoll from trying to do any rx path servicing. * If we don't do this there is a chance ndo_poll_controller * or ndo_poll may be running while we open the device */ netpoll_poll_disable(dev); ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); ret = notifier_to_errno(ret); if (ret) return ret; set_bit(__LINK_STATE_START, &dev->state); if (ops->ndo_validate_addr) ret = ops->ndo_validate_addr(dev); if (!ret && ops->ndo_open) ret = ops->ndo_open(dev); netpoll_poll_enable(dev); if (ret) clear_bit(__LINK_STATE_START, &dev->state); else { dev->flags |= IFF_UP; dev_set_rx_mode(dev); dev_activate(dev); add_device_randomness(dev->dev_addr, dev->addr_len); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5332.52%1050.00%
Johannes Berg2314.11%15.00%
David S. Miller2112.88%15.00%
Stephen Hemminger1811.04%15.00%
Jeff Garzik159.20%15.00%
Theodore Y. Ts'o116.75%15.00%
Neil Horman95.52%15.00%
Patrick McHardy84.91%210.00%
Ben Hutchings31.84%15.00%
Eric W. Biedermann21.23%15.00%
Total163100.00%20100.00%

/** * dev_open - prepare an interface for use. * @dev: device to open * * Takes a device from down to up state. The device's private open * function is invoked and then the multicast lists are loaded. Finally * the device is moved into the up state and a %NETDEV_UP message is * sent to the netdev notifier chain. * * Calling this function on an active interface is a nop. On a failure * a negative errno code is returned. */
int dev_open(struct net_device *dev) { int ret; if (dev->flags & IFF_UP) return 0; ret = __dev_open(dev); if (ret < 0) return ret; rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); call_netdevice_notifiers(NETDEV_UP, dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy5079.37%116.67%
Linus Torvalds (pre-git)1015.87%350.00%
Alexei Starovoitov23.17%116.67%
Pavel Emelyanov11.59%116.67%
Total63100.00%6100.00%

EXPORT_SYMBOL(dev_open);
static int __dev_close_many(struct list_head *head) { struct net_device *dev; ASSERT_RTNL(); might_sleep(); list_for_each_entry(dev, head, close_list) { /* Temporarily disable netpoll until the interface is down */ netpoll_poll_disable(dev); call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, it * can be even on different cpu. So just clear netif_running(). * * dev->stop() will invoke napi_disable() on all of it's * napi_struct instances on this device. */ smp_mb__after_atomic(); /* Commit netif_running(). */ } dev_deactivate_many(head); list_for_each_entry(dev, head, close_list) { const struct net_device_ops *ops = dev->netdev_ops; /* * Call the device specific close. This cannot fail. * Only if device is UP * * We allow it to be called even after a DETACH hot-plug * event. */ if (ops->ndo_stop) ops->ndo_stop(dev); dev->flags &= ~IFF_UP; netpoll_poll_enable(dev); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3833.33%942.86%
Octavian Purdila3631.58%14.76%
Eric W. Biedermann1311.40%314.29%
Stephen Hemminger87.02%14.76%
David S. Miller65.26%29.52%
Patrick McHardy54.39%14.76%
Ben Hutchings32.63%14.76%
Matti Linnanvuori32.63%14.76%
Pavel Emelyanov10.88%14.76%
Peter Zijlstra10.88%14.76%
Total114100.00%21100.00%


static int __dev_close(struct net_device *dev) { int retval; LIST_HEAD(single); list_add(&dev->close_list, &single); retval = __dev_close_many(&single); list_del(&single); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila2451.06%125.00%
Linus Torvalds1429.79%125.00%
Patrick McHardy817.02%125.00%
Eric W. Biedermann12.13%125.00%
Total47100.00%4100.00%


int dev_close_many(struct list_head *head, bool unlink) { struct net_device *dev, *tmp; /* Remove the devices that don't need to be closed */ list_for_each_entry_safe(dev, tmp, head, close_list) if (!(dev->flags & IFF_UP)) list_del_init(&dev->close_list); __dev_close_many(head); list_for_each_entry_safe(dev, tmp, head, close_list) { rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); call_netdevice_notifiers(NETDEV_DOWN, dev); if (unlink) list_del_init(&dev->close_list); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila4846.60%112.50%
Patrick McHardy2625.24%112.50%
Eric W. Biedermann1312.62%112.50%
David S. Miller76.80%112.50%
Linus Torvalds (pre-git)65.83%225.00%
Alexei Starovoitov21.94%112.50%
Pavel Emelyanov10.97%112.50%
Total103100.00%8100.00%

EXPORT_SYMBOL(dev_close_many); /** * dev_close - shutdown an interface. * @dev: device to shutdown * * This function moves an active device into down state. A * %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device * is then deactivated and finally a %NETDEV_DOWN is sent to the notifier * chain. */
int dev_close(struct net_device *dev) { if (dev->flags & IFF_UP) { LIST_HEAD(single); list_add(&dev->close_list, &single); dev_close_many(&single, true); list_del(&single); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila3056.60%114.29%
Eric Dumazet1018.87%114.29%
Linus Torvalds611.32%114.29%
Linus Torvalds (pre-git)35.66%114.29%
David S. Miller23.77%114.29%
Eric W. Biedermann11.89%114.29%
Ding Tianhong11.89%114.29%
Total53100.00%7100.00%

EXPORT_SYMBOL(dev_close); /** * dev_disable_lro - disable Large Receive Offload on a device * @dev: device * * Disable Large Receive Offload (LRO) on a net device. Must be * called under RTNL. This is needed if received packets may be * forwarded to another interface. */
void dev_disable_lro(struct net_device *dev) { struct net_device *lower_dev; struct list_head *iter; dev->wanted_features &= ~NETIF_F_LRO; netdev_update_features(dev); if (unlikely(dev->features & NETIF_F_LRO)) netdev_WARN(dev, "failed to disable LRO!\n"); netdev_for_each_lower_dev(dev, lower_dev, iter) dev_disable_lro(lower_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings2438.10%120.00%
Michal Kubeček2336.51%120.00%
Michał Mirosław1625.40%360.00%
Total63100.00%5100.00%

EXPORT_SYMBOL(dev_disable_lro);
static int call_netdevice_notifier(struct notifier_block *nb, unsigned long val, struct net_device *dev) { struct netdev_notifier_info info; netdev_notifier_info_init(&info, dev); return nb->notifier_call(nb, val, &info); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko45100.00%1100.00%
Total45100.00%1100.00%

static int dev_boot_phase = 1; /** * register_netdevice_notifier - register a network notifier block * @nb: notifier * * Register a notifier to be called when network device events occur. * The notifier passed is linked into the kernel structures and must * not be reused until it has been unregistered. A negative errno code * is returned on a failure. * * When registered all registration and up events are replayed * to the new notifier to allow device to have a race free * view of the network device list. */
int register_netdevice_notifier(struct notifier_block *nb) { struct net_device *dev; struct net_device *last; struct net *net; int err; rtnl_lock(); err = raw_notifier_chain_register(&netdev_chain, nb); if (err) goto unlock; if (dev_boot_phase) goto unlock; for_each_net(net) { for_each_netdev(net, dev) { err = call_netdevice_notifier(nb, NETDEV_REGISTER, dev); err = notifier_to_errno(err); if (err) goto rollback; if (!(dev->flags & IFF_UP)) continue; call_netdevice_notifier(nb, NETDEV_UP, dev); } } unlock: rtnl_unlock(); return err; rollback: last = dev; for_each_net(net) { for_each_netdev(net, dev) { if (dev == last) goto outroll; if (dev->flags & IFF_UP) { call_netdevice_notifier(nb, NETDEV_GOING_DOWN, dev); call_netdevice_notifier(nb, NETDEV_DOWN, dev); } call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev); } } outroll: raw_notifier_chain_unregister(&netdev_chain, nb); goto unlock; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu8542.08%19.09%
Stephen Hemminger4924.26%19.09%
Eric W. Biedermann2813.86%19.09%
Linus Torvalds (pre-git)178.42%327.27%
Pavel Emelyanov125.94%218.18%
Jiri Pirko52.48%19.09%
Li RongQing52.48%19.09%
Alan Stern10.50%19.09%
Total202100.00%11100.00%

EXPORT_SYMBOL(register_netdevice_notifier); /** * unregister_netdevice_notifier - unregister a network notifier block * @nb: notifier * * Unregister a notifier previously registered by * register_netdevice_notifier(). The notifier is unlinked into the * kernel structures and may then be reused. A negative errno code * is returned on a failure. * * After unregistering unregister and down device events are synthesized * for all devices on the device list to the removed notifier to remove * the need for special case cleanup code. */
int unregister_netdevice_notifier(struct notifier_block *nb) { struct net_device *dev; struct net *net; int err; rtnl_lock(); err = raw_notifier_chain_unregister(&netdev_chain, nb); if (err) goto unlock; for_each_net(net) { for_each_netdev(net, dev) { if (dev->flags & IFF_UP) { call_netdevice_notifier(nb, NETDEV_GOING_DOWN, dev); call_netdevice_notifier(nb, NETDEV_DOWN, dev); } call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev); } } unlock: rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann6765.69%116.67%
Linus Torvalds (pre-git)1716.67%233.33%
Herbert Xu1413.73%116.67%
Jiri Pirko32.94%116.67%
Alan Stern10.98%116.67%
Total102100.00%6100.00%

EXPORT_SYMBOL(unregister_netdevice_notifier); /** * call_netdevice_notifiers_info - call all network notifier blocks * @val: value passed unmodified to notifier function * @dev: net_device pointer passed unmodified to notifier function * @info: notifier information data * * Call all network notifier blocks. Parameters and return value * are as for raw_notifier_call_chain(). */
static int call_netdevice_notifiers_info(unsigned long val, struct net_device *dev, struct netdev_notifier_info *info) { ASSERT_RTNL(); netdev_notifier_info_init(info, dev); return raw_notifier_call_chain(&netdev_chain, val, info); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko2048.78%233.33%
Roland Dreier1639.02%116.67%
Eric W. Biedermann37.32%116.67%
Alan Stern12.44%116.67%
Stephen Hemminger12.44%116.67%
Total41100.00%6100.00%

/** * call_netdevice_notifiers - call all network notifier blocks * @val: value passed unmodified to notifier function * @dev: net_device pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value * are as for raw_notifier_call_chain(). */
int call_netdevice_notifiers(unsigned long val, struct net_device *dev) { struct netdev_notifier_info info; return call_netdevice_notifiers_info(val, dev, &info); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko2586.21%133.33%
Roland Dreier310.34%133.33%
Eric W. Biedermann13.45%133.33%
Total29100.00%3100.00%

EXPORT_SYMBOL(call_netdevice_notifiers); #ifdef CONFIG_NET_INGRESS static struct static_key ingress_needed __read_mostly;
void net_inc_ingress_queue(void) { static_key_slow_inc(&ingress_needed); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann13100.00%1100.00%
Total13100.00%1100.00%

EXPORT_SYMBOL_GPL(net_inc_ingress_queue);
void net_dec_ingress_queue(void) { static_key_slow_dec(&ingress_needed); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann13100.00%1100.00%
Total13100.00%1100.00%

EXPORT_SYMBOL_GPL(net_dec_ingress_queue); #endif #ifdef CONFIG_NET_EGRESS static struct static_key egress_needed __read_mostly;
void net_inc_egress_queue(void) { static_key_slow_inc(&egress_needed); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann13100.00%1100.00%
Total13100.00%1100.00%

EXPORT_SYMBOL_GPL(net_inc_egress_queue);
void net_dec_egress_queue(void) { static_key_slow_dec(&egress_needed); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann13100.00%1100.00%
Total13100.00%1100.00%

EXPORT_SYMBOL_GPL(net_dec_egress_queue); #endif static struct static_key netstamp_needed __read_mostly; #ifdef HAVE_JUMP_LABEL static atomic_t netstamp_needed_deferred; static atomic_t netstamp_wanted;
static void netstamp_clear(struct work_struct *work) { int deferred = atomic_xchg(&netstamp_needed_deferred, 0); int wanted; wanted = atomic_add_return(deferred, &netstamp_wanted); if (wanted > 0) static_key_enable(&netstamp_needed); else static_key_disable(&netstamp_needed); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet5092.59%375.00%
Patrick McHardy47.41%125.00%
Total54100.00%4100.00%

static DECLARE_WORK(netstamp_work, netstamp_clear); #endif
void net_enable_timestamp(void) { #ifdef HAVE_JUMP_LABEL int wanted; while (1) { wanted = atomic_read(&netstamp_wanted); if (wanted <= 0) break; if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted + 1) == wanted) return; } atomic_inc(&netstamp_needed_deferred); schedule_work(&netstamp_work); #else static_key_slow_inc(&netstamp_needed); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6690.41%250.00%
Patrick McHardy68.22%125.00%
Ingo Molnar11.37%125.00%
Total73100.00%4100.00%

EXPORT_SYMBOL(net_enable_timestamp);
void net_disable_timestamp(void) { #ifdef HAVE_JUMP_LABEL int wanted; while (1) { wanted = atomic_read(&netstamp_wanted); if (wanted <= 1) break; if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted - 1) == wanted) return; } atomic_dec(&netstamp_needed_deferred); schedule_work(&netstamp_work); #else static_key_slow_dec(&netstamp_needed); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6082.19%360.00%
Patrick McHardy1216.44%120.00%
Ingo Molnar11.37%120.00%
Total73100.00%5100.00%

EXPORT_SYMBOL(net_disable_timestamp);
static inline void net_timestamp_set(struct sk_buff *skb) { skb->tstamp = 0; if (static_key_false(&netstamp_needed)) __net_timestamp(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Patrick McHardy1651.61%250.00%
Eric Dumazet1445.16%125.00%
Ingo Molnar13.23%125.00%
Total31100.00%4100.00%

#define net_timestamp_check(COND, SKB) \ if (static_key_false(&netstamp_needed)) { \ if ((COND) && !(SKB)->tstamp) \ __net_timestamp(SKB); \ } \ bool is_skb_forwardable(const struct net_device *dev, const struct sk_buff *skb) { unsigned int len; if (!(dev->flags & IFF_UP)) return false; len = dev->mtu + dev->hard_header_len + VLAN_HLEN; if (skb->len <= len) return true; /* if TSO is enabled, we don't care about the length as the packet * could be forwarded without being segmented before */ if (skb_is_gso(skb)) return true; return false; } EXPORT_SYMBOL_GPL(is_skb_forwardable);
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb) { int ret = ____dev_forward_skb(dev, skb); if (likely(!ret)) { skb->protocol = eth_type_trans(skb, dev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Arnd Bergmann2642.62%112.50%
Martin KaFai Lau1321.31%112.50%
Jay Vosburgh1219.67%112.50%
Daniel Lezcano34.92%112.50%
Herbert Xu34.92%112.50%
Américo Wang23.28%112.50%
Eric Dumazet23.28%225.00%
Total61100.00%8100.00%

EXPORT_SYMBOL_GPL(__dev_forward_skb); /** * dev_forward_skb - loopback an skb to another netif * * @dev: destination network device * @skb: buffer to forward * * return values: * NET_RX_SUCCESS (no congestion) * NET_RX_DROP (packet was dropped, but freed) * * dev_forward_skb can be used for injecting an skb from the * start_xmit function of one device into the receive queue * of another device. * * The receiving device may be in another namespace, so * we have to clear all information in the skb that could * impact namespace isolation. */
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) { return __dev_forward_skb(dev, skb) ?: netif_rx_internal(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2379.31%133.33%
Arnd Bergmann517.24%133.33%
Ben Hutchings13.45%133.33%
Total29100.00%3100.00%

EXPORT_SYMBOL_GPL(dev_forward_skb);
static inline int deliver_skb(struct sk_buff *skb, struct packet_type *pt_prev, struct net_device *orig_dev) { if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) return -ENOMEM; atomic_inc(&skb->users); return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Changli Gao4674.19%150.00%
Michael S. Tsirkin1625.81%150.00%
Total62100.00%2100.00%


static inline void deliver_ptype_list_skb(struct sk_buff *skb, struct packet_type **pt, struct net_device *orig_dev, __be16 type, struct list_head *ptype_list) { struct packet_type *ptype, *pt_prev = *pt; list_for_each_entry_rcu(ptype, ptype_list, list) { if (ptype->type != type) continue; if (pt_prev) deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } *pt = pt_prev; }

Contributors

PersonTokensPropCommitsCommitProp
Salam Noureddine8197.59%150.00%
Jiri Pirko22.41%150.00%
Total83100.00%2100.00%


static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) { if (!ptype->af_packet_priv || !skb->sk) return false; if (ptype->id_match) return ptype->id_match(ptype, skb->sk); else if ((struct sock *)ptype->af_packet_priv == skb->sk) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Leblond72100.00%2100.00%
Total72100.00%2100.00%

/* * Support routine. Sends outgoing frames to any network * taps currently in use. */
void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) { struct packet_type *ptype; struct sk_buff *skb2 = NULL; struct packet_type *pt_prev = NULL; struct list_head *ptype_list = &ptype_all; rcu_read_lock(); again: list_for_each_entry_rcu(ptype, ptype_list, list) { /* Never send packets back to the socket * they originated from - MvS (miquels@drinkel.ow.org) */ if (skb_loop_sk(ptype, skb)) continue; if (pt_prev) { deliver_skb(skb2, pt_prev, skb->dev); pt_prev = ptype; continue; } /* need to clone skb, done only once */ skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) goto out_unlock; net_timestamp_set(skb2); /* skb->nh should be correctly * set by sender, so that the second statement is * just protection against buggy protocols. */ skb_reset_mac_header(skb2); if (skb_network_header(skb2) < skb2->data || skb_network_header(skb2) > skb_tail_pointer(skb2)) { net_crit_ratelimited("protocol %04x is buggy, dev %s\n", ntohs(skb2->protocol), dev->name); skb_reset_network_header(skb2); } skb2->transport_header = skb2->network_header; skb2->pkt_type = PACKET_OUTGOING; pt_prev = ptype; } if (ptype_list == &ptype_all) { ptype_list = &dev->ptype_all; goto again; } out_unlock: if (pt_prev) pt_prev->func(skb2, skb->dev, pt_prev, skb->dev); rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8939.38%419.05%
Changli Gao4921.68%14.76%
Salam Noureddine3716.37%14.76%
Arnaldo Carvalho de Melo156.64%523.81%
Stephen Hemminger104.42%14.76%
Simon Horman62.65%14.76%
Eric Dumazet52.21%14.76%
Eric Leblond41.77%14.76%
David S. Miller41.77%14.76%
Sebastian Andrzej Siewior31.33%14.76%
Joe Perches20.88%29.52%
Petr Vandrovec10.44%14.76%
Linus Torvalds10.44%14.76%
Total226100.00%21100.00%

EXPORT_SYMBOL_GPL(dev_queue_xmit_nit); /** * netif_setup_tc - Handle tc mappings on real_num_tx_queues change * @dev: Network device * @txq: number of queues available * * If real_num_tx_queues is changed the tc mappings may no longer be * valid. To resolve this verify the tc mapping remains valid and if * not NULL the mapping. With no priorities mapping to this * offset/count pair it will no longer be used. In the worst case TC0 * is invalid nothing can be done so disable priority mappings. If is * expected that drivers will fix this mapping if they can before * calling netif_set_real_num_tx_queues. */
static void netif_setup_tc(struct net_device *dev, unsigned int txq) { int i; struct netdev_tc_txq *tc = &dev->tc_to_txq[0]; /* If TC0 is invalidated disable TC mapping */ if (tc->offset + tc->count > txq) { pr_warn("Number of in use tx queues changed invalidating tc mappings. Priority traffic classification disabled!\n"); dev->num_tc = 0; return; } /* Invalidated prio to tc mappings set to TC0 */ for (i = 1; i < TC_BITMASK + 1; i++) { int q = netdev_get_prio_tc_map(dev, i); tc = &dev->tc_to_txq[q]; if (tc->offset + tc->count > txq) { pr_warn("Number of in use tx queues changed. Priority %i to tc mapping %i is no longer valid. Setting map to 0\n", i, q); netdev_set_prio_tc_map(dev, i, 0); } } }

Contributors

PersonTokensPropCommitsCommitProp
John Fastabend12396.09%133.33%
Joe Perches43.12%133.33%
Eric Dumazet10.78%133.33%
Total128100.00%3100.00%


int netdev_txq_to_tc(struct net_device *dev, unsigned int txq) { if (dev->num_tc) { struct netdev_tc_txq *tc = &dev->tc_to_txq[0]; int i; for (i = 0; i < TC_MAX_QUEUE; i++, tc++) { if ((txq - tc->offset) < tc->count) return i; } return -1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck80100.00%1100.00%
Total80100.00%1100.00%

#ifdef CONFIG_XPS static DEFINE_MUTEX(xps_map_mutex); #define xmap_dereference(P) \ rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
static bool remove_xps_queue(struct xps_dev_maps *dev_maps, int tci, u16 index) { struct xps_map *map = NULL; int pos; if (dev_maps) map = xmap_dereference(dev_maps->cpu_map[tci]); if (!map) return false; for (pos = map->len; pos--;) { if (map->queues[pos] != index) continue; if (map->len > 1) { map->queues[pos] = map->queues[--map->len]; break; } RCU_INIT_POINTER(dev_maps->cpu_map[tci], NULL); kfree_rcu(map, rcu); return false; } return true; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck130100.00%3100.00%
Total130100.00%3100.00%


static bool remove_xps_queue_cpu(struct net_device *dev, struct xps_dev_maps *dev_maps, int cpu, u16 offset, u16 count) { int num_tc = dev->num_tc ? : 1; bool active = false; int tci; for (tci = cpu * num_tc; num_tc--; tci++) { int i, j; for (i = count, j = offset; i--; j++) { if (!remove_xps_queue(dev_maps, cpu, j)) break; } active |= i < 0; } return active; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck104100.00%3100.00%
Total104100.00%3100.00%


static void netif_reset_xps_queues(struct net_device *dev, u16 offset, u16 count) { struct xps_dev_maps *dev_maps; int cpu, i; bool active = false; mutex_lock(&xps_map_mutex); dev_maps = xmap_dereference(dev->xps_maps); if (!dev_maps) goto out_no_maps; for_each_possible_cpu(cpu) active |= remove_xps_queue_cpu(dev, dev_maps, cpu, offset, count); if (!active) { RCU_INIT_POINTER(dev->xps_maps, NULL); kfree_rcu(dev_maps, rcu); } for (i = offset + (count - 1); count--; i--) netdev_queue_numa_node_write(netdev_get_tx_queue(dev, i), NUMA_NO_NODE); out_no_maps: mutex_unlock(&xps_map_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck135100.00%4100.00%
Total135100.00%4100.00%


static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index) { netif_reset_xps_queues(dev, index, dev->num_tx_queues - index); }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck27100.00%1100.00%
Total27100.00%1100.00%


static struct xps_map *expand_xps_map(struct xps_map *map, int cpu, u16 index) { struct xps_map *new_map; int alloc_len = XPS_MIN_MAP_ALLOC; int i, pos; for (pos = 0; map && pos < map->len; pos++) { if (map->queues[pos] != index) continue; return map; } /* Need to add queue to this CPU's existing map */ if (map) { if (pos < map->alloc_len) return map; alloc_len = map->alloc_len * 2; } /* Need to allocate new map to store queue on this CPU's map */ new_map = kzalloc_node(XPS_MAP_SIZE(alloc_len), GFP_KERNEL, cpu_to_node(cpu)); if (!new_map) return NULL; for (i = 0; i < pos; i++) new_map->queues[i] = map->queues[i]; new_map->alloc_len = alloc_len; new_map->len = pos; return new_map; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck162100.00%2100.00%
Total162100.00%2100.00%


int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask, u16 index) { struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; int i, cpu, tci, numa_node_id = -2; int maps_sz, num_tc = 1, tc = 0; struct xps_map *map, *new_map; bool active = false; if (dev->num_tc) { num_tc = dev->num_tc; tc = netdev_txq_to_tc(dev, index); if (tc < 0) return -EINVAL; } maps_sz = XPS_DEV_MAPS_SIZE(num_tc); if (maps_sz < L1_CACHE_BYTES) maps_sz = L1_CACHE_BYTES; mutex_lock(&xps_map_mutex); dev_maps = xmap_dereference(dev->xps_maps); /* allocate memory for queue storage */ for_each_cpu_and(cpu, cpu_online_mask, mask) { if (!new_dev_maps) new_dev_maps = kzalloc(maps_sz, GFP_KERNEL); if (!new_dev_maps) { mutex_unlock(&xps_map_mutex); return -ENOMEM; } tci = cpu * num_tc + tc; map = dev_maps ? xmap_dereference(dev_maps->cpu_map[tci]) : NULL; map = expand_xps_map(map, cpu, index); if (!map) goto error; RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map); } if (!new_dev_maps) goto out_no_new_maps; for_each_possible_cpu(cpu) { /* copy maps belonging to foreign traffic classes */ for (i = tc, tci = cpu * num_tc; dev_maps && i--; tci++) { /* fill in the new device map from the old device map */ map = xmap_dereference(dev_maps->cpu_map[tci]); RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map); } /* We need to explicitly update tci as prevous loop * could break out early if dev_maps is NULL. */ tci = cpu * num_tc + tc; if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) { /* add queue to CPU maps */ int pos = 0; map = xmap_dereference(new_dev_maps->cpu_map[tci]); while ((pos < map->len) && (map->queues[pos] != index)) pos++; if (pos == map->len) map->queues[map->len++] = index; #ifdef CONFIG_NUMA if (numa_node_id == -2) numa_node_id = cpu_to_node(cpu); else if (numa_node_id != cpu_to_node(cpu)) numa_node_id = -1; #endif } else if (dev_maps) { /* fill in the new device map from the old device map */ map = xmap_dereference(dev_maps->cpu_map[tci]); RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map); } /* copy maps belonging to foreign traffic classes */ for (i = num_tc - tc, tci++; dev_maps && --i; tci++) { /* fill in the new device map from the old device map */ map = xmap_dereference(dev_maps->cpu_map[tci]); RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map); } } rcu_assign_pointer(dev->xps_maps, new_dev_maps); /* Cleanup old maps */ if (!dev_maps) goto out_no_old_maps; for_each_possible_cpu(cpu) { for (i = num_tc, tci = cpu * num_tc; i--; tci++) { new_map = xmap_dereference(new_dev_maps->cpu_map[tci]); map = xmap_dereference(dev_maps->cpu_map[tci]); if (map && map != new_map) kfree_rcu(map, rcu); } } kfree_rcu(dev_maps, rcu); out_no_old_maps: dev_maps = new_dev_maps; active = true; out_no_new_maps: /* update Tx queue numa node */ netdev_queue_numa_node_write(netdev_get_tx_queue(dev, index), (numa_node_id >= 0) ? numa_node_id : NUMA_NO_NODE); if (!dev_maps) goto out_no_maps; /* removes queue from unused CPUs */ for_each_possible_cpu(cpu) { for (i = tc, tci = cpu * num_tc; i--; tci++) active |= remove_xps_queue(dev_maps, tci, index); if (!cpumask_test_cpu(cpu, mask) || !cpu_online(cpu)) active |= remove_xps_queue(dev_maps, tci, index); for (i = num_tc - tc, tci++; --i; tci++) active |= remove_xps_queue(dev_maps, tci, index); } /* free map if not active */ if (!active) { RCU_INIT_POINTER(dev->xps_maps, NULL); kfree_rcu(dev_maps, rcu); } out_no_maps: mutex_unlock(&xps_map_mutex); return 0; error: /* remove any maps that we added */ for_each_possible_cpu(cpu) { for (i = num_tc, tci = cpu * num_tc; i--; tci++) { new_map = xmap_dereference(new_dev_maps->cpu_map[tci]); map = dev_maps ? xmap_dereference(dev_maps->cpu_map[tci]) : NULL; if (new_map && new_map != map) kfree(new_map); } } mutex_unlock(&xps_map_mutex); kfree(new_dev_maps); return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck83099.88%480.00%
Michael S. Tsirkin10.12%120.00%
Total831100.00%5100.00%

EXPORT_SYMBOL(netif_set_xps_queue); #endif
void netdev_reset_tc(struct net_device *dev) { #ifdef CONFIG_XPS netif_reset_xps_queues_gt(dev, 0); #endif dev->num_tc = 0; memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq)); memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map)); }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck60100.00%2100.00%
Total60100.00%2100.00%

EXPORT_SYMBOL(netdev_reset_tc);
int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset) { if (tc >= dev->num_tc) return -EINVAL; #ifdef CONFIG_XPS netif_reset_xps_queues(dev, offset, count); #endif dev->tc_to_txq[tc].count = count; dev->tc_to_txq[tc].offset = offset; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck70100.00%2100.00%
Total70100.00%2100.00%

EXPORT_SYMBOL(netdev_set_tc_queue);
int netdev_set_num_tc(struct net_device *dev, u8 num_tc) { if (num_tc > TC_MAX_QUEUE) return -EINVAL; #ifdef CONFIG_XPS netif_reset_xps_queues_gt(dev, 0); #endif dev->num_tc = num_tc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck44100.00%2100.00%
Total44100.00%2100.00%

EXPORT_SYMBOL(netdev_set_num_tc); /* * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. */
int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) { int rc; if (txq < 1 || txq > dev->num_tx_queues) return -EINVAL; if (dev->reg_state == NETREG_REGISTERED || dev->reg_state == NETREG_UNREGISTERING) { ASSERT_RTNL(); rc = netdev_queue_update_kobjects(dev, dev->real_num_tx_queues, txq); if (rc) return rc; if (dev->num_tc) netif_setup_tc(dev, txq); if (txq < dev->real_num_tx_queues) { qdisc_reset_all_tx_gt(dev, txq); #ifdef CONFIG_XPS netif_reset_xps_queues_gt(dev, txq); #endif } } dev->real_num_tx_queues = txq; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
John Fastabend5443.90%228.57%
Tom Herbert4939.84%342.86%
Alexander Duyck1411.38%114.29%
Ben Hutchings64.88%114.29%
Total123100.00%7100.00%

EXPORT_SYMBOL(netif_set_real_num_tx_queues); #ifdef CONFIG_SYSFS /** * netif_set_real_num_rx_queues - set actual number of RX queues used * @dev: Network device * @rxq: Actual number of RX queues * * This must be called either with the rtnl_lock held or before * registration of the net device. Returns 0 on success, or a * negative error code. If called before registration, it always * succeeds. */
int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq) { int rc; if (rxq < 1 || rxq > dev->num_rx_queues) return -EINVAL; if (dev->reg_state == NETREG_REGISTERED) { ASSERT_RTNL(); rc = net_rx_queue_update_kobjects(dev, dev->real_num_rx_queues, rxq); if (rc) return rc; } dev->real_num_rx_queues = rxq; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings5168.00%133.33%
Tom Herbert1520.00%133.33%
Denys Vlasenko912.00%133.33%
Total75100.00%3100.00%

EXPORT_SYMBOL(netif_set_real_num_rx_queues); #endif /** * netif_get_num_default_rss_queues - default number of RSS queues * * This routine should set an upper limit on the number of RSS queues * used by default by multiqueue devices. */
int netif_get_num_default_rss_queues(void) { return is_kdump_kernel() ? 1 : min_t(int, DEFAULT_MAX_NUM_RSS_QUEUES, num_online_cpus()); }

Contributors

PersonTokensPropCommitsCommitProp
Yuval Mintz1565.22%133.33%
Hariprasad Shenai521.74%133.33%
Ben Hutchings313.04%133.33%
Total23100.00%3100.00%

EXPORT_SYMBOL(netif_get_num_default_rss_queues);
static void __netif_reschedule(struct Qdisc *q) { struct softnet_data *sd; unsigned long flags; local_irq_save(flags); sd = this_cpu_ptr(&softnet_data); q->next_sched = NULL; *sd->output_queue_tailp = q; sd->output_queue_tailp = &q->next_sched; raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko4264.62%114.29%
Changli Gao1015.38%114.29%
David S. Miller913.85%342.86%
Christoph Lameter23.08%114.29%
Jarek Poplawski23.08%114.29%
Total65100.00%7100.00%


void __netif_schedule(struct Qdisc *q) { if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) __netif_reschedule(q); }

Contributors

PersonTokensPropCommitsCommitProp
Jarek Poplawski2796.43%150.00%
Denys Vlasenko13.57%150.00%
Total28100.00%2100.00%

EXPORT_SYMBOL(__netif_schedule); struct dev_kfree_skb_cb { enum skb_free_reason reason; };
static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb) { return (struct dev_kfree_skb_cb *)skb->cb; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet24100.00%1100.00%
Total24100.00%1100.00%


void netif_schedule_queue(struct netdev_queue *txq) { rcu_read_lock(); if (!(txq->state & QUEUE_STATE_ANY_XOFF)) { struct Qdisc *q = rcu_dereference(txq->qdisc); __netif_schedule(q); } rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
John Fastabend46100.00%1100.00%
Total46100.00%1100.00%

EXPORT_SYMBOL(netif_schedule_queue);
void netif_tx_wake_queue(struct netdev_queue *dev_queue) { if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) { struct Qdisc *q; rcu_read_lock(); q = rcu_dereference(dev_queue->qdisc); __netif_schedule(q); rcu_read_unlock(); } }

Contributors

PersonTokensPropCommitsCommitProp
John Fastabend49100.00%1100.00%
Total49100.00%1100.00%

EXPORT_SYMBOL(netif_tx_wake_queue);
void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) { unsigned long flags; if (unlikely(!skb)) return; if (likely(atomic_read(&skb->users) == 1)) { smp_rmb(); atomic_set(&skb->users, 0); } else if (likely(!atomic_dec_and_test(&skb->users))) { return; } get_kfree_skb_cb(skb)->reason = reason; local_irq_save(flags); skb->next = __this_cpu_read(softnet_data.completion_queue); __this_cpu_write(softnet_data.completion_queue, skb); raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6554.62%125.00%
Denys Vlasenko2521.01%125.00%
Stephen Hemminger2016.81%125.00%
Myungho Jung97.56%125.00%
Total119100.00%4100.00%

EXPORT_SYMBOL(__dev_kfree_skb_irq);
void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) { if (in_irq() || irqs_disabled()) __dev_kfree_skb_irq(skb, reason); else dev_kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko2777.14%150.00%
Eric Dumazet822.86%150.00%
Total35100.00%2100.00%

EXPORT_SYMBOL(__dev_kfree_skb_any); /** * netif_device_detach - mark device as removed * @dev: network device * * Mark device as removed from system and therefore no longer available. */
void netif_device_detach(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)) { netif_tx_stop_all_queues(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko3397.06%150.00%
Alexander Duyck12.94%150.00%
Total34100.00%2100.00%

EXPORT_SYMBOL(netif_device_detach); /** * netif_device_attach - mark device as attached * @dev: network device * * Mark device as attached from system and restart if needed. */
void netif_device_attach(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)) { netif_tx_wake_all_queues(dev); __netdev_watchdog_up(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko3997.50%150.00%
Alexander Duyck12.50%150.00%
Total40100.00%2100.00%

EXPORT_SYMBOL(netif_device_attach); /* * Returns a Tx hash based on the given packet descriptor a Tx queues' number * to be used as a distribution range. */
u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, unsigned int num_tx_queues) { u32 hash; u16 qoffset = 0; u16 qcount = num_tx_queues; if (skb_rx_queue_recorded(skb)) { hash = skb_get_rx_queue(skb); while (unlikely(hash >= num_tx_queues)) hash -= num_tx_queues; return hash; } if (dev->num_tc) { u8 tc = netdev_get_prio_tc_map(dev, skb->priority); qoffset = dev->tc_to_txq[tc].offset; qcount = dev->tc_to_txq[tc].count; } return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko123100.00%1100.00%
Total123100.00%1100.00%

EXPORT_SYMBOL(__skb_tx_hash);
static void skb_warn_bad_offload(const struct sk_buff *skb) { static const netdev_features_t null_features; struct net_device *dev = skb->dev; const char *name = ""; if (!net_ratelimit()) return; if (dev) { if (dev->dev.parent) name = dev_driver_string(dev->dev.parent); else name = netdev_name(dev); } WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d " "gso_type=%d ip_summed=%d\n", name, dev ? &dev->features : &null_features, skb->sk ? &skb->sk->sk_route_caps : &null_features, skb->len, skb->data_len, skb_shinfo(skb)->gso_size, skb_shinfo(skb)->gso_type, skb->ip_summed); }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings10175.94%125.00%
Björn Mork1612.03%125.00%
Michał Mirosław96.77%125.00%
Ben Greear75.26%125.00%
Total133100.00%4100.00%

/* * Invalidate hardware checksum when packet is to be mangled, and * complete checksum manually on outgoing path. */
int skb_checksum_help(struct sk_buff *skb) { __wsum csum; int ret = 0, offset; if (skb->ip_summed == CHECKSUM_COMPLETE) goto out_set_summed; if (unlikely(skb_shinfo(skb)->gso_size)) { skb_warn_bad_offload(skb); return -EINVAL; } /* Before computing a checksum, we should make sure no frag could * be modified by an external entity : checksum could be wrong. */ if (skb_has_shared_frag(skb)) { ret = __skb_linearize(skb); if (ret) goto out; } offset = skb_checksum_start_offset(skb); BUG_ON(offset >= skb_headlen(skb)); csum = skb_checksum(skb, offset, skb->len - offset, 0); offset += skb->csum_offset; BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb)); if (skb_cloned(skb) && !skb_clone_writable(skb, offset + sizeof(__sum16))) { ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (ret) goto out; } *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0; out_set_summed: skb->ip_summed = CHECKSUM_NONE; out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu8842.11%428.57%
Linus Torvalds5626.79%17.14%
Eric Dumazet2712.92%214.29%
James Morris115.26%17.14%
Ben Hutchings94.31%17.14%
Kris Katterjohn83.83%17.14%
Patrick McHardy52.39%17.14%
Al Viro20.96%17.14%
Arnaldo Carvalho de Melo20.96%17.14%
Michał Mirosław10.48%17.14%
Total209100.00%14100.00%

EXPORT_SYMBOL(skb_checksum_help);
__be16 skb_network_protocol(struct sk_buff *skb, int *depth) { __be16 type = skb->protocol; /* Tunnel gso handlers can set protocol to ethernet. */ if (type == htons(ETH_P_TEB)) { struct ethhdr *eth; if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) return 0; eth = (struct ethhdr *)skb_mac_header(skb); type = eth->h_proto; } return __vlan_get_protocol(skb, type, depth); }

Contributors

PersonTokensPropCommitsCommitProp
Pravin B Shelar5968.60%222.22%
Vlad Yasevich78.14%222.22%
Herbert Xu78.14%111.11%
Nikolay Aleksandrov55.81%111.11%
Jesse Gross33.49%111.11%
Toshiaki Makita33.49%111.11%
Li RongQing22.33%111.11%
Total86100.00%9100.00%

/** * skb_mac_gso_segment - mac layer segmentation handler. * @skb: buffer to segment * @features: features for the output path (see dev->features) */
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); struct packet_offload *ptype; int vlan_depth = skb->mac_len; __be16 type = skb_network_protocol(skb, &vlan_depth); if (unlikely(!type)) return ERR_PTR(-EINVAL); __skb_pull(skb, vlan_depth); rcu_read_lock(); list_for_each_entry_rcu(ptype, &offload_base, list) { if (ptype->type == type && ptype->callbacks.gso_segment) { segs = ptype->callbacks.gso_segment(skb, features); break; } } rcu_read_unlock(); __skb_push(skb, skb->data - skb_mac_header(skb)); return segs; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu6246.27%228.57%
Pravin B Shelar5339.55%114.29%
Vlad Yasevich1611.94%342.86%
Arnaldo Carvalho de Melo32.24%114.29%
Total134100.00%7100.00%

EXPORT_SYMBOL(skb_mac_gso_segment); /* openvswitch calls this on rx path, so we need a different check. */
static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) { if (tx_path) return skb->ip_summed != CHECKSUM_PARTIAL && skb->ip_summed != CHECKSUM_NONE; return skb->ip_summed == CHECKSUM_NONE; }

Contributors

PersonTokensPropCommitsCommitProp
Pravin B Shelar3384.62%150.00%
Eric Dumazet615.38%150.00%
Total39100.00%2100.00%

/** * __skb_gso_segment - Perform segmentation on skb. * @skb: buffer to segment * @features: features for the output path (see dev->features) * @tx_path: whether it is called in TX path * * This function segments the given skb and returns a list of segments. * * It may return NULL if the skb requires no segmentation. This is * only possible when GSO is used for verifying header integrity. * * Segmentation preserves SKB_SGO_CB_OFFSET bytes of previous skb cb. */
struct sk_buff *__skb_gso_segment(struct sk_buff *skb, netdev_features_t features, bool tx_path) { struct sk_buff *segs; if (unlikely(skb_needs_check(skb, tx_path))) { int err; /* We're going to init ->check field in TCP or UDP header */ err = skb_cow_head(skb, 0); if (err < 0) return ERR_PTR(err); } /* Only report GSO partial support if it will enable us to * support segmentation on this frame without needing additional * work. */ if (features & NETIF_F_GSO_PARTIAL) { netdev_features_t partial_features = NETIF_F_GSO_ROBUST; struct net_device *dev = skb->dev; partial_features |= dev->features & dev->gso_partial_features; if (!skb_gso_ok(skb, features | partial_features)) features &= ~NETIF_F_GSO_PARTIAL; } BUILD_BUG_ON(SKB_SGO_CB_OFFSET + sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb)); SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); SKB_GSO_CB(skb)->encap_level = 0; skb_reset_mac_header(skb); skb_reset_mac_len(skb); segs = skb_mac_gso_segment(skb, features); if (unlikely(skb_needs_check(skb, tx_path))) skb_warn_bad_offload(skb); return segs; }

Contributors

PersonTokensPropCommitsCommitProp
Pravin B Shelar7840.41%228.57%
Alexander Duyck5025.91%114.29%
Eric Dumazet3719.17%228.57%
Konstantin Khlebnikov2110.88%114.29%
François Romieu73.63%114.29%
Total193100.00%7100.00%

EXPORT_SYMBOL(__skb_gso_segment); /* Take action when hardware reception checksum errors are detected. */ #ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev) { if (net_ratelimit()) { pr_err("%s: hw csum failure\n", dev ? dev->name : "<unknown>"); dump_stack(); } }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2781.82%133.33%
Stephen Hemminger412.12%133.33%
Joe Perches26.06%133.33%
Total33100.00%3100.00%

EXPORT_SYMBOL(netdev_rx_csum_fault); #endif /* Actually, we should eliminate this check as soon as we know, that: * 1. IOMMU is present and allows to map all the memory. * 2. No high memory really exists on this machine. */
static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) { #ifdef CONFIG_HIGHMEM int i; if (!(dev->features & NETIF_F_HIGHDMA)) { for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; if (PageHighMem(skb_frag_page(frag))) return 1; } } if (PCI_DMA_BUS_IS_PHYS) { struct device *pdev = dev->dev.parent; if (!pdev) return 0; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; dma_addr_t addr = page_to_phys(skb_frag_page(frag)); if (!pdev->dma_mask || addr + PAGE_SIZE - 1 > *pdev->dma_mask) return 1; } } #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
FUJITA Tomonori7541.67%116.67%
Linus Torvalds6133.89%116.67%
Ian Campbell3016.67%116.67%
Eric Dumazet84.44%116.67%
Herbert Xu52.78%116.67%
Dave Hansen10.56%116.67%
Total180100.00%6100.00%

/* If MPLS offload request, verify we are testing hardware MPLS features * instead of standard features for the netdev. */ #if IS_ENABLED(CONFIG_NET_MPLS_GSO)
static netdev_features_t net_mpls_features(struct sk_buff *skb, netdev_features_t features, __be16 type) { if (eth_p_mpls(type)) features &= skb->dev->mpls_features; return features; }

Contributors

PersonTokensPropCommitsCommitProp
Simon Horman35100.00%2100.00%
Total35100.00%2100.00%

#else
static netdev_features_t net_mpls_features(struct sk_buff *skb, netdev_features_t features, __be16 type) { return features; }

Contributors

PersonTokensPropCommitsCommitProp
Simon Horman20100.00%1100.00%
Total20100.00%1100.00%

#endif
static netdev_features_t harmonize_features(struct sk_buff *skb, netdev_features_t features) { int tmp; __be16 type; type = skb_network_protocol(skb, &tmp); features = net_mpls_features(skb, features, type); if (skb->ip_summed != CHECKSUM_NONE && !can_checksum_protocol(features, type)) { features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); } if (illegal_highdma(skb->dev, skb)) features &= ~NETIF_F_SG; return features; }

Contributors

PersonTokensPropCommitsCommitProp
Jesse Gross4349.43%220.00%
Simon Horman2528.74%110.00%
Ed L. Cashin66.90%110.00%
Alexander Duyck44.60%110.00%
Vlad Yasevich33.45%110.00%
Michał Mirosław22.30%110.00%
Florian Westphal22.30%110.00%
Tom Herbert11.15%110.00%
Eric Dumazet11.15%110.00%
Total87100.00%10100.00%


netdev_features_t passthru_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { return features; }

Contributors

PersonTokensPropCommitsCommitProp
Toshiaki Makita21100.00%1100.00%
Total21100.00%1100.00%

EXPORT_SYMBOL(passthru_features_check);
static netdev_features_t dflt_features_check(const struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { return vlan_features_check(skb, features); }

Contributors

PersonTokensPropCommitsCommitProp
Toshiaki Makita28100.00%1100.00%
Total28100.00%1100.00%


static netdev_features_t gso_features_check(const struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { u16 gso_segs = skb_shinfo(skb)->gso_segs; if (gso_segs > dev->gso_max_segs) return features & ~NETIF_F_GSO_MASK; /* Support for GSO partial features requires software * intervention before we can actually process the packets * so we need to strip support for any partial features now * and we can pull them back in after we have partially * segmented the frame. */ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL)) features &= ~dev->gso_partial_features; /* Make sure to clear the IPv4 ID mangling feature if the * IPv4 header has the potential to be fragmented. */ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { struct iphdr *iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); if (!(iph->frag_off & htons(IP_DF))) features &= ~NETIF_F_TSO_MANGLEID; } return features; }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Duyck8872.73%228.57%
Ben Hutchings1310.74%114.29%
Eric Dumazet129.92%114.29%
Jesse Gross64.96%228.57%
Michał Mirosław21.65%114.29%
Total121100.00%7100.00%


netdev_features_t netif_skb_features(struct sk_buff *skb) { struct net_device *dev = skb->dev; netdev_features_t features = dev->features; if (skb_is_gso(skb)) features = gso_features_check(skb, dev, features); /* If encapsulation offload request, verify we are testing * hardware encapsulation features instead of standard * features for the netdev */ if (skb->encapsulation) features &= dev->hw_enc_features; if (skb_vlan_tagged(skb)) features = netdev_intersect_features(features, dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); if (dev->netdev_ops->ndo_features_check) features &= dev->netdev_ops->ndo_features_check(skb, dev, features); else features &= dflt_features_check(skb, dev, features); return harmonize_features(skb, features); }

Contributors

PersonTokensPropCommitsCommitProp
Jesse Gross5141.80%433.33%
Alexander Duyck4234.43%18.33%
Toshiaki Makita1713.93%325.00%
Michal Kubeček64.92%18.33%
Patrick McHardy32.46%216.67%
Ben Hutchings32.46%18.33%
Total122100.00%12100.00%

EXPORT_SYMBOL(netif_skb_features);
static int xmit_one(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, bool more) { unsigned int len; int rc; if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) dev_queue_xmit_nit(skb, dev); len = skb->len; trace_net_dev_start_xmit(skb, dev); rc = netdev_start_xmit(skb, dev, txq, more); trace_net_dev_xmit(skb, rc, dev, len); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller4344.79%433.33%
Herbert Xu2121.88%18.33%
Jesse Gross1515.62%216.67%
Salam Noureddine99.38%18.33%
Patrick McHardy33.12%18.33%
Patrick Ohly22.08%18.33%
Koki Sanagi22.08%18.33%
Stephen Hemminger11.04%18.33%
Total96100.00%12100.00%


struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev, struct netdev_queue *txq, int *ret) { struct sk_buff *skb = first; int rc = NETDEV_TX_OK; while (skb) { struct sk_buff *next = skb->next; skb->next = NULL; rc = xmit_one(skb, dev, txq, next != NULL); if (unlikely(!dev_xmit_complete(rc))) { skb->next = next; goto out; } skb = next; if (netif_xmit_stopped(txq) && skb) { rc = NETDEV_TX_BUSY; break; } } out: *ret = rc; return skb; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller9373.81%337.50%
Herbert Xu1713.49%225.00%
John Fastabend97.14%112.50%
Alexander Duyck64.76%112.50%
Jesse Gross10.79%112.50%
Total126100.00%8100.00%


static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t features) { if (skb_vlan_tag_present(skb) && !vlan_hw_offload_capable(features, skb->vlan_proto)) skb = __vlan_hwaccel_push_inside(skb); return skb; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller1330.23%215.38%
Herbert Xu1125.58%215.38%
Eric Dumazet716.28%323.08%
John Fastabend613.95%17.69%
Koki Sanagi36.98%215.38%
Jiri Pirko24.65%215.38%
Patrick Ohly12.33%17.69%
Total43100.00%13100.00%


static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev) { netdev_features_t features; features = netif_skb_features(skb); skb = validate_xmit_vlan(skb, features); if (unlikely(!skb)) goto out_null; if (netif_needs_gso(skb, features)) { struct sk_buff *segs; segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { goto out_kfree_skb; } else if (segs) { consume_skb(skb); skb = segs; } } else { if (skb_needs_linearize(skb, features) && __skb_linearize(skb)) goto out_kfree_skb; /* If packet is not checksummed and device does not * support checksumming for this protocol, complete * checksumming here. */ if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->encapsulation) skb_set_inner_transport_header(skb, skb_checksum_start_offset(skb)); else skb_set_transport_header(skb, skb_checksum_start_offset(skb)); if (!(features & NETIF_F_CSUM_MASK) && skb_checksum_help(skb)) goto out_kfree_skb; } } return skb; out_kfree_skb: kfree_skb(skb); out_null: atomic_long_inc(&dev->tx_dropped); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller3618.09%413.79%
John Fastabend3417.09%13.45%
Jesse Gross2512.56%517.24%
Herbert Xu2211.06%26.90%
Américo Wang2010.05%13.45%
Alexander Duyck168.04%26.90%
Eric Dumazet147.04%310.34%
Jason (Hui) Wang115.53%26.90%
Sridhar Samudrala63.02%13.45%
Koki Sanagi42.01%26.90%
Ben Hutchings31.51%13.45%
Patrick McHardy31.51%13.45%
Michał Mirosław21.01%26.90%
Michael Chan21.01%13.45%
Tom Herbert10.50%13.45%
Total199100.00%29100.00%


struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *next, *head = NULL, *tail; for (; skb != NULL; skb = next) { next = skb->next; skb->next = NULL; /* in case skb wont be segmented, point to itself */ skb->prev = skb; skb = validate_xmit_skb(skb, dev); if (!skb) continue; if (!head) head = skb; else tail->next = skb; /* If skb was segmented, skb->prev points to * the last segment. If not, it still contains skb. */ tail = skb->prev; } return head; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet10097.09%266.67%
John Fastabend32.91%133.33%
Total103100.00%3100.00%

EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
static void qdisc_pkt_len_init(struct sk_buff *skb) { const struct skb_shared_info *shinfo = skb_shinfo(skb); qdisc_skb_cb(skb)->pkt_len = skb->len; /* To get more precise estimation of bytes sent on wire, * we add to pkt_len the headers size of all segments */ if (shinfo->gso_size) { unsigned int hdr_len; u16 gso_segs = shinfo->gso_segs; /* mac layer + network layer */ hdr_len = skb_transport_header(skb) - skb_mac_header(skb); /* + transport layer */ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) hdr_len += tcp_hdrlen(skb); else hdr_len += sizeof(struct udphdr); if (shinfo->gso_type & SKB_GSO_DODGY) gso_segs = DIV_ROUND_UP(skb->len - hdr_len, shinfo->gso_size); qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet10677.94%266.67%
Jason (Hui) Wang3022.06%133.33%
Total136100.00%3100.00%


static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev, struct netdev_queue *txq) { spinlock_t *root_lock = qdisc_lock(q); struct sk_buff *to_free = NULL; bool contended; int rc; qdisc_calculate_pkt_len(skb, q); /* * Heuristic to force contended enqueues to serialize on a * separate lock before trying to get qdisc main lock. * This permits qdisc->running owner to get the lock more * often and dequeue packets faster. */ contended = qdisc_is_running(q); if (unlikely(contended)) spin_lock(&q->busylock); spin_lock(root_lock); if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { __qdisc_drop(skb, &to_free); rc = NET_XMIT_DROP; } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) && qdisc_run_begin(q)) { /* * This is a work-conserving queue; there are no old skbs * waiting to be sent out; and the qdisc is not running - * xmit the skb directly. */ qdisc_bstats_update(q, skb); if (sch_direct_xmit(skb, q, dev, txq, root_lock, true)) { if (unlikely(contended)) { spin_unlock(&q->busylock); contended = false; } __qdisc_run(q); } else qdisc_run_end(q); rc = NET_XMIT_SUCCESS; } else { rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK; if (qdisc_run_begin(q)) { if (unlikely(contended)) { spin_unlock(&q->busylock); contended = false; } __qdisc_run(q); } } spin_unlock(root_lock); if (unlikely(to_free)) kfree_skb_list(to_free); if (unlikely(contended)) spin_unlock(&q->busylock); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet14249.13%746.67%
Krishna Kumar11138.41%16.67%
Linus Torvalds (pre-git)144.84%320.00%
Linus Torvalds103.46%16.67%
Herbert Xu62.08%16.67%
Arnaldo Carvalho de Melo31.04%16.67%
David S. Miller31.04%16.67%
Total289100.00%15100.00%

#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
static void skb_update_prio(struct sk_buff *skb) { struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); if (!skb->priority && skb->sk && map) { unsigned int prioidx = sock_cgroup_prioidx(&skb->sk->sk_cgrp_data); if (prioidx < map->priomap_len) skb->priority = map->priomap[prioidx]; } }

Contributors

PersonTokensPropCommitsCommitProp
Neil Horman4764.38%125.00%
Eric Dumazet2027.40%125.00%
Tejun Heo56.85%125.00%
Igor Maravić11.37%125.00%
Total73100.00%4100.00%

#else #define skb_update_prio(skb) #endif DEFINE_PER_CPU(int, xmit_recursion); EXPORT_SYMBOL(xmit_recursion); /** * dev_loopback_xmit - loop back @skb * @net: network namespace this loopback is happening in * @sk: sk needed to be a netfilter okfn * @skb: buffer to transmit */
int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) { skb_reset_mac_header(skb); __skb_pull(skb, skb_network_offset(skb)); skb->pkt_type = PACKET_LOOPBACK; skb->ip_summed = CHECKSUM_UNNECESSARY; WARN_ON(!skb_dst(skb)); skb_dst_force(skb); netif_rx_ni(skb); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Michel Machado5985.51%133.33%
Eric W. Biedermann57.25%133.33%
David S. Miller57.25%133.33%
Total69100.00%3100.00%

EXPORT_SYMBOL(dev_loopback_xmit); #ifdef CONFIG_NET_EGRESS
static struct sk_buff * sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev) { struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list); struct tcf_result cl_res; if (!cl) return skb; /* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */ qdisc_bstats_cpu_update(cl->q, skb); switch (tc_classify(skb, cl, &cl_res, false)) { case TC_ACT_OK: case TC_ACT_RECLASSIFY: skb->tc_index = TC_H_MIN(cl_res.classid); break; case TC_ACT_SHOT: qdisc_qstats_cpu_drop(cl->q); *ret = NET_XMIT_DROP; kfree_skb(skb); return NULL; case TC_ACT_STOLEN: case TC_ACT_QUEUED: *ret = NET_XMIT_SUCCESS; consume_skb(skb); return NULL; case TC_ACT_REDIRECT: /* No need to push/pop skb's mac_header here on egress! */ skb_do_redirect(skb); *ret = NET_XMIT_SUCCESS; return NULL; default: break; } return skb; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann15399.35%266.67%
Willem de Bruijn10.65%133.33%
Total154100.00%3100.00%

#endif /* CONFIG_NET_EGRESS */
static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) { #ifdef CONFIG_XPS struct xps_dev_maps *dev_maps; struct xps_map *map; int queue_index = -1; rcu_read_lock(); dev_maps = rcu_dereference(dev->xps_maps); if (dev_maps) { unsigned int tci = skb->sender_cpu - 1; if (dev->num_tc) { tci *= dev->num_tc; tci += netdev_get_prio_tc_map(dev, skb->priority); } map = rcu_dereference(dev_maps->cpu_map[tci]); if (map) { if (map->len == 1) queue_index = map->queues[0]; else queue_index = map->queues[reciprocal_scale(skb_get_hash(skb), map->len)]; if (unlikely(queue_index >= dev->real_num_tx_queues)) queue_index = -1; } } rcu_read_unlock(); return queue_index; #else return -1; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko13879.31%150.00%
Alexander Duyck3620.69%150.00%
Total174100.00%2100.00%


static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb) { struct sock *sk = skb->sk; int queue_index = sk_tx_queue_get(sk); if (queue_index < 0 || skb->ooo_okay || queue_index >= dev->real_num_tx_queues) { int new_index = get_xps_queue(dev, skb); if (new_index < 0) new_index = skb_tx_hash(dev, skb); if (queue_index != new_index && sk && sk_fullsock(sk) && rcu_access_pointer(sk->sk_dst_cache)) sk_tx_queue_set(sk, new_index); queue_index = new_index; } return queue_index; }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko10595.45%150.00%
Eric Dumazet54.55%150.00%
Total110100.00%2100.00%


struct netdev_queue *netdev_pick_tx(struct net_device *dev, struct sk_buff *skb, void *accel_priv) { int queue_index = 0; #ifdef CONFIG_XPS u32 sender_cpu = skb->sender_cpu - 1; if (sender_cpu >= (u32)NR_CPUS) skb->sender_cpu = raw_smp_processor_id() + 1; #endif if (dev->real_num_tx_queues != 1) { const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_select_queue) queue_index = ops->ndo_select_queue(dev, skb, accel_priv, __netdev_pick_tx); else queue_index = __netdev_pick_tx(dev, skb); if (!accel_priv) queue_index = netdev_cap_txqueue(dev, queue_index); } skb_set_queue_mapping(skb, queue_index); return netdev_get_tx_queue(dev, queue_index); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko12489.86%150.00%
Eric Dumazet1410.14%150.00%
Total138100.00%2100.00%

/** * __dev_queue_xmit - transmit a buffer * @skb: buffer to transmit * @accel_priv: private data used for L2 forwarding offload * * Queue a buffer for transmission to a network device. The caller must * have set the device and priority and built the buffer before calling * this function. The function can be called from an interrupt. * * A negative errno code is returned on a failure. A success does not * guarantee the frame will be transmitted as it may be dropped due * to congestion or traffic shaping. * * ----------------------------------------------------------------------------------- * I notice this method can also return errors from the queue disciplines, * including NET_XMIT_DROP, which is a positive value. So, errors can also * be positive. * * Regardless of the return value, the skb is consumed, so it is currently * difficult to retry a send to this method. (You can bump the ref count * before sending to hold a reference for retry if you are careful.) * * When calling this method, interrupts MUST be enabled. This is because * the BH enable code must have IRQs enabled so that it will not deadlock. * --BLG */
static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) { struct net_device *dev = skb->dev; struct netdev_queue *txq; struct Qdisc *q; int rc = -ENOMEM; skb_reset_mac_header(skb); if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP)) __skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ rcu_read_lock_bh(); skb_update_prio(skb); qdisc_pkt_len_init(skb); #ifdef CONFIG_NET_CLS_ACT skb->tc_at_ingress = 0; # ifdef CONFIG_NET_EGRESS if (static_key_false(&egress_needed)) { skb = sch_handle_egress(skb, &rc, dev); if (!skb) goto out; } # endif #endif /* If device/qdisc don't need skb->dst, release it right now while * its hot in this cpu cache. */ if (dev->priv_flags & IFF_XMIT_DST_RELEASE) skb_dst_drop(skb); else skb_dst_force(skb); txq = netdev_pick_tx(dev, skb, accel_priv); q = rcu_dereference_bh(txq->qdisc); trace_net_dev_queue(skb); if (q->enqueue) { rc = __dev_xmit_skb(skb, q, dev, txq); goto out; } /* The device has no queue. Common case for software devices: * loopback, all the sorts of tunnels... * Really, it is unlikely that netif_tx_lock protection is necessary * here. (f.e. loopback and IP tunnels are clean ignoring statistics * counters.) * However, it is possible, that they rely on protection * made by us here. * Check this and shot the lock. It is not prone from deadlocks. *Either shot noqueue qdisc, it is even simpler 8) */ if (dev->flags & IFF_UP) { int cpu = smp_processor_id(); /* ok because BHs are off */ if (txq->xmit_lock_owner != cpu) { if (unlikely(__this_cpu_read(xmit_recursion) > XMIT_RECURSION_LIMIT)) goto recursion_alert; skb = validate_xmit_skb(skb, dev); if (!skb) goto out; HARD_TX_LOCK(dev, txq, cpu); if (!netif_xmit_stopped(txq)) { __this_cpu_inc(xmit_recursion); skb = dev_hard_start_xmit(skb, dev, txq, &rc); __this_cpu_dec(xmit_recursion); if (dev_xmit_complete(rc)) { HARD_TX_UNLOCK(dev, txq); goto out; } } HARD_TX_UNLOCK(dev, txq); net_crit_ratelimited("Virtual device %s asks to queue packet!\n", dev->name); } else { /* Recursion is detected! It is possible, * unfortunately */ recursion_alert: net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", dev->name); } } rc = -ENETDOWN; rcu_read_unlock_bh(); atomic_long_inc(&dev->tx_dropped); kfree_skb_list(skb); return rc; out: rcu_read_unlock_bh(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11529.79%1630.19%
Eric Dumazet6115.80%59.43%
Daniel Borkmann5313.73%23.77%
David S. Miller328.29%713.21%
Willem de Bruijn297.51%23.77%
Arnaldo Carvalho de Melo235.96%11.89%
Jesper Dangaard Brouer143.63%11.89%
Patrick McHardy71.81%11.89%
Jason (Hui) Wang71.81%11.89%
Andi Kleen71.81%11.89%
Neil Horman51.30%11.89%
Koki Sanagi51.30%11.89%
Tommy S. Christensen51.30%11.89%
Krishna Kumar51.30%11.89%
Joe Perches41.04%23.77%
Arthur Kepner30.78%11.89%
Herbert Xu30.78%23.77%
Dipankar Sarma20.52%11.89%
Tom Herbert10.26%11.89%
Tobin C Harding10.26%11.89%
Paul E. McKenney10.26%11.89%
Américo Wang10.26%11.89%
Rashika Kheria10.26%11.89%
Peter P. Waskiewicz Jr10.26%11.89%
Total386100.00%53100.00%


int dev_queue_xmit(struct sk_buff *skb) { return __dev_queue_xmit(skb, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Jason (Hui) Wang1794.44%150.00%
Eric W. Biedermann15.56%150.00%
Total18100.00%2100.00%

EXPORT_SYMBOL(dev_queue_xmit);
int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv) { return __dev_queue_xmit(skb, accel_priv); }

Contributors

PersonTokensPropCommitsCommitProp
Jason (Hui) Wang22100.00%1100.00%
Total22100.00%1100.00%

EXPORT_SYMBOL(dev_queue_xmit_accel); /************************************************************************* * Receiver routines *************************************************************************/ int netdev_max_backlog __read_mostly = 1000; EXPORT_SYMBOL(netdev_max_backlog); int netdev_tstamp_prequeue __read_mostly = 1; int netdev_budget __read_mostly = 300; int weight_p __read_mostly = 64; /* old backlog weight */ int dev_weight_rx_bias __read_mostly = 1; /* bias for backlog weight */ int dev_weight_tx_bias __read_mostly = 1; /* bias for output_queue quota */ int dev_rx_weight __read_mostly = 64; int dev_tx_weight __read_mostly = 64; /* Called with irq disabled */
static inline void ____napi_schedule(struct softnet_data *sd, struct napi_struct *napi) { list_add_tail(&napi->poll_list, &sd->poll_list); __raise_softirq_irqoff(NET_RX_SOFTIRQ); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet35100.00%1100.00%
Total35100.00%1100.00%

#ifdef CONFIG_RPS /* One global table that all flow-based protocols share. */ struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly; EXPORT_SYMBOL(rps_sock_flow_table); u32 rps_cpu_mask __read_mostly; EXPORT_SYMBOL(rps_cpu_mask); struct static_key rps_needed __read_mostly; EXPORT_SYMBOL(rps_needed); struct static_key rfs_needed __read_mostly; EXPORT_SYMBOL(rfs_needed);
static struct rps_dev_flow * set_rps_cpu(struct net_device *dev, struct sk_buff *skb, struct rps_dev_flow *rflow, u16 next_cpu) { if (next_cpu < nr_cpu_ids) { #ifdef CONFIG_RFS_ACCEL struct netdev_rx_queue *rxqueue; struct rps_dev_flow_table *flow_table; struct rps_dev_flow *old_rflow; u32 flow_id; u16 rxq_index; int rc; /* Should we steer this flow to a different hardware queue? */ if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap || !(dev->features & NETIF_F_NTUPLE)) goto out; rxq_index = cpu_rmap_lookup_index(dev->rx_cpu_rmap, next_cpu); if (rxq_index == skb_get_rx_queue(skb)) goto out; rxqueue = dev->_rx + rxq_index; flow_table = rcu_dereference(rxqueue->rps_flow_table); if (!flow_table) goto out; flow_id = skb_get_hash(skb) & flow_table->mask; rc = dev->netdev_ops->ndo_rx_flow_steer(dev, skb, rxq_index, flow_id); if (rc < 0) goto out; old_rflow = rflow; rflow = &flow_table->flows[flow_id]; rflow->filter = rc; if (old_rflow->filter == rflow->filter) old_rflow->filter = RPS_NO_FILTER; out: #endif rflow->last_qtail = per_cpu(softnet_data, next_cpu).input_queue_head; } rflow->cpu = next_cpu; return rflow; }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings22997.86%360.00%
Tom Herbert31.28%120.00%
Eric Dumazet20.85%120.00%
Total234100.00%5100.00%

/* * get_rps_cpu is called from netif_receive_skb and returns the target * CPU from the RPS map of the receiving queue for a given skb. * rcu_read_lock must be held on entry. */
static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, struct rps_dev_flow **rflowp) { const struct rps_sock_flow_table *sock_flow_table; struct netdev_rx_queue *rxqueue = dev->_rx; struct rps_dev_flow_table *flow_table; struct rps_map *map; int cpu = -1; u32 tcpu; u32 hash; if (skb_rx_queue_recorded(skb)) { u16 index = skb_get_rx_queue(skb); if (unlikely(index >= dev->real_num_rx_queues)) { WARN_ONCE(dev->real_num_rx_queues > 1, "%s received packet on queue %u, but number " "of RX queues is %u\n", dev->name, index, dev->real_num_rx_queues); goto done; } rxqueue += index; } /* Avoid computing hash if RFS/RPS is not active for this rxqueue */ flow_table = rcu_dereference(rxqueue->rps_flow_table); map = rcu_dereference(rxqueue->rps_map); if (!flow_table && !map) goto done; skb_reset_network_header(skb); hash = skb_get_hash(skb); if (!hash) goto done; sock_flow_table = rcu_dereference(rps_sock_flow_table); if (flow_table && sock_flow_table) { struct rps_dev_flow *rflow; u32 next_cpu; u32 ident; /* First check into global flow table if there is a match */ ident = sock_flow_table->ents[hash & sock_flow_table->mask]; if ((ident ^ hash) & ~rps_cpu_mask) goto try_rps; next_cpu = ident & rps_cpu_mask; /* OK, now we know there is a match, * we can look at the local (per receive queue) flow table */ rflow = &flow_table->flows[hash & flow_table->mask]; tcpu = rflow->cpu; /* * If the desired CPU (where last recvmsg was done) is * different from current CPU (one in the rx-queue flow * table entry), switch if one of the following holds: * - Current CPU is unset (>= nr_cpu_ids). * - Current CPU is offline. * - The current CPU's queue tail has advanced beyond the * last packet that was enqueued using this table entry. * This guarantees that all previous packets for the flow * have been dequeued, thus preserving in order delivery. */ if (unlikely(tcpu != next_cpu) && (tcpu >= nr_cpu_ids || !cpu_online(tcpu) || ((int)(per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail)) >= 0)) { tcpu = next_cpu; rflow = set_rps_cpu(dev, skb, rflow, next_cpu); } if (tcpu < nr_cpu_ids && cpu_online(tcpu)) { *rflowp = rflow; cpu = tcpu; goto done; } } try_rps: if (map) { tcpu = map->cpus[reciprocal_scale(hash, map->len)]; if (cpu_online(tcpu)) { cpu = tcpu; goto done; } } done: return cpu; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert17545.81%642.86%
Krishna Kumar10326.96%17.14%
Eric Dumazet7018.32%214.29%
Changli Gao184.71%214.29%
Ben Hutchings123.14%214.29%
Daniel Borkmann41.05%17.14%
Total382100.00%14100.00%

#ifdef CONFIG_RFS_ACCEL /** * rps_may_expire_flow - check whether an RFS hardware filter may be removed * @dev: Device on which the filter was set * @rxq_index: RX queue index * @flow_id: Flow ID passed to ndo_rx_flow_steer() * @filter_id: Filter ID returned by ndo_rx_flow_steer() * * Drivers that implement ndo_rx_flow_steer() should periodically call * this function for each installed filter and remove the filters for * which it returns %true. */
bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index, u32 flow_id, u16 filter_id) { struct netdev_rx_queue *rxqueue = dev->_rx + rxq_index; struct rps_dev_flow_table *flow_table; struct rps_dev_flow *rflow; bool expire = true; unsigned int cpu; rcu_read_lock(); flow_table = rcu_dereference(rxqueue->rps_flow_table); if (flow_table && flow_id <= flow_table->mask) { rflow = &flow_table->flows[flow_id]; cpu = ACCESS_ONCE(rflow->cpu); if (rflow->filter == filter_id && cpu < nr_cpu_ids && ((int)(per_cpu(softnet_data, cpu).input_queue_head - rflow->last_qtail) < (int)(10 * flow_table->mask))) expire = false; } rcu_read_unlock(); return expire; }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings14297.93%150.00%
Eric Dumazet32.07%150.00%
Total145100.00%2100.00%

EXPORT_SYMBOL(rps_may_expire_flow); #endif /* CONFIG_RFS_ACCEL */ /* Called from hardirq (IPI) context */
static void rps_trigger_softirq(void *data) { struct softnet_data *sd = data; ____napi_schedule(sd, &sd->backlog); sd->received_rps++; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert2475.00%125.00%
Eric Dumazet618.75%250.00%
Changli Gao26.25%125.00%
Total32100.00%4100.00%

#endif /* CONFIG_RPS */ /* * Check if this softnet_data structure is another cpu one * If yes, queue it to our IPI list and return 1 * If no, return 0 */
static int rps_ipi_queued(struct softnet_data *sd) { #ifdef CONFIG_RPS struct softnet_data *mysd = this_cpu_ptr(&softnet_data); if (sd != mysd) { sd->rps_ipi_next = mysd->rps_ipi_list; mysd->rps_ipi_list = sd; __raise_softirq_irqoff(NET_RX_SOFTIRQ); return 1; } #endif /* CONFIG_RPS */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet5996.72%150.00%
Christoph Lameter23.28%150.00%
Total61100.00%2100.00%

#ifdef CONFIG_NET_FLOW_LIMIT int netdev_flow_limit_table_len __read_mostly = (1 << 12); #endif
static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen) { #ifdef CONFIG_NET_FLOW_LIMIT struct sd_flow_limit *fl; struct softnet_data *sd; unsigned int old_flow, new_flow; if (qlen < (netdev_max_backlog >> 1)) return false; sd = this_cpu_ptr(&softnet_data); rcu_read_lock(); fl = rcu_dereference(sd->flow_limit); if (fl) { new_flow = skb_get_hash(skb) & (fl->num_buckets - 1); old_flow = fl->history[fl->history_head]; fl->history[fl->history_head] = new_flow; fl->history_head++; fl->history_head &= FLOW_LIMIT_HISTORY - 1; if (likely(fl->buckets[old_flow])) fl->buckets[old_flow]--; if (++fl->buckets[new_flow] > (FLOW_LIMIT_HISTORY >> 1)) { fl->count++; rcu_read_unlock(); return true; } } rcu_read_unlock(); #endif return false; }

Contributors

PersonTokensPropCommitsCommitProp
Willem de Bruijn17798.33%133.33%
Christoph Lameter21.11%133.33%
Tom Herbert10.56%133.33%
Total180100.00%3100.00%

/* * enqueue_to_backlog is called to queue an skb to a per CPU backlog * queue (may be a remote CPU queue). */
static int enqueue_to_backlog(struct sk_buff *skb, int cpu, unsigned int *qtail) { struct softnet_data *sd; unsigned long flags; unsigned int qlen; sd = &per_cpu(softnet_data, cpu); local_irq_save(flags); rps_lock(sd); if (!netif_running(skb->dev)) goto drop; qlen = skb_queue_len(&sd->input_pkt_queue); if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) { if (qlen) { enqueue: __skb_queue_tail(&sd->input_pkt_queue, skb); input_queue_tail_incr_save(sd, qtail); rps_unlock(sd); local_irq_restore(flags); return NET_RX_SUCCESS; } /* Schedule NAPI for backlog device * We can use non atomic operation since we own the queue lock */ if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) { if (!rps_ipi_queued(sd)) ____napi_schedule(sd, &sd->backlog); } goto enqueue; } drop: sd->dropped++; rps_unlock(sd); local_irq_restore(flags); atomic_long_inc(&skb->dev->rx_dropped); kfree_skb(skb); return NET_RX_DROP; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6130.05%626.09%
Tom Herbert4522.17%417.39%
Eric Dumazet3416.75%417.39%
Willem de Bruijn188.87%14.35%
Changli Gao178.37%313.04%
Julian Anastasov157.39%14.35%
Robert Love94.43%14.35%
Christoph Hellwig20.99%14.35%
Li RongQing10.49%14.35%
Stephen Hemminger10.49%14.35%
Total203100.00%23100.00%


static int netif_rx_internal(struct sk_buff *skb) { int ret; net_timestamp_check(netdev_tstamp_prequeue, skb); trace_netif_rx(skb); #ifdef CONFIG_RPS if (static_key_false(&rps_needed)) { struct rps_dev_flow voidflow, *rflow = &voidflow; int cpu; preempt_disable(); rcu_read_lock(); cpu = get_rps_cpu(skb->dev, skb, &rflow); if (cpu < 0) cpu = smp_processor_id(); ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); rcu_read_unlock(); preempt_enable(); } else #endif { unsigned int qtail; ret = enqueue_to_backlog(skb, get_cpu(), &qtail); put_cpu(); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert7557.25%325.00%
Eric Dumazet4232.06%541.67%
Changli Gao64.58%18.33%
Koki Sanagi53.82%18.33%
Ben Hutchings21.53%18.33%
Ingo Molnar10.76%18.33%
Total131100.00%12100.00%

/** * netif_rx - post buffer to the network code * @skb: buffer to post * * This function receives a packet from a device driver and queues it for * the upper (protocol) levels to process. It always succeeds. The buffer * may be dropped during processing for congestion control or by the * protocol layers. * * return values: * NET_RX_SUCCESS (no congestion) * NET_RX_DROP (packet was dropped) * */
int netif_rx(struct sk_buff *skb) { trace_netif_rx_entry(skb); return netif_rx_internal(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings21100.00%1100.00%
Total21100.00%1100.00%

EXPORT_SYMBOL(netif_rx);
int netif_rx_ni(struct sk_buff *skb) { int err; trace_netif_rx_ni_entry(skb); preempt_disable(); err = netif_rx_internal(skb); if (local_softirq_pending()) do_softirq(); preempt_enable(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller3583.33%250.00%
Ben Hutchings614.29%125.00%
Christoph Hellwig12.38%125.00%
Total42100.00%4100.00%

EXPORT_SYMBOL(netif_rx_ni);
static __latent_entropy void net_tx_action(struct softirq_action *h) { struct softnet_data *sd = this_cpu_ptr(&softnet_data); if (sd->completion_queue) { struct sk_buff *clist; local_irq_disable(); clist = sd->completion_queue; sd->completion_queue = NULL; local_irq_enable(); while (clist) { struct sk_buff *skb = clist; clist = clist->next; WARN_ON(atomic_read(&skb->users)); if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) trace_consume_skb(skb); else trace_kfree_skb(skb, net_tx_action); if (skb->fclone != SKB_FCLONE_UNAVAILABLE) __kfree_skb(skb); else __kfree_skb_defer(skb); } __kfree_skb_flush(); } if (sd->output_queue) { struct Qdisc *head; local_irq_disable(); head = sd->output_queue; sd->output_queue = NULL; sd->output_queue_tailp = &sd->output_queue; local_irq_enable(); while (head) { struct Qdisc *q = head; spinlock_t *root_lock; head = head->next_sched; root_lock = qdisc_lock(q); spin_lock(root_lock); /* We need to make sure head->next_sched is read * before clearing __QDISC_STATE_SCHED */ smp_mb__before_atomic(); clear_bit(__QDISC_STATE_SCHED, &q->state); qdisc_run(q); spin_unlock(root_lock); } } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12353.02%526.32%
Eric Dumazet239.91%210.53%
Andi Kleen198.19%15.26%
David S. Miller177.33%315.79%
Jesper Dangaard Brouer177.33%15.26%
Jarek Poplawski125.17%15.26%
Changli Gao93.88%15.26%
Koki Sanagi73.02%15.26%
Christoph Lameter20.86%15.26%
Emese Revfy10.43%15.26%
Ilpo Järvinen10.43%15.26%
Peter Zijlstra10.43%15.26%
Total232100.00%19100.00%

#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_ATM_LANE) /* This hook is defined here for ATM LANE */ int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr) __read_mostly; EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); #endif
static inline struct sk_buff * sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) { #ifdef CONFIG_NET_CLS_ACT struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list); struct tcf_result cl_res; /* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ if (!cl) return skb; if (*pt_prev) { *ret = deliver_skb(skb, *pt_prev, orig_dev); *pt_prev = NULL; } qdisc_skb_cb(skb)->pkt_len = skb->len; skb->tc_at_ingress = 1; qdisc_bstats_cpu_update(cl->q, skb); switch (tc_classify(skb, cl, &cl_res, false)) { case TC_ACT_OK: case TC_ACT_RECLASSIFY: skb->tc_index = TC_H_MIN(cl_res.classid); break; case TC_ACT_SHOT: qdisc_qstats_cpu_drop(cl->q); kfree_skb(skb); return NULL; case TC_ACT_STOLEN: case TC_ACT_QUEUED: consume_skb(skb); return NULL; case TC_ACT_REDIRECT: /* skb_mac_header check was done by cls/act_bpf, so * we can safely push the L2 header back before * redirecting to another netdev */ __skb_push(skb, skb->mac_len); skb_do_redirect(skb); return NULL; default: break; } #endif /* CONFIG_NET_CLS_ACT */ return skb; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu7637.07%17.69%
Daniel Borkmann7134.63%646.15%
Alexei Starovoitov2110.24%17.69%
Eric Dumazet209.76%323.08%
Florian Westphal157.32%17.69%
Willem de Bruijn20.98%17.69%
Total205100.00%13100.00%

/** * netdev_is_rx_handler_busy - check if receive handler is registered * @dev: device to check * * Check if a receive handler is already registered for a given device. * Return true if there one. * * The caller must hold the rtnl_mutex. */
bool netdev_is_rx_handler_busy(struct net_device *dev) { ASSERT_RTNL(); return dev && rtnl_dereference(dev->rx_handler); }

Contributors

PersonTokensPropCommitsCommitProp
Mahesh Bandewar23100.00%1100.00%
Total23100.00%1100.00%

EXPORT_SYMBOL_GPL(netdev_is_rx_handler_busy); /** * netdev_rx_handler_register - register receive handler * @dev: device to register a handler for * @rx_handler: receive handler to register * @rx_handler_data: data pointer that is used by rx handler * * Register a receive handler for a device. This handler will then be * called from __netif_receive_skb. A negative errno code is returned * on a failure. * * The caller must hold the rtnl_mutex. * * For a general description of rx_handler, see enum rx_handler_result. */
int netdev_rx_handler_register(struct net_device *dev, rx_handler_func_t *rx_handler, void *rx_handler_data) { if (netdev_is_rx_handler_busy(dev)) return -EBUSY; /* Note: rx_handler_data must be set before rx_handler */ rcu_assign_pointer(dev->rx_handler_data, rx_handler_data); rcu_assign_pointer(dev->rx_handler, rx_handler); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko4792.16%250.00%
Mahesh Bandewar35.88%125.00%
Eric Dumazet11.96%125.00%
Total51100.00%4100.00%

EXPORT_SYMBOL_GPL(netdev_rx_handler_register); /** * netdev_rx_handler_unregister - unregister receive handler * @dev: device to unregister a handler from * * Unregister a receive handler from a device. * * The caller must hold the rtnl_mutex. */
void netdev_rx_handler_unregister(struct net_device *dev) { ASSERT_RTNL(); RCU_INIT_POINTER(dev->rx_handler, NULL); /* a reader seeing a non NULL rx_handler in a rcu_read_lock() * section has a guarantee to see a non NULL rx_handler_data * as well. */ synchronize_net(); RCU_INIT_POINTER(dev->rx_handler_data, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko2982.86%250.00%
Eric Dumazet411.43%125.00%
Stephen Hemminger25.71%125.00%
Total35100.00%4100.00%

EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. */
static bool skb_pfmemalloc_protocol(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_ARP): case htons(ETH_P_IP): case htons(ETH_P_IPV6): case htons(ETH_P_8021Q): case htons(ETH_P_8021AD): return true; default: return false; } }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman4682.14%133.33%
Patrick McHardy58.93%133.33%
Joe Perches58.93%133.33%
Total56100.00%3100.00%


static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) { #ifdef CONFIG_NETFILTER_INGRESS if (nf_hook_ingress_active(skb)) { int ingress_retval; if (*pt_prev) { *ret = deliver_skb(skb, *pt_prev, orig_dev); *pt_prev = NULL; } rcu_read_lock(); ingress_retval = nf_hook_ingress(skb); rcu_read_unlock(); return ingress_retval; } #endif /* CONFIG_NETFILTER_INGRESS */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Pablo Neira Ayuso6977.53%133.33%
Aaron Conole1415.73%133.33%
Daniel Borkmann66.74%133.33%
Total89100.00%3100.00%


static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) { struct packet_type *ptype, *pt_prev; rx_handler_func_t *rx_handler; struct net_device *orig_dev; bool deliver_exact = false; int ret = NET_RX_DROP; __be16 type; net_timestamp_check(!netdev_tstamp_prequeue, skb); trace_netif_receive_skb(skb); orig_dev = skb->dev; skb_reset_network_header(skb); if (!skb_transport_header_was_set(skb)) skb_reset_transport_header(skb); skb_reset_mac_len(skb); pt_prev = NULL; another_round: skb->skb_iif = skb->dev->ifindex; __this_cpu_inc(softnet_data.processed); if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || skb->protocol == cpu_to_be16(ETH_P_8021AD)) { skb = skb_vlan_untag(skb); if (unlikely(!skb)) goto out; } if (skb_skip_tc_classify(skb)) goto skip_classify; if (pfmemalloc) goto skip_taps; list_for_each_entry_rcu(ptype, &ptype_all, list) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } skip_taps: #ifdef CONFIG_NET_INGRESS if (static_key_false(&ingress_needed)) { skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev); if (!skb) goto out; if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0) goto out; } #endif skb_reset_tc(skb); skip_classify: if (pfmemalloc && !skb_pfmemalloc_protocol(skb)) goto drop; if (skb_vlan_tag_present(skb)) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = NULL; } if (vlan_do_receive(&skb)) goto another_round; else if (unlikely(!skb)) goto out; } rx_handler = rcu_dereference(skb->dev->rx_handler); if (rx_handler) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = NULL; } switch (rx_handler(&skb)) { case RX_HANDLER_CONSUMED: ret = NET_RX_SUCCESS; goto out; case RX_HANDLER_ANOTHER: goto another_round; case RX_HANDLER_EXACT: deliver_exact = true; case RX_HANDLER_PASS: break; default: BUG(); } } if (unlikely(skb_vlan_tag_present(skb))) { if (skb_vlan_tag_get_id(skb)) skb->pkt_type = PACKET_OTHERHOST; /* Note: we might in the future use prio bits * and set skb->priority like in vlan_do_receive() * For the time being, just ignore Priority Code Point */ skb->vlan_tci = 0; } type = skb->protocol; /* deliver only exact match when indicated */ if (likely(!deliver_exact)) { deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, &ptype_base[ntohs(type) & PTYPE_HASH_MASK]); } deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, &orig_dev->ptype_specific); if (unlikely(skb->dev != orig_dev)) { deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, &skb->dev->ptype_specific); } if (pt_prev) { if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) goto drop; else ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); } else { drop: if (!deliver_exact) atomic_long_inc(&skb->dev->rx_dropped); else atomic_long_inc(&skb->dev->rx_nohandler); kfree_skb(skb); /* Jamal, now you will not able to escape explaining * me how you were going to use this. :-) */ ret = NET_RX_DROP; } out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko9114.17%710.61%
Salam Noureddine8713.55%11.52%
Linus Torvalds (pre-git)7311.37%1319.70%
David S. Miller649.97%57.58%
Eric Dumazet457.01%710.61%
Jesse Gross406.23%11.52%
Florian Zumbiehl233.58%11.52%
Jamal Hadi Salim223.43%11.52%
Mel Gorman223.43%11.52%
Pablo Neira Ayuso223.43%23.03%
Patrick McHardy192.96%23.03%
Jarod Wilson162.49%11.52%
Michael S. Tsirkin162.49%23.03%
Daniel Borkmann132.02%23.03%
Stephen Hemminger132.02%34.55%
Andrew Morton132.02%11.52%
John Fastabend111.71%23.03%
Herbert Xu91.40%23.03%
Willem de Bruijn81.25%23.03%
Arnaldo Carvalho de Melo71.09%23.03%
Simon Barber60.93%11.52%
Julian Anastasov60.93%11.52%
Koki Sanagi50.78%11.52%
Cristian Bercaru40.62%11.52%
Joe Eykholt30.47%11.52%
Bart De Schuymer20.31%11.52%
Al Viro10.16%11.52%
Vlad Yasevich10.16%11.52%
Total642100.00%66100.00%


static int __netif_receive_skb(struct sk_buff *skb) { int ret; if (sk_memalloc_socks() && skb_pfmemalloc(skb)) { unsigned long pflags = current->flags; /* * PFMEMALLOC skbs are special, they should * - be delivered to SOCK_MEMALLOC sockets only * - stay away from userspace * - have bounded memory usage * * Use PF_MEMALLOC as this saves us from propagating the allocation * context down to all allocation sites. */ current->flags |= PF_MEMALLOC; ret = __netif_receive_skb_core(skb, true); tsk_restore_flags(current, pflags, PF_MEMALLOC); } else ret = __netif_receive_skb_core(skb, false); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller6387.50%266.67%
Mel Gorman912.50%133.33%
Total72100.00%3100.00%


static int netif_receive_skb_internal(struct sk_buff *skb) { int ret; net_timestamp_check(netdev_tstamp_prequeue, skb); if (skb_defer_rx_timestamp(skb)) return NET_RX_SUCCESS; rcu_read_lock(); #ifdef CONFIG_RPS if (static_key_false(&rps_needed)) { struct rps_dev_flow voidflow, *rflow = &voidflow; int cpu = get_rps_cpu(skb->dev, skb, &rflow); if (cpu >= 0) { ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); rcu_read_unlock(); return ret; } } #endif ret = __netif_receive_skb(skb); rcu_read_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert6455.65%327.27%
Eric Dumazet2219.13%436.36%
Julian Anastasov1613.91%19.09%
Richard Cochran108.70%19.09%
Ben Hutchings21.74%19.09%
Ingo Molnar10.87%19.09%
Total115100.00%11100.00%

/** * netif_receive_skb - process receive buffer from network * @skb: buffer to process * * netif_receive_skb() is the main receive data processing function. * It always succeeds. The buffer may be dropped during processing * for congestion control or by the protocol layers. * * This function may only be called from softirq context and interrupts * should be enabled. * * Return values (usually ignored): * NET_RX_SUCCESS: no congestion * NET_RX_DROP: packet was dropped */
int netif_receive_skb(struct sk_buff *skb) { trace_netif_receive_skb_entry(skb); return netif_receive_skb_internal(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings2095.24%150.00%
Eric W. Biedermann14.76%150.00%
Total21100.00%2100.00%

EXPORT_SYMBOL(netif_receive_skb); DEFINE_PER_CPU(struct work_struct, flush_works); /* Network device is going away, flush any packets still pending */
static void flush_backlog(struct work_struct *work) { struct sk_buff *skb, *tmp; struct softnet_data *sd; local_bh_disable(); sd = this_cpu_ptr(&softnet_data); local_irq_disable(); rps_lock(sd); skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) { if (skb->dev->reg_state == NETREG_UNREGISTERING) { __skb_unlink(skb, &sd->input_pkt_queue); kfree_skb(skb); input_queue_head_incr(sd); } } rps_unlock(sd); local_irq_enable(); skb_queue_walk_safe(&sd->process_queue, skb, tmp) { if (skb->dev->reg_state == NETREG_UNREGISTERING) { __skb_unlink(skb, &sd->process_queue); kfree_skb(skb); input_queue_head_incr(sd); } } local_bh_enable(); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger4230.43%111.11%
Changli Gao4129.71%222.22%
Paolo Abeni2921.01%111.11%
Tom Herbert1510.87%333.33%
Eric Dumazet117.97%222.22%
Total138100.00%9100.00%


static void flush_all_backlogs(void) { unsigned int cpu; get_online_cpus(); for_each_online_cpu(cpu) queue_work_on(cpu, system_highpri_wq, per_cpu_ptr(&flush_works, cpu)); for_each_online_cpu(cpu) flush_work(per_cpu_ptr(&flush_works, cpu)); put_online_cpus(); }

Contributors

PersonTokensPropCommitsCommitProp
Paolo Abeni4484.62%133.33%
Eric Dumazet713.46%133.33%
Stephen Hemminger11.92%133.33%
Total52100.00%3100.00%


static int napi_gro_complete(struct sk_buff *skb) { struct packet_offload *ptype; __be16 type = skb->protocol; struct list_head *head = &offload_base; int err = -ENOENT; BUILD_BUG_ON(sizeof(struct napi_gro_cb) > sizeof(skb->cb)); if (NAPI_GRO_CB(skb)->count == 1) { skb_shinfo(skb)->gso_size = 0; goto out; } rcu_read_lock(); list_for_each_entry_rcu(ptype, head, list) { if (ptype->type != type || !ptype->callbacks.gro_complete) continue; err = ptype->callbacks.gro_complete(skb, 0); break; } rcu_read_unlock(); if (err) { WARN_ON(&ptype->list == head); kfree_skb(skb); return NET_RX_SUCCESS; } out: return netif_receive_skb_internal(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu9158.33%327.27%
David S. Miller3119.87%19.09%
Eric Dumazet1610.26%19.09%
Stephen Hemminger85.13%19.09%
Vlad Yasevich63.85%218.18%
Jerry Chu21.28%19.09%
Ben Hutchings10.64%19.09%
Arnaldo Carvalho de Melo10.64%19.09%
Total156100.00%11100.00%

/* napi->gro_list contains packets ordered by age. * youngest packets at the head of it. * Complete skbs in reverse order to reduce latencies. */
void napi_gro_flush(struct napi_struct *napi, bool flush_old) { struct sk_buff *skb, *prev = NULL; /* scan list and build reverse chain */ for (skb = napi->gro_list; skb != NULL; skb = skb->next) { skb->prev = prev; prev = skb; } for (skb = prev; skb; skb = prev) { skb->next = NULL; if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) return; prev = skb->prev; napi_gro_complete(skb); napi->gro_count--; } napi->gro_list = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu5550.00%250.00%
Eric Dumazet5449.09%125.00%
Stephen Hemminger10.91%125.00%
Total110100.00%4100.00%

EXPORT_SYMBOL(napi_gro_flush);
static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff *p; unsigned int maclen = skb->dev->hard_header_len; u32 hash = skb_get_hash_raw(skb); for (p = napi->gro_list; p; p = p->next) { unsigned long diffs; NAPI_GRO_CB(p)->flush = 0; if (hash != skb_get_hash_raw(p)) { NAPI_GRO_CB(p)->same_flow = 0; continue; } diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; diffs |= p->vlan_tci ^ skb->vlan_tci; diffs |= skb_metadata_dst_cmp(p, skb); if (maclen == ETH_HLEN) diffs |= compare_ether_header(skb_mac_header(p), skb_mac_header(skb)); else if (!diffs) diffs = memcmp(skb_mac_header(p), skb_mac_header(skb), maclen); NAPI_GRO_CB(p)->same_flow = !diffs; } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet11965.38%240.00%
Tom Herbert3820.88%120.00%
Herbert Xu168.79%120.00%
Jesse Gross94.95%120.00%
Total182100.00%5100.00%


static void skb_gro_reset_offset(struct sk_buff *skb) { const struct skb_shared_info *pinfo = skb_shinfo(skb); const skb_frag_t *frag0 = &pinfo->frags[0]; NAPI_GRO_CB(skb)->data_offset = 0; NAPI_GRO_CB(skb)->frag0 = NULL; NAPI_GRO_CB(skb)->frag0_len = 0; if (skb_mac_header(skb) == skb_tail_pointer(skb) && pinfo->nr_frags && !PageHighMem(skb_frag_page(frag0))) { NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int, skb_frag_size(frag0), skb->end - skb->tail); } }

Contributors

PersonTokensPropCommitsCommitProp
Jerry Chu10287.18%125.00%
Eric Dumazet1411.97%250.00%
Herbert Xu10.85%125.00%
Total117100.00%4100.00%


static void gro_pull_from_frag0(struct sk_buff *skb, int grow) { struct skb_shared_info *pinfo = skb_shinfo(skb); BUG_ON(skb->end - skb->tail < grow); memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); skb->data_len -= grow; skb->tail += grow; pinfo->frags[0].page_offset += grow; skb_frag_size_sub(&pinfo->frags[0], grow); if (unlikely(!skb_frag_size(&pinfo->frags[0]))) { skb_frag_unref(skb, 0); memmove(pinfo->frags, pinfo->frags + 1, --pinfo->nr_frags * sizeof(pinfo->frags[0])); } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet144100.00%1100.00%
Total144100.00%1100.00%


static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; struct packet_offload *ptype; __be16 type = skb->protocol; struct list_head *head = &offload_base; int same_flow; enum gro_result ret; int grow; if (!(skb->dev->features & NETIF_F_GRO)) goto normal; if (skb->csum_bad) goto normal; gro_list_prepare(napi, skb); rcu_read_lock(); list_for_each_entry_rcu(ptype, head, list) { if (ptype->type != type || !ptype->callbacks.gro_receive) continue; skb_set_network_header(skb, skb_gro_offset(skb)); skb_reset_mac_len(skb); NAPI_GRO_CB(skb)->same_flow = 0; NAPI_GRO_CB(skb)->flush = skb_is_gso(skb) || skb_has_frag_list(skb); NAPI_GRO_CB(skb)->free = 0; NAPI_GRO_CB(skb)->encap_mark = 0; NAPI_GRO_CB(skb)->recursion_counter = 0; NAPI_GRO_CB(skb)->is_fou = 0; NAPI_GRO_CB(skb)->is_atomic = 1; NAPI_GRO_CB(skb)->gro_remcsum_start = 0; /* Setup for GRO checksum validation */ switch (skb->ip_summed) { case CHECKSUM_COMPLETE: NAPI_GRO_CB(skb)->csum = skb->csum; NAPI_GRO_CB(skb)->csum_valid = 1; NAPI_GRO_CB(skb)->csum_cnt = 0; break; case CHECKSUM_UNNECESSARY: NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1; NAPI_GRO_CB(skb)->csum_valid = 0; break; default: NAPI_GRO_CB(skb)->csum_cnt = 0; NAPI_GRO_CB(skb)->csum_valid = 0; } pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); break; } rcu_read_unlock(); if (&ptype->list == head) goto normal; if (IS_ERR(pp) && PTR_ERR(pp) == -EINPROGRESS) { ret = GRO_CONSUMED; goto ok; } same_flow = NAPI_GRO_CB(skb)->same_flow; ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED; if (pp) { struct sk_buff *nskb = *pp; *pp = nskb->next; nskb->next = NULL; napi_gro_complete(nskb); napi->gro_count--; } if (same_flow) goto ok; if (NAPI_GRO_CB(skb)->flush) goto normal; if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) { struct sk_buff *nskb = napi->gro_list; /* locate the end of the list to select the 'oldest' flow */ while (nskb->next) { pp = &nskb->next; nskb = *pp; } *pp = NULL; nskb->next = NULL; napi_gro_complete(nskb); } else { napi->gro_count++; } NAPI_GRO_CB(skb)->count = 1; NAPI_GRO_CB(skb)->age = jiffies; NAPI_GRO_CB(skb)->last = skb; skb_shinfo(skb)->gso_size = skb_gro_len(skb); skb->next = napi->gro_list; napi->gro_list = skb; ret = GRO_HELD; pull: grow = skb_gro_offset(skb) - skb_headlen(skb); if (grow > 0) gro_pull_from_frag0(skb, grow); ok: return ret; normal: ret = GRO_NORMAL; goto pull; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu32253.94%1134.38%
Eric Dumazet10517.59%721.88%
Tom Herbert9916.58%412.50%
Steffen Klassert244.02%13.12%
Alexander Duyck183.02%26.25%
Sabrina Dubroca91.51%13.12%
Or Gerlitz81.34%13.12%
Vlad Yasevich61.01%26.25%
Ben Hutchings40.67%13.12%
Jesse Gross10.17%13.12%
Rami Rosen10.17%13.12%
Total597100.00%32100.00%


struct packet_offload *gro_find_receive_by_type(__be16 type) { struct list_head *offload_head = &offload_base; struct packet_offload *ptype; list_for_each_entry_rcu(ptype, offload_head, list) { if (ptype->type != type || !ptype->callbacks.gro_receive) continue; return ptype; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jerry Chu55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL(gro_find_receive_by_type);
struct packet_offload *gro_find_complete_by_type(__be16 type) { struct list_head *offload_head = &offload_base; struct packet_offload *ptype; list_for_each_entry_rcu(ptype, offload_head, list) { if (ptype->type != type || !ptype->callbacks.gro_complete) continue; return ptype; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jerry Chu55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL(gro_find_complete_by_type);
static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) { switch (ret) { case GRO_NORMAL: if (netif_receive_skb_internal(skb)) ret = GRO_DROP; break; case GRO_DROP: kfree_skb(skb); break; case GRO_MERGED_FREE: if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) { skb_dst_drop(skb); secpath_reset(skb); kmem_cache_free(skbuff_head_cache, skb); } else { __kfree_skb(skb); } break; case GRO_HELD: case GRO_MERGED: case GRO_CONSUMED: break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu3636.36%325.00%
Eric Dumazet2626.26%216.67%
Ben Hutchings1919.19%325.00%
Jesse Gross99.09%18.33%
Steffen Klassert88.08%216.67%
Rami Rosen11.01%18.33%
Total99100.00%12100.00%


gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { skb_mark_napi_id(skb, napi); trace_napi_gro_receive_entry(skb); skb_gro_reset_offset(skb); return napi_skb_finish(dev_gro_receive(napi, skb), skb); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2964.44%545.45%
Eric Dumazet1328.89%327.27%
Ben Hutchings24.44%218.18%
Simon Horman12.22%19.09%
Total45100.00%11100.00%

EXPORT_SYMBOL(napi_gro_receive);
static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) { if (unlikely(skb->pfmemalloc)) { consume_skb(skb); return; } __skb_pull(skb, skb_headlen(skb)); /* restore the reserve we had after netdev_alloc_skb_ip_align() */ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb)); skb->vlan_tci = 0; skb->dev = napi->dev; skb->skb_iif = 0; skb->encapsulation = 0; skb_shinfo(skb)->gso_type = 0; skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); secpath_reset(skb); napi->skb = skb; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu5143.97%220.00%
Eric Dumazet3227.59%330.00%
Jerry Chu1512.93%110.00%
Andy Gospodarek65.17%110.00%
Jesse Gross65.17%110.00%
Steffen Klassert54.31%110.00%
Stephen Hemminger10.86%110.00%
Total116100.00%10100.00%


struct sk_buff *napi_get_frags(struct napi_struct *napi) { struct sk_buff *skb = napi->skb; if (!skb) { skb = napi_alloc_skb(napi, GRO_MAX_HEAD); if (skb) { napi->skb = skb; skb_mark_napi_id(skb, napi); } } return skb; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu4474.58%450.00%
Eric Dumazet1423.73%337.50%
Alexander Duyck11.69%112.50%
Total59100.00%8100.00%

EXPORT_SYMBOL(napi_get_frags);
static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, gro_result_t ret) { switch (ret) { case GRO_NORMAL: case GRO_HELD: __skb_push(skb, ETH_HLEN); skb->protocol = eth_type_trans(skb, skb->dev); if (ret == GRO_NORMAL && netif_receive_skb_internal(skb)) ret = GRO_DROP; break; case GRO_DROP: case GRO_MERGED_FREE: napi_reuse_skb(napi, skb); break; case GRO_MERGED: case GRO_CONSUMED: break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu4246.15%225.00%
Eric Dumazet2729.67%112.50%
Ben Hutchings1819.78%337.50%
Steffen Klassert33.30%112.50%
Rami Rosen11.10%112.50%
Total91100.00%8100.00%

/* Upper GRO stack assumes network header starts at gro_offset=0 * Drivers could call both napi_gro_frags() and napi_gro_receive() * We copy ethernet header into skb->data to have a common layout. */
static struct sk_buff *napi_frags_skb(struct napi_struct *napi) { struct sk_buff *skb = napi->skb; const struct ethhdr *eth; unsigned int hlen = sizeof(*eth); napi->skb = NULL; skb_reset_mac_header(skb); skb_gro_reset_offset(skb); eth = skb_gro_header_fast(skb, 0); if (unlikely(skb_gro_header_hard(skb, hlen))) { eth = skb_gro_header_slow(skb, hlen, 0); if (unlikely(!eth)) { net_warn_ratelimited("%s: dropping impossible skb from %s\n", __func__, napi->dev->name); napi_reuse_skb(napi, skb); return NULL; } } else { gro_pull_from_frag0(skb, hlen); NAPI_GRO_CB(skb)->frag0 += hlen; NAPI_GRO_CB(skb)->frag0_len -= hlen; } __skb_pull(skb, hlen); /* * This works because the only protocols we care about don't require * special handling. * We'll fix it up properly in napi_frags_finish() */ skb->protocol = eth->h_proto; return skb; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet9254.76%233.33%
Herbert Xu5432.14%233.33%
Aaron Conole137.74%116.67%
Jerry Chu95.36%116.67%
Total168100.00%6100.00%


gro_result_t napi_gro_frags(struct napi_struct *napi) { struct sk_buff *skb = napi_frags_skb(napi); if (!skb) return GRO_DROP; trace_napi_gro_frags_entry(skb); return napi_frags_finish(napi, skb, dev_gro_receive(napi, skb)); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu4083.33%457.14%
Ben Hutchings714.58%228.57%
Eric Dumazet12.08%114.29%
Total48100.00%7100.00%

EXPORT_SYMBOL(napi_gro_frags); /* Compute the checksum from gro_offset and return the folded value * after adding in any pseudo checksum. */
__sum16 __skb_gro_checksum_complete(struct sk_buff *skb) { __wsum wsum; __sum16 sum; wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0); /* NAPI_GRO_CB(skb)->csum holds pseudo checksum */ sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum)); if (likely(!sum)) { if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !skb->csum_complete_sw) netdev_rx_csum_fault(skb->dev); } NAPI_GRO_CB(skb)->csum = wsum; NAPI_GRO_CB(skb)->csum_valid = 1; return sum; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert107100.00%1100.00%
Total107100.00%1100.00%

EXPORT_SYMBOL(__skb_gro_checksum_complete); /* * net_rps_action_and_irq_enable sends any pending IPI's for rps. * Note: called with local irq disabled, but exits with local irq enabled. */
static void net_rps_action_and_irq_enable(struct softnet_data *sd) { #ifdef CONFIG_RPS struct softnet_data *remsd = sd->rps_ipi_list; if (remsd) { sd->rps_ipi_list = NULL; local_irq_enable(); /* Send pending IPI's to kick RPS processing on remote cpus. */ while (remsd) { struct softnet_data *next = remsd->rps_ipi_next; if (cpu_online(remsd->cpu)) smp_call_function_single_async(remsd->cpu, &remsd->csd); remsd = next; } } else #endif local_irq_enable(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet8498.82%150.00%
Frédéric Weisbecker11.18%150.00%
Total85100.00%2100.00%


static bool sd_has_rps_ipi_waiting(struct softnet_data *sd) { #ifdef CONFIG_RPS return sd->rps_ipi_list != NULL; #else return false; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet28100.00%1100.00%
Total28100.00%1100.00%


static int process_backlog(struct napi_struct *napi, int quota) { struct softnet_data *sd = container_of(napi, struct softnet_data, backlog); bool again = true; int work = 0; /* Check if we have pending ipi, its better to send them now, * not waiting net_rx_action() end. */ if (sd_has_rps_ipi_waiting(sd)) { local_irq_disable(); net_rps_action_and_irq_enable(sd); } napi->weight = dev_rx_weight; while (again) { struct sk_buff *skb; while ((skb = __skb_dequeue(&sd->process_queue))) { rcu_read_lock(); __netif_receive_skb(skb); rcu_read_unlock(); input_queue_head_incr(sd); if (++work >= quota) return work; } local_irq_disable(); rps_lock(sd); if (skb_queue_empty(&sd->input_pkt_queue)) { /* * Inline a custom version of __napi_complete(). * only current cpu owns and manipulates this napi, * and NAPI_STATE_SCHED is the only possible flag set * on backlog. * We can use a plain write instead of clear_bit(), * and we dont need an smp_mb() memory barrier. */ napi->state = 0; again = false; } else { skb_queue_splice_tail_init(&sd->input_pkt_queue, &sd->process_queue); } rps_unlock(sd); local_irq_enable(); } return work; }

Contributors

PersonTokensPropCommitsCommitProp
Changli Gao4626.44%215.38%
Herbert Xu4022.99%17.69%
Eric Dumazet3318.97%430.77%
Tom Herbert2715.52%323.08%
Paolo Abeni2112.07%17.69%
Julian Anastasov63.45%17.69%
Matthias Tafelmeier10.57%17.69%
Total174100.00%13100.00%

/** * __napi_schedule - schedule for receive * @n: entry to schedule * * The entry's receive function will be scheduled to run. * Consider using __napi_schedule_irqoff() if hard irqs are masked. */
void __napi_schedule(struct napi_struct *n) { unsigned long flags; local_irq_save(flags); ____napi_schedule(this_cpu_ptr(&softnet_data), n); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu3085.71%133.33%
Eric Dumazet38.57%133.33%
Christoph Lameter25.71%133.33%
Total35100.00%3100.00%

EXPORT_SYMBOL(__napi_schedule); /** * napi_schedule_prep - check if napi can be scheduled * @n: napi context * * Test if NAPI routine is already running, and if not mark * it as running. This is used as a condition variable * insure only one NAPI poll instance runs. We also make * sure there is no pending NAPI disable. */
bool napi_schedule_prep(struct napi_struct *n) { unsigned long val, new; do { val = READ_ONCE(n->state); if (unlikely(val & NAPIF_STATE_DISABLE)) return false; new = val | NAPIF_STATE_SCHED; /* Sets STATE_MISSED bit if STATE_SCHED was already set * This was suggested by Alexander Duyck, as compiler * emits better code than : * if (val & NAPIF_STATE_SCHED) * new |= NAPIF_STATE_MISSED; */ new |= (val & NAPIF_STATE_SCHED) / NAPIF_STATE_SCHED * NAPIF_STATE_MISSED; } while (cmpxchg(&n->state, val, new) != val); return !(val & NAPIF_STATE_SCHED); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet84100.00%1100.00%
Total84100.00%1100.00%

EXPORT_SYMBOL(napi_schedule_prep); /** * __napi_schedule_irqoff - schedule for receive * @n: entry to schedule * * Variant of __napi_schedule() assuming hard irqs are masked */
void __napi_schedule_irqoff(struct napi_struct *n) { ____napi_schedule(this_cpu_ptr(&softnet_data), n); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet21100.00%1100.00%
Total21100.00%1100.00%

EXPORT_SYMBOL(__napi_schedule_irqoff);
bool napi_complete_done(struct napi_struct *n, int work_done) { unsigned long flags, val, new; /* * 1) Don't let napi dequeue from the cpu poll list * just in case its running on a different cpu. * 2) If we are busy polling, do nothing here, we have * the guarantee we will be called later. */ if (unlikely(n->state & (NAPIF_STATE_NPSVC | NAPIF_STATE_IN_BUSY_POLL))) return false; if (n->gro_list) { unsigned long timeout = 0; if (work_done) timeout = n->dev->gro_flush_timeout; if (timeout) hrtimer_start(&n->timer, ns_to_ktime(timeout), HRTIMER_MODE_REL_PINNED); else napi_gro_flush(n, false); } if (unlikely(!list_empty(&n->poll_list))) { /* If n->poll_list is not empty, we need to mask irqs */ local_irq_save(flags); list_del_init(&n->poll_list); local_irq_restore(flags); } do { val = READ_ONCE(n->state); WARN_ON_ONCE(!(val & NAPIF_STATE_SCHED)); new = val & ~(NAPIF_STATE_MISSED | NAPIF_STATE_SCHED); /* If STATE_MISSED was set, leave STATE_SCHED set, * because we will call napi->poll() one more time. * This C code was suggested by Alexander Duyck to help gcc. */ new |= (val & NAPIF_STATE_MISSED) / NAPIF_STATE_MISSED * NAPIF_STATE_SCHED; } while (cmpxchg(&n->state, val, new) != val); if (unlikely(val & NAPIF_STATE_MISSED)) { __napi_schedule(n); return false; } return true; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet17381.22%777.78%
Herbert Xu2712.68%111.11%
Stephen Hemminger136.10%111.11%
Total213100.00%9100.00%

EXPORT_SYMBOL(napi_complete_done); /* must be called under rcu_read_lock(), as we dont take a reference */
static struct napi_struct *napi_by_id(unsigned int napi_id) { unsigned int hash = napi_id % HASH_SIZE(napi_hash); struct napi_struct *napi; hlist_for_each_entry_rcu(napi, &napi_hash[hash], napi_hash_node) if (napi->napi_id == napi_id) return napi; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Eliezer Tamir4998.00%150.00%
Eric Dumazet12.00%150.00%
Total50100.00%2100.00%

#if defined(CONFIG_NET_RX_BUSY_POLL) #define BUSY_POLL_BUDGET 8
static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock) { int rc; /* Busy polling means there is a high chance device driver hard irq * could not grab NAPI_STATE_SCHED, and that NAPI_STATE_MISSED was * set in napi_schedule_prep(). * Since we are about to call napi->poll() once more, we can safely * clear NAPI_STATE_MISSED. * * Note: x86 could use a single "lock and ..." instruction * to perform these two clear_bit() */ clear_bit(NAPI_STATE_MISSED, &napi->state); clear_bit(NAPI_STATE_IN_BUSY_POLL, &napi->state); local_bh_disable(); /* All we really want here is to re-enable device interrupts. * Ideally, a new ndo_busy_poll_stop() could avoid another round. */ rc = napi->poll(napi, BUSY_POLL_BUDGET); netpoll_poll_unlock(have_poll_lock); if (rc == BUSY_POLL_BUDGET) __napi_schedule(napi); local_bh_enable(); if (local_softirq_pending()) do_softirq(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet81100.00%2100.00%
Total81100.00%2100.00%


bool sk_busy_loop(struct sock *sk, int nonblock) { unsigned long end_time = !nonblock ? sk_busy_loop_end_time(sk) : 0; int (*napi_poll)(struct napi_struct *napi, int budget); void *have_poll_lock = NULL; struct napi_struct *napi; int rc; restart: rc = false; napi_poll = NULL; rcu_read_lock(); napi = napi_by_id(sk->sk_napi_id); if (!napi) goto out; preempt_disable(); for (;;) { rc = 0; local_bh_disable(); if (!napi_poll) { unsigned long val = READ_ONCE(napi->state); /* If multiple threads are competing for this napi, * we avoid dirtying napi->state as much as we can. */ if (val & (NAPIF_STATE_DISABLE | NAPIF_STATE_SCHED | NAPIF_STATE_IN_BUSY_POLL)) goto count; if (cmpxchg(&napi->state, val, val | NAPIF_STATE_IN_BUSY_POLL | NAPIF_STATE_SCHED) != val) goto count; have_poll_lock = netpoll_poll_lock(napi); napi_poll = napi->poll; } rc = napi_poll(napi, BUSY_POLL_BUDGET); trace_napi_poll(napi, rc, BUSY_POLL_BUDGET); count: if (rc > 0) __NET_ADD_STATS(sock_net(sk), LINUX_MIB_BUSYPOLLRXPACKETS, rc); local_bh_enable(); if (nonblock || !skb_queue_empty(&sk->sk_receive_queue) || busy_loop_timeout(end_time)) break; if (unlikely(need_resched())) { if (napi_poll) busy_poll_stop(napi, have_poll_lock); preempt_enable(); rcu_read_unlock(); cond_resched(); rc = !skb_queue_empty(&sk->sk_receive_queue); if (rc || busy_loop_timeout(end_time)) return rc; goto restart; } cpu_relax(); } if (napi_poll) busy_poll_stop(napi, have_poll_lock); preempt_enable(); rc = !skb_queue_empty(&sk->sk_receive_queue); out: rcu_read_unlock(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet31897.85%562.50%
Jesper Dangaard Brouer41.23%112.50%
Eliezer Tamir20.62%112.50%
Linus Torvalds10.31%112.50%
Total325100.00%8100.00%

EXPORT_SYMBOL(sk_busy_loop); #endif /* CONFIG_NET_RX_BUSY_POLL */
static void napi_hash_add(struct napi_struct *napi) { if (test_bit(NAPI_STATE_NO_BUSY_POLL, &napi->state) || test_and_set_bit(NAPI_STATE_HASHED, &napi->state)) return; spin_lock(&napi_hash_lock); /* 0..NR_CPUS+1 range is reserved for sender_cpu use */ do { if (unlikely(++napi_gen_id < NR_CPUS + 1)) napi_gen_id = NR_CPUS + 1; } while (napi_by_id(napi_gen_id)); napi->napi_id = napi_gen_id; hlist_add_head_rcu(&napi->napi_hash_node, &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]); spin_unlock(&napi_hash_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Eliezer Tamir6966.99%125.00%
Eric Dumazet3433.01%375.00%
Total103100.00%4100.00%

/* Warning : caller is responsible to make sure rcu grace period * is respected before freeing memory containing @napi */
bool napi_hash_del(struct napi_struct *napi) { bool rcu_sync_needed = false; spin_lock(&napi_hash_lock); if (test_and_clear_bit(NAPI_STATE_HASHED, &napi->state)) { rcu_sync_needed = true; hlist_del_rcu(&napi->napi_hash_node); } spin_unlock(&napi_hash_lock); return rcu_sync_needed; }

Contributors

PersonTokensPropCommitsCommitProp
Eliezer Tamir4173.21%150.00%
Eric Dumazet1526.79%150.00%
Total56100.00%2100.00%

EXPORT_SYMBOL_GPL(napi_hash_del);
static enum hrtimer_restart napi_watchdog(struct hrtimer *timer) { struct napi_struct *napi; napi = container_of(timer, struct napi_struct, timer); /* Note : we use a relaxed variant of napi_schedule_prep() not setting * NAPI_STATE_MISSED, since we do not react to a device IRQ. */ if (napi->gro_list && !napi_disable_pending(napi) && !test_and_set_bit(NAPI_STATE_SCHED, &napi->state)) __napi_schedule_irqoff(napi); return HRTIMER_NORESTART; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet5895.08%250.00%
David S. Miller23.28%125.00%
Herbert Xu11.64%125.00%
Total61100.00%4100.00%


void netif_napi_add(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight) { INIT_LIST_HEAD(&napi->poll_list); hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); napi->timer.function = napi_watchdog; napi->gro_count = 0; napi->gro_list = NULL; napi->skb = NULL; napi->poll = poll; if (weight > NAPI_POLL_WEIGHT) pr_err_once("netif_napi_add() called with weight %d on device %s\n", weight, dev->name); napi->weight = weight; list_add(&napi->dev_list, &dev->napi_list); napi->dev = dev; #ifdef CONFIG_NETPOLL napi->poll_owner = -1; #endif set_bit(NAPI_STATE_SCHED, &napi->state); napi_hash_add(napi); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu8052.63%327.27%
Eric Dumazet4227.63%327.27%
David S. Miller1610.53%19.09%
Stephen Hemminger106.58%218.18%
Linus Torvalds (pre-git)31.97%19.09%
Andi Kleen10.66%19.09%
Total152100.00%11100.00%

EXPORT_SYMBOL(netif_napi_add);
void napi_disable(struct napi_struct *n) { might_sleep(); set_bit(NAPI_STATE_DISABLE, &n->state); while (test_and_set_bit(NAPI_STATE_SCHED, &n->state)) msleep(1); while (test_and_set_bit(NAPI_STATE_NPSVC, &n->state)) msleep(1); hrtimer_cancel(&n->timer); clear_bit(NAPI_STATE_DISABLE, &n->state); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet5877.33%150.00%
Neil Horman1722.67%150.00%
Total75100.00%2100.00%

EXPORT_SYMBOL(napi_disable); /* Must be called in process context */
void netif_napi_del(struct napi_struct *napi) { might_sleep(); if (napi_hash_del(napi)) synchronize_net(); list_del_init(&napi->dev_list); napi_free_frags(napi); kfree_skb_list(napi->gro_list); napi->gro_list = NULL; napi->gro_count = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2545.45%436.36%
Eric Dumazet1527.27%218.18%
Stephen Hemminger916.36%19.09%
Linus Torvalds (pre-git)35.45%218.18%
David S. Miller23.64%19.09%
Peter P. Waskiewicz Jr11.82%19.09%
Total55100.00%11100.00%

EXPORT_SYMBOL(netif_napi_del);
static int napi_poll(struct napi_struct *n, struct list_head *repoll) { void *have; int work, weight; list_del_init(&n->poll_list); have = netpoll_poll_lock(n); weight = n->weight; /* This NAPI_STATE_SCHED test is for avoiding a race * with netpoll's poll_napi(). Only the entity which * obtains the lock and sees NAPI_STATE_SCHED set will * actually make the ->poll() call. Therefore we avoid * accidentally calling ->poll() when NAPI is not scheduled. */ work = 0; if (test_bit(NAPI_STATE_SCHED, &n->state)) { work = n->poll(n, weight); trace_napi_poll(n, work, weight); } WARN_ON_ONCE(work > weight); if (likely(work < weight)) goto out_unlock; /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can * move the instance around on the list at-will. */ if (unlikely(napi_disable_pending(n))) { napi_complete(n); goto out_unlock; } if (n->gro_list) { /* flush too old packets * If HZ < 1000, flush all packets. */ napi_gro_flush(n, HZ >= 1000); } /* Some drivers may have called napi_schedule * prior to exhausting their budget. */ if (unlikely(!list_empty(&n->poll_list))) { pr_warn_once("%s: Budget exhausted after napi rescheduled\n", n->dev ? n->dev->name : "backlog"); goto out_unlock; } list_add_tail(&n->poll_list, repoll); out_unlock: netpoll_poll_unlock(have); return work; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu6532.50%323.08%
David S. Miller5025.00%323.08%
Stephen Hemminger2814.00%17.69%
Eric Dumazet2814.00%215.38%
Matt Mackall189.00%215.38%
Neil Horman73.50%17.69%
Jesper Dangaard Brouer42.00%17.69%
Total200100.00%13100.00%


static __latent_entropy void net_rx_action(struct softirq_action *h) { struct softnet_data *sd = this_cpu_ptr(&softnet_data); unsigned long time_limit = jiffies + 2; int budget = netdev_budget; LIST_HEAD(list); LIST_HEAD(repoll); local_irq_disable(); list_splice_init(&sd->poll_list, &list); local_irq_enable(); for (;;) { struct napi_struct *n; if (list_empty(&list)) { if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll)) goto out; break; } n = list_first_entry(&list, struct napi_struct, poll_list); budget -= napi_poll(n, &repoll); /* If softirq window is exhausted then punt. * Allow this to run for 2 jiffies since which will allow * an average latency of 1.5/HZ. */ if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit))) { sd->time_squeeze++; break; } } local_irq_disable(); list_splice_tail_init(&sd->poll_list, &list); list_splice_tail(&repoll, &list); list_splice(&list, &sd->poll_list); if (!list_empty(&sd->poll_list)) __raise_softirq_irqoff(NET_RX_SOFTIRQ); net_rps_action_and_irq_enable(sd); out: __kfree_skb_flush(); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu14568.72%333.33%
Eric Dumazet6329.86%333.33%
Emese Revfy10.47%111.11%
Linus Torvalds (pre-git)10.47%111.11%
Tom Herbert10.47%111.11%
Total211100.00%9100.00%

struct netdev_adjacent { struct net_device *dev; /* upper master flag, there can only be one master device per list */ bool master; /* counter for the number of times this device was added to us */ u16 ref_nr; /* private field for the users */ void *private; struct list_head list; struct rcu_head rcu; };
static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev, struct list_head *adj_list) { struct netdev_adjacent *adj; list_for_each_entry(adj, adj_list, list) { if (adj->dev == adj_dev) return adj; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico1634.04%457.14%
Américo Wang1429.79%114.29%
Patrick McHardy1225.53%114.29%
Wang Chen510.64%114.29%
Total47100.00%7100.00%


static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data) { struct net_device *dev = data; return upper_dev == dev; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern27100.00%1100.00%
Total27100.00%1100.00%

/** * netdev_has_upper_dev - Check if device is linked to an upper device * @dev: device * @upper_dev: upper device to check * * Find out if a device is linked to specified upper device and return true * in case it is. Note that this checks only immediate upper device, * not through a complete stack of devices. The caller must hold the RTNL lock. */
bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev) { ASSERT_RTNL(); return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, upper_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)828.57%228.57%
Américo Wang725.00%114.29%
David Ahern517.86%114.29%
Wang Chen414.29%114.29%
Patrick McHardy310.71%114.29%
Veaceslav Falico13.57%114.29%
Total28100.00%7100.00%

EXPORT_SYMBOL(netdev_has_upper_dev); /** * netdev_has_upper_dev_all - Check if device is linked to an upper device * @dev: device * @upper_dev: upper device to check * * Find out if a device is linked to specified upper device and return true * in case it is. Note that this checks the entire upper device chain. * The caller must hold rcu lock. */
bool netdev_has_upper_dev_all_rcu(struct net_device *dev, struct net_device *upper_dev) { return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, upper_dev); }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern27100.00%1100.00%
Total27100.00%1100.00%

EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); /** * netdev_has_any_upper_dev - Check if device is linked to some device * @dev: device * * Find out if a device is linked to an upper device and return true in case * it is. The caller must hold the RTNL lock. */
static bool netdev_has_any_upper_dev(struct net_device *dev) { ASSERT_RTNL(); return !list_empty(&dev->adj_list.upper); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1453.85%112.50%
Patrick McHardy623.08%225.00%
Veaceslav Falico27.69%112.50%
Linus Torvalds (pre-git)13.85%112.50%
Wang Chen13.85%112.50%
David Ahern13.85%112.50%
Stephen Hemminger13.85%112.50%
Total26100.00%8100.00%

/** * netdev_master_upper_dev_get - Get master upper device * @dev: device * * Find a master upper device and return pointer to it or NULL in case * it's not there. The caller must hold the RTNL lock. */
struct net_device *netdev_master_upper_dev_get(struct net_device *dev) { struct netdev_adjacent *upper; ASSERT_RTNL(); if (list_empty(&dev->adj_list.upper)) return NULL; upper = list_first_entry(&dev->adj_list.upper, struct netdev_adjacent, list); if (likely(upper->master)) return upper->dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang3043.48%114.29%
Patrick McHardy2637.68%114.29%
Veaceslav Falico811.59%228.57%
Stephen Hemminger34.35%114.29%
Jiri Pirko22.90%228.57%
Total69100.00%7100.00%

EXPORT_SYMBOL(netdev_master_upper_dev_get); /** * netdev_has_any_lower_dev - Check if device is linked to some device * @dev: device * * Find out if a device is linked to a lower device and return true in case * it is. The caller must hold the RTNL lock. */
static bool netdev_has_any_lower_dev(struct net_device *dev) { ASSERT_RTNL(); return !list_empty(&dev->adj_list.lower); }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern26100.00%1100.00%
Total26100.00%1100.00%


void *netdev_adjacent_get_private(struct list_head *adj_list) { struct netdev_adjacent *adj; adj = list_entry(adj_list, struct netdev_adjacent, list); return adj->private; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico33100.00%1100.00%
Total33100.00%1100.00%

EXPORT_SYMBOL(netdev_adjacent_get_private); /** * netdev_upper_get_next_dev_rcu - Get the next dev from upper list * @dev: device * @iter: list_head ** of the current position * * Gets the next device from the dev's upper list, starting from iter * position. The caller must hold RCU read lock. */
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *upper; WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); if (&upper->list == &dev->adj_list.upper) return NULL; *iter = &upper->list; return upper->dev; }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich81100.00%1100.00%
Total81100.00%1100.00%

EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *upper; WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); if (&upper->list == &dev->adj_list.upper) return NULL; *iter = &upper->list; return upper->dev; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern82100.00%1100.00%
Total82100.00%1100.00%


int netdev_walk_all_upper_dev_rcu(struct net_device *dev, int (*fn)(struct net_device *dev, void *data), void *data) { struct net_device *udev; struct list_head *iter; int ret; for (iter = &dev->adj_list.upper, udev = netdev_next_upper_dev_rcu(dev, &iter); udev; udev = netdev_next_upper_dev_rcu(dev, &iter)) { /* first is the upper device itself */ ret = fn(udev, data); if (ret) return ret; /* then look at all of its upper devices */ ret = netdev_walk_all_upper_dev_rcu(udev, fn, data); if (ret) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern117100.00%1100.00%
Total117100.00%1100.00%

EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); /** * netdev_lower_get_next_private - Get the next ->private from the * lower neighbour list * @dev: device * @iter: list_head ** of the current position * * Gets the next netdev_adjacent->private from the dev's lower neighbour * list, starting from iter position. The caller must hold either hold the * RTNL lock or its own locking that guarantees that the neighbour lower * list will remain unchanged. */
void *netdev_lower_get_next_private(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *lower; lower = list_entry(*iter, struct netdev_adjacent, list); if (&lower->list == &dev->adj_list.lower) return NULL; *iter = lower->list.next; return lower->private; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico66100.00%1100.00%
Total66100.00%1100.00%

EXPORT_SYMBOL(netdev_lower_get_next_private); /** * netdev_lower_get_next_private_rcu - Get the next ->private from the * lower neighbour list, RCU * variant * @dev: device * @iter: list_head ** of the current position * * Gets the next netdev_adjacent->private from the dev's lower neighbour * list, starting from iter position. The caller must hold RCU read lock. */
void *netdev_lower_get_next_private_rcu(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *lower; WARN_ON_ONCE(!rcu_read_lock_held()); lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); if (&lower->list == &dev->adj_list.lower) return NULL; *iter = &lower->list; return lower->private; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico76100.00%1100.00%
Total76100.00%1100.00%

EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); /** * netdev_lower_get_next - Get the next device from the lower neighbour * list * @dev: device * @iter: list_head ** of the current position * * Gets the next netdev_adjacent from the dev's lower neighbour * list, starting from iter position. The caller must hold RTNL lock or * its own locking that guarantees that the neighbour lower * list will remain unchanged. */
void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *lower; lower = list_entry(*iter, struct netdev_adjacent, list); if (&lower->list == &dev->adj_list.lower) return NULL; *iter = lower->list.next; return lower->dev; }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich6496.97%150.00%
Nikolay Aleksandrov23.03%150.00%
Total66100.00%2100.00%

EXPORT_SYMBOL(netdev_lower_get_next);
static struct net_device *netdev_next_lower_dev(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *lower; lower = list_entry((*iter)->next, struct netdev_adjacent, list); if (&lower->list == &dev->adj_list.lower) return NULL; *iter = &lower->list; return lower->dev; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern71100.00%2100.00%
Total71100.00%2100.00%


int netdev_walk_all_lower_dev(struct net_device *dev, int (*fn)(struct net_device *dev, void *data), void *data) { struct net_device *ldev; struct list_head *iter; int ret; for (iter = &dev->adj_list.lower, ldev = netdev_next_lower_dev(dev, &iter); ldev; ldev = netdev_next_lower_dev(dev, &iter)) { /* first is the lower device itself */ ret = fn(ldev, data); if (ret) return ret; /* then look at all of its lower devices */ ret = netdev_walk_all_lower_dev(ldev, fn, data); if (ret) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern117100.00%1100.00%
Total117100.00%1100.00%

EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, struct list_head **iter) { struct netdev_adjacent *lower; lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); if (&lower->list == &dev->adj_list.lower) return NULL; *iter = &lower->list; return lower->dev; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern4664.79%266.67%
Jiri Pirko2535.21%133.33%
Total71100.00%3100.00%


int netdev_walk_all_lower_dev_rcu(struct net_device *dev, int (*fn)(struct net_device *dev, void *data), void *data) { struct net_device *ldev; struct list_head *iter; int ret; for (iter = &dev->adj_list.lower, ldev = netdev_next_lower_dev_rcu(dev, &iter); ldev; ldev = netdev_next_lower_dev_rcu(dev, &iter)) { /* first is the lower device itself */ ret = fn(ldev, data); if (ret) return ret; /* then look at all of its lower devices */ ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data); if (ret) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern117100.00%1100.00%
Total117100.00%1100.00%

EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev_rcu); /** * netdev_lower_get_first_private_rcu - Get the first ->private from the * lower neighbour list, RCU * variant * @dev: device * * Gets the first netdev_adjacent->private from the dev's lower neighbour * list. The caller must hold RCU read lock. */
void *netdev_lower_get_first_private_rcu(struct net_device *dev) { struct netdev_adjacent *lower; lower = list_first_or_null_rcu(&dev->adj_list.lower, struct netdev_adjacent, list); if (lower) return lower->private; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Ding Tianhong45100.00%1100.00%
Total45100.00%1100.00%

EXPORT_SYMBOL(netdev_lower_get_first_private_rcu); /** * netdev_master_upper_dev_get_rcu - Get master upper device * @dev: device * * Find a master upper device and return pointer to it or NULL in case * it's not there. The caller must hold the RCU read lock. */
struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev) { struct netdev_adjacent *upper; upper = list_first_or_null_rcu(&dev->adj_list.upper, struct netdev_adjacent, list); if (upper && likely(upper->master)) return upper->dev; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang2852.83%120.00%
Stephen Hemminger1426.42%120.00%
Stefan Rompf611.32%120.00%
Veaceslav Falico59.43%240.00%
Total53100.00%5100.00%

EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
static int netdev_adjacent_sysfs_add(struct net_device *dev, struct net_device *adj_dev, struct list_head *dev_list) { char linkname[IFNAMSIZ+7]; sprintf(linkname, dev_list == &dev->adj_list.upper ? "upper_%s" : "lower_%s", adj_dev->name); return sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), linkname); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico7498.67%150.00%
Rashika Kheria11.33%150.00%
Total75100.00%2100.00%


static void netdev_adjacent_sysfs_del(struct net_device *dev, char *name, struct list_head *dev_list) { char linkname[IFNAMSIZ+7]; sprintf(linkname, dev_list == &dev->adj_list.upper ? "upper_%s" : "lower_%s", name); sysfs_remove_link(&(dev->dev.kobj), linkname); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico6198.39%150.00%
Rashika Kheria11.61%150.00%
Total62100.00%2100.00%


static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev, struct net_device *adj_dev, struct list_head *dev_list) { return (dev_list == &dev->adj_list.upper || dev_list == &dev->adj_list.lower) && net_eq(dev_net(dev), dev_net(adj_dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Y. Fomichev5089.29%150.00%
Veaceslav Falico610.71%150.00%
Total56100.00%2100.00%


static int __netdev_adjacent_dev_insert(struct net_device *dev, struct net_device *adj_dev, struct list_head *dev_list, void *private, bool master) { struct netdev_adjacent *adj; int ret; adj = __netdev_find_adj(adj_dev, dev_list); if (adj) { adj->ref_nr += 1; pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d\n", dev->name, adj_dev->name, adj->ref_nr); return 0; } adj = kmalloc(sizeof(*adj), GFP_KERNEL); if (!adj) return -ENOMEM; adj->dev = adj_dev; adj->master = master; adj->ref_nr = 1; adj->private = private; dev_hold(adj_dev); pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", dev->name, adj_dev->name, adj->ref_nr, adj_dev->name); if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) { ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); if (ret) goto free_adj; } /* Ensure that master link is always the first item in list. */ if (master) { ret = sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), "master"); if (ret) goto remove_symlinks; list_add_rcu(&adj->list, dev_list); } else { list_add_tail_rcu(&adj->list, dev_list); } return 0; remove_symlinks: if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); free_adj: kfree(adj); dev_put(adj_dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico22478.87%741.18%
David Ahern269.15%211.76%
Américo Wang103.52%15.88%
Linus Torvalds (pre-git)93.17%211.76%
Nikolay Aleksandrov51.76%15.88%
Patrick McHardy51.76%211.76%
Alexander Y. Fomichev41.41%15.88%
Andrew Collins10.35%15.88%
Total284100.00%17100.00%


static void __netdev_adjacent_dev_remove(struct net_device *dev, struct net_device *adj_dev, u16 ref_nr, struct list_head *dev_list) { struct netdev_adjacent *adj; pr_debug("Remove adjacency: dev %s adj_dev %s ref_nr %d\n", dev->name, adj_dev->name, ref_nr); adj = __netdev_find_adj(adj_dev, dev_list); if (!adj) { pr_err("Adjacency does not exist for device %s from %s\n", dev->name, adj_dev->name); WARN_ON(1); return; } if (adj->ref_nr > ref_nr) { pr_debug("adjacency: %s to %s ref_nr - %d = %d\n", dev->name, adj_dev->name, ref_nr, adj->ref_nr - ref_nr); adj->ref_nr -= ref_nr; return; } if (adj->master) sysfs_remove_link(&(dev->dev.kobj), "master"); if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); list_del_rcu(&adj->list); pr_debug("adjacency: dev_put for %s, because link removed from %s to %s\n", adj_dev->name, dev->name, adj_dev->name); dev_put(adj_dev); kfree_rcu(adj, rcu); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico15981.12%654.55%
David Ahern2311.73%19.09%
Andrew Collins94.59%19.09%
Alexander Y. Fomichev42.04%218.18%
Stephen Hemminger10.51%19.09%
Total196100.00%11100.00%


static int __netdev_adjacent_dev_link_lists(struct net_device *dev, struct net_device *upper_dev, struct list_head *up_list, struct list_head *down_list, void *private, bool master) { int ret; ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private, master); if (ret) return ret; ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private, false); if (ret) { __netdev_adjacent_dev_remove(dev, upper_dev, 1, up_list); return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico9396.88%350.00%
Andrew Collins11.04%116.67%
Stephen Hemminger11.04%116.67%
David Ahern11.04%116.67%
Total96100.00%6100.00%


static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, struct net_device *upper_dev, u16 ref_nr, struct list_head *up_list, struct list_head *down_list) { __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico4384.31%250.00%
Andrew Collins713.73%125.00%
Stephen Hemminger11.96%125.00%
Total51100.00%4100.00%


static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, struct net_device *upper_dev, void *private, bool master) { return __netdev_adjacent_dev_link_lists(dev, upper_dev, &dev->adj_list.upper, &upper_dev->adj_list.lower, private, master); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico4897.96%375.00%
Stephen Hemminger12.04%125.00%
Total49100.00%4100.00%


static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, struct net_device *upper_dev) { __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1, &dev->adj_list.upper, &upper_dev->adj_list.lower); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico3692.31%250.00%
Andrew Collins25.13%125.00%
Stephen Hemminger12.56%125.00%
Total39100.00%4100.00%


static int __netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev, bool master, void *upper_priv, void *upper_info) { struct netdev_notifier_changeupper_info changeupper_info; int ret = 0; ASSERT_RTNL(); if (dev == upper_dev) return -EBUSY; /* To prevent loops, check if dev is not upper device to upper_dev. */ if (netdev_has_upper_dev(upper_dev, dev)) return -EBUSY; if (netdev_has_upper_dev(dev, upper_dev)) return -EEXIST; if (master && netdev_master_upper_dev_get(dev)) return -EBUSY; changeupper_info.upper_dev = upper_dev; changeupper_info.master = master; changeupper_info.linking = true; changeupper_info.upper_info = upper_info; ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev, &changeupper_info.info); ret = notifier_to_errno(ret); if (ret) return ret; ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, upper_priv, master); if (ret) return ret; ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, &changeupper_info.info); ret = notifier_to_errno(ret); if (ret) goto rollback; return 0; rollback: __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico9647.06%320.00%
David Ahern5426.47%16.67%
Jiri Pirko2110.29%426.67%
Ido Schimmel136.37%16.67%
Américo Wang94.41%16.67%
Linus Torvalds (pre-git)62.94%320.00%
Patrick McHardy31.47%16.67%
Andrew Collins20.98%16.67%
Total204100.00%15100.00%

/** * netdev_upper_dev_link - Add a link to the upper device * @dev: device * @upper_dev: new upper device * * Adds a link to device which is upper to this one. The caller must hold * the RTNL lock. On a failure a negative errno code is returned. * On success the reference counts are adjusted and the function * returns zero. */
int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev) { return __netdev_upper_dev_link(dev, upper_dev, false, NULL, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1448.28%125.00%
Patrick McHardy1137.93%125.00%
Jiri Pirko26.90%125.00%
Veaceslav Falico26.90%125.00%
Total29100.00%4100.00%

EXPORT_SYMBOL(netdev_upper_dev_link); /** * netdev_master_upper_dev_link - Add a master link to the upper device * @dev: device * @upper_dev: new upper device * @upper_priv: upper device private * @upper_info: upper info to be passed down via notifier * * Adds a link to device which is upper to this one. In this case, only * one master upper device can be linked, although other non-master devices * might be linked as well. The caller must hold the RTNL lock. * On a failure a negative errno code is returned. On success the reference * counts are adjusted and the function returns zero. */
int netdev_master_upper_dev_link(struct net_device *dev, struct net_device *upper_dev, void *upper_priv, void *upper_info) { return __netdev_upper_dev_link(dev, upper_dev, true, upper_priv, upper_info); }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico1745.95%120.00%
Américo Wang1129.73%120.00%
Jiri Pirko821.62%240.00%
Patrick McHardy12.70%120.00%
Total37100.00%5100.00%

EXPORT_SYMBOL(netdev_master_upper_dev_link); /** * netdev_upper_dev_unlink - Removes a link to upper device * @dev: device * @upper_dev: new upper device * * Removes a link to device which is upper to this one. The caller must hold * the RTNL lock. */
void netdev_upper_dev_unlink(struct net_device *dev, struct net_device *upper_dev) { struct netdev_notifier_changeupper_info changeupper_info; ASSERT_RTNL(); changeupper_info.upper_dev = upper_dev; changeupper_info.master = netdev_master_upper_dev_get(dev) == upper_dev; changeupper_info.linking = false; call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev, &changeupper_info.info); __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, &changeupper_info.info); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko5065.79%342.86%
Patrick McHardy1317.11%114.29%
Américo Wang1114.47%114.29%
Veaceslav Falico11.32%114.29%
Linus Torvalds (pre-git)11.32%114.29%
Total76100.00%7100.00%

EXPORT_SYMBOL(netdev_upper_dev_unlink); /** * netdev_bonding_info_change - Dispatch event about slave change * @dev: device * @bonding_info: info to dispatch * * Send NETDEV_BONDING_INFO to netdev notifiers with info. * The caller must hold the RTNL lock. */
void netdev_bonding_info_change(struct net_device *dev, struct netdev_bonding_info *bonding_info) { struct netdev_notifier_bonding_info info; memcpy(&info.bonding_info, bonding_info, sizeof(struct netdev_bonding_info)); call_netdevice_notifiers_info(NETDEV_BONDING_INFO, dev, &info.info); }

Contributors

PersonTokensPropCommitsCommitProp
Moni Shoua47100.00%1100.00%
Total47100.00%1100.00%

EXPORT_SYMBOL(netdev_bonding_info_change);
static void netdev_adjacent_add_links(struct net_device *dev) { struct netdev_adjacent *iter; struct net *net = dev_net(dev); list_for_each_entry(iter, &dev->adj_list.upper, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_add(iter->dev, dev, &iter->dev->adj_list.lower); netdev_adjacent_sysfs_add(dev, iter->dev, &dev->adj_list.upper); } list_for_each_entry(iter, &dev->adj_list.lower, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_add(iter->dev, dev, &iter->dev->adj_list.upper); netdev_adjacent_sysfs_add(dev, iter->dev, &dev->adj_list.lower); } }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Y. Fomichev14599.32%150.00%
Eric Dumazet10.68%150.00%
Total146100.00%2100.00%


static void netdev_adjacent_del_links(struct net_device *dev) { struct netdev_adjacent *iter; struct net *net = dev_net(dev); list_for_each_entry(iter, &dev->adj_list.upper, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_del(iter->dev, dev->name, &iter->dev->adj_list.lower); netdev_adjacent_sysfs_del(dev, iter->dev->name, &dev->adj_list.upper); } list_for_each_entry(iter, &dev->adj_list.lower, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_del(iter->dev, dev->name, &iter->dev->adj_list.upper); netdev_adjacent_sysfs_del(dev, iter->dev->name, &dev->adj_list.lower); } }

Contributors

PersonTokensPropCommitsCommitProp
Alexander Y. Fomichev15399.35%150.00%
Eric Dumazet10.65%150.00%
Total154100.00%2100.00%


void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) { struct netdev_adjacent *iter; struct net *net = dev_net(dev); list_for_each_entry(iter, &dev->adj_list.upper, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_del(iter->dev, oldname, &iter->dev->adj_list.lower); netdev_adjacent_sysfs_add(iter->dev, dev, &iter->dev->adj_list.lower); } list_for_each_entry(iter, &dev->adj_list.lower, list) { if (!net_eq(net, dev_net(iter->dev))) continue; netdev_adjacent_sysfs_del(iter->dev, oldname, &iter->dev->adj_list.upper); netdev_adjacent_sysfs_add(iter->dev, dev, &iter->dev->adj_list.upper); } }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico11172.55%266.67%
Alexander Y. Fomichev4227.45%133.33%
Total153100.00%3100.00%


void *netdev_lower_dev_get_private(struct net_device *dev, struct net_device *lower_dev) { struct netdev_adjacent *lower; if (!lower_dev) return NULL; lower = __netdev_find_adj(lower_dev, &dev->adj_list.lower); if (!lower) return NULL; return lower->private; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico56100.00%1100.00%
Total56100.00%1100.00%

EXPORT_SYMBOL(netdev_lower_dev_get_private);
int dev_get_nest_level(struct net_device *dev) { struct net_device *lower = NULL; struct list_head *iter; int max_nest = -1; int nest; ASSERT_RTNL(); netdev_for_each_lower_dev(dev, lower, iter) { nest = dev_get_nest_level(lower); if (max_nest < nest) max_nest = nest; } return max_nest + 1; }

Contributors

PersonTokensPropCommitsCommitProp
Vlad Yasevich6496.97%150.00%
Sabrina Dubroca23.03%150.00%
Total66100.00%2100.00%

EXPORT_SYMBOL(dev_get_nest_level); /** * netdev_lower_change - Dispatch event about lower device state change * @lower_dev: device * @lower_state_info: state to dispatch * * Send NETDEV_CHANGELOWERSTATE to netdev notifiers with info. * The caller must hold the RTNL lock. */
void netdev_lower_state_changed(struct net_device *lower_dev, void *lower_state_info) { struct netdev_notifier_changelowerstate_info changelowerstate_info; ASSERT_RTNL(); changelowerstate_info.lower_state_info = lower_state_info; call_netdevice_notifiers_info(NETDEV_CHANGELOWERSTATE, lower_dev, &changelowerstate_info.info); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko39100.00%1100.00%
Total39100.00%1100.00%

EXPORT_SYMBOL(netdev_lower_state_changed);
static void dev_change_rx_flags(struct net_device *dev, int flags) { const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_change_rx_flags) ops->ndo_change_rx_flags(dev, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang2051.28%133.33%
Stephen Hemminger1948.72%266.67%
Total39100.00%3100.00%


static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) { unsigned int old_flags = dev->flags; kuid_t uid; kgid_t gid; ASSERT_RTNL(); dev->flags |= IFF_PROMISC; dev->promiscuity += inc; if (dev->promiscuity == 0) { /* * Avoid overflow. * If inc causes overflow, untouch promisc and return error. */ if (inc < 0) dev->flags &= ~IFF_PROMISC; else { dev->promiscuity -= inc; pr_warn("%s: promiscuity touches roof, set promiscuity failed. promiscuity feature of device might be broken.\n", dev->name); return -EOVERFLOW; } } if (dev->flags != old_flags) { pr_info("device %s %s promiscuous mode\n", dev->name, dev->flags & IFF_PROMISC ? "entered" : "left"); if (audit_enabled) { current_uid_gid(&uid, &gid); audit_log(current->audit_context, GFP_ATOMIC, AUDIT_ANOM_PROMISCUOUS, "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u", dev->name, (dev->flags & IFF_PROMISC), (old_flags & IFF_PROMISC), from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, uid), from_kgid(&init_user_ns, gid), audit_get_sessionid(current)); } dev_change_rx_flags(dev, IFF_PROMISC); } if (notify) __dev_notify_flags(dev, old_flags, IFF_PROMISC); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang16875.68%133.33%
Stephen Hemminger3817.12%133.33%
Nicolas Dichtel167.21%133.33%
Total222100.00%3100.00%

/** * dev_set_promiscuity - update promiscuity count on a device * @dev: device * @inc: modifier * * Add or remove promiscuity from a device. While the count in the device * remains above zero the interface remains promiscuous. Once it hits zero * the device reverts back to normal filtering operation. A negative inc * value is used to drop promiscuity on the device. * Return 0 if successful or a negative errno code on error. */
int dev_set_promiscuity(struct net_device *dev, int inc) { unsigned int old_flags = dev->flags; int err; err = __dev_set_promiscuity(dev, inc, true); if (err < 0) return err; if (dev->flags != old_flags) dev_set_rx_mode(dev); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1830.00%112.50%
Jay Vosburgh1830.00%112.50%
Vlad Dogaru915.00%112.50%
Jiri Pirko58.33%225.00%
Theodore Y. Ts'o46.67%112.50%
Stephen Hemminger46.67%112.50%
Nicolas Dichtel23.33%112.50%
Total60100.00%8100.00%

EXPORT_SYMBOL(dev_set_promiscuity);
static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify) { unsigned int old_flags = dev->flags, old_gflags = dev->gflags; ASSERT_RTNL(); dev->flags |= IFF_ALLMULTI; dev->allmulti += inc; if (dev->allmulti == 0) { /* * Avoid overflow. * If inc causes overflow, untouch allmulti and return error. */ if (inc < 0) dev->flags &= ~IFF_ALLMULTI; else { dev->allmulti -= inc; pr_warn("%s: allmulti touches roof, set allmulti failed. allmulti feature of device might be broken.\n", dev->name); return -EOVERFLOW; } } if (dev->flags ^ old_flags) { dev_change_rx_flags(dev, IFF_ALLMULTI); dev_set_rx_mode(dev); if (notify) __dev_notify_flags(dev, old_flags, dev->gflags ^ old_gflags); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang7455.22%133.33%
Jiri Pirko3223.88%133.33%
Nicolas Dichtel2820.90%133.33%
Total134100.00%3100.00%

/** * dev_set_allmulti - update allmulti count on a device * @dev: device * @inc: modifier * * Add or remove reception of all multicast frames to a device. While the * count in the device remains above zero the interface remains listening * to all interfaces. Once it hits zero the device reverts back to normal * filtering operation. A negative @inc value is used to drop the counter * when releasing a resource needing all multicasts. * Return 0 if successful or a negative errno code on error. */
int dev_set_allmulti(struct net_device *dev, int inc) { return __dev_set_allmulti(dev, inc, true); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Dichtel23100.00%1100.00%
Total23100.00%1100.00%

EXPORT_SYMBOL(dev_set_allmulti); /* * Upload unicast and multicast address lists to device and * configure RX filtering. When the device doesn't support unicast * filtering it is put in promiscuous mode while unicast addresses * are present. */
void __dev_set_rx_mode(struct net_device *dev) { const struct net_device_ops *ops = dev->netdev_ops; /* dev_open will call this function so the list will stay sane. */ if (!(dev->flags&IFF_UP)) return; if (!netif_device_present(dev)) return; if (!(dev->priv_flags & IFF_UNICAST_FLT)) { /* Unicast addresses changes may only happen under the rtnl, * therefore calling __dev_set_promiscuity here is safe. */ if (!netdev_uc_empty(dev) && !dev->uc_promisc) { __dev_set_promiscuity(dev, 1, false); dev->uc_promisc = true; } else if (netdev_uc_empty(dev) && dev->uc_promisc) { __dev_set_promiscuity(dev, -1, false); dev->uc_promisc = false; } } if (ops->ndo_set_rx_mode) ops->ndo_set_rx_mode(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang7558.14%19.09%
Linus Torvalds (pre-git)1612.40%436.36%
Jeff Garzik1511.63%19.09%
Arnaldo Carvalho de Melo86.20%19.09%
Matt Domsch86.20%19.09%
Nicolas Dichtel43.10%19.09%
Roland Dreier21.55%19.09%
John Dykstra10.78%19.09%
Total129100.00%11100.00%


void dev_set_rx_mode(struct net_device *dev) { netif_addr_lock_bh(dev); __dev_set_rx_mode(dev); netif_addr_unlock_bh(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1872.00%150.00%
Jeff Garzik728.00%150.00%
Total25100.00%2100.00%

/** * dev_get_flags - get flags reported to userspace * @dev: device * * Get the combination of flag bits exported through APIs to userspace. */
unsigned int dev_get_flags(const struct net_device *dev) { unsigned int flags; flags = (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI | IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) | (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); if (netif_running(dev)) { if (netif_oper_up(dev)) flags |= IFF_RUNNING; if (netif_carrier_ok(dev)) flags |= IFF_LOWER_UP; if (netif_dormant(dev)) flags |= IFF_DORMANT; } return flags; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang6569.15%120.00%
Jeff Garzik1718.09%120.00%
Linus Torvalds (pre-git)99.57%240.00%
Jarek Poplawski33.19%120.00%
Total94100.00%5100.00%

EXPORT_SYMBOL(dev_get_flags);
int __dev_change_flags(struct net_device *dev, unsigned int flags) { unsigned int old_flags = dev->flags; int ret; ASSERT_RTNL(); /* * Set the flags on our device. */ dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | IFF_AUTOMEDIA)) | (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | IFF_ALLMULTI)); /* * Load in the correct multicast list now the flags have changed. */ if ((old_flags ^ flags) & IFF_MULTICAST) dev_change_rx_flags(dev, IFF_MULTICAST); dev_set_rx_mode(dev); /* * Have we downed the interface. We handle IFF_UP ourselves * according to user attempts to set it, rather than blindly * setting it. */ ret = 0; if ((old_flags ^ flags) & IFF_UP) ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? 1 : -1; unsigned int old_flags = dev->flags; dev->gflags ^= IFF_PROMISC; if (__dev_set_promiscuity(dev, inc, false) >= 0) if (dev->flags != old_flags) dev_set_rx_mode(dev); } /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI * is important. Some (broken) drivers set IFF_PROMISC, when * IFF_ALLMULTI is requested not asking us and not reporting. */ if ((flags ^ dev->gflags) & IFF_ALLMULTI) { int inc = (flags & IFF_ALLMULTI) ? 1 : -1; dev->gflags ^= IFF_ALLMULTI; __dev_set_allmulti(dev, inc, false); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang15665.27%15.88%
Linus Torvalds (pre-git)4317.99%1058.82%
Nicolas Dichtel3112.97%15.88%
Arnaldo Carvalho de Melo31.26%15.88%
Roland Dreier20.84%15.88%
Richard Cochran20.84%15.88%
Tobin C Harding10.42%15.88%
Stephen Hemminger10.42%15.88%
Total239100.00%17100.00%


void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, unsigned int gchanges) { unsigned int changes = dev->flags ^ old_flags; if (gchanges) rtmsg_ifinfo(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC); if (changes & IFF_UP) { if (dev->flags & IFF_UP) call_netdevice_notifiers(NETDEV_UP, dev); else call_netdevice_notifiers(NETDEV_DOWN, dev); } if (dev->flags & IFF_UP && (changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) { struct netdev_notifier_change_info change_info; change_info.flags_changed = changes; call_netdevice_notifiers_info(NETDEV_CHANGE, dev, &change_info.info); } }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang5242.98%111.11%
Linus Torvalds (pre-git)2823.14%444.44%
Jiri Pirko1814.88%111.11%
Nicolas Dichtel1714.05%111.11%
Eric W. Biedermann43.31%111.11%
Alexei Starovoitov21.65%111.11%
Total121100.00%9100.00%

/** * dev_change_flags - change device settings * @dev: device * @flags: device state flags * * Change settings on device based state flags. The flags are * in the userspace exported format. */
int dev_change_flags(struct net_device *dev, unsigned int flags) { int ret; unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags; ret = __dev_change_flags(dev, flags); if (ret < 0) return ret; changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags); __dev_notify_flags(dev, old_flags, changes); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang4758.02%112.50%
Nicolas Dichtel1822.22%225.00%
Linus Torvalds (pre-git)1113.58%337.50%
Jeff Garzik44.94%112.50%
Eric W. Biedermann11.23%112.50%
Total81100.00%8100.00%

EXPORT_SYMBOL(dev_change_flags);
static int __dev_set_mtu(struct net_device *dev, int new_mtu) { const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_change_mtu) return ops->ndo_change_mtu(dev, new_mtu); dev->mtu = new_mtu; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Veaceslav Falico2857.14%133.33%
Américo Wang2040.82%133.33%
Jeff Garzik12.04%133.33%
Total49100.00%3100.00%

/** * dev_set_mtu - Change maximum transfer unit * @dev: device * @new_mtu: new transfer unit * * Change the maximum transfer size of the network device. */
int dev_set_mtu(struct net_device *dev, int new_mtu) { int err, orig_mtu; if (new_mtu == dev->mtu) return 0; /* MTU must be positive, and in range */ if (new_mtu < 0 || new_mtu < dev->min_mtu) { net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", dev->name, new_mtu, dev->min_mtu); return -EINVAL; } if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", dev->name, new_mtu, dev->max_mtu); return -EINVAL; } if (!netif_device_present(dev)) return -ENODEV; err = call_netdevice_notifiers(NETDEV_PRECHANGEMTU, dev); err = notifier_to_errno(err); if (err) return err; orig_mtu = dev->mtu; err = __dev_set_mtu(dev, new_mtu); if (!err) { err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); err = notifier_to_errno(err); if (err) { /* setting mtu back and notifying everyone again, * so that they have a chance to revert changes. */ __dev_set_mtu(dev, orig_mtu); call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); } } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jarod Wilson5829.74%114.29%
Veaceslav Falico5628.72%228.57%
Américo Wang4824.62%114.29%
Linus Torvalds2412.31%114.29%
Jeff Garzik84.10%114.29%
Jakub Kiciński10.51%114.29%
Total195100.00%7100.00%

EXPORT_SYMBOL(dev_set_mtu); /** * dev_set_group - Change group this device belongs to * @dev: device * @new_group: group this device should belong to */
void dev_set_group(struct net_device *dev, int new_group) { dev->group = new_group; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1789.47%150.00%
Linus Torvalds210.53%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL(dev_set_group); /** * dev_set_mac_address - Change Media Access Control Address * @dev: device * @sa: new address * * Change the hardware (MAC) address of the device */
int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) { const struct net_device_ops *ops = dev->netdev_ops; int err; if (!ops->ndo_set_mac_address) return -EOPNOTSUPP; if (sa->sa_family != dev->type) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; err = ops->ndo_set_mac_address(dev, sa); if (err) return err; dev->addr_assign_type = NET_ADDR_SET; call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); add_device_randomness(dev->dev_addr, dev->addr_len); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang7467.27%111.11%
Linus Torvalds (pre-git)2421.82%555.56%
Eric W. Biedermann76.36%222.22%
Linus Torvalds54.55%111.11%
Total110100.00%9100.00%

EXPORT_SYMBOL(dev_set_mac_address); /** * dev_change_carrier - Change device carrier * @dev: device * @new_carrier: new value * * Change device carrier */
int dev_change_carrier(struct net_device *dev, bool new_carrier) { const struct net_device_ops *ops = dev->netdev_ops; if (!ops->ndo_change_carrier) return -EOPNOTSUPP; if (!netif_device_present(dev)) return -ENODEV; return ops->ndo_change_carrier(dev, new_carrier); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang4173.21%150.00%
Linus Torvalds (pre-git)1526.79%150.00%
Total56100.00%2100.00%

EXPORT_SYMBOL(dev_change_carrier); /** * dev_get_phys_port_id - Get device physical port ID * @dev: device * @ppid: port ID * * Get device physical port ID */
int dev_get_phys_port_id(struct net_device *dev, struct netdev_phys_item_id *ppid) { const struct net_device_ops *ops = dev->netdev_ops; if (!ops->ndo_get_phys_port_id) return -EOPNOTSUPP; return ops->ndo_get_phys_port_id(dev, ppid); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Pirko46100.00%2100.00%
Total46100.00%2100.00%

EXPORT_SYMBOL(dev_get_phys_port_id); /** * dev_get_phys_port_name - Get device physical port name * @dev: device * @name: port name * @len: limit of bytes to copy to name * * Get device physical port name */
int dev_get_phys_port_name(struct net_device *dev, char *name, size_t len) { const struct net_device_ops *ops = dev->netdev_ops; if (!ops->ndo_get_phys_port_name) return -EOPNOTSUPP; return ops->ndo_get_phys_port_name(dev, name, len); }

Contributors

PersonTokensPropCommitsCommitProp
David Ahern50100.00%1100.00%
Total50100.00%1100.00%

EXPORT_SYMBOL(dev_get_phys_port_name); /** * dev_change_proto_down - update protocol port state information * @dev: device * @proto_down: new value * * This info can be used by switch drivers to set the phys state of the * port. */
int dev_change_proto_down(struct net_device *dev, bool proto_down) { const struct net_device_ops *ops = dev->netdev_ops; if (!ops->ndo_change_proto_down) return -EOPNOTSUPP; if (!netif_device_present(dev)) return -ENODEV; return ops->ndo_change_proto_down(dev, proto_down); }

Contributors

PersonTokensPropCommitsCommitProp
Anuradha Karuppiah56100.00%1100.00%
Total56100.00%1100.00%

EXPORT_SYMBOL(dev_change_proto_down); /** * dev_change_xdp_fd - set or clear a bpf program for a device rx path * @dev: device * @fd: new program fd or negative value to clear * @flags: xdp-related flags * * Set or clear a bpf program for a device */
int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags) { const struct net_device_ops *ops = dev->netdev_ops; struct bpf_prog *prog = NULL; struct netdev_xdp xdp; int err; ASSERT_RTNL(); if (!ops->ndo_xdp) return -EOPNOTSUPP; if (fd >= 0) { if (flags & XDP_FLAGS_UPDATE_IF_NOEXIST) { memset(&xdp, 0, sizeof(xdp)); xdp.command = XDP_QUERY_PROG; err = ops->ndo_xdp(dev, &xdp); if (err < 0) return err; if (xdp.prog_attached) return -EBUSY; } prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP); if (IS_ERR(prog)) return PTR_ERR(prog); } memset(&xdp, 0, sizeof(xdp)); xdp.command = XDP_SETUP_PROG; xdp.prog = prog; err = ops->ndo_xdp(dev, &xdp); if (err < 0 && prog) bpf_prog_put(prog); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Brenden Blanco11860.51%150.00%
Daniel Borkmann7739.49%150.00%
Total195100.00%2100.00%

/** * dev_new_index - allocate an ifindex * @net: the applicable net namespace * * Returns a suitable unique value for a new device interface * number. The caller must hold the rtnl semaphore or the * dev_base_lock to be sure it remains unique. */
static int dev_new_index(struct net *net) { int ifindex = net->ifindex; for (;;) { if (++ifindex <= 0) ifindex = 1; if (!__dev_get_by_index(net, ifindex)) return net->ifindex = ifindex; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3769.81%342.86%
Pavel Emelyanov815.09%114.29%
Eric W. Biedermann611.32%114.29%
Christoph Hellwig11.89%114.29%
Arnaldo Carvalho de Melo11.89%114.29%
Total53100.00%7100.00%

/* Delayed registration/unregisteration */ static LIST_HEAD(net_todo_list); DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
static void net_set_todo(struct net_device *dev) { list_add_tail(&dev->todo_list, &net_todo_list); dev_net(dev)->dev_unreg_count++; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2273.33%150.00%
Eric W. Biedermann826.67%150.00%
Total30100.00%2100.00%


static void rollback_registered_many(struct list_head *head) { struct net_device *dev, *tmp; LIST_HEAD(close_head); BUG_ON(dev_boot_phase); ASSERT_RTNL(); list_for_each_entry_safe(dev, tmp, head, unreg_list) { /* Some devices call without registering * for initialization unwind. Remove those * devices and proceed with the remaining. */ if (dev->reg_state == NETREG_UNINITIALIZED) { pr_debug("unregister_netdevice: device %s/%p never was registered\n", dev->name, dev); WARN_ON(1); list_del(&dev->unreg_list); continue; } dev->dismantle = true; BUG_ON(dev->reg_state != NETREG_REGISTERED); } /* If device is running, close it first. */ list_for_each_entry(dev, head, unreg_list) list_add_tail(&dev->close_list, &close_head); dev_close_many(&close_head, true); list_for_each_entry(dev, head, unreg_list) { /* And unlink it from device chain. */ unlist_netdevice(dev); dev->reg_state = NETREG_UNREGISTERING; } flush_all_backlogs(); synchronize_net(); list_for_each_entry(dev, head, unreg_list) { struct sk_buff *skb = NULL; /* Shutdown queueing discipline. */ dev_shutdown(dev); /* Notify protocols, that we are about to destroy * this device. They should clean all the things. */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); if (!dev->rtnl_link_ops || dev->rtnl_link_state == RTNL_LINK_INITIALIZED) skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, GFP_KERNEL); /* * Flush the unicast and multicast chains */ dev_uc_flush(dev); dev_mc_flush(dev); if (dev->netdev_ops->ndo_uninit) dev->netdev_ops->ndo_uninit(dev); if (skb) rtmsg_ifinfo_send(skb, dev, GFP_KERNEL); /* Notifier chain MUST detach us all upper devices. */ WARN_ON(netdev_has_any_upper_dev(dev)); WARN_ON(netdev_has_any_lower_dev(dev)); /* Remove entries from kobject tree */ netdev_unregister_kobject(dev); #ifdef CONFIG_XPS /* Remove XPS queueing entries */ netif_reset_xps_queues_gt(dev, 0); #endif } synchronize_net(); list_for_each_entry(dev, head, unreg_list) dev_put(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Lezcano11136.75%14.00%
Mahesh Bandewar3712.25%14.00%
Eric Dumazet3611.92%312.00%
Eric W. Biedermann3411.26%312.00%
Krishna Kumar165.30%14.00%
Octavian Purdila144.64%28.00%
Alexander Duyck134.30%14.00%
Jiri Pirko103.31%416.00%
Roopa Prabhu103.31%14.00%
David Ahern82.65%14.00%
Stephen Hemminger61.99%14.00%
David S. Miller20.66%14.00%
Julian Anastasov10.33%14.00%
Joe Perches10.33%14.00%
Paolo Abeni10.33%14.00%
Ilpo Järvinen10.33%14.00%
Tobin C Harding10.33%14.00%
Total302100.00%25100.00%


static void rollback_registered(struct net_device *dev) { LIST_HEAD(single); list_add(&dev->unreg_list, &single); rollback_registered_many(&single); list_del(&single); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet39100.00%2100.00%
Total39100.00%2100.00%


static netdev_features_t netdev_sync_upper_features(struct net_device *lower, struct net_device *upper, netdev_features_t features) { netdev_features_t upper_disables = NETIF_F_UPPER_DISABLES; netdev_features_t feature; int feature_bit; for_each_netdev_feature(&upper_disables, feature_bit) { feature = __NETIF_F_BIT(feature_bit); if (!(upper->wanted_features & feature) && (features & feature)) { netdev_dbg(lower, "Dropping feature %pNF, upper dev %s has it off.\n", &feature, upper->name); features &= ~feature; } } return features; }

Contributors

PersonTokensPropCommitsCommitProp
Jarod Wilson86100.00%2100.00%
Total86100.00%2100.00%


static void netdev_sync_lower_features(struct net_device *upper, struct net_device *lower, netdev_features_t features) { netdev_features_t upper_disables = NETIF_F_UPPER_DISABLES; netdev_features_t feature; int feature_bit; for_each_netdev_feature(&upper_disables, feature_bit) { feature = __NETIF_F_BIT(feature_bit); if (!(features & feature) && (lower->features & feature)) { netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", &feature, lower->name); lower->wanted_features &= ~feature; netdev_update_features(lower); if (unlikely(lower->features & feature)) netdev_WARN(upper, "failed to disable %pNF on %s!\n", &feature, lower->name); } } }

Contributors

PersonTokensPropCommitsCommitProp
Jarod Wilson115100.00%2100.00%
Total115100.00%2100.00%


static netdev_features_t netdev_fix_features(struct net_device *dev, netdev_features_t features) { /* Fix illegal checksum combinations */ if ((features & NETIF_F_HW_CSUM) && (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { netdev_warn(dev, "mixed HW and IP checksum settings.\n"); features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); } /* TSO requires that SG is present as well. */ if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) { netdev_dbg(dev, "Dropping TSO features since no SG feature.\n"); features &= ~NETIF_F_ALL_TSO; } if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) && !(features & NETIF_F_IP_CSUM)) { netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n"); features &= ~NETIF_F_TSO; features &= ~NETIF_F_TSO_ECN; } if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) && !(features & NETIF_F_IPV6_CSUM)) { netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n"); features &= ~NETIF_F_TSO6; } /* TSO with IPv4 ID mangling requires IPv4 TSO be enabled */ if ((features & NETIF_F_TSO_MANGLEID) && !(features & NETIF_F_TSO)) features &= ~NETIF_F_TSO_MANGLEID; /* TSO ECN requires that TSO is present as well. */ if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN) features &= ~NETIF_F_TSO_ECN; /* Software GSO depends on SG. */ if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG feature.\n"); features &= ~NETIF_F_GSO; } /* UFO needs SG and checksumming */ if (features & NETIF_F_UFO) { /* maybe split UFO into V4 and V6? */ if (!(features & NETIF_F_HW_CSUM) && ((features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) != (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) { netdev_dbg(dev, "Dropping NETIF_F_UFO since no checksum offload features.\n"); features &= ~NETIF_F_UFO; } if (!(features & NETIF_F_SG)) { netdev_dbg(dev, "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\n"); features &= ~NETIF_F_UFO; } } /* GSO partial features require GSO partial be set */ if ((features & dev->gso_partial_features) && !(features & NETIF_F_GSO_PARTIAL)) { netdev_dbg(dev, "Dropping partially supported GSO features since no GSO partial.\n"); features &= ~dev->gso_partial_features; } return features; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu10330.65%17.69%
Michał Mirosław10230.36%753.85%
Pravin B Shelar5616.67%17.69%
Alexander Duyck5516.37%215.38%
Ben Hutchings164.76%17.69%
Tom Herbert41.19%17.69%
Total336100.00%13100.00%


int __netdev_update_features(struct net_device *dev) { struct net_device *upper, *lower; netdev_features_t features; struct list_head *iter; int err = -1; ASSERT_RTNL(); features = netdev_get_wanted_features(dev); if (dev->netdev_ops->ndo_fix_features) features = dev->netdev_ops->ndo_fix_features(dev, features); /* driver might be less strict about feature dependencies */ features = netdev_fix_features(dev, features); /* some features can't be enabled if they're off an an upper device */ netdev_for_each_upper_dev_rcu(dev, upper, iter) features = netdev_sync_upper_features(dev, upper, features); if (dev->features == features) goto sync_lower; netdev_dbg(dev, "Features changed: %pNF -> %pNF\n", &dev->features, &features); if (dev->netdev_ops->ndo_set_features) err = dev->netdev_ops->ndo_set_features(dev, features); else err = 0; if (unlikely(err < 0)) { netdev_err(dev, "set_features() failed (%d); wanted %pNF, left %pNF\n", err, &features, &dev->features); /* return non-0 since some features might have changed and * it's better to fire a spurious notification than miss it */ return -1; } sync_lower: /* some features must be disabled on lower devices when disabled * on an upper device (think: bonding master or bridge) */ netdev_for_each_lower_dev(dev, lower, iter) netdev_sync_lower_features(dev, lower, features); if (!err) dev->features = features; return err < 0 ? 0 : 1; }

Contributors

PersonTokensPropCommitsCommitProp
Michał Mirosław14566.51%444.44%
Jarod Wilson6429.36%222.22%
Nikolay Aleksandrov83.67%222.22%
Michael S. Tsirkin10.46%111.11%
Total218100.00%9100.00%

/** * netdev_update_features - recalculate device features * @dev: the device to check * * Recalculate dev->features set and send notifications if it * has changed. Should be called after driver or hardware dependent * conditions might have changed that influence the features. */
void netdev_update_features(struct net_device *dev) { if (__netdev_update_features(dev)) netdev_features_change(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Michał Mirosław22100.00%2100.00%
Total22100.00%2100.00%

EXPORT_SYMBOL(netdev_update_features); /** * netdev_change_features - recalculate device features * @dev: the device to check * * Recalculate dev->features set and send notifications even * if they have not changed. Should be called instead of * netdev_update_features() if also dev->vlan_features might * have changed to allow the changes to be propagated to stacked * VLAN devices. */
void netdev_change_features(struct net_device *dev) { __netdev_update_features(dev); netdev_features_change(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Michał Mirosław20100.00%1100.00%
Total20100.00%1100.00%

EXPORT_SYMBOL(netdev_change_features); /** * netif_stacked_transfer_operstate - transfer operstate * @rootdev: the root or lower level device to transfer state from * @dev: the device to transfer operstate to * * Transfer operational state from root to device. This is normally * called when a stacking relationship exists between the root * device and the device(a leaf device). */
void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev) { if (rootdev->operstate == IF_OPER_DORMANT) netif_dormant_on(dev); else netif_dormant_off(dev); if (netif_carrier_ok(rootdev)) { if (!netif_carrier_ok(dev)) netif_carrier_on(dev); } else { if (netif_carrier_ok(dev)) netif_carrier_off(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Patrick Mullaney72100.00%1100.00%
Total72100.00%1100.00%

EXPORT_SYMBOL(netif_stacked_transfer_operstate); #ifdef CONFIG_SYSFS
static int netif_alloc_rx_queues(struct net_device *dev) { unsigned int i, count = dev->num_rx_queues; struct netdev_rx_queue *rx; size_t sz = count * sizeof(*rx); BUG_ON(count < 1); rx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); if (!rx) { rx = vzalloc(sz); if (!rx) return -ENOMEM; } dev->_rx = rx; for (i = 0; i < count; i++) rx[i].dev = dev; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet7163.96%125.00%
Pankaj Gupta3127.93%125.00%
Tom Herbert98.11%250.00%
Total111100.00%4100.00%

#endif
static void netdev_init_one_queue(struct net_device *dev, struct netdev_queue *queue, void *_unused) { /* Initialize queue lock */ spin_lock_init(&queue->_xmit_lock); netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); queue->xmit_lock_owner = -1; netdev_queue_numa_node_write(queue, NUMA_NO_NODE); queue->dev = dev; #ifdef CONFIG_BQL dql_init(&queue->dql, HZ); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Changli Gao6180.26%266.67%
Tom Herbert1519.74%133.33%
Total76100.00%3100.00%


static void netif_free_tx_queues(struct net_device *dev) { kvfree(dev->_tx); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet1794.44%150.00%
Américo Wang15.56%150.00%
Total18100.00%2100.00%


static int netif_alloc_netdev_queues(struct net_device *dev) { unsigned int count = dev->num_tx_queues; struct netdev_queue *tx; size_t sz = count * sizeof(*tx); if (count < 1 || count > 0xffff) return -EINVAL; tx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); if (!tx) { tx = vzalloc(sz); if (!tx) return -ENOMEM; } dev->_tx = tx; netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); spin_lock_init(&dev->tx_global_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Tom Herbert5852.25%120.00%
Eric Dumazet4237.84%240.00%
Patrick Mullaney87.21%120.00%
Changli Gao32.70%120.00%
Total111100.00%5100.00%


void netif_tx_stop_all_queues(struct net_device *dev) { unsigned int i; for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq = netdev_get_tx_queue(dev, i); netif_tx_stop_queue(txq); } }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko48100.00%1100.00%
Total48100.00%1100.00%

EXPORT_SYMBOL(netif_tx_stop_all_queues); /** * register_netdevice - register a network device * @dev: device to register * * Take a completed network device structure and add it to the kernel * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * * Callers must hold the rtnl semaphore. You may want * register_netdev() instead of this. * * BUGS: * The locking appears insufficient to guarantee two parallel registers * will not get the same name. */
int register_netdevice(struct net_device *dev) { int ret; struct net *net = dev_net(dev); BUG_ON(dev_boot_phase); ASSERT_RTNL(); might_sleep(); /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); BUG_ON(!net); spin_lock_init(&dev->addr_list_lock); netdev_set_addr_lockdep_class(dev); ret = dev_get_valid_name(net, dev, dev->name); if (ret < 0) goto out; /* Init, if this function is available */ if (dev->netdev_ops->ndo_init) { ret = dev->netdev_ops->ndo_init(dev); if (ret) { if (ret > 0) ret = -EIO; goto out; } } if (((dev->hw_features | dev->features) & NETIF_F_HW_VLAN_CTAG_FILTER) && (!dev->netdev_ops->ndo_vlan_rx_add_vid || !dev->netdev_ops->ndo_vlan_rx_kill_vid)) { netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n"); ret = -EINVAL; goto err_uninit; } ret = -EBUSY; if (!dev->ifindex) dev->ifindex = dev_new_index(net); else if (__dev_get_by_index(net, dev->ifindex)) goto err_uninit; /* Transfer changeable features to wanted_features and enable * software offloads (GSO and GRO). */ dev->hw_features |= NETIF_F_SOFT_FEATURES; dev->features |= NETIF_F_SOFT_FEATURES; dev->wanted_features = dev->features & dev->hw_features; if (!(dev->flags & IFF_LOOPBACK)) dev->hw_features |= NETIF_F_NOCACHE_COPY; /* If IPv4 TCP segmentation offload is supported we should also * allow the device to enable segmenting the frame with the option * of ignoring a static IP ID value. This doesn't enable the * feature itself but allows the user to enable it later. */ if (dev->hw_features & NETIF_F_TSO) dev->hw_features |= NETIF_F_TSO_MANGLEID; if (dev->vlan_features & NETIF_F_TSO) dev->vlan_features |= NETIF_F_TSO_MANGLEID; if (dev->mpls_features & NETIF_F_TSO) dev->mpls_features |= NETIF_F_TSO_MANGLEID; if (dev->hw_enc_features & NETIF_F_TSO) dev->hw_enc_features |= NETIF_F_TSO_MANGLEID; /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. */ dev->vlan_features |= NETIF_F_HIGHDMA; /* Make NETIF_F_SG inheritable to tunnel devices. */ dev->hw_enc_features |= NETIF_F_SG | NETIF_F_GSO_PARTIAL; /* Make NETIF_F_SG inheritable to MPLS. */ dev->mpls_features |= NETIF_F_SG; ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); ret = notifier_to_errno(ret); if (ret) goto err_uninit; ret = netdev_register_kobject(dev); if (ret) goto err_uninit; dev->reg_state = NETREG_REGISTERED; __netdev_update_features(dev); /* * Default initial state at registry is that the * device is present. */ set_bit(__LINK_STATE_PRESENT, &dev->state); linkwatch_init_dev(dev); dev_init_scheduler(dev); dev_hold(dev); list_netdevice(dev); add_device_randomness(dev->dev_addr, dev->addr_len); /* If the device has permanent device address, driver should * set dev_addr and also addr_assign_type should be set to * NET_ADDR_PERM (default value). */ if (dev->addr_assign_type == NET_ADDR_PERM) memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* Notify protocols, that a new device appeared. */ ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); ret = notifier_to_errno(ret); if (ret) { rollback_registered(dev); dev->reg_state = NETREG_UNREGISTERED; } /* * Prevent userspace races by waiting until the network * device is fully setup before sending notifications. */ if (!dev->rtnl_link_ops || dev->rtnl_link_state == RTNL_LINK_INITIALIZED) rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); out: return ret; err_uninit: if (dev->netdev_ops->ndo_uninit) dev->netdev_ops->ndo_uninit(dev); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
Michał Mirosław8716.26%816.00%
David S. Miller6712.52%36.00%
Alexander Duyck5911.03%36.00%
Linus Torvalds (pre-git)519.53%714.00%
Herbert Xu315.79%24.00%
Stephen Hemminger305.61%24.00%
Pavel Emelyanov285.23%24.00%
Jiri Pirko244.49%12.00%
Johannes Berg234.30%12.00%
Andrew Morton224.11%12.00%
Weiping Pan (潘卫平)203.74%12.00%
Eric W. Biedermann173.18%48.00%
Patrick McHardy142.62%24.00%
Theodore Y. Ts'o112.06%12.00%
Daniel Lezcano91.68%12.00%
Pravin B Shelar71.31%12.00%
Simon Horman71.31%12.00%
Tom Herbert61.12%12.00%
Ben Hutchings50.93%12.00%
Arnaldo Carvalho de Melo50.93%12.00%
Brandon Philips50.93%12.00%
Alexei Starovoitov20.37%12.00%
Gao Feng20.37%12.00%
Adrian Bunk10.19%12.00%
Eric Dumazet10.19%12.00%
Ananda Raju10.19%12.00%
Total535100.00%50100.00%

EXPORT_SYMBOL(register_netdevice); /** * init_dummy_netdev - init a dummy network device for NAPI * @dev: device to init * * This takes a network device structure and initialize the minimum * amount of fields so it can be used to schedule NAPI polls without * registering a full blown interface. This is to be used by drivers * that need to tie several hardware interfaces to a single NAPI * poll scheduler due to HW limitations. */
int init_dummy_netdev(struct net_device *dev) { /* Clear everything. Note we don't initialize spinlocks * are they aren't supposed to be taken by any of the * NAPI code and this dummy netdev is supposed to be * only ever used for NAPI polls */ memset(dev, 0, sizeof(struct net_device)); /* make sure we BUG if trying to hit standard * register/unregister code path */ dev->reg_state = NETREG_DUMMY; /* NAPI wants this */ INIT_LIST_HEAD(&dev->napi_list); /* a dummy interface is started by default */ set_bit(__LINK_STATE_PRESENT, &dev->state); set_bit(__LINK_STATE_START, &dev->state); /* Note : We dont allocate pcpu_refcnt for dummy devices, * because users of this 'device' dont need to change * its refcount. */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt6498.46%150.00%
Eric Dumazet11.54%150.00%
Total65100.00%2100.00%

EXPORT_SYMBOL_GPL(init_dummy_netdev); /** * register_netdev - register a network device * @dev: device to register * * Take a completed network device structure and add it to the kernel * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * * This is a wrapper around register_netdevice that takes the rtnl semaphore * and expands the device name if you passed a format string to * alloc_netdev. */
int register_netdev(struct net_device *dev) { int err; rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig29100.00%1100.00%
Total29100.00%1100.00%

EXPORT_SYMBOL(register_netdev);
int netdev_refcnt_read(const struct net_device *dev) { int i, refcnt = 0; for_each_possible_cpu(i) refcnt += *per_cpu_ptr(dev->pcpu_refcnt, i); return refcnt; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet37100.00%1100.00%
Total37100.00%1100.00%

EXPORT_SYMBOL(netdev_refcnt_read); /** * netdev_wait_allrefs - wait until all references are gone. * @dev: target net_device * * This is called when unregistering network devices. * * Any protocol or device that holds a reference should register * for netdevice notification, and cleanup and put back the * reference if they receive an UNREGISTER event. * We can get stuck here if buggy protocols don't correctly * call dev_put. */
static void netdev_wait_allrefs(struct net_device *dev) { unsigned long rebroadcast_time, warning_time; int refcnt; linkwatch_forget_dev(dev); rebroadcast_time = warning_time = jiffies; refcnt = netdev_refcnt_read(dev); while (refcnt != 0) { if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { rtnl_lock(); /* Rebroadcast unregister notification */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); __rtnl_unlock(); rcu_barrier(); rtnl_lock(); call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { /* We must not have linkwatch events * pending on unregister. If this * happens, we simply run the queue * unscheduled, resulting in a noop * for this device. */ linkwatch_run_queue(); } __rtnl_unlock(); rebroadcast_time = jiffies; } msleep(250); refcnt = netdev_refcnt_read(dev); if (time_after(jiffies, warning_time + 10 * HZ)) { pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n", dev->name, refcnt); warning_time = jiffies; } } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller11070.97%111.11%
Eric Dumazet3824.52%444.44%
Stephen Hemminger21.29%111.11%
Nishanth Aravamudan21.29%111.11%
Joe Perches21.29%111.11%
Pavel Emelyanov10.65%111.11%
Total155100.00%9100.00%

/* The sequence is: * * rtnl_lock(); * ... * register_netdevice(x1); * register_netdevice(x2); * ... * unregister_netdevice(y1); * unregister_netdevice(y2); * ... * rtnl_unlock(); * free_netdev(y1); * free_netdev(y2); * * We are invoked by rtnl_unlock(). * This allows us to deal with problems: * 1) We can delete sysfs objects which invoke hotplug * without deadlocking with linkwatch via keventd. * 2) Since we run with the RTNL semaphore not held, we can sleep * safely in order to wait for the netdev refcnt to drop to zero. * * We must not return until all unregister events added during * the interval the lock was held have been completed. */
void netdev_run_todo(void) { struct list_head list; /* Snapshot list, allow later requests */ list_replace_init(&net_todo_list, &list); __rtnl_unlock(); /* Wait for rcu callbacks to finish before next phase */ if (!list_empty(&list)) rcu_barrier(); while (!list_empty(&list)) { struct net_device *dev = list_first_entry(&list, struct net_device, todo_list); list_del(&dev->todo_list); rtnl_lock(); call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); __rtnl_unlock(); if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { pr_err("network todo '%s' but state %d\n", dev->name, dev->reg_state); dump_stack(); continue; } dev->reg_state = NETREG_UNREGISTERED; netdev_wait_allrefs(dev); /* paranoia */ BUG_ON(netdev_refcnt_read(dev)); BUG_ON(!list_empty(&dev->ptype_all)); BUG_ON(!list_empty(&dev->ptype_specific)); WARN_ON(rcu_access_pointer(dev->ip_ptr)); WARN_ON(rcu_access_pointer(dev->ip6_ptr)); WARN_ON(dev->dn_ptr); if (dev->destructor) dev->destructor(dev); /* Report a network device has been unregistered */ rtnl_lock(); dev_net(dev)->dev_unreg_count--; __rtnl_unlock(); wake_up(&netdev_unregistering_wq); /* Free network device */ kobject_put(&dev->dev.kobj); } }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger10846.75%731.82%
David S. Miller3816.45%29.09%
Eric W. Biedermann3314.29%29.09%
Salam Noureddine2410.39%14.55%
Eric Dumazet219.09%627.27%
Ilpo Järvinen31.30%14.55%
Herbert Xu20.87%14.55%
Oleg Nesterov10.43%14.55%
Joe Perches10.43%14.55%
Total231100.00%22100.00%

/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has * all the same fields in the same order as net_device_stats, with only * the type differing, but rtnl_link_stats64 may have additional fields * at the end for newer counters. */
void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, const struct net_device_stats *netdev_stats) { #if BITS_PER_LONG == 64 BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats)); memcpy(stats64, netdev_stats, sizeof(*stats64)); /* zero out counters that only exist in rtnl_link_stats64 */ memset((char *)stats64 + sizeof(*netdev_stats), 0, sizeof(*stats64) - sizeof(*netdev_stats)); #else size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long); const unsigned long *src = (const unsigned long *)netdev_stats; u64 *dst = (u64 *)stats64; BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64)); for (i = 0; i < n; i++) dst[i] = src[i]; /* zero out counters that only exist in rtnl_link_stats64 */ memset((char *)stats64 + n * sizeof(u64), 0, sizeof(*stats64) - n * sizeof(u64)); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Ben Hutchings12463.59%150.00%
Jarod Wilson7136.41%150.00%
Total195100.00%2100.00%

EXPORT_SYMBOL(netdev_stats_to_stats64); /** * dev_get_stats - get network device statistics * @dev: device to get statistics from * @storage: place to store stats * * Get network statistics from device. Return @storage. * The device driver may provide its own method by setting * dev->netdev_ops->get_stats64 or dev->netdev_ops->get_stats; * otherwise the internal statistics structure is used. */
struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, struct rtnl_link_stats64 *storage) { const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_get_stats64) { memset(storage, 0, sizeof(*storage)); ops->ndo_get_stats64(dev, storage); } else if (ops->ndo_get_stats) { netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev)); } else { netdev_stats_to_stats64(storage, &dev->stats); } storage->rx_dropped += atomic_long_read(&dev->rx_dropped); storage->tx_dropped += atomic_long_read(&dev->tx_dropped); storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler); return storage; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet10177.69%450.00%
Ben Hutchings1511.54%225.00%
Jarod Wilson129.23%112.50%
Rusty Russell21.54%112.50%
Total130100.00%8100.00%

EXPORT_SYMBOL(dev_get_stats);
struct netdev_queue *dev_ingress_queue_create(struct net_device *dev) { struct netdev_queue *queue = dev_ingress_queue(dev); #ifdef CONFIG_NET_CLS_ACT if (queue) return queue; queue = kzalloc(sizeof(*queue), GFP_KERNEL); if (!queue) return NULL; netdev_init_one_queue(dev, queue, NULL); RCU_INIT_POINTER(queue->qdisc, &noop_qdisc); queue->qdisc_sleeping = &noop_qdisc; rcu_assign_pointer(dev->ingress_queue, queue); #endif return queue; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6468.82%233.33%
David S. Miller2931.18%466.67%
Total93100.00%6100.00%

static const struct ethtool_ops default_ethtool_ops;
void netdev_set_default_ethtool_ops(struct net_device *dev, const struct ethtool_ops *ops) { if (dev->ethtool_ops == &default_ethtool_ops) dev->ethtool_ops = ops; }

Contributors

PersonTokensPropCommitsCommitProp
Stanislaw Gruszka31100.00%1100.00%
Total31100.00%1100.00%

EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
void netdev_freemem(struct net_device *dev) { char *addr = (char *)dev - dev->padded; kvfree(addr); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet2896.55%150.00%
Américo Wang13.45%150.00%
Total29100.00%2100.00%

/** * alloc_netdev_mqs - allocate network device * @sizeof_priv: size of private data to allocate space for * @name: device name format string * @name_assign_type: origin of device name * @setup: callback to initialize device * @txqs: the number of TX subqueues to allocate * @rxqs: the number of RX subqueues to allocate * * Allocates a struct net_device with private data area for driver use * and performs basic initialization. Also allocates subqueue structs * for each queue on the device. */
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, unsigned char name_assign_type, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs) { struct net_device *dev; size_t alloc_size; struct net_device *p; BUG_ON(strlen(name) >= sizeof(dev->name)); if (txqs < 1) { pr_err("alloc_netdev: Unable to allocate device with zero queues\n"); return NULL; } #ifdef CONFIG_SYSFS if (rxqs < 1) { pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n"); return NULL; } #endif alloc_size = sizeof(struct net_device); if (sizeof_priv) { /* ensure 32-byte alignment of private area */ alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); alloc_size += sizeof_priv; } /* ensure 32-byte alignment of whole construct */ alloc_size += NETDEV_ALIGN - 1; p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); if (!p) p = vzalloc(alloc_size); if (!p) return NULL; dev = PTR_ALIGN(p, NETDEV_ALIGN); dev->padded = (char *)dev - (char *)p; dev->pcpu_refcnt = alloc_percpu(int); if (!dev->pcpu_refcnt) goto free_dev; if (dev_addr_init(dev)) goto free_pcpu; dev_mc_init(dev); dev_uc_init(dev); dev_net_set(dev, &init_net); dev->gso_max_size = GSO_MAX_SIZE; dev->gso_max_segs = GSO_MAX_SEGS; INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); INIT_LIST_HEAD(&dev->close_list); INIT_LIST_HEAD(&dev->link_watch_list); INIT_LIST_HEAD(&dev->adj_list.upper); INIT_LIST_HEAD(&dev->adj_list.lower); INIT_LIST_HEAD(&dev->ptype_all); INIT_LIST_HEAD(&dev->ptype_specific); #ifdef CONFIG_NET_SCHED hash_init(dev->qdisc_hash); #endif dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; setup(dev); if (!dev->tx_queue_len) { dev->priv_flags |= IFF_NO_QUEUE; dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; } dev->num_tx_queues = txqs; dev->real_num_tx_queues = txqs; if (netif_alloc_netdev_queues(dev)) goto free_all; #ifdef CONFIG_SYSFS dev->num_rx_queues = rxqs; dev->real_num_rx_queues = rxqs; if (netif_alloc_rx_queues(dev)) goto free_all; #endif strcpy(dev->name, name); dev->name_assign_type = name_assign_type; dev->group = INIT_NETDEV_GROUP; if (!dev->ethtool_ops) dev->ethtool_ops = &default_ethtool_ops; nf_hook_ingress_init(dev); return dev; free_all: free_netdev(dev); return NULL; free_pcpu: free_percpu(dev->pcpu_refcnt); free_dev: netdev_freemem(dev); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig9419.18%12.33%
Eric Dumazet8918.16%716.28%
David S. Miller6413.06%24.65%
Tom Herbert408.16%24.65%
Jiri Pirko357.14%511.63%
Eric W. Biedermann204.08%36.98%
Phil Sutter204.08%36.98%
Veaceslav Falico204.08%12.33%
Stephen Hemminger204.08%36.98%
Alexey Dobriyan132.65%12.33%
Jiri Kosina122.45%12.33%
Salam Noureddine112.24%12.33%
Tom Gundersen102.04%12.33%
Peter P. Waskiewicz Jr71.43%24.65%
Vlad Dogaru61.22%12.33%
Ben Hutchings61.22%12.33%
Pablo Neira Ayuso51.02%12.33%
Herbert Xu40.82%12.33%
Hideaki Yoshifuji / 吉藤英明40.82%12.33%
Pavel Emelyanov40.82%12.33%
Joe Perches20.41%12.33%
Michael Dalton20.41%12.33%
Jesper Dangaard Brouer10.20%12.33%
Paolo 'Blaisorblade' Giarrusso10.20%12.33%
Total490100.00%43100.00%

EXPORT_SYMBOL(alloc_netdev_mqs); /** * free_netdev - free network device * @dev: device * * This function does the last stage of destroying an allocated device * interface. The reference to the device object is released. If this * is the last reference then it will be freed.Must be called in process * context. */
void free_netdev(struct net_device *dev) { struct napi_struct *p, *n; might_sleep(); netif_free_tx_queues(dev); #ifdef CONFIG_SYSFS kvfree(dev->_rx); #endif kfree(rcu_dereference_protected(dev->ingress_queue, 1)); /* Flush device addresses */ dev_addr_flush(dev); list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) netif_napi_del(p); free_percpu(dev->pcpu_refcnt); dev->pcpu_refcnt = NULL; /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { netdev_freemem(dev); return; } BUG_ON(dev->reg_state != NETREG_UNREGISTERED); dev->reg_state = NETREG_RELEASED; /* will free via device release */ put_device(&dev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger4737.60%212.50%
Eric Dumazet3024.00%637.50%
Herbert Xu2318.40%16.25%
Tom Herbert108.00%16.25%
Peter P. Waskiewicz Jr43.20%16.25%
David S. Miller43.20%16.25%
Greg Kroah-Hartman32.40%16.25%
Jiri Pirko21.60%16.25%
Michael Dalton10.80%16.25%
Pankaj Gupta10.80%16.25%
Total125100.00%16100.00%

EXPORT_SYMBOL(free_netdev); /** * synchronize_net - Synchronize with packet receive processing * * Wait for packets currently being received to be done. * Does not block later packets from starting. */
void synchronize_net(void) { might_sleep(); if (rtnl_is_locked()) synchronize_rcu_expedited(); else synchronize_rcu(); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger1254.55%250.00%
Eric Dumazet940.91%125.00%
Paul E. McKenney14.55%125.00%
Total22100.00%4100.00%

EXPORT_SYMBOL(synchronize_net); /** * unregister_netdevice_queue - remove device from the kernel * @dev: device * @head: list * * This function shuts down a device interface and removes it * from the kernel tables. * If head not NULL, device is queued to be unregistered later. * * Callers must hold the rtnl semaphore. You may want * unregister_netdev() instead of this. */
void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) { ASSERT_RTNL(); if (head) { list_move_tail(&dev->unreg_list, head); } else { rollback_registered(dev); /* Finish processing unregister after unlock */ net_set_todo(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet2450.00%111.11%
Linus Torvalds (pre-git)816.67%111.11%
Stephen Hemminger714.58%333.33%
David S. Miller48.33%111.11%
Herbert Xu36.25%111.11%
Eric W. Biedermann12.08%111.11%
Daniel Lezcano12.08%111.11%
Total48100.00%9100.00%

EXPORT_SYMBOL(unregister_netdevice_queue); /** * unregister_netdevice_many - unregister many devices * @head: list of devices * * Note: As most callers use a stack allocated list_head, * we force a list_del() to make sure stack wont be corrupted later. */
void unregister_netdevice_many(struct list_head *head) { struct net_device *dev; if (!list_empty(head)) { rollback_registered_many(head); list_for_each_entry(dev, head, unreg_list) net_set_todo(dev); list_del(head); } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet48100.00%2100.00%
Total48100.00%2100.00%

EXPORT_SYMBOL(unregister_netdevice_many); /** * unregister_netdev - remove device from the kernel * @dev: device * * This function shuts down a device interface and removes it * from the kernel tables. * * This is just a wrapper for unregister_netdevice that takes * the rtnl semaphore. In general you want to use this and not * unregister_netdevice. */
void unregister_netdev(struct net_device *dev) { rtnl_lock(); unregister_netdevice(dev); rtnl_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig21100.00%1100.00%
Total21100.00%1100.00%

EXPORT_SYMBOL(unregister_netdev); /** * dev_change_net_namespace - move device to different nethost namespace * @dev: device * @net: network namespace * @pat: If not NULL name pattern to try if the current device name * is already taken in the destination network namespace. * * This function shuts down a device interface and moves it * to a new network namespace. On success 0 is returned, on * a failure a netagive errno code is returned. * * Callers must hold the rtnl semaphore. */
int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) { int err; ASSERT_RTNL(); /* Don't allow namespace local devices to be moved. */ err = -EINVAL; if (dev->features & NETIF_F_NETNS_LOCAL) goto out; /* Ensure the device has been registrered */ if (dev->reg_state != NETREG_REGISTERED) goto out; /* Get out if there is nothing todo */ err = 0; if (net_eq(dev_net(dev), net)) goto out; /* Pick the destination device name, and ensure * we can use it in the destination network namespace. */ err = -EEXIST; if (__dev_get_by_name(net, dev->name)) { /* We get here if we can't use the current device name */ if (!pat) goto out; if (dev_get_valid_name(net, dev, pat) < 0) goto out; } /* * And now a mini version of register_netdevice unregister_netdevice. */ /* If device is running close it first. */ dev_close(dev); /* And unlink it from device chain */ err = -ENODEV; unlist_netdevice(dev); synchronize_net(); /* Shutdown queueing discipline. */ dev_shutdown(dev); /* Notify protocols, that we are about to destroy * this device. They should clean all the things. * * Note that dev->reg_state stays at NETREG_REGISTERED. * This is wanted because this way 8021q and macvlan know * the device is just moving and can keep their slaves up. */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); rcu_barrier(); call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); /* * Flush the unicast and multicast chains */ dev_uc_flush(dev); dev_mc_flush(dev); /* Send a netdev-removed uevent to the old namespace */ kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); netdev_adjacent_del_links(dev); /* Actually switch the network namespace */ dev_net_set(dev, net); /* If there is an ifindex conflict assign a new one */ if (__dev_get_by_index(net, dev->ifindex)) dev->ifindex = dev_new_index(net); /* Send a netdev-add uevent to the new namespace */ kobject_uevent(&dev->dev.kobj, KOBJ_ADD); netdev_adjacent_add_links(dev); /* Fixup kobjects */ err = device_rename(&dev->dev, dev->name); WARN_ON(err); /* Add the device back in the hashes */ list_netdevice(dev); /* Notify protocols, that a new device appeared. */ call_netdevice_notifiers(NETDEV_REGISTER, dev); /* * Prevent userspace races by waiting until the network * device is fully setup before sending notifications. */ rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); synchronize_net(); err = 0; out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann22572.35%523.81%
Serge E. Hallyn268.36%14.76%
Hideaki Yoshifuji / 吉藤英明113.54%29.52%
Octavian Purdila103.22%29.52%
Alexander Y. Fomichev103.22%14.76%
Rusty Russell92.89%14.76%
Jiri Pirko82.57%419.05%
Gao Feng61.93%29.52%
Alexei Starovoitov41.29%14.76%
Daniel Lezcano10.32%14.76%
Tobin C Harding10.32%14.76%
Total311100.00%21100.00%

EXPORT_SYMBOL_GPL(dev_change_net_namespace);
static int dev_cpu_dead(unsigned int oldcpu) { struct sk_buff **list_skb; struct sk_buff *skb; unsigned int cpu; struct softnet_data *sd, *oldsd; local_irq_disable(); cpu = smp_processor_id(); sd = &per_cpu(softnet_data, cpu); oldsd = &per_cpu(softnet_data, oldcpu); /* Find end of our completion_queue. */ list_skb = &sd->completion_queue; while (*list_skb) list_skb = &(*list_skb)->next; /* Append completion queue from offline CPU. */ *list_skb = oldsd->completion_queue; oldsd->completion_queue = NULL; /* Append output queue from offline CPU. */ if (oldsd->output_queue) { *sd->output_queue_tailp = oldsd->output_queue; sd->output_queue_tailp = oldsd->output_queue_tailp; oldsd->output_queue = NULL; oldsd->output_queue_tailp = &oldsd->output_queue; } /* Append NAPI poll list from offline CPU, with one exception : * process_backlog() must be called by cpu owning percpu backlog. * We properly handle process_queue & input_pkt_queue later. */ while (!list_empty(&oldsd->poll_list)) { struct napi_struct *napi = list_first_entry(&oldsd->poll_list, struct napi_struct, poll_list); list_del_init(&napi->poll_list); if (napi->poll == process_backlog) napi->state = 0; else ____napi_schedule(sd, napi); } raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_enable(); /* Process offline CPU's input_pkt_queue */ while ((skb = __skb_dequeue(&oldsd->process_queue))) { netif_rx_ni(skb); input_queue_head_incr(oldsd); } while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) { netif_rx_ni(skb); input_queue_head_incr(oldsd); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rusty Russell12647.55%110.00%
Changli Gao4215.85%220.00%
Eric Dumazet3914.72%220.00%
Heiko Carstens259.43%110.00%
Tom Herbert166.04%220.00%
Eric W. Biedermann134.91%110.00%
Sebastian Andrzej Siewior41.51%110.00%
Total265100.00%10100.00%

/** * netdev_increment_features - increment feature set by one * @all: current feature set * @one: new feature set * @mask: mask feature set * * Computes a new feature set after adding a device with feature set * @one to the master device with current feature set @all. Will not * enable anything that is off in @mask. Returns the new feature set. */
netdev_features_t netdev_increment_features(netdev_features_t all, netdev_features_t one, netdev_features_t mask) { if (mask & NETIF_F_HW_CSUM) mask |= NETIF_F_CSUM_MASK; mask |= NETIF_F_VLAN_CHALLENGED; all |= one & (NETIF_F_ONE_FOR_ALL | NETIF_F_CSUM_MASK) & mask; all &= one | ~NETIF_F_ALL_FOR_ALL; /* If one device supports hw checksumming, set for all. */ if (all & NETIF_F_HW_CSUM) all &= ~(NETIF_F_CSUM_MASK & ~NETIF_F_HW_CSUM); return all; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu3247.76%228.57%
Michał Mirosław2232.84%228.57%
Tom Herbert1319.40%342.86%
Total67100.00%7100.00%

EXPORT_SYMBOL(netdev_increment_features);
static struct hlist_head * __net_init netdev_create_hash(void) { int i; struct hlist_head *hash; hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL); if (hash != NULL) for (i = 0; i < NETDEV_HASHENTRIES; i++) INIT_HLIST_HEAD(&hash[i]); return hash; }

Contributors

PersonTokensPropCommitsCommitProp
Pavel Emelyanov6498.46%150.00%
Baruch Siach11.54%150.00%
Total65100.00%2100.00%

/* Initialize per network namespace state */
static int __net_init netdev_init(struct net *net) { if (net != &init_net) INIT_LIST_HEAD(&net->dev_base_head); net->dev_name_head = netdev_create_hash(); if (net->dev_name_head == NULL) goto err_name; net->dev_index_head = netdev_create_hash(); if (net->dev_index_head == NULL) goto err_idx; return 0; err_idx: kfree(net->dev_name_head); err_name: return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann3644.44%19.09%
Pavel Emelyanov2227.16%218.18%
Mark D Rustad78.64%19.09%
Stephen Hemminger67.41%218.18%
Linus Torvalds (pre-git)44.94%218.18%
Arnaldo Carvalho de Melo33.70%19.09%
Kai Germaschewski33.70%218.18%
Total81100.00%11100.00%

/** * netdev_drivername - network driver for the device * @dev: network device * * Determine network driver for device. */
const char *netdev_drivername(const struct net_device *dev) { const struct device_driver *driver; const struct device *parent; const char *empty = ""; parent = dev->dev.parent; if (!parent) return empty; driver = parent->driver; if (driver && driver->name) return driver->name; return empty; }

Contributors

PersonTokensPropCommitsCommitProp
Arjan van de Ven5578.57%133.33%
David S. Miller1217.14%133.33%
Stephen Hemminger34.29%133.33%
Total70100.00%3100.00%


static void __netdev_printk(const char *level, const struct net_device *dev, struct va_format *vaf) { if (dev && dev->dev.parent) { dev_printk_emit(level[1] - '0', dev->dev.parent, "%s %s %s%s: %pV", dev_driver_string(dev->dev.parent), dev_name(dev->dev.parent), netdev_name(dev), netdev_reg_state(dev), vaf); } else if (dev) { printk("%s%s%s: %pV", level, netdev_name(dev), netdev_reg_state(dev), vaf); } else { printk("%s(NULL net_device): %pV", level, vaf); } }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches10890.00%480.00%
Veaceslav Falico1210.00%120.00%
Total120100.00%5100.00%


void netdev_printk(const char *level, const struct net_device *dev, const char *format, ...) { struct va_format vaf; va_list args; va_start(args, format); vaf.fmt = format; vaf.va = &args; __netdev_printk(level, dev, &vaf); va_end(args); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Perches65100.00%2100.00%
Total65100.00%2100.00%

EXPORT_SYMBOL(netdev_printk); #define define_netdev_printk_level(func, level) \ void func(const struct net_device *dev, const char *fmt, ...) \ { \ struct va_format vaf; \ va_list args; \ \ va_start(args, fmt); \ \ vaf.fmt = fmt; \ vaf.va = &args; \ \ __netdev_printk(level, dev, &vaf); \ \ va_end(args); \ } \ EXPORT_SYMBOL(func); define_netdev_printk_level(netdev_emerg, KERN_EMERG); define_netdev_printk_level(netdev_alert, KERN_ALERT); define_netdev_printk_level(netdev_crit, KERN_CRIT); define_netdev_printk_level(netdev_err, KERN_ERR); define_netdev_printk_level(netdev_warn, KERN_WARNING); define_netdev_printk_level(netdev_notice, KERN_NOTICE); define_netdev_printk_level(netdev_info, KERN_INFO);
static void __net_exit netdev_exit(struct net *net) { kfree(net->dev_name_head); kfree(net->dev_index_head); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann2596.15%150.00%
Pavel Emelyanov13.85%150.00%
Total26100.00%2100.00%

static struct pernet_operations __net_initdata netdev_net_ops = { .init = netdev_init, .exit = netdev_exit, };
static void __net_exit default_device_exit(struct net *net) { struct net_device *dev, *aux; /* * Push all migratable network devices back to the * initial network namespace */ rtnl_lock(); for_each_netdev_safe(net, dev, aux) { int err; char fb_name[IFNAMSIZ]; /* Ignore unmoveable devices (i.e. loopback) */ if (dev->features & NETIF_F_NETNS_LOCAL) continue; /* Leave virtual devices for the generic cleanup */ if (dev->rtnl_link_ops) continue; /* Push remaining network devices to init_net */ snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); err = dev_change_net_namespace(dev, &init_net, fb_name); if (err) { pr_emerg("%s: failed to move %s to init_net: %d\n", __func__, dev->name, err); BUG(); } } rtnl_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann8777.68%342.86%
Pavel Emelyanov2320.54%228.57%
Lucas De Marchi10.89%114.29%
Joe Perches10.89%114.29%
Total112100.00%7100.00%


static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) { /* Return with the rtnl_lock held when there are no network * devices unregistering in any network namespace in net_list. */ struct net *net; bool unregistering; DEFINE_WAIT_FUNC(wait, woken_wake_function); add_wait_queue(&netdev_unregistering_wq, &wait); for (;;) { unregistering = false; rtnl_lock(); list_for_each_entry(net, net_list, exit_list) { if (net->dev_unreg_count > 0) { unregistering = true; break; } } if (!unregistering) break; __rtnl_unlock(); wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } remove_wait_queue(&netdev_unregistering_wq, &wait); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann8480.77%150.00%
Peter Zijlstra2019.23%150.00%
Total104100.00%2100.00%


static void __net_exit default_device_exit_batch(struct list_head *net_list) { /* At exit all network devices most be removed from a network * namespace. Do this in the reverse order of registration. * Do this across as many network namespaces as possible to * improve batching efficiency. */ struct net_device *dev; struct net *net; LIST_HEAD(dev_kill_list); /* To prevent network device cleanup code from dereferencing * loopback devices or network devices that have been freed * wait here for all pending unregistrations to complete, * before unregistring the loopback device and allowing the * network namespace be freed. * * The netdev todo list containing all network devices * unregistrations that happen in default_device_exit_batch * will run in the rtnl_unlock() at the end of * default_device_exit_batch. */ rtnl_lock_unregistering(net_list); list_for_each_entry(net, net_list, exit_list) { for_each_netdev_reverse(net, dev) { if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) dev->rtnl_link_ops->dellink(dev, &dev_kill_list); else unregister_netdevice_queue(dev, &dev_kill_list); } } unregister_netdevice_many(&dev_kill_list); rtnl_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann8792.55%250.00%
Jiri Pirko66.38%125.00%
Uwe Kleine-König11.06%125.00%
Total94100.00%4100.00%

static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, .exit_batch = default_device_exit_batch, }; /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not * present) and leaves us with a valid list of present and active devices. * */ /* * This is called single threaded during boot, so no need * to take the rtnl semaphore. */
static int __init net_dev_init(void) { int i, rc = -ENOMEM; BUG_ON(!dev_boot_phase); if (dev_proc_init()) goto out; if (netdev_kobject_init()) goto out; INIT_LIST_HEAD(&ptype_all); for (i = 0; i < PTYPE_HASH_SIZE; i++) INIT_LIST_HEAD(&ptype_base[i]); INIT_LIST_HEAD(&offload_base); if (register_pernet_subsys(&netdev_net_ops)) goto out; /* * Initialise the packet receive queues. */ for_each_possible_cpu(i) { struct work_struct *flush = per_cpu_ptr(&flush_works, i); struct softnet_data *sd = &per_cpu(softnet_data, i); INIT_WORK(flush, flush_backlog); skb_queue_head_init(&sd->input_pkt_queue); skb_queue_head_init(&sd->process_queue); INIT_LIST_HEAD(&sd->poll_list); sd->output_queue_tailp = &sd->output_queue; #ifdef CONFIG_RPS sd->csd.func = rps_trigger_softirq; sd->csd.info = sd; sd->cpu = i; #endif sd->backlog.poll = process_backlog; sd->backlog.weight = weight_p; } dev_boot_phase = 0; /* The loopback device is special if any other network devices * is present in a network namespace the loopback device must * be present. Since we now dynamically allocate and free the * loopback device ensure this invariant is maintained by * keeping the loopback device as the first device on the * list of network devices. Ensuring the loopback devices * is the first device that appears and the last network device * that disappears. */ if (register_pernet_device(&loopback_net_ops)) goto out; if (register_pernet_device(&default_device_ops)) goto out; open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action); rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead", NULL, dev_cpu_dead); WARN_ON(rc < 0); dst_subsys_init(); rc = 0; out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann8029.30%39.68%
Eric Dumazet4014.65%516.13%
Linus Torvalds (pre-git)3914.29%722.58%
Stephen Hemminger248.79%39.68%
Tom Herbert176.23%26.45%
Changli Gao176.23%26.45%
David S. Miller165.86%13.23%
Sebastian Andrzej Siewior155.49%13.23%
Arnaldo Carvalho de Melo72.56%13.23%
Vlad Yasevich62.20%13.23%
Rusty Russell51.83%13.23%
Andi Kleen41.47%13.23%
Thomas Graf10.37%13.23%
Kamezawa Hiroyuki10.37%13.23%
Pavel Emelyanov10.37%13.23%
Total273100.00%31100.00%

subsys_initcall(net_dev_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet443214.17%14615.63%
Alexander Duyck20886.68%212.25%
Herbert Xu20096.42%434.60%
Linus Torvalds (pre-git)17735.67%667.07%
Veaceslav Falico14274.56%151.61%
Stephen Hemminger12854.11%525.57%
Eric W. Biedermann12483.99%262.78%
Américo Wang11493.67%80.86%
Jiri Pirko11343.63%384.07%
David S. Miller10803.45%485.14%
Tom Herbert9453.02%272.89%
Ben Hutchings9232.95%222.36%
David Ahern8302.65%80.86%
Daniel Borkmann4781.53%111.18%
Michał Mirosław4611.47%232.46%
Vlad Yasevich4301.37%101.07%
Jarod Wilson4231.35%60.64%
Changli Gao4171.33%101.07%
Alexander Y. Fomichev4081.30%20.21%
Jarek Poplawski4031.29%30.32%
Pravin B Shelar3911.25%70.75%
John Fastabend3511.12%70.75%
Patrick McHardy3141.00%131.39%
Salam Noureddine2710.87%10.11%
Joe Perches2650.85%70.75%
Willem de Bruijn2580.82%60.64%
Denys Vlasenko2520.81%20.21%
Krishna Kumar2510.80%30.32%
Octavian Purdila2410.77%30.32%
Jerry Chu2380.76%30.32%
Linus Torvalds2350.75%111.18%
Jesse Gross2090.67%121.28%
Pavel Emelyanov2060.66%111.18%
Daniel Lezcano2020.65%30.32%
Eliezer Tamir1920.61%10.11%
Nicolas Dichtel1840.59%40.43%
Christoph Hellwig1670.53%40.43%
Rusty Russell1470.47%30.32%
Arnaldo Carvalho de Melo1380.44%90.96%
Brenden Blanco1210.39%10.11%
Paolo Abeni1030.33%10.11%
Simon Horman1030.33%40.43%
Neil Horman1020.33%40.43%
Pablo Neira Ayuso1000.32%20.21%
Jason (Hui) Wang980.31%60.64%
Nicolas Schichan960.31%10.11%
Patrick Mullaney860.27%10.11%
FUJITA Tomonori780.25%10.11%
Mel Gorman780.25%10.11%
Gao Feng760.24%20.21%
Eric Leblond760.24%20.21%
Toshiaki Makita740.24%50.54%
Jeff Garzik700.22%30.32%
Benjamin Herrenschmidt700.22%10.11%
Mahesh Bandewar690.22%30.32%
Michel Machado640.20%10.11%
Anuradha Karuppiah620.20%10.11%
Arjan van de Ven580.19%20.21%
Ding Tianhong530.17%30.32%
Moni Shoua520.17%10.11%
Johannes Berg510.16%30.32%
Julian Anastasov440.14%20.21%
Tom Gundersen420.13%20.21%
Jesper Dangaard Brouer400.13%40.43%
Steffen Klassert400.13%20.21%
Arnd Bergmann390.12%10.11%
David L Stevens390.12%10.11%
Koki Sanagi370.12%30.32%
Stanislaw Gruszka360.12%10.11%
Andi Kleen360.12%20.21%
Thomas Graf360.12%20.21%
Andrew Morton360.12%30.32%
Loic Prylli350.11%10.11%
Brian Haley350.11%10.11%
Or Gerlitz350.11%30.32%
Alexei Starovoitov350.11%20.21%
Michael S. Tsirkin340.11%40.43%
Michal Kubeček320.10%30.32%
Pankaj Gupta320.10%10.11%
Hideaki Yoshifuji / 吉藤英明310.10%30.32%
Jay Vosburgh300.10%20.21%
Ian Campbell300.10%10.11%
Matthias Tafelmeier270.09%10.11%
Aaron Conole270.09%20.21%
Serge E. Hallyn260.08%10.11%
Theodore Y. Ts'o260.08%10.11%
Heiko Carstens250.08%10.11%
Oliver Hartkopp230.07%10.11%
Florian Zumbiehl230.07%10.11%
Roland Dreier230.07%20.21%
Peter Zijlstra220.07%20.21%
Andrew Collins220.07%10.11%
Sebastian Andrzej Siewior220.07%20.21%
Jamal Hadi Salim220.07%10.11%
Konstantin Khlebnikov220.07%10.11%
Phil Sutter200.06%30.32%
Weiping Pan (潘卫平)200.06%10.11%
Yuval Mintz200.06%10.11%
Nikolay Aleksandrov200.06%50.54%
Matt Mackall190.06%30.32%
Florian Westphal180.06%20.21%
Tobin C Harding170.05%20.21%
Maneesh Soni160.05%10.11%
Björn Mork160.05%10.11%
Richard Cochran160.05%20.21%
Wang Chen150.05%30.32%
Vlad Dogaru150.05%10.11%
Martin KaFai Lau130.04%10.11%
Ido Schimmel130.04%10.11%
Peter P. Waskiewicz Jr130.04%40.43%
Alexey Dobriyan130.04%10.11%
Jiri Kosina120.04%10.11%
Alexey Khoroshilov120.04%10.11%
James Morris120.04%10.11%
Sabrina Dubroca110.04%20.21%
Randy Dunlap100.03%40.43%
Roopa Prabhu100.03%10.11%
Christoph Lameter100.03%10.11%
Thomas Gleixner100.03%30.32%
Myungho Jung90.03%10.11%
Robert Love90.03%10.11%
Hariprasad Shenai80.03%10.11%
Rémi Denis-Courmont80.03%20.21%
Li RongQing80.03%30.32%
Matt Domsch80.03%10.11%
Tejun Heo80.03%20.21%
Ingo Molnar80.03%10.11%
Kris Katterjohn80.03%10.11%
François Romieu70.02%10.11%
Ben Greear70.02%10.11%
Mark D Rustad70.02%10.11%
Kai Germaschewski70.02%20.21%
Alan Stern70.02%20.21%
Andy Gospodarek60.02%10.11%
Stefan Rompf60.02%10.11%
Ed L. Cashin60.02%10.11%
Arthur Kepner60.02%10.11%
Sridhar Samudrala60.02%10.11%
Simon Barber60.02%10.11%
Matthew Thode50.02%10.11%
Ilpo Järvinen50.02%10.11%
Nishanth Aravamudan50.02%10.11%
Hannes Frederic Sowa50.02%10.11%
Greg Kroah-Hartman50.02%10.11%
Brandon Philips50.02%10.11%
Michael Dalton50.02%10.11%
Tommy S. Christensen50.02%10.11%
Cristian Bercaru40.01%10.11%
Jochen Friedrich40.01%10.11%
Sergey Lapin40.01%10.11%
Adrian Bunk30.01%30.32%
Rami Rosen30.01%10.11%
Denis V. Lunev30.01%20.21%
Rashika Kheria30.01%10.11%
Patrick Ohly30.01%10.11%
Steve Grubb30.01%10.11%
Christopher Leech30.01%10.11%
Stephen Rothwell30.01%10.11%
Joe Eykholt30.01%10.11%
Matti Linnanvuori30.01%10.11%
Al Viro30.01%20.21%
Michael Chan20.01%10.11%
Masanari Iida20.01%20.21%
Cheng Renquan20.01%10.11%
Bart De Schuymer20.01%10.11%
Javier Martinez Canillas20.01%10.11%
Paul E. McKenney20.01%20.21%
Subash Abhinov Kasiviswanathan20.01%10.11%
Dipankar Sarma20.01%10.11%
Emese Revfy20.01%10.11%
Lucas De Marchi10.00%10.11%
Petr Vandrovec10.00%10.11%
Frédéric Weisbecker10.00%10.11%
Baruch Siach10.00%10.11%
Borislav Petkov10.00%10.11%
Kusanagi Kouichi10.00%10.11%
Igor Maravić10.00%10.11%
Dave Hansen10.00%10.11%
Ananda Raju10.00%10.11%
Kamezawa Hiroyuki10.00%10.11%
Paolo 'Blaisorblade' Giarrusso10.00%10.11%
Jaswinder Singh Rajput10.00%10.11%
John Dykstra10.00%10.11%
Jan Engelhardt10.00%10.11%
Luis de Bethencourt10.00%10.11%
Zhi Yong Wu10.00%10.11%
Oleg Nesterov10.00%10.11%
Steven Cole10.00%10.11%
Jakub Kiciński10.00%10.11%
Uwe Kleine-König10.00%10.11%
Cong Wang0.00%00.00%
Total31278100.00%934100.00%
Directory: net/core
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.