STRUCT NET_DEVICE(9)
π struct net_device(9)
okay bestie, welcome to the Kernel API Manual β¨ β no cap, you're gonna want to sit down for this one. We're talking about struct net_device, and this is Part 1 of 4, so hydrate before you scroll, because there's more coming π«Ά
π¦ NAME π¦
struct net_device β literally the DEVICE structure. that's it. that's the whole vibe. it's the struct, it's the device, it's giving main character energy in the networking stack π
more parts incoming β don't go anywhere, bestie π
β¨ SYNOPSIS β¨
okay bestie, deep breath. struct net_device is the main character struct of the whole networking stack β this is the thing your NIC driver fills in, this is the thing every ip link command is secretly poking at β and she is long. like, "scrolling for twenty minutes" long. so we're doing this in chunks, and every single field is coming with us. no field left behind. periodt. π
quick legend before we dive: those #ifdef / #endif and IS_ENABLED(...) wrappers mean the field only exists in the compiled struct when that kernel config is turned on. so depending on your build, some of these cuties just aren't there. π«Ά
struct net_device {
;
struct {
unsigned long priv_flags:32;
unsigned long lltx:1;
unsigned long netmem_tx:2;
};
const struct net_device_ops *netdev_ops;
const struct header_ops *header_ops;
struct netdev_queue *_tx;
netdev_features_t gso_partial_features;
unsigned int real_num_tx_queues;
unsigned int gso_max_size;
unsigned int gso_ipv4_max_size;
u16 gso_max_segs;
s16 num_tc;
unsigned int mtu;
unsigned short needed_headroom;
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
#ifdef CONFIG_XPS;
struct xps_dev_maps *xps_maps[XPS_MAPS_MAX];
#endif;
#ifdef CONFIG_NETFILTER_EGRESS;
struct nf_hook_entries *nf_hooks_egress;
#endif;
#ifdef CONFIG_NET_XGRESS;
struct bpf_mprog_entry *tcx_egress;
#endif;
;
;
right off the bat we've got an anonymous struct of bitfields β priv_flags:32, lltx:1, netmem_tx:2 β squished into unsigned longs because our girl loves a compact layout. π
then the transmit side of the family: netdev_ops and header_ops (the big callback tables π), _tx, real_num_tx_queues, the gso_* trio and gso_partial_features, num_tc with tc_to_txq[TC_MAX_QUEUE], plus mtu and needed_headroom. then alll the conditional egress bits: xps_maps[XPS_MAPS_MAX] when CONFIG_XPS is on, nf_hooks_egress for CONFIG_NETFILTER_EGRESS, and tcx_egress for CONFIG_NET_XGRESS. and then two lonely ; lines. no thoughts, head empty. π
next chunk, and we're switching to the receive side. the vibe check: sims, states, and features.
union {
struct pcpu_lstats __percpu *lstats;
struct pcpu_sw_netstats __percpu *tstats;
struct pcpu_dstats __percpu *dstats;
};
unsigned long state;
unsigned int flags;
unsigned short hard_header_len;
enum netdev_stat_type pcpu_stat_type:8;
netdev_features_t features;
struct inet6_dev *ip6_ptr;
;
;
struct bpf_prog *xdp_prog;
struct list_head ptype_specific;
int ifindex;
unsigned int real_num_rx_queues;
struct netdev_rx_queue *_rx;
unsigned int gro_max_size;
unsigned int gro_ipv4_max_size;
rx_handler_func_t *rx_handler;
void *rx_handler_data;
possible_net_t nd_net;
#ifdef CONFIG_NETPOLL;
struct netpoll_info *npinfo;
#endif;
#ifdef CONFIG_NET_XGRESS;
struct bpf_mprog_entry *tcx_ingress;
#endif;
;
ok so the union is giving "pick your per-CPU stat flavour": lstats, tstats, or dstats, and pcpu_stat_type:8 is the 8-bit enum telling everyone which one you picked. iconic. β¨
then state, flags, hard_header_len, features, ip6_ptr, and pcpu_stat_type. and yes β two more lil ; lines just vibing. then xdp_prog, ptype_specific, ifindex (the number you see in ip link, ily), real_num_rx_queues, _rx, gro_max_size, gro_ipv4_max_size, rx_handler / rx_handler_data, and nd_net. conditional girlies: npinfo under CONFIG_NETPOLL and tcx_ingress under CONFIG_NET_XGRESS. π
π¦ the identity era
names, addresses, and the whole friend-group of lists:
char name[IFNAMSIZ];
struct netdev_name_node *name_node;
struct dev_ifalias *ifalias;
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
#ifdef CONFIG_DEBUG_NET_SMALL_RTNL;
struct list_head unreg_list_net;
#endif;
struct list_head close_list;
struct list_head ptype_all;
struct {
struct list_head upper;
struct list_head lower;
} adj_list;
xdp_features_t xdp_features;
const struct xdp_metadata_ops *xdp_metadata_ops;
const struct xsk_tx_metadata_ops *xsk_tx_metadata_ops;
unsigned short gflags;
unsigned short needed_tailroom;
netdev_features_t hw_features;
netdev_features_t wanted_features;
netdev_features_t vlan_features;
netdev_features_t hw_enc_features;
netdev_features_t mpls_features;
netdev_features_t mangleid_features;
unsigned int min_mtu;
unsigned int max_mtu;
unsigned short type;
unsigned char min_header_len;
unsigned char name_assign_type;
int group;
struct net_device_stats stats;
struct net_device_core_stats __percpu *core_stats;
atomic_t carrier_up_count;
atomic_t carrier_down_count;
name[IFNAMSIZ] β the actual name, capital-I Iconic. her nickname lives in name_node, her alias in ifalias. then the memory trio mem_end / mem_start / base_addr, and the list-head gang: dev_list, napi_list, unreg_list (plus unreg_list_net when CONFIG_DEBUG_NET_SMALL_RTNL is on), close_list, ptype_all, and that cute anonymous struct with upper / lower living inside adj_list. π«Ά
features, features, features: hw_features, wanted_features, vlan_features, hw_enc_features, mpls_features, mangleid_features. not me listing them like a prayer. π and min_mtu / max_mtu bracketing your mtu. plus type, min_header_len, name_assign_type, group, the classic stats and per-CPU core_stats, and the two atomics counting carrier_up_count / carrier_down_count.
β ops o'clock
every optional callback table in the building, plus the addressing-era fields:
#ifdef CONFIG_WIRELESS_EXT;
const struct iw_handler_def *wireless_handlers;
#endif;
const struct ethtool_ops *ethtool_ops;
#ifdef CONFIG_NET_L3_MASTER_DEV;
const struct l3mdev_ops *l3mdev_ops;
#endif;
#if IS_ENABLED(CONFIG_IPV6);
const struct ndisc_ops *ndisc_ops;
#endif;
#ifdef CONFIG_XFRM_OFFLOAD;
const struct xfrmdev_ops *xfrmdev_ops;
#endif;
#if IS_ENABLED(CONFIG_TLS_DEVICE);
const struct tlsdev_ops *tlsdev_ops;
#endif;
unsigned int operstate;
unsigned char link_mode;
unsigned char if_port;
unsigned char dma;
unsigned char perm_addr[MAX_ADDR_LEN];
unsigned char addr_assign_type;
unsigned char addr_len;
unsigned char upper_level;
unsigned char lower_level;
u8 threaded;
unsigned short neigh_priv_len;
unsigned short dev_id;
unsigned short dev_port;
int irq;
u32 priv_len;
spinlock_t addr_list_lock;
struct netdev_hw_addr_list uc;
struct netdev_hw_addr_list mc;
struct netdev_hw_addr_list dev_addrs;
#ifdef CONFIG_SYSFS;
struct kset *queues_kset;
#endif;
#ifdef CONFIG_LOCKDEP;
struct list_head unlink_list;
#endif;
unsigned int promiscuity;
unsigned int allmulti;
bool uc_promisc;
struct list_head work_node;
netdevice_tracker work_tracker;
unsigned long work_pending;
unsigned long work_core_pending;
struct netdev_hw_addr_list rx_mode_addr_cache;
struct timer_list rx_mode_retry_timer;
unsigned int rx_mode_retry_count;
#ifdef CONFIG_LOCKDEP;
unsigned char nested_level;
#endif;
ethtool_ops is the only unconditional one in that ops parade β everybody else is fenced off: wireless_handlers (CONFIG_WIRELESS_EXT), l3mdev_ops (CONFIG_NET_L3_MASTER_DEV), ndisc_ops (IS_ENABLED(CONFIG_IPV6)), xfrmdev_ops (CONFIG_XFRM_OFFLOAD), tlsdev_ops (IS_ENABLED(CONFIG_TLS_DEVICE)). conditional queens only. π
then the address era: operstate, link_mode, if_port, dma, perm_addr[MAX_ADDR_LEN], addr_assign_type, addr_len, upper_level, lower_level, threaded, neigh_priv_len, dev_id, dev_port, irq, priv_len, and addr_list_lock guarding the three address lists uc, mc, dev_addrs. queues_kset shows up under CONFIG_SYSFS, unlink_list under CONFIG_LOCKDEP.
then the promisc / rx-mode corner: promiscuity, allmulti, uc_promisc, plus work_node, work_tracker, work_pending, work_core_pending, rx_mode_addr_cache, rx_mode_retry_timer, rx_mode_retry_count β and nested_level if CONFIG_LOCKDEP said yes. π this is a lot, bestie, but we're locked in.
π protocol pointers & the queue counts
this is where every subsystem gets a lil guest slot in the struct:
struct in_device *ip_ptr;
struct hlist_head fib_nh_head;
#if IS_ENABLED(CONFIG_VLAN_8021Q);
struct vlan_info *vlan_info;
#endif;
#if IS_ENABLED(CONFIG_NET_DSA);
struct dsa_port *dsa_ptr;
#endif;
#if IS_ENABLED(CONFIG_TIPC);
struct tipc_bearer *tipc_ptr;
#endif;
#if IS_ENABLED(CONFIG_CFG80211);
struct wireless_dev *ieee80211_ptr;
#endif;
#if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN);
struct wpan_dev *ieee802154_ptr;
#endif;
#if IS_ENABLED(CONFIG_MPLS_ROUTING);
struct mpls_dev *mpls_ptr;
#endif;
#if IS_ENABLED(CONFIG_MCTP);
struct mctp_dev *mctp_ptr;
#endif;
#if IS_ENABLED(CONFIG_INET_PSP);
struct psp_dev *psp_dev;
#endif;
const unsigned char *dev_addr;
unsigned int num_rx_queues;
#define GRO_LEGACY_MAX_SIZE 65536u;
#define GRO_MAX_SIZE (8 * 65535u);
unsigned int xdp_zc_max_segs;
struct netdev_queue *ingress_queue;
#ifdef CONFIG_NETFILTER_INGRESS;
struct nf_hook_entries *nf_hooks_ingress;
#endif;
unsigned char broadcast[MAX_ADDR_LEN];
#ifdef CONFIG_RFS_ACCEL;
struct cpu_rmap *rx_cpu_rmap;
#endif;
struct hlist_node index_hlist;
unsigned int num_tx_queues;
struct Qdisc *qdisc;
unsigned int tx_queue_len;
spinlock_t tx_global_lock;
struct xdp_dev_bulk_queue __percpu *xdp_bulkq;
#ifdef CONFIG_NET_SCHED;
unsigned long qdisc_hash[1 << (( 4) - 1)];
#endif;
struct timer_list watchdog_timer;
int watchdog_timeo;
spinlock_t watchdog_lock;
bool watchdog_ref_held;
u32 proto_down_reason;
struct list_head todo_list;
#ifdef CONFIG_PCPU_DEV_REFCNT;
int __percpu *pcpu_refcnt;
#else;
refcount_t dev_refcnt;
#endif;
struct ref_tracker_dir refcnt_tracker;
struct list_head link_watch_list;
u8 reg_state;
bool dismantle;
bool moving_ns;
bool rtnl_link_initializing;
bool needs_free_netdev;
void (*priv_destructor)(struct net_device *dev);
void *ml_priv;
enum netdev_ml_priv_type ml_priv_type;
#if IS_ENABLED(CONFIG_GARP);
struct garp_port *garp_port;
#endif;
#if IS_ENABLED(CONFIG_MRP);
struct mrp_port *mrp_port;
#endif;
#if IS_ENABLED(CONFIG_NET_DROP_MONITOR);
struct dm_hw_stat_delta *dm_private;
#endif;
ip_ptr and fib_nh_head are unconditional; then the guest list: vlan_info, dsa_ptr, tipc_ptr, ieee80211_ptr, ieee802154_ptr (on CONFIG_IEEE802154 or CONFIG_6LOWPAN β either one gets her in π), mpls_ptr, mctp_ptr, psp_dev.
then constants time, and these are literal, copy them exactly:
GRO_LEGACY_MAX_SIZEis65536uGRO_MAX_SIZEis(8 * 65535u)
followed by xdp_zc_max_segs, ingress_queue, nf_hooks_ingress (under CONFIG_NETFILTER_INGRESS), broadcast[MAX_ADDR_LEN], rx_cpu_rmap (under CONFIG_RFS_ACCEL), index_hlist, num_tx_queues, qdisc, tx_queue_len, tx_global_lock, xdp_bulkq, and under CONFIG_NET_SCHED the qdisc_hash[1 << (( 4) - 1)] array. (yes that double space inside (( 4) is in the original, we do not touch it, we respect her.)
the watchdog trio-turned-quartet: watchdog_timer, watchdog_timeo, watchdog_lock, watchdog_ref_held. also proto_down_reason and todo_list.
refcount representation is a whole #ifdef/#else situation, so look closely:
#ifdef CONFIG_PCPU_DEV_REFCNT;
int __percpu *pcpu_refcnt;
#else;
refcount_t dev_refcnt;
#endif;
then refcnt_tracker, link_watch_list, and the registration-state bbs: reg_state, dismantle, moving_ns, rtnl_link_initializing, needs_free_netdev, priv_destructor, ml_priv, ml_priv_type. and more conditional besties: garp_port, mrp_port, dm_private. πΈ
π§ the grand finale of this part
struct device, sysfs groups, more constants, and a truly unhinged number of bools:
struct device dev;
const struct attribute_group *sysfs_groups[5];
const struct attribute_group *sysfs_rx_queue_group;
const struct rtnl_link_ops *rtnl_link_ops;
const struct netdev_stat_ops *stat_ops;
const struct netdev_queue_mgmt_ops *queue_mgmt_ops;
#define GSO_MAX_SEGS 65535u;
#define GSO_LEGACY_MAX_SIZE 65536u;
#define GSO_MAX_SIZE (8 * GSO_MAX_SEGS);
#define TSO_LEGACY_MAX_SIZE 65536;
#define TSO_MAX_SIZE UINT_MAX;
unsigned int tso_max_size;
#define TSO_MAX_SEGS U16_MAX;
u16 tso_max_segs;
#ifdef CONFIG_DCB;
const struct dcbnl_rtnl_ops *dcbnl_ops;
#endif;
u8 prio_tc_map[TC_BITMASK + 1];
#if IS_ENABLED(CONFIG_FCOE);
unsigned int fcoe_ddp_xid;
#endif;
#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO);
struct netprio_map *priomap;
#endif;
struct phy_link_topology *link_topo;
struct phy_device *phydev;
struct sfp_bus *sfp_bus;
struct lock_class_key *qdisc_tx_busylock;
bool proto_down;
bool irq_affinity_auto;
bool rx_cpu_rmap_auto;
unsigned long see_all_hwtstamp_requests:1;
unsigned long change_proto_down:1;
unsigned long netns_immutable:1;
unsigned long fcoe_mtu:1;
struct list_head net_notifier_list;
#if IS_ENABLED(CONFIG_MACSEC);
const struct macsec_ops *macsec_ops;
#endif;
const struct udp_tunnel_nic_info *udp_tunnel_nic_info;
struct udp_tunnel_nic *udp_tunnel_nic;
struct netdev_config *cfg;
struct netdev_config *cfg_pending;
struct ethtool_netdev_state *ethtool;
struct bpf_xdp_entity xdp_state[__MAX_XDP_MODE];
u8 dev_addr_shadow[MAX_ADDR_LEN];
netdevice_tracker linkwatch_dev_tracker;
netdevice_tracker watchdog_dev_tracker;
netdevice_tracker dev_registered_tracker;
struct rtnl_hw_stats64 *offload_xstats_l3;
struct devlink_port *devlink_port;
#if IS_ENABLED(CONFIG_DPLL);
struct dpll_pin *dpll_pin;
#endif;
#if IS_ENABLED(CONFIG_PAGE_POOL);
struct hlist_head page_pools;
#endif;
struct dim_irq_moder *irq_moder;
u64 max_pacing_offload_horizon;
struct napi_config *napi_config;
u32 num_napi_configs;
u32 napi_defer_hard_irqs;
unsigned long gro_flush_timeout;
bool up;
bool request_ops_lock;
okay the macro section deserves a lil scroll of honour, all exact:
GSO_MAX_SEGS=65535uGSO_LEGACY_MAX_SIZE=65536uGSO_MAX_SIZE=(8 * GSO_MAX_SEGS)TSO_LEGACY_MAX_SIZE=65536TSO_MAX_SIZE=UINT_MAXTSO_MAX_SEGS=U16_MAX
with tso_max_size and tso_max_segs as the actual fields sitting between them. dcbnl_ops needs CONFIG_DCB, prio_tc_map[TC_BITMASK + 1] is just there being a map, fcoe_ddp_xid needs IS_ENABLED(CONFIG_FCOE), priomap needs IS_ENABLED(CONFIG_CGROUP_NET_PRIO).
then physical-layer besties link_topo, phydev, sfp_bus, qdisc_tx_busylock, and the flags: proto_down, irq_affinity_auto, rx_cpu_rmap_auto, plus the :1 bitfields see_all_hwtstamp_requests, change_proto_down, netns_immutable, fcoe_mtu, and net_notifier_list. π¦
macsec_ops needs IS_ENABLED(CONFIG_MACSEC). then udp_tunnel_nic_info / udp_tunnel_nic, cfg / cfg_pending, ethtool, xdp_state[__MAX_XDP_MODE], dev_addr_shadow[MAX_ADDR_LEN], three netdevice_trackers (linkwatch_dev_tracker, watchdog_dev_tracker, dev_registered_tracker), offload_xstats_l3, devlink_port, then dpll_pin (CONFIG_DPLL) and page_pools (CONFIG_PAGE_POOL).
and we land on: irq_moder, max_pacing_offload_horizon, napi_config, num_napi_configs, napi_defer_hard_irqs, gro_flush_timeout, up, request_ops_lock.
and that's where this chunk of the struct stops β she keeps going, so don't you dare close the brace yet, bestie. π
no cap, we covered every single field in this stretch, conditionals and macros and all. ate and left no crumbs. π₯
β¦and the struct itself wraps up with these last few fields, bestie β copy them exactly, no cap:
struct mutex lock;
#if IS_ENABLED(CONFIG_NET_SHAPER);
struct net_shaper_hierarchy *net_shaper_hierarchy;
#endif;
struct hlist_head neighbours[NEIGH_NR_TABLES];
struct hwtstamp_provider *hwprov;
u8 priv[];
};
π«Ά Members π«Ά
Okay so this is the member list and it is long β we're going through every single one, no skipping, periodt. π
{unnamed_struct}β anonymous π that's the whole description, bestie.priv_flagsβ flags invisible to userspace, defined as bits; go look atenum netdev_priv_flagsfor the actual definitions πlltxβ device supports lockless Tx. Deprecated for real HW drivers β mainly used by logical interfaces, like bonding and tunnels.netmem_txβ device netmem TX mode β¨netdev_opsβ includes several pointers to callbacks, for when you wanna override thendo_*()functions.header_opsβ includes callbacks for creating, parsing, caching, etc. of Layer 2 headers π_txβ array of TX queues.gso_partial_featuresβ value(s) fromNETIF_F_GSO.real_num_tx_queuesβ number of TX queues currently active in device.gso_max_sizeβ maximum size of generic segmentation offload.gso_ipv4_max_sizeβ maximum size of generic segmentation offload, for IPv4.gso_max_segsβ maximum number of segments that can be passed to the NIC for GSO.num_tcβ number of traffic classes in the net device.mtuβ interface MTU value.needed_headroomβ extra headroom the hardware may need β but not in all cases can this be guaranteed, so don't come for me πtc_to_txqβ XXX: need comments on this one (yes really, that's the official description).xps_mapsβ XXX: need comments on this one too, bestie.nf_hooks_egressβ netfilter hooks executed for egress packets.tcx_egressβ BPF & clsact qdisc specific data for egress processing.{unnamed_union}β anonymous again π«lstatsβ loopback statistics: packets, bytes.tstatsβ tunnel statistics: RX/TX packets, RX/TX bytes.dstatsβ dummy statistics: RX/TX/drop packets, RX/TX bytes.stateβ generic network queuing layer state, seenetdev_state_t.flagsβ interface flags (a la BSD).hard_header_lenβ maximum hardware header length.pcpu_stat_typeβ type of device statistics which the core should allocate/free:none,lstats,tstats,dstats.nonemeans the driver is handling statistics allocation/freeing internally.featuresβ currently active device features.ip6_ptrβ IPv6 specific data.xdp_progβ XDP sockets filter program pointer.ptype_specificβ device-specific, protocol-specific packet handlers.ifindexβ interface index π’real_num_rx_queuesβ number of RX queues currently active in device._rxβ array of RX queues.gro_max_sizeβ maximum size of aggregated packet in generic receive offload (GRO).gro_ipv4_max_sizeβ maximum size of aggregated packet in generic receive offload (GRO), for IPv4.rx_handlerβ handler for received packets.rx_handler_dataβ XXX: need comments on this one. iconic of them honestly.nd_netβ network namespace this network device is inside, protected by lock πnpinfoβ XXX: need comments on this one.tcx_ingressβ BPF & clsact qdisc specific data for ingress processing.nameβ this is the first field of the "visible" part of this structure (i.e. as seen by users in the"Space.c"file). It is the name of the interface π·οΈname_nodeβ name hashlist node.ifaliasβ SNMP alias.mem_endβ shared memory end.mem_startβ shared memory start.base_addrβ device I/O address.dev_listβ the global list of network devices.napi_listβ list entry used for polling NAPI devices.unreg_listβ list entry when we are unregistering the device; see the functionunregister_netdev.unreg_list_netβ list entry when we are unregistering the cross-netns device; see the functionunregister_netdevice_queue_net.close_listβ list entry used when we are closing the device.ptype_allβ device-specific packet handlers for all protocols.adj_listβ directly linked devices, like slaves for bonding βοΈxdp_featuresβ XDP capability supported by the device.xdp_metadata_opsβ includes pointers to XDP metadata callbacks.xsk_tx_metadata_opsβ includes pointers to AF_XDP TX metadata callbacks.gflagsβ global flags (kept as legacy) π«Άneeded_tailroomβ extra tailroom the hardware may need, but not in all cases can this be guaranteed. Some cases also useLL_MAX_HEADERinstead to allocate the skb.hw_featuresβ user-changeable features.wanted_featuresβ user-requested features.vlan_featuresβ mask of features inheritable by VLAN devices.hw_enc_featuresβ mask of features inherited by encapsulating devices. This field indicates what encapsulation offloads the hardware is capable of doing, and drivers will need to set them appropriately πmpls_featuresβ mask of features inheritable by MPLS.mangleid_featuresβ mask of features requiring MANGLEID, will be disabled together with the latter.min_mtuβ interface minimum MTU value.max_mtuβ interface maximum MTU value.typeβ interface hardware type.min_header_lenβ minimum hardware header length.name_assign_typeβ network interface name assignment type.groupβ the group the device belongs to.statsβ statistics struct, which was left as a legacy β usertnl_link_stats64instead.core_statsβ core networking counters, do not use this in drivers.carrier_up_countβ number of times the carrier has been up β¬οΈcarrier_down_countβ number of times the carrier has been down β¬οΈwireless_handlersβ list of functions to handle Wireless Extensions, instead of ioctl; see<net/iw_handler.h>for details.ethtool_opsβ management operations.l3mdev_opsβ Layer 3 master device operations.ndisc_opsβ includes callbacks for different IPv6 neighbour discovery handling. Necessary for e.g. 6LoWPAN π¦xfrmdev_opsβ transformation offload operations.tlsdev_opsβ Transport Layer Security offload operations.operstateβRFC2863operstate.link_modeβ mapping policy to operstate.if_portβ selectable AUI, TP, ...dmaβ DMA channel.perm_addrβ permanent hw address.addr_assign_typeβ hw address assignment type.addr_lenβ hardware address length.upper_levelβ maximum depth level of upper devices.lower_levelβ maximum depth level of lower devices.threadedβ napi threaded state.neigh_priv_lenβ used inneigh_alloc.dev_idβ used to differentiate devices that share the same link layer address.dev_portβ used to differentiate devices that share the same function.irqβ device IRQ number β‘priv_lenβ size of the->privflexible array.addr_list_lockβ XXX: need comments on this one.ucβ unicast mac addresses.mcβ multicast mac addresses π‘dev_addrsβ list of device hw addresses.queues_ksetβ group of all Kobjects in the Tx and RX queues.unlink_listβ asnetif_addr_lockcan be called recursively, keep a list of interfaces to be deleted.promiscuityβ number of times the NIC is told to work in promiscuous mode; if it becomes0the NIC will exit promiscuous mode πallmultiβ counter, enables or disables allmulticast mode.uc_promiscβ counter that indicates promiscuous mode has been enabled due to the need to listen to additional unicast addresses in a device that does not implementndo_set_rx_mode.work_nodeβ list entry for asyncnetdev_workprocessing.work_trackerβ refcount tracker for asyncnetdev_work.work_pendingβ driver-defined pendingnetdev_work, passed tondo_work(seenetdev_work_sched).work_core_pendingβ core-defined pendingnetdev_work(NETDEV_WORK_*).rx_mode_addr_cacheβ recycled snapshot entries for rx_mode work.rx_mode_retry_timerβ timer that re-queues rx_mode work after failure β°rx_mode_retry_countβ number of consecutive retries already scheduled.nested_levelβ used as a parameter ofspin_lock_nestedofdev->addr_list_lock.ip_ptrβ IPv4 specific data.fib_nh_headβ nexthops associated with this netdev.vlan_infoβ VLAN info.dsa_ptrβ dsa specific data.tipc_ptrβ TIPC specific data.ieee80211_ptrβ IEEE 802.11 specific data, assign before registering πΆieee802154_ptrβ IEEE 802.15.4 low-rate Wireless Personal Area Network device struct.mpls_ptrβmpls_devstruct pointer.mctp_ptrβ MCTP specific data.psp_devβ PSP crypto device registered for this netdev πdev_addrβ hw address (before bcast, because most packets are unicast).num_rx_queuesβ number of RX queues allocated atregister_netdevtime.xdp_zc_max_segsβ maximum number of segments supported by AF_XDP zero copy driver.ingress_queueβ XXX: need comments on this one.nf_hooks_ingressβ netfilter hooks executed for ingress packets.broadcastβ hw bcast address π£rx_cpu_rmapβ CPU reverse-mapping for RX completion interrupts, indexed by RX queue number. Assigned by driver. This must only be set if thendo_rx_flow_steeroperation is defined.index_hlistβ device index hash chain.num_tx_queuesβ number of TX queues allocated atalloc_netdev_mqtime.qdiscβ root qdisc from userspace point of view.tx_queue_lenβ max frames per queue allowed.tx_global_lockβ XXX: need comments on this one.xdp_bulkqβ XDP device bulk queue.qdisc_hashβ qdisc hash table.watchdog_timerβ list of timers.watchdog_timeoβ represents the timeout that is used by the watchdog (seedev_watchdog).watchdog_lockβ protectwatchdog_ref_held.watchdog_ref_heldβ true if the watchdog device ref is taken.proto_down_reasonβ reason a netdev interface is held down.todo_listβ delayed register/unregister.pcpu_refcntβ number of references to this device.dev_refcntβ number of references to this device. (yes, two of them, they said what they said π)
okay bestie we're still in the members section, she's long, she's iconic, she contains multitudes π buckle up, here's the rest:
refcnt_trackerβ the tracker directory for tracked references to this device πlink_watch_listβXXX: need comments on this oneπ literally the kernel devs left us on readreg_stateβ the register/unregister state machine, she runs the whole getting-registered pipeline β¨dismantleβ this device is about to be freed, so like... say your goodbyes πmoving_nsβ the device is changing netns, and it's protected bylockπrtnl_link_initializingβ device is being created, so pls suppress events while she's having her moment πneeds_free_netdevβ should unregister performfree_netdev? that's the whole question π«Άpriv_destructorβ called fromunregisterml_privβ mid-layer private (the mid layer's lil secret π€«)ml_priv_typeβ mid-layer private type, the label on the secretgarp_portβ GARP π¦mrp_portβ MRP πΈdm_privateβ drop monitor privatedevβ the class/net/name entry, her whole identity lowkey πsysfs_groupsβ space for optional device, statistics and wireless sysfs groupssysfs_rx_queue_groupβ space for optional per-rx queue attributesrtnl_link_opsβRtnl_link_opsstat_opsβ optional ops for queue-aware statistics πqueue_mgmt_opsβ optional ops for queue managementtso_max_sizeβ device (as in HW) limit on the max TSO request sizetso_max_segsβ device (as in HW) limit on the max TSO segment countdcbnl_opsβ Data Center Bridging netlink opsprio_tc_mapβXXX: need comments on this one(again!! the lore is missing π©)fcoe_ddp_xidβ max exchange id for FCoE LRO by ddppriomapβXXX: need comments on this onelink_topoβ physical link topology tracking attached PHYsphydevβ physical device may attach itself for hardware timestamping β±οΈsfp_busβ attachedstruct sfp_busstructure.qdisc_tx_busylockβ lockdep class annotatingQdisc->busylockspinlockproto_downβ protocol port state information can be sent to the switch driver and used to set the phys state of the switch port.irq_affinity_autoβ driver wants the core to store and re-assign the IRQ affinity. Set bynetif_enable_irq_affinity, then the driver must create a persistent napi bynetif_napi_add_configand finally bind the napi to IRQ (vianetif_napi_set_irq). slay, that's a whole three-step routine πrx_cpu_rmap_autoβ driver wants the core to manage the ARFS rmap. Set by callingnetif_enable_cpu_rmap.see_all_hwtstamp_requestsβ device wants to see calls tondo_hwtstamp_setfor all timestamp requests regardless of source, even if those aren'tHWTSTAMP_SOURCE_NETDEVπchange_proto_downβ device supports setting carrier viaIFLA_PROTO_DOWNnetns_immutableβ interface can't change network namespaces, she's staying right here π«fcoe_mtuβ device supports maximum FCoE MTU, 2158 bytesnet_notifier_listβ list of per-net netdev notifier block that follow this device when it is moved to another network namespace.macsec_opsβ MACsec offloading opsudp_tunnel_nic_infoβ static structure describing the UDP tunnel offload capabilities of the deviceudp_tunnel_nicβ UDP tunnel offload statecfgβ net_device queue-related configurationcfg_pendingβ same ascfgbut when device is being actively reconfigured; includes any changes to the configuration requested by the user, but which may or may not be rejected. suspense?? πethtoolβ ethtool related statexdp_stateβ stores info on attached XDP BPF programsdev_addr_shadowβ copy ofdev_addrto catch direct writes π―linkwatch_dev_trackerβ refcount tracker used by linkwatch.watchdog_dev_trackerβ refcount tracker used by watchdog. πdev_registered_trackerβ tracker for reference held while registeredoffload_xstats_l3β L3 HW stats for this netdevice.devlink_portβ pointer to related devlink port structure. Assigned by a driver before netdev registration usingSET_NETDEV_DEVLINK_PORTmacro. This pointer is static during the time netdevice is registered.dpll_pinβ pointer to the SyncE source pin of a DPLL subsystem, where the clock is recovered.page_poolsβ page pools created for this netdeviceirq_moderβ dim parameters used ifIS_ENABLED(CONFIG_DIMLIB).max_pacing_offload_horizonβ max EDT offload horizon in nsec.napi_configβ an array ofnapi_configstructures containing per-NAPI settings.num_napi_configsβ number of allocated NAPI config structs, always>= max(num_rx_queues, num_tx_queues).napi_defer_hard_irqsβ if not zero, provides a counter that would allow to avoid NIC hard IRQ, on busy queues.gro_flush_timeoutβ timeout for GRO layer in NAPIupβ copy of state'sIFF_UP, but safe to read with justlock. May report false negatives while the device is being opened or closed (lockdoes not protect.ndo_open, or.ndo_close). so like... she's usually right, but not always π«request_ops_lockβ request the core to run allnetdev_opsandethtool_opsunder thelock.lockβ netdev-scope lock, protects a small selection of fields. Should always be taken usingnetdev_lock/netdev_unlockhelpers. Drivers are free to use it for other protection. π
for the drivers that implement shaper or queue API, the scope of this lock is expanded to cover most ndo/queue/ethtool/sysfs operations. Drivers may opt-in to this behavior by setting request_ops_lock.
lock protection mixes with rtnl_lock in multiple ways, fields are either:
- simply protected by the instance lock;
- double protected β writers hold both locks, readers hold either;
- ops protected β protected by the lock held around the NDOs and other callbacks, that is the instance lock on devices for which
netdev_need_ops_lockreturns true, otherwise byrtnl_lock; - double ops protected β always protected by
rtnl_lockbut for devices for whichnetdev_need_ops_lockreturns true β also the instance lock.
simply protects: gro_flush_timeout, napi_defer_hard_irqs, napi_list, net_shaper_hierarchy, reg_state, threaded
double protects: up, moving_ns, nd_net, xdp_features
ops protects: cfg, cfg_pending, ethtool, hwprov
double ops protects: real_num_rx_queues, real_num_tx_queues
also protects some fields in: struct napi_struct, struct netdev_queue, struct netdev_rx_queue β¨
Ordering, aka the queuing rules of the group chat π:
- take after
rtnl_lock - for the case of netdev queue leasing, the netdev-scope lock is taken for both the virtual and the physical device; to prevent deadlocks, the virtual device's lock must always be acquired before the physical device's (see
netdev_nl_queue_create_doit) π do NOT get this backwards net_shaper_hierarchyβ data tracking the current shaper status seeinclude/net/net_shapers.hneighboursβ list heads pointing to this device's neighbours'dev_list, one per address-family.hwprovβ tracks which PTP performs hardware packet time stamping.privβ flexible array containing private data
π DESCRIPTION π
okay so. this is genuinely the funniest part. actually, this whole structure is a big mistake. She mixes I/O data with strictly "high-level" data, and she has to know about almost every data structure used in the INET module. no thoughts, just a struct that knows everything π
interface address info:
FIXME: cleanup struct net_device such that network protocol info moves out.
(yes that's a real FIXME, we're all just living with it π«Ά)
π SEE ALSO π
kernel file ./include/linux/netdevice.h β struct gro_node(9), and then the whole friend group:
napi_is_scheduled(9),napi_schedule(9),napi_schedule_irqoff(9),napi_complete_done(9),napi_synchronize(9),napi_if_scheduled_mark_missed(9)enum netdev_priv_flags(9),netdev_priv(9),netdev_from_priv(9)netif_napi_add(9),netif_napi_add_config(9),netif_napi_add_tx(9),__netif_napi_del(9),netif_napi_del(9)netif_start_queue(9),netif_wake_queue(9),netif_stop_queue(9),netif_queue_stopped(9)netdev_queue_set_dql_min_limit(9),netdev_txq_bql_enqueue_prefetchw(9),netdev_txq_bql_complete_prefetchw(9)netdev_tx_sent_queue(9),netdev_sent_queue(9),netdev_tx_completed_queue(9),netdev_completed_queue(9),netdev_tx_reset_subqueue(9),netdev_reset_queue(9)netdev_cap_txqueue(9),netif_running(9)netif_start_subqueue(9),netif_stop_subqueue(9),__netif_subqueue_stopped(9),netif_subqueue_stopped(9),netif_wake_subqueue(9)netif_attr_test_mask(9),netif_attr_test_online(9),netif_attrmask_next(9),netif_attrmask_next_and(9)netif_is_multiqueue(9),dev_hold(9),dev_put(9),linkwatch_sync_dev(9)netif_carrier_ok(9),netif_dormant_on(9),netif_dormant_off(9),netif_dormant(9),netif_testing_on(9),netif_testing_off(9),netif_testing(9),netif_oper_up(9)netif_device_present(9),netif_tx_lock(9)__dev_uc_sync(9),__dev_uc_unsync(9),__dev_mc_sync(9),__dev_mc_unsync(9)
and that's the whole page bestie, you made it π this one came out of ./include/linux and it's stamped October 2026, and she's filed under struct net_device(9) β go forth and read the source, iykyk πβ¨π
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms