当前位置: 首页 > news >正文

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结构体,如代码 

        

        

        

        

        

        

         

http://www.lqws.cn/news/501139.html

相关文章:

  • 新中国风通用读书颂词分享PPT模版
  • 对手机屏中断路和短路的单元进行切割或熔接,实现液晶线路激光修复原理
  • libevent(1)之基础概述
  • bmc TrueSight 监控 Oracle 11g 配置
  • Flutter 与 原生(Android/iOS)通信 Platform Channel
  • ASP.NET Core 中 Kestrel 的应用及在前后端分离项目中的角色
  • SnowConvert:自动化数据迁移的技术解析与最佳实践
  • 深入JVM:从零到实战,解锁Java性能与调优的终极武器
  • JDK 17 中 java.lang.System 常用方法及应用场景
  • 对于高考边界的理解以及未来就业层级的学习与思考
  • 鸿蒙HarmonyOS 5开发:AlphabetIndexer组件在通讯录中的高效索引实现(附:代码)
  • Linux环境下MariaDB如何实现负载均衡
  • 华为云Flexus+DeepSeek征文 | 基于CCE容器的AI Agent高可用部署架构与弹性扩容实践
  • C++修炼:异常
  • Excel学习04
  • 代理模式:控制对象访问的守门员[特殊字符],优雅实现功能增强与访问控制!
  • 嵌入式Linux驱动开发基础-1 hello驱动
  • 【大模型问题】ms-swift微调时,显存持续增长原因分析与解决方案
  • 【CS创世SD NAND征文】基于全志V3S与CS创世SD NAND的物联网智能路灯网关数据存储方案
  • Nginx负载均衡
  • Docker 数据持久化完全指南:Volume、Bind Mount 与匿名卷
  • OpenCV CUDA模块设备层-----创建一个“常量指针访问器” 的工具函数constantPtr()
  • Docker Compose与私有仓库部署
  • Vue3+TypeScript移动端H5播放器选型指南:M3U8与主流播放器深度解析
  • 聚宽量化——股票时间序列函数
  • 传统消防演练与 VR 消防演练的区别有哪些
  • Unreal5从入门到精通之如何录制360°VR全景视频
  • Python-3-数据结构(列表)
  • Android edge-to-edge兼容适配
  • 监管报送面试回答思路和示例