Linux 设备驱动之网络设备驱动
一、 Linux 网络设备驱动的结构
层次 | 核心功能 | 关键数据结构 / 接口 | 与上下层关系 | 典型示例 / 说明 |
---|---|---|---|---|
网络协议接口层 | 向上层协议(如 ARP、IP)提供统一的数据包收发接口,屏蔽底层设备差异 | dev_queue_xmit() (发送接口)netif_rx() (接收接口) | 上层协议(网络层)通过此接口收发数据,下层通过设备接口层注册到协议层 | 实现 “协议无关性”,上层协议无需关心具体硬件,如 IP 层调用dev_queue_xmit() 发送 IP 包 |
网络设备接口层 | 定义统一的设备描述结构体net_device ,规划设备驱动的通用框架 | net_device 结构体(包含设备属性、操作方法) | 向上为协议接口层提供标准化设备操作(如发送 / 接收),向下规范设备驱动的实现格式 | net_device 包含name (设备名,如eth0 )、mtu (最大传输单元)、ops (操作函数指针集合) |
设备驱动功能层 | 实现net_device 结构体中的具体函数,驱动硬件完成数据收发 | hard_start_xmit() (启动发送)中断处理函数(触发接收) | 作为net_device 的具体实现,向上注册到设备接口层,向下直接操作硬件寄存器 / 缓冲区 | 例如e1000_xmit() 函数填充硬件发送队列,e1000_intr() 处理网卡中断并调用netif_rx() 通知协议层 |
网络设备与媒介层 | 完成数据收发的物理实体,包括硬件适配器(如网卡)和传输媒介(如双绞线、光纤) | 物理设备(如 PCIe 网卡)、虚拟设备(如lo 回环接口、VLAN 设备) | 作为驱动功能层的操作对象,向上提供物理层面的信号传输能力 | 支持虚拟设备(如docker0 网桥、tun 隧道设备),实现 “软件定义网络”(SDN)场景 |
在设计具体的网络设备驱动程序时,我们需要完成的主要工作是编写设备驱动功 能层的相关函数以填充 net_device 数据结构的内容并将 net_device 注册入内核
1.1 网络协议接口层
网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口。当上层ARP或IP需要发送数据包时,它将调用网络协议层的dev_queue_xmit()函数发送该数据包,同时需要传递给该函数一个指向struct sk_buff数据结构的指针。dev_queue_xmit()函数的原型为:
同样地,上层对数据包的接收也通过netif_rx()函数传递一个struct sk_buff数据结构的指针来完成。netif_rx()函数的原型为:
sk_buff结构体非常重要,它定义include/linux/skbuff.h文件中,含义为“套接字缓冲器”,用于在linux网络子系统中的各层之间传递数据,是linux网络子系统数据传递的“中枢神经”。
当发送数据包时,linux内核的网络处理模块必须建立一个包含要传输的数据包的sk_buff,然后将sk_buff递交给下层,各层在sk_buff中添加不同的协议头直至交给网络设备发送。同样地,当网络设备从网络媒介上收到数据包后,它必须将收到的数据转换为sk_buff数据结构并传递给上层,各层剥去相应的协议头直至交给用户。sk_buff结构体中的成员如下:
840 struct sk_buff {841 union {842 struct {843 /* These two members must be first to match sk_buff_head. */844 struct sk_buff *next;845 struct sk_buff *prev;846 847 union {848 struct net_device *dev;849 /* Some protocols might use this space to store information,850 * while device pointer would be NULL.851 * UDP receive path is one user.852 */853 unsigned long dev_scratch;854 };855 };856 struct rb_node rbnode; /* used in netem, ip4 defrag, and tcp stack */857 struct list_head list;858 struct llist_node ll_node;859 };860 861 struct sock *sk;862 863 union {864 ktime_t tstamp;865 u64 skb_mstamp_ns; /* earliest departure time */866 };867 /*868 * This is the control buffer. It is free to use for every869 * layer. Please put your private variables there. If you870 * want to keep them across layers you have to do a skb_clone()871 * first. This is owned by whoever has the skb queued ATM.872 */873 char cb[48] __aligned(8);874 875 union {876 struct {877 unsigned long _skb_refdst;878 void (*destructor)(struct sk_buff *skb);879 };880 struct list_head tcp_tsorted_anchor;881 #ifdef CONFIG_NET_SOCK_MSG882 unsigned long _sk_redir;883 #endif884 };885 886 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)887 unsigned long _nfct;888 #endif889 unsigned int len,890 data_len;891 __u16 mac_len,892 hdr_len;893 894 /* Following fields are _not_ copied in __copy_skb_header()895 * Note that queue_mapping is here mostly to fill a hole.896 */897 __u16 queue_mapping;898 899 /* if you move cloned around you also must adapt those constants */900 #ifdef __BIG_ENDIAN_BITFIELD901 #define CLONED_MASK (1 << 7)902 #else903 #define CLONED_MASK 1904 #endif905 #define CLONED_OFFSET offsetof(struct sk_buff, __cloned_offset)906 907 /* private: */908 __u8 __cloned_offset[0];909 /* public: */910 __u8 cloned:1,911 nohdr:1,912 fclone:2,913 peeked:1,914 head_frag:1,915 pfmemalloc:1,916 pp_recycle:1; /* page_pool recycle indicator */917 #ifdef CONFIG_SKB_EXTENSIONS918 __u8 active_extensions;919 #endif920 921 /* Fields enclosed in headers group are copied922 * using a single memcpy() in __copy_skb_header()923 */924 struct_group(headers,925 926 /* private: */927 __u8 __pkt_type_offset[0];928 /* public: */929 __u8 pkt_type:3; /* see PKT_TYPE_MAX */930 __u8 ignore_df:1;931 __u8 dst_pending_confirm:1;932 __u8 ip_summed:2;933 __u8 ooo_okay:1;934 935 /* private: */936 __u8 __mono_tc_offset[0];937 /* public: */938 __u8 mono_delivery_time:1; /* See SKB_MONO_DELIVERY_TIME_MASK */939 #ifdef CONFIG_NET_XGRESS940 __u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */941 __u8 tc_skip_classify:1;942 #endif943 __u8 remcsum_offload:1;944 __u8 csum_complete_sw:1;945 __u8 csum_level:2;946 __u8 inner_protocol_type:1;947 948 __u8 l4_hash:1;949 __u8 sw_hash:1;950 #ifdef CONFIG_WIRELESS951 __u8 wifi_acked_valid:1;952 __u8 wifi_acked:1;953 #endif954 __u8 no_fcs:1;955 /* Indicates the inner headers are valid in the skbuff. */956 __u8 encapsulation:1;957 __u8 encap_hdr_csum:1;958 __u8 csum_valid:1;959 #ifdef CONFIG_IPV6_NDISC_NODETYPE960 __u8 ndisc_nodetype:2;961 #endif962 963 #if IS_ENABLED(CONFIG_IP_VS)964 __u8 ipvs_property:1;965 #endif966 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)967 __u8 nf_trace:1;968 #endif969 #ifdef CONFIG_NET_SWITCHDEV970 __u8 offload_fwd_mark:1;971 __u8 offload_l3_fwd_mark:1;972 #endif973 __u8 redirected:1;974 #ifdef CONFIG_NET_REDIRECT975 __u8 from_ingress:1;976 #endif977 #ifdef CONFIG_NETFILTER_SKIP_EGRESS978 __u8 nf_skip_egress:1;979 #endif980 #ifdef CONFIG_TLS_DEVICE981 __u8 decrypted:1;982 #endif983 __u8 slow_gro:1;984 #if IS_ENABLED(CONFIG_IP_SCTP)985 __u8 csum_not_inet:1;986 #endif987 988 #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS)989 __u16 tc_index; /* traffic control index */990 #endif991 992 u16 alloc_cpu;993 994 union {995 __wsum csum;996 struct {997 __u16 csum_start;998 __u16 csum_offset;999 };
1000 };
1001 __u32 priority;
1002 int skb_iif;
1003 __u32 hash;
1004 union {
1005 u32 vlan_all;
1006 struct {
1007 __be16 vlan_proto;
1008 __u16 vlan_tci;
1009 };
1010 };
1011 #if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)
1012 union {
1013 unsigned int napi_id;
1014 unsigned int sender_cpu;
1015 };
1016 #endif
1017 #ifdef CONFIG_NETWORK_SECMARK
1018 __u32 secmark;
1019 #endif
1020
1021 union {
1022 __u32 mark;
1023 __u32 reserved_tailroom;
1024 };
1025
1026 union {
1027 __be16 inner_protocol;
1028 __u8 inner_ipproto;
1029 };
1030
1031 __u16 inner_transport_header;
1032 __u16 inner_network_header;
1033 __u16 inner_mac_header;
1034
1035 __be16 protocol;
1036 __u16 transport_header;
1037 __u16 network_header;
1038 __u16 mac_header;
1039
1040 #ifdef CONFIG_KCOV
1041 u64 kcov_handle;
1042 #endif
1043
1044 ); /* end headers group */
1045
1046 /* These elements must be at the end, see alloc_skb() for details. */
1047 sk_buff_data_t tail;
1048 sk_buff_data_t end;
1049 unsigned char *head,
1050 *data;
1051 unsigned int truesize;
1052 refcount_t users;
1053
1054 #ifdef CONFIG_SKB_EXTENSIONS
1055 /* only useable after checking ->active_extensions != 0 */
1056 struct skb_ext *extensions;
1057 #endif
1058 };
下面我们来分析套接字缓冲区涉及的操作函数,linux套接字区支持分配、释放、变更等功能函数
1)
linux内核中用于分配套接字缓冲区的函数有:
alloc_skb()函数分配一个套接字缓冲区和一个数据缓冲区,参数len为数据缓冲区的空间大小,通常以 L1_CACHE_BYTES对(对于ARM为32)对齐,参数priority为内存分配的优先级。dev_alloc_skb()函数GFP_ATOMIC优先级进行skb的分配,原因是该函数经常在设备驱动的接收中断里被调用
2)释放
linux内核中用于释放套接字缓冲区的函数有:
上诉函数用于释放被alloc_skb函数分配的套接字缓冲区和数据缓冲区
linux内核内部使用kfree_skb函数 ,而在网络设备驱动程序中最好用dev_kfree_skb()、dev_kfree_skb_irq()或dev_kfree_skb_any()函数进行套接字缓冲区的释放。其中,dev_kfree_skb()函数用于非中断上下文,dev_kfree_irq()函数用于中断上下文,而dev_kfree_skb_any()函数在中断和中断上下文中皆采用,它其实是做一个非常简单的上下文判断,然后再调用__dev_kfree_skb_irq()或者dev_kfree_skb(),这从其代码的实现中也可以看出:
3)变更
在linux内核中可以用如下函数在缓冲区尾部增加数据:
它会导致skb->tail后移len(skb->tail += len) ,而skb->len会增加len的大小(skb->len+=len)。通常。在设备驱动的接收数据处理中会调用此函数。
在linux内核中可以用如下函数在缓冲区开头增加数据:
它会导致skb->data前移动len(skb->data-=len),而skb->len会增加len的大小(skb->len += len) 。与该函数功能完成相反的函数是skb_pull(),它可以在缓冲区开头移除数据,执行的动作是skb->len-=len,skb->data+=len。
对于一个空的缓冲区而言,调用如下函数可以调整缓冲区头部:
内核中有很多这样的代码
1.2 网络设备接口层
网路设备接口层的主要功能是为千变万化的网络设备定义统一、抽象的数据结构net_device结构体,以不变应万变,实现多种硬件在软件层次的统一。
net_device结构体在内核中指代一个网络设备,它定义于include/linux/netdevice.h文件中,网络设备驱动程序只需通过填充net_device的具体成员并注册net_device即可实现硬件操作函数与内核的挂接。
net_device是一个巨大的结构体,定义与include/linux/netdevice.h中,包含网络设备的属性描述和操作接口,成员如下:
2067 struct net_device {
2068 char name[IFNAMSIZ];
2069 struct netdev_name_node *name_node;
2070 struct dev_ifalias __rcu *ifalias;
2071 /*
2072 * I/O specific fields
2073 * FIXME: Merge these and struct ifmap into one
2074 */
2075 unsigned long mem_end;
2076 unsigned long mem_start;
2077 unsigned long base_addr;
2078
2079 /*
2080 * Some hardware also needs these fields (state,dev_list,
2081 * napi_list,unreg_list,close_list) but they are not
2082 * part of the usual set specified in Space.c.
2083 */
2084
2085 unsigned long state;
2086
2087 struct list_head dev_list;
2088 struct list_head napi_list;
2089 struct list_head unreg_list;
2090 struct list_head close_list;
2091 struct list_head ptype_all;
2092 struct list_head ptype_specific;
2093
2094 struct {
2095 struct list_head upper;
2096 struct list_head lower;
2097 } adj_list;
2098
2099 /* Read-mostly cache-line for fast-path access */
2100 unsigned int flags;
2101 xdp_features_t xdp_features;
2102 unsigned long long priv_flags;
2103 const struct net_device_ops *netdev_ops;
2104 const struct xdp_metadata_ops *xdp_metadata_ops;
2105 int ifindex;
2106 unsigned short gflags;
2107 unsigned short hard_header_len;
2108
2109 /* Note : dev->mtu is often read without holding a lock.
2110 * Writers usually hold RTNL.
2111 * It is recommended to use READ_ONCE() to annotate the reads,
2112 * and to use WRITE_ONCE() to annotate the writes.
2113 */
2114 unsigned int mtu;
2115 unsigned short needed_headroom;
2116 unsigned short needed_tailroom;
2117
2118 netdev_features_t features;
2119 netdev_features_t hw_features;
2120 netdev_features_t wanted_features;
2121 netdev_features_t vlan_features;
2122 netdev_features_t hw_enc_features;
2123 netdev_features_t mpls_features;
2124 netdev_features_t gso_partial_features;
2125
2126 unsigned int min_mtu;
2127 unsigned int max_mtu;
2128 unsigned short type;
2129 unsigned char min_header_len;
2130 unsigned char name_assign_type;
2131
2132 int group;
2133
2134 struct net_device_stats stats; /* not used by modern drivers */
2135
2136 struct net_device_core_stats __percpu *core_stats;
2137
2138 /* Stats to monitor link on/off, flapping */
2139 atomic_t carrier_up_count;
2140 atomic_t carrier_down_count;
2141
2142 #ifdef CONFIG_WIRELESS_EXT
2143 const struct iw_handler_def *wireless_handlers;
2144 struct iw_public_data *wireless_data;
2145 #endif
2146 const struct ethtool_ops *ethtool_ops;
2147 #ifdef CONFIG_NET_L3_MASTER_DEV
2148 const struct l3mdev_ops *l3mdev_ops;
2149 #endif
2150 #if IS_ENABLED(CONFIG_IPV6)
2151 const struct ndisc_ops *ndisc_ops;
2152 #endif
2153
2154 #ifdef CONFIG_XFRM_OFFLOAD
2155 const struct xfrmdev_ops *xfrmdev_ops;
2156 #endif
2157
2158 #if IS_ENABLED(CONFIG_TLS_DEVICE)
2159 const struct tlsdev_ops *tlsdev_ops;
2160 #endif
2161 2162 const struct header_ops *header_ops;
2163
2164 unsigned char operstate;
2165 unsigned char link_mode;
2166
2167 unsigned char if_port;
2168 unsigned char dma;
2169
2170 /* Interface address info. */
2171 unsigned char perm_addr[MAX_ADDR_LEN];
2172 unsigned char addr_assign_type;
2173 unsigned char addr_len;
2174 unsigned char upper_level;
2175 unsigned char lower_level;
2176
2177 unsigned short neigh_priv_len;
2178 unsigned short dev_id;
2179 unsigned short dev_port;
2180 unsigned short padded;
2181
2182 spinlock_t addr_list_lock;
2183 int irq;
2184
2185 struct netdev_hw_addr_list uc;
2186 struct netdev_hw_addr_list mc;
2187 struct netdev_hw_addr_list dev_addrs;
2188
2189 #ifdef CONFIG_SYSFS
2190 struct kset *queues_kset;
2191 #endif
2192 #ifdef CONFIG_LOCKDEP
2193 struct list_head unlink_list;
2194 #endif
2195 unsigned int promiscuity;
2196 unsigned int allmulti;
2197 bool uc_promisc;
2198 #ifdef CONFIG_LOCKDEP
2199 unsigned char nested_level;
2200 #endif
2201
2202
2203 /* Protocol-specific pointers */
2204
2205 struct in_device __rcu *ip_ptr;
2206 struct inet6_dev __rcu *ip6_ptr;
2207 #if IS_ENABLED(CONFIG_VLAN_8021Q)
2208 struct vlan_info __rcu *vlan_info;
2209 #endif
2210 #if IS_ENABLED(CONFIG_NET_DSA)
2211 struct dsa_port *dsa_ptr;
2212 #endif
2213 #if IS_ENABLED(CONFIG_TIPC)
2214 struct tipc_bearer __rcu *tipc_ptr;
2215 #endif
2216 #if IS_ENABLED(CONFIG_ATALK)
2217 void *atalk_ptr;
2218 #endif
2219 #if IS_ENABLED(CONFIG_AX25)
2220 void *ax25_ptr;
2221 #endif
2222 #if IS_ENABLED(CONFIG_CFG80211)
2223 struct wireless_dev *ieee80211_ptr;
2224 #endif
2225 #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN)
2226 struct wpan_dev *ieee802154_ptr;
2227 #endif
2228 #if IS_ENABLED(CONFIG_MPLS_ROUTING)
2229 struct mpls_dev __rcu *mpls_ptr;
2230 #endif
2231 #if IS_ENABLED(CONFIG_MCTP)
2232 struct mctp_dev __rcu *mctp_ptr;
2233 #endif
2234
2235 /*
2236 * Cache lines mostly used on receive path (including eth_type_trans())
2237 */
2238 /* Interface address info used in eth_type_trans() */
2239 const unsigned char *dev_addr;
2240
2241 struct netdev_rx_queue *_rx;
2242 unsigned int num_rx_queues;
2243 unsigned int real_num_rx_queues;
2244
2245 struct bpf_prog __rcu *xdp_prog;
2246 unsigned long gro_flush_timeout;
2247 int napi_defer_hard_irqs;
2248 #define GRO_LEGACY_MAX_SIZE 65536u
2249 /* TCP minimal MSS is 8 (TCP_MIN_GSO_SIZE),
2250 * and shinfo->gso_segs is a 16bit field.
2251 */
2252 #define GRO_MAX_SIZE (8 * 65535u)
2253 unsigned int gro_max_size;
2254 unsigned int gro_ipv4_max_size;
2255 unsigned int xdp_zc_max_segs;
2256 rx_handler_func_t __rcu *rx_handler;
2257 void __rcu *rx_handler_data;
2258 #ifdef CONFIG_NET_XGRESS
2259 struct bpf_mprog_entry __rcu *tcx_ingress;
2260 #endif
2261 struct netdev_queue __rcu *ingress_queue;
2262 #ifdef CONFIG_NETFILTER_INGRESS
2263 struct nf_hook_entries __rcu *nf_hooks_ingress;
2264 #endif
2265
2266 unsigned char broadcast[MAX_ADDR_LEN];
2267 #ifdef CONFIG_RFS_ACCEL
2268 struct cpu_rmap *rx_cpu_rmap;
2269 #endif
2270 struct hlist_node index_hlist;
2271
2272 /*
2273 * Cache lines mostly used on transmit path
2274 */
2275 struct netdev_queue *_tx ____cacheline_aligned_in_smp;
2276 unsigned int num_tx_queues;
2277 unsigned int real_num_tx_queues;
2278 struct Qdisc __rcu *qdisc;
2279 unsigned int tx_queue_len;
2280 spinlock_t tx_global_lock;
2281
2282 struct xdp_dev_bulk_queue __percpu *xdp_bulkq;
2283
2284 #ifdef CONFIG_XPS
2285 struct xps_dev_maps __rcu *xps_maps[XPS_MAPS_MAX];
2286 #endif
2287 #ifdef CONFIG_NET_XGRESS
2288 struct bpf_mprog_entry __rcu *tcx_egress;
2289 #endif
2290 #ifdef CONFIG_NETFILTER_EGRESS
2291 struct nf_hook_entries __rcu *nf_hooks_egress;
2292 #endif
2293
2294 #ifdef CONFIG_NET_SCHED
2295 DECLARE_HASHTABLE (qdisc_hash, 4);
2296 #endif
2297 /* These may be needed for future network-power-down code. */
2298 struct timer_list watchdog_timer;
2299 int watchdog_timeo;
2300
2301 u32 proto_down_reason;
2302
2303 struct list_head todo_list;
2304
2305 #ifdef CONFIG_PCPU_DEV_REFCNT
2306 int __percpu *pcpu_refcnt;
2307 #else
2308 refcount_t dev_refcnt;
2309 #endif
2310 struct ref_tracker_dir refcnt_tracker;
2311
2312 struct list_head link_watch_list;
2313
2314 enum { NETREG_UNINITIALIZED=0,
2315 NETREG_REGISTERED, /* completed register_netdevice */
2316 NETREG_UNREGISTERING, /* called unregister_netdevice */
2317 NETREG_UNREGISTERED, /* completed unregister todo */
2318 NETREG_RELEASED, /* called free_netdev */
2319 NETREG_DUMMY, /* dummy device for NAPI poll */
2320 } reg_state:8;
2321
2322 bool dismantle;
2323
2324 enum {
2325 RTNL_LINK_INITIALIZED,
2326 RTNL_LINK_INITIALIZING,
2327 } rtnl_link_state:16;
2328
2329 bool needs_free_netdev;
2330 void (*priv_destructor)(struct net_device *dev);
2331
2332 #ifdef CONFIG_NETPOLL
2333 struct netpoll_info __rcu *npinfo;
2334 #endif
2335
2336 possible_net_t nd_net;
2337
2338 /* mid-layer private */
2339 void *ml_priv;
2340 enum netdev_ml_priv_type ml_priv_type;
2341
2342 enum netdev_stat_type pcpu_stat_type:8;
2343 union {
2344 struct pcpu_lstats __percpu *lstats;
2345 struct pcpu_sw_netstats __percpu *tstats;
2346 struct pcpu_dstats __percpu *dstats;
2347 };
2348
2349 #if IS_ENABLED(CONFIG_GARP)
2350 struct garp_port __rcu *garp_port;
2351 #endif
2352 #if IS_ENABLED(CONFIG_MRP)
2353 struct mrp_port __rcu *mrp_port;
2354 #endif
2355 #if IS_ENABLED(CONFIG_NET_DROP_MONITOR)
2356 struct dm_hw_stat_delta __rcu *dm_private;
2357 #endif
2358 struct device dev;
2359 const struct attribute_group *sysfs_groups[4];
2360 const struct attribute_group *sysfs_rx_queue_group;
2361
2362 const struct rtnl_link_ops *rtnl_link_ops;
2363
2364 /* for setting kernel sock attribute on TCP connection setup */
2365 #define GSO_MAX_SEGS 65535u
2366 #define GSO_LEGACY_MAX_SIZE 65536u
2367 /* TCP minimal MSS is 8 (TCP_MIN_GSO_SIZE),
2368 * and shinfo->gso_segs is a 16bit field.
2369 */
2370 #define GSO_MAX_SIZE (8 * GSO_MAX_SEGS)
2371
2372 unsigned int gso_max_size;
2373 #define TSO_LEGACY_MAX_SIZE 65536
2374 #define TSO_MAX_SIZE UINT_MAX
2375 unsigned int tso_max_size;
2376 u16 gso_max_segs;
2377 #define TSO_MAX_SEGS U16_MAX
2378 u16 tso_max_segs;
2379 unsigned int gso_ipv4_max_size;
2380
2381 #ifdef CONFIG_DCB
2382 const struct dcbnl_rtnl_ops *dcbnl_ops;
2383 #endif
2384 s16 num_tc;
2385 struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
2386 u8 prio_tc_map[TC_BITMASK + 1];
2387
2388 #if IS_ENABLED(CONFIG_FCOE)
2389 unsigned int fcoe_ddp_xid;
2390 #endif
2391 #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
2392 struct netprio_map __rcu *priomap;
2393 #endif
2394 struct phy_device *phydev;
2395 struct sfp_bus *sfp_bus;
2396 struct lock_class_key *qdisc_tx_busylock;
2397 bool proto_down;
2398 unsigned wol_enabled:1;
2399 unsigned threaded:1;
2400
2401 struct list_head net_notifier_list;
2402
2403 #if IS_ENABLED(CONFIG_MACSEC)
2404 /* MACsec management functions */
2405 const struct macsec_ops *macsec_ops;
2406 #endif
2407 const struct udp_tunnel_nic_info *udp_tunnel_nic_info;
2408 struct udp_tunnel_nic *udp_tunnel_nic;
2409
2410 /* protected by rtnl_lock */
2411 struct bpf_xdp_entity xdp_state[__MAX_XDP_MODE];
2412
2413 u8 dev_addr_shadow[MAX_ADDR_LEN];
2414 netdevice_tracker linkwatch_dev_tracker;
2415 netdevice_tracker watchdog_dev_tracker;
2416 netdevice_tracker dev_registered_tracker;
2417 struct rtnl_hw_stats64 *offload_xstats_l3;
2418
2419 struct devlink_port *devlink_port;
2420 };
1)全局信息
2) 硬件信息
mem_start和mem_end分别定义了设备所使用的共享内存的起始和结束地址
base_addr为网络设备I/O基地址
irq为设备使用的中断号
if_port指定多端口设备使用哪一个端口,该字段仅针对多端口设备。例如,如果设备同时支持IF_PORT_10BASE2同轴电缆和IF_PORT_10BASET(双绞线) ,则可以使用该字段。
dma是指定分配给设备的DMA通道
3)接口信息
hard_header_len是网络设备的硬件头长度,在以太网设备初始化函数中,该成员被赋为ETH_HLEN,即14
type是接口的硬件类型
mtu是指最大传输单元(MTU)
用于存放设备的硬件地址,驱动可能提供设置MAC地址的接口,这会导致用户设置的MAC地址等存入该成员。函数名字类似这种***set_mac_address***结构
4)设备操作函数
该结构体是网络设备的一系列硬件操作行数的集合,它也定义于include/linux/netdevice.h中,这个结构体很大,结构成员如下:
1410 struct net_device_ops {
1411 int (*ndo_init)(struct net_device *dev);
1412 void (*ndo_uninit)(struct net_device *dev);
1413 int (*ndo_open)(struct net_device *dev);
1414 int (*ndo_stop)(struct net_device *dev);
1415 netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
1416 struct net_device *dev);
1417 netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
1418 struct net_device *dev,
1419 netdev_features_t features);
1420 u16 (*ndo_select_queue)(struct net_device *dev,
1421 struct sk_buff *skb,
1422 struct net_device *sb_dev);
1423 void (*ndo_change_rx_flags)(struct net_device *dev,
1424 int flags);
1425 void (*ndo_set_rx_mode)(struct net_device *dev);
1426 int (*ndo_set_mac_address)(struct net_device *dev,
1427 void *addr);
1428 int (*ndo_validate_addr)(struct net_device *dev);
1429 int (*ndo_do_ioctl)(struct net_device *dev,
1430 struct ifreq *ifr, int cmd);
1431 int (*ndo_eth_ioctl)(struct net_device *dev,
1432 struct ifreq *ifr, int cmd);
1433 int (*ndo_siocbond)(struct net_device *dev,
1434 struct ifreq *ifr, int cmd);
1435 int (*ndo_siocwandev)(struct net_device *dev,
1436 struct if_settings *ifs);
1437 int (*ndo_siocdevprivate)(struct net_device *dev,
1438 struct ifreq *ifr,
1439 void __user *data, int cmd);
1440 int (*ndo_set_config)(struct net_device *dev,
1441 struct ifmap *map);
1442 int (*ndo_change_mtu)(struct net_device *dev,
1443 int new_mtu);
1444 int (*ndo_neigh_setup)(struct net_device *dev,
1445 struct neigh_parms *);
1446 void (*ndo_tx_timeout) (struct net_device *dev,
1447 unsigned int txqueue);
1448
1449 void (*ndo_get_stats64)(struct net_device *dev,
1450 struct rtnl_link_stats64 *storage);
1451 bool (*ndo_has_offload_stats)(const struct net_device *dev, int attr_id);
1452 int (*ndo_get_offload_stats)(int attr_id,
1453 const struct net_device *dev,
1454 void *attr_data);
1455 struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
1456
1457 int (*ndo_vlan_rx_add_vid)(struct net_device *dev,
1458 __be16 proto, u16 vid);
1459 int (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
1460 __be16 proto, u16 vid);
1461 #ifdef CONFIG_NET_POLL_CONTROLLER
1462 void (*ndo_poll_controller)(struct net_device *dev);
1463 int (*ndo_netpoll_setup)(struct net_device *dev,
1464 struct netpoll_info *info);
1465 void (*ndo_netpoll_cleanup)(struct net_device *dev);
1466 #endif
1467 int (*ndo_set_vf_mac)(struct net_device *dev,
1468 int queue, u8 *mac);
1469 int (*ndo_set_vf_vlan)(struct net_device *dev,
1470 int queue, u16 vlan,
1471 u8 qos, __be16 proto);
1472 int (*ndo_set_vf_rate)(struct net_device *dev,
1473 int vf, int min_tx_rate,
1474 int max_tx_rate);
1475 int (*ndo_set_vf_spoofchk)(struct net_device *dev,
1476 int vf, bool setting);
1477 int (*ndo_set_vf_trust)(struct net_device *dev,
1478 int vf, bool setting);
1479 int (*ndo_get_vf_config)(struct net_device *dev,
1480 int vf,
1481 struct ifla_vf_info *ivf);
1482 int (*ndo_set_vf_link_state)(struct net_device *dev,
1483 int vf, int link_state);
1484 int (*ndo_get_vf_stats)(struct net_device *dev,
1485 int vf,
1486 struct ifla_vf_stats
1487 *vf_stats);
1488 int (*ndo_set_vf_port)(struct net_device *dev,
1489 int vf,
1490 struct nlattr *port[]);
1491 int (*ndo_get_vf_port)(struct net_device *dev,
1492 int vf, struct sk_buff *skb);
1493 int (*ndo_get_vf_guid)(struct net_device *dev,
1494 int vf,
1495 struct ifla_vf_guid *node_guid,
1496 struct ifla_vf_guid *port_guid);
1497 int (*ndo_set_vf_guid)(struct net_device *dev,
1498 int vf, u64 guid,
1499 int guid_type);
1500 int (*ndo_set_vf_rss_query_en)(
1501 struct net_device *dev,
1502 int vf, bool setting);
1503 int (*ndo_setup_tc)(struct net_device *dev,
1504 enum tc_setup_type type,
1505 void *type_data);
1506 #if IS_ENABLED(CONFIG_FCOE)
1507 int (*ndo_fcoe_enable)(struct net_device *dev);
1508 int (*ndo_fcoe_disable)(struct net_device *dev);
1509 int (*ndo_fcoe_ddp_setup)(struct net_device *dev,
1510 u16 xid,
1511 struct scatterlist *sgl,
1512 unsigned int sgc);
1513 int (*ndo_fcoe_ddp_done)(struct net_device *dev,
1514 u16 xid);
1515 int (*ndo_fcoe_ddp_target)(struct net_device *dev,
1516 u16 xid,
1517 struct scatterlist *sgl,
1518 unsigned int sgc);
1519 int (*ndo_fcoe_get_hbainfo)(struct net_device *dev,
1520 struct netdev_fcoe_hbainfo *hbainfo);
1521 #endif
1522
1523 #if IS_ENABLED(CONFIG_LIBFCOE)
1524 #define NETDEV_FCOE_WWNN 0
1525 #define NETDEV_FCOE_WWPN 1
1526 int (*ndo_fcoe_get_wwn)(struct net_device *dev,
1527 u64 *wwn, int type);
1528 #endif
1529
1530 #ifdef CONFIG_RFS_ACCEL
1531 int (*ndo_rx_flow_steer)(struct net_device *dev,
1532 const struct sk_buff *skb,
1533 u16 rxq_index,
1534 u32 flow_id);
1535 #endif
1536 int (*ndo_add_slave)(struct net_device *dev,
1537 struct net_device *slave_dev,
1538 struct netlink_ext_ack *extack);
1539 int (*ndo_del_slave)(struct net_device *dev,
1540 struct net_device *slave_dev);
1541 struct net_device* (*ndo_get_xmit_slave)(struct net_device *dev,
1542 struct sk_buff *skb,
1543 bool all_slaves);
1544 struct net_device* (*ndo_sk_get_lower_dev)(struct net_device *dev,
1545 struct sock *sk);
1546 netdev_features_t (*ndo_fix_features)(struct net_device *dev,
1547 netdev_features_t features);
1548 int (*ndo_set_features)(struct net_device *dev,
1549 netdev_features_t features);
1550 int (*ndo_neigh_construct)(struct net_device *dev,
1551 struct neighbour *n);
1552 void (*ndo_neigh_destroy)(struct net_device *dev,
1553 struct neighbour *n);
1554
1555 int (*ndo_fdb_add)(struct ndmsg *ndm,
1556 struct nlattr *tb[],
1557 struct net_device *dev,
1558 const unsigned char *addr,
1559 u16 vid,
1560 u16 flags,
1561 struct netlink_ext_ack *extack);
1562 int (*ndo_fdb_del)(struct ndmsg *ndm,
1563 struct nlattr *tb[],
1564 struct net_device *dev,
1565 const unsigned char *addr,
1566 u16 vid, struct netlink_ext_ack *extack);
1567 int (*ndo_fdb_del_bulk)(struct ndmsg *ndm,
1568 struct nlattr *tb[],
1569 struct net_device *dev,
1570 u16 vid,
1571 struct netlink_ext_ack *extack);
1572 int (*ndo_fdb_dump)(struct sk_buff *skb,
1573 struct netlink_callback *cb,
1574 struct net_device *dev,
1575 struct net_device *filter_dev,
1576 int *idx);
1577 int (*ndo_fdb_get)(struct sk_buff *skb,
1578 struct nlattr *tb[],
1579 struct net_device *dev,
1580 const unsigned char *addr,
1581 u16 vid, u32 portid, u32 seq,
1582 struct netlink_ext_ack *extack);
1583 int (*ndo_mdb_add)(struct net_device *dev,
1584 struct nlattr *tb[],
1585 u16 nlmsg_flags,
1586 struct netlink_ext_ack *extack);
1587 int (*ndo_mdb_del)(struct net_device *dev,
1588 struct nlattr *tb[],
1589 struct netlink_ext_ack *extack);
1590 int (*ndo_mdb_dump)(struct net_device *dev,
1591 struct sk_buff *skb,
1592 struct netlink_callback *cb);
1593 int (*ndo_bridge_setlink)(struct net_device *dev,
1594 struct nlmsghdr *nlh,
1595 u16 flags,
1596 struct netlink_ext_ack *extack);
1597 int (*ndo_bridge_getlink)(struct sk_buff *skb,
1598 u32 pid, u32 seq,
1599 struct net_device *dev,
1600 u32 filter_mask,
1601 int nlflags);
1602 int (*ndo_bridge_dellink)(struct net_device *dev,
1603 struct nlmsghdr *nlh,
1604 u16 flags);
1605 int (*ndo_change_carrier)(struct net_device *dev,
1606 bool new_carrier);
1607 int (*ndo_get_phys_port_id)(struct net_device *dev,
1608 struct netdev_phys_item_id *ppid);
1609 int (*ndo_get_port_parent_id)(struct net_device *dev,
1610 struct netdev_phys_item_id *ppid);
1611 int (*ndo_get_phys_port_name)(struct net_device *dev,
1612 char *name, size_t len);
1613 void* (*ndo_dfwd_add_station)(struct net_device *pdev,
1614 struct net_device *dev);
1615 void (*ndo_dfwd_del_station)(struct net_device *pdev,
1616 void *priv);
1617
1618 int (*ndo_set_tx_maxrate)(struct net_device *dev,
1619 int queue_index,
1620 u32 maxrate);
1621 int (*ndo_get_iflink)(const struct net_device *dev);
1622 int (*ndo_fill_metadata_dst)(struct net_device *dev,
1623 struct sk_buff *skb);
1624 void (*ndo_set_rx_headroom)(struct net_device *dev,
1625 int needed_headroom);
1626 int (*ndo_bpf)(struct net_device *dev,
1627 struct netdev_bpf *bpf);
1628 int (*ndo_xdp_xmit)(struct net_device *dev, int n,
1629 struct xdp_frame **xdp,
1630 u32 flags);
1631 struct net_device * (*ndo_xdp_get_xmit_slave)(struct net_device *dev,
1632 struct xdp_buff *xdp);
1633 int (*ndo_xsk_wakeup)(struct net_device *dev,
1634 u32 queue_id, u32 flags);
1635 int (*ndo_tunnel_ctl)(struct net_device *dev,
1636 struct ip_tunnel_parm *p, int cmd);
1637 struct net_device * (*ndo_get_peer_dev)(struct net_device *dev);
1638 int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
1639 struct net_device_path *path);
1640 ktime_t (*ndo_get_tstamp)(struct net_device *dev,
1641 const struct skb_shared_hwtstamps *hwtstamps,
1642 bool cycles);
1643 int (*ndo_hwtstamp_get)(struct net_device *dev,
1644 struct kernel_hwtstamp_config *kernel_config);
1645 int (*ndo_hwtstamp_set)(struct net_device *dev,
1646 struct kernel_hwtstamp_config *kernel_config,
1647 struct netlink_ext_ack *extack);
1648 };
ndo_open()函数的作用是打开网络接口设备,获得设备需要的I/O地址、IRQ、DMA通道等,stop函数的作用是停止网络设备接口,与open()函数的作用相反。
ndo_start_xmit()函数会启动数据包的发送,当系统调用驱动程序的xmit函数时,需要向其传入一个sk_buff结构体指针,以使得驱动程序能获取从上层传递下来的数据包。
当数据包发送超时时,ndo_tx_timeout()函数会被调用,该函数需要采取重新启动数据包发送过程或重新启动硬件措施来恢复网络设备到正常状态。
ndo_get_status()函数用于获得网络设备的状态信息,它返回一个net_device_stats结构指针。net_device_stats结构体保存了详细的网络设备流量统计信息,如发送和接收的数据包数、字节数等
ndo_do_ioctl()函数进行设备特定的I/O控制。
ndo_set_config()函数进行配置接口,也可以用于改变设备的I/O地址和中断号
ndo_set_mac_address()函数用于设置设备的MAC地址
除了netdev_ops以外,在net_device中还存在类似与ethtool_ops、header_ops这样的操作集:
ethtool_ops成员函数与用户空间ethtool工具的各个命令选项对应,ethtool提供了网卡及其网卡驱动管理能力,能够为linux网络开发人员和管理人员提供对网卡硬件、驱动程序和网络协议栈的设置、查看以及调试等功能。
header_ops对应硬件头部操作,主要是完成创建硬件头部和从给定的sk_buff分析出硬件头部等操作。
5)辅助成员
trans_start记录最后的数据包开始发送时的时间戳,last_rx记录最后一次接收到数据包时的时间戳,这两个时间戳都是jiffies,驱动程序应维护这两个成员。
通常情况下,网络设备驱动以中断方式接收数据包,而poll_controller()则采用纯轮询方式,另外一种数据接收方式NAPI(NEW API),其数据接收流程为“接收中断来临-----关闭接收中断---以轮询方式接收所有的数据包直到收空---开启接收中断---接收中断来临..........”内核中提供如下与NAPI相关的API:
以上两个函数分别用于初始化和移除一个NAPI,netif_napi_add()的poll参数是NAPI要调度执行的轮询函数。
以上两个函数分别用于使能和禁止NAPI调度
该函数用于检查NAPI是否可以调度,而napi_schedule()函数用于调度轮询实例的运行,其原型为:
在NAPI处理完成的时候应该调用:
1.3 设备驱动功能层
net_device结构体的成员(属性和net_device_ops结构体中的函数指针)需要被设备驱动功能层赋予具体的数据和函数。对于具体的设备xxx,工程师应该编写相应的设备驱动功能层的函数,这些函数如xxx_open、xxx_stop、xxx_tx、xxx_hard_header、xxx_get_stats和xxx_tx_timeout等
由于网络数据包的接收可由中断引发,设备驱动功能层中的另一个主体部分将是中断处理函数,它负责读取硬件上接收到的数据包并传递给上层协议,因此可能包含xxx_interrupt()和xxx_rx函数,前者完成中断类型判断等基本工作,后者则需要完成数据包的生层将其交个上层等复杂工作。
二、 网络设备驱动的注册与注销
网络设备驱动的注册与注销由register_netdev()和unregister_netdev()函数完成,原型为:
这两个函数都接收一个net_device结构指针为参数,可见其在网络设备驱动中都核心地位。
net_device的生成和成员的赋值并一定 要工程师亲自动手逐个完成,可以利用下面的宏帮我们填充:
alloc_netdev以及alloc_etherdev宏引用的alloc_netdev_mqs()函数原型如上图所示
alloc_netdev_mqs()函数生成一个net_device结构体,对其成员赋值返回该结构体的指针,第一个参数为设备私有成员的大小,第二个参数为设备名,第三个参数为net_device的setup函数指针,第四、五个参数为要分配的发送和接收子队列的数量。setup() 函数接收的参数也为struct net_device指针,用于预置net_device成员的值。
free_netdev()完成与alloc_enetdev()和alloc_etherdev()函数相反的功能,即释放net_device结构体的函数:
net_device结构体的分配和网络设备驱动的注册需要在网络设备驱动程序初始化时进行,而net_device结构的释放和网络设备驱动的注销在设备或驱动被移除的时候执行。
三、 网络设备的初始化
网络设备的初始化主要需要完成如下几个方面的工作:
1)进行硬件上的准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源。
2)进行软件接口的准备工作,分配net_device结构并对其数据和函数指针成员赋值
3)获得设备的私有信息指针并初始化各成员的值。如果私有信息中包括自旋锁或信号量等并发或同步机制,则需对其进行初始化。
对net_device结构体成员及私有数据的赋值都可能需要与硬件初始化协同工作,即硬件检测出了相应的资源,需要根据检测结果填充net_device结果成员和私有数据。
网络设备驱动的初始化函数模板如下图所示,具体的设备驱动初始化函数并不一定完成和本模板一样,但其本质过程是一致的。
四、 网络设备的打开与释放
网络设备的打开函数需要完成如下工作。
1)使能设备使用的硬件资源,申请I/O区域、中断和DMA通道等
2)调用linux内核提供的netif_start_queue()函数,激活设备发送队列。
网络设备的关闭函数需要完成如下工作。
1)调用linux内核提供的netif_stop_queue()函数,停止设备传输包
2)释放设备所使用的I/O区域、中断和DMA资源
原型:
根据以上分析,网络设备打开和释放函数的模板为:
五、 数据发送流程
从前面的网络设备驱动程序的结构分析可知,linux网络子系统在发送数据包时,会调用驱动程序提供的ndo_start_xmit(旧的版本可能叫hadr_start_xmit)
函数,该函数用于启动数据包的发送。在设备初始化的时候,这个函数需被初始化以执行设备的xxx_tx()函数。
网络设备驱动完成数据包发送的流程如下。
1)网络设备驱动层从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。
2)对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZIEN,则给临时缓冲区的末尾填充0
3)设置硬件的寄存器,驱使网络设备进行数据发送操作
完成以上三个步骤的网络驱动程序的数据包发送函数模板如下:
这里特别要强调第22行对netif_stop_queue()的调用,当发送队列为满或因其他原因来不及发送当前上层传下来的数据包时,则调用此函数阻止上层继续向网络设备驱动传递数据包。当忙于发送的数据包被发送完成后,在以TX结束的中断处理中,应该调用netif_wake_queue()唤醒被阻塞的上层,以启动它继续向网络设备驱动传送数据包。
当数据传输超时时,意味着当前的发送操作失败或硬件已陷入未知状态,此时,数据包发送超时处理函数xxx_tx_timeout()将被调用。这个函数也需要调用由linux内核提供的netif_wake_queue()函数以重新启动设备发送队列。
从前文可知,netif_wake_queue()和netif_stop_queue()是数据发送流程中要调用的两个非常重要的函数,分别用于唤醒和阻止上层向下传送数据包,它们定义于include/linux/netdevice.h文件中。
六、 数据接收流程
网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据和数据缓冲区将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。代码模板如图
如果是NAPI兼容的设备驱动,则可以通过poll方式接收数据包。在这种情况下,我们需要为该设备驱动提供作为netif_napi_add()参数的xxx_poll函数 。
虽然NAPI兼容的设备驱动以xxx_polll()方式接收数据包,但是仍然需要首次数据包接收中断来触发这个过程。与数据包的中断接收方式不同的是,以轮询方式接收数据包时,当第一次中断发生后,中断程序要禁止设备的数据包接收中断并调度NAPI,如图
上述代码的第7行napi_schedule()函数被轮询方式驱动的中断程序调用,将设备的poll方式添加到网络层的poll处理队列,排队并准备接收数据包,最终触发一个NET_RX_SOFTIRQ软中断,从而通知网络层接收数据包。
在支持NAPI的网络设备驱动中,通常还会 进行如下与NAPI相关的工作。
1)在私有数据结构(如xxx_priv)中增加一个成员:
在代码中可以方便地使用container_of()通过NAPI成员反向获得对应的xxx_priv指针。
2) 通常会在设备驱动初始化时调用
3)通常会在net_device结构体的open()和stop()成员函数中分别调用napi_enabel()和napi_diaable() 。
七、 网络链接状态
网络适配器硬件电路可以检测出链路上是否载波,载波反映了网络的连接是否正常。网络设备驱动可以通过netif_carrier_on()和netif_carrier_of()函数改变设备的连接状态,如果驱动检测到连接状态发生变化,也应该以netif_carrier_on()和netif_carrier_off()函数显示地通知内核。
除了neiif_carrier_on()和netif_carrier_off()函数以外,另一个函数netif_carrier_ok()可用于向调用者返回链路上的载波信号是否存在。
在网络设备驱动程序中可采取一定的手段来检测和报告链路状态,最常用的方法是采用中断,其次可以设置一个定时器来对链路状态进行周期性的检查。当定时器到期之后,在定时器处理函数中读取物理设备的相关的寄存器以获得载波状态,从而更新设备的链接状态,如
上诉代码第10行调用xxx_chk_link()函数来读取网络适配器 硬件相关寄存器,以获得链路链接状态,具体实现由硬件决定。当链路连接上时,第12行的netif_carrier_on()函数显式地通知内核链路正常;反正,第18行的netif_carrier_off()同样显式地通知内核链路失去连接。
此外,从上诉源代码还可以看出,定时器处理函数会不停地利用第24-28行代码启动新的定时器以实现周期性检测的目的。那么最初启动定时器的地方在哪里呢?很显然,它最适合在设备的打开函数中完成,如图
八、 参数设置和统计数据
网络设备的驱动程序还提供一下供系统对设备的参数进行设置或读取设备相关信息的方法。
当用户调用ioctl()函数,并指定SIOCSIFHWADDR命令时,意味着要设置这个设备的MAC地址。设置网络设备的MAC地址:
上诉程序先用 netif_running()宏判断设备是否正在运行,如果是,则意味这设备忙,此时不允许设置MAC地址;否则,调用xxx_set_mac()函数在网络适配器硬件内写入新的MAC地址。这要求设备在硬件上支持MAC地址的修改,而实际上,许多设备并不提供修改MAC地址的接口:
当用户调用ioctl()函数时,若命令为SIOCSIFMAP(如在控制台中运行网络配置命令ifconfig就会引发这一调用),系统会调用驱动程序的set_config()函数。
系统会向set_config()函数传递一个ifmap结构体,该结构体主要包含用户欲设置的设备要使用的I/O地址、中断信息。注意,并不是ifmap结构体中给出的所有修改都是可以接受的。实际上,大多数设并不适合包含set_config()函数。set_config()函数的例子如代码
上述代码中的set_confi()函数接收IRQ的修改,拒绝设备I/O地址的修改。具体的设备是否可以接收这些信息的修改,要视硬件的设计而定。
驱动程序还应提供get_stats()函数以向用户返回设备状态和统计信息,该函数返回的是一个net_device_stats结构体,如代码