这一篇主要是学习网络设备驱动框架性的东西具体的实例分析可以参考Linux 驱动框架---dm9000分析 。Linux 对于网络设备的驱动的定义分了四层分别是网络接口层对上是IP,ARP等网络协议,因为网络协议还是相对复杂的肯定是由内核来实现的(符合Linux驱动一贯的风格就是内核做的更多);网络设备接口层实际上就是对网络设备操作的封装,封装成一个结构体由驱动工程师来填充内容从而做到抽象;设备驱动功能层其实就是网络设备接口层封装好的接口的具体实现以操作硬件设备完成指定动作的软件部分;网络设备与媒介层(MAC和PHY偏硬件部分)。网络协议接口层就是对上提供的发送和接收接口。发送接口接受上层协议下发的应用数据(已经使用struct sk_buff 数据结构封装)然后调用设备接口层驱动硬件完成数据发送;其次是数据接收其主要是在由物理层接收完数据后同样用struct sk_buff 结构封装后交给网络协议层的接口。驱动框架的简单的层级结构如下:

网络协议接口层对网络层提供两个了主要接口用于数据的发送(int dev_queue_xmit(struct sk_buff* skb))和接收(int netif_rx(struct sk_buff* skb))。

数据发送

数据发送接口由应用程序和协议栈主动在内核空间调用,这一部分偏内核部分(内核实现)的就是操作net_device 上的一个queue将数据包放进去,最后进行合适的调度调用网络设备接口层进而进入设备驱动功能层完成数据包的发送。

int dev_queue_xmit(struct sk_buff *skb)
{
return __dev_queue_xmit(skb, NULL);
}
=======》
static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
{
struct net_device *dev = skb->dev;
struct netdev_queue *txq;
struct Qdisc *q;
int rc = -ENOMEM; skb_reset_mac_header(skb); /* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
rcu_read_lock_bh(); skb_update_prio(skb); txq = netdev_pick_tx(dev, skb, accel_priv);
q = rcu_dereference_bh(txq->qdisc); #ifdef CONFIG_NET_CLS_ACT
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
#endif
trace_net_dev_queue(skb);
if (q->enqueue) {
rc = __dev_xmit_skb(skb, q, dev, txq);
goto out;
} /* The device has no queue. Common case for software devices:
loopback, all the sorts of tunnels... Really, it is unlikely that netif_tx_lock protection is necessary
here. (f.e. loopback and IP tunnels are clean ignoring statistics
counters.)
However, it is possible, that they rely on protection
made by us here. Check this and shot the lock. It is not prone from deadlocks.
Either shot noqueue qdisc, it is even simpler 8)
*/
if (dev->flags & IFF_UP) {
int cpu = smp_processor_id(); /* ok because BHs are off */ if (txq->xmit_lock_owner != cpu) { if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)
goto recursion_alert; HARD_TX_LOCK(dev, txq, cpu); if (!netif_xmit_stopped(txq)) {
__this_cpu_inc(xmit_recursion);
rc = dev_hard_start_xmit(skb, dev, txq);
__this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
goto out;
}
}
HARD_TX_UNLOCK(dev, txq);
net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
dev->name);
} else {
/* Recursion is detected! It is possible,
* unfortunately
*/
recursion_alert:
net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
dev->name);
}
} rc = -ENETDOWN;
rcu_read_unlock_bh(); atomic_long_inc(&dev->tx_dropped);
kfree_skb(skb);
return rc;
out:
rcu_read_unlock_bh();
return rc;
}

数据接收

数据接收接口也是内核的部分代码由内核实现,是内核留给驱动层接口上报接收到数据的接口路径,网络设备驱动在中断或轮询中收到数据包后需要打包一个socket数据包(struct sk_buff)然后通过内核数据接收接口上报给内核上层。

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

由上面的代码可以看出来 struct sk_buff 在网络驱动中是一个非常重要的数据结构。网络数据的整个传输过程就是对这个数据结构的访问修改读取的过程,所以先来简单了解一下这个数据结构

struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev; union {
ktime_t tstamp;
struct skb_mstamp skb_mstamp;
}; struct sock *sk;
struct net_device *dev; /*
* This is the control buffer. It is free to use for every
* layer. Please put your private variables there. If you
* want to keep them across layers you have to do a skb_clone()
* first. This is owned by whoever has the skb queued ATM.
*/
char cb[48] __aligned(8); unsigned long _skb_refdst;
#ifdef CONFIG_XFRM
struct sec_path *sp;
#endif
unsigned int len,
data_len;
__u16 mac_len,
hdr_len;
union {
__wsum csum;
struct {
__u16 csum_start;
__u16 csum_offset;
};
};
__u32 priority;
kmemcheck_bitfield_begin(flags1);
__u8 ignore_df:1,
cloned:1,
ip_summed:2,
nohdr:1,
nfctinfo:3;
__u8 pkt_type:3,
fclone:2,
ipvs_property:1,
peeked:1,
nf_trace:1;
kmemcheck_bitfield_end(flags1);
__be16 protocol; void (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct nf_conntrack *nfct;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info *nf_bridge;
#endif int skb_iif; __u32 hash; __be16 vlan_proto;
__u16 vlan_tci; #ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
__u16 tc_verd; /* traffic control verdict */
#endif
#endif __u16 queue_mapping;
kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif
__u8 pfmemalloc:1;
__u8 ooo_okay:1;
__u8 l4_hash:1;
__u8 wifi_acked_valid:1;
__u8 wifi_acked:1;
__u8 no_fcs:1;
__u8 head_frag:1;
/* Encapsulation protocol and NIC drivers should use
* this flag to indicate to each other if the skb contains
* encapsulated packet or not and maybe use the inner packet
* headers if needed
*/
__u8 encapsulation:1;
__u8 encap_hdr_csum:1;
__u8 csum_valid:1;
__u8 csum_complete_sw:1;
/* 3/5 bit hole (depending on ndisc_nodetype presence) */
kmemcheck_bitfield_end(flags2); #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
union {
unsigned int napi_id;
dma_cookie_t dma_cookie;
};
#endif
#ifdef CONFIG_NETWORK_SECMARK
__u32 secmark;
#endif
union {
__u32 mark;
__u32 dropcount;
__u32 reserved_tailroom;
}; __be16 inner_protocol;
__u16 inner_transport_header;
__u16 inner_network_header;
__u16 inner_mac_header;
__u16 transport_header;
__u16 network_header;
__u16 mac_header;
/* These elements must be at the end, see alloc_skb() for details. */
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head,
*data;
unsigned int truesize;
atomic_t users;
};

成员还是比较多的但是内核提供了对应的接口函数来直观的操作他,其中数据相关重要的成语有四个head、data、tail、end对这个结构的关系如下图

除此之外与之相关的驱动接口有如下几个。

申请套接字缓冲区

struct sk_buff* alloc_sbk(unsigned int len,gfp_t priority)
struct sk_buff* dev_alloc_skb(unsigned int len)

其中len为数据缓冲区的大小,对应释放的接口有

void kfree_skb(struct sk_buff* skb);
void dev_kfree_skb(unsigned int len);
void dev_kfree_skb_irq(unsigned int len);
//其实就是在上面两种接口的封装增加了是否为中断中的判断。
void dev_kfree_skb_any(unsigned int len);

数据包操作

//skb->tail向后移动len,skb->len增加len
unsigned char *skb_put(struct sk_buff* skb,unsigned int len);
//skb->data向前移动len,skb->len增加len
unsigned char *skb_push(struct sk_buff* skb,unsigned int len);
//skb->data向后移动len,skb->len减少len
unsigned char *skb_pull(struct sk_buff* skb,unsigned int len);
//skb->tail和skb->data同时向后移动len
unsigned char *skb_reserve(struct sk_buff* skb,unsigned int len);

上面这些接口会在驱动中调用具体驱动分析时在详细学习。

网络设备接口

内核抽象了网络设备接口的封装但是这个结构十分庞大且复杂其中涵盖统计属性、配置等定义如下:

  1 struct net_device {
2
3 /*
4 * This is the first field of the "visible" part of this structure
5 * (i.e. as seen by users in the "Space.c" file). It is the name
6 * of the interface.
7 */
8 char name[IFNAMSIZ];
9
10 /* device name hash chain, please keep it close to name[] */
11 struct hlist_node name_hlist;
12
13 /* snmp alias */
14 char *ifalias;
15
16 /*
17 * I/O specific fields
18 * FIXME: Merge these and struct ifmap into one
19 */
20 unsigned long mem_end; /* shared mem end */
21 unsigned long mem_start; /* shared mem start */
22 unsigned long base_addr; /* device I/O address */
23 int irq; /* device IRQ number */
24
25 /*
26 * Some hardware also needs these fields, but they are not
27 * part of the usual set specified in Space.c.
28 */
29
30 unsigned long state;
31
32 struct list_head dev_list;
33 struct list_head napi_list;
34 struct list_head unreg_list;
35 struct list_head close_list;
36
37 /* directly linked devices, like slaves for bonding */
38 struct {
39 struct list_head upper;
40 struct list_head lower;
41 } adj_list;
42
43 /* all linked devices, *including* neighbours */
44 struct {
45 struct list_head upper;
46 struct list_head lower;
47 } all_adj_list;
48
49
50 /* currently active device features */
51 netdev_features_t features;
52 /* user-changeable features */
53 netdev_features_t hw_features;
54 /* user-requested features */
55 netdev_features_t wanted_features;
56 /* mask of features inheritable by VLAN devices */
57 netdev_features_t vlan_features;
58 /* mask of features inherited by encapsulating devices
59 * This field indicates what encapsulation offloads
60 * the hardware is capable of doing, and drivers will
61 * need to set them appropriately.
62 */
63 netdev_features_t hw_enc_features;
64 /* mask of fetures inheritable by MPLS */
65 netdev_features_t mpls_features;
66
67 /* Interface index. Unique device identifier */
68 int ifindex;
69 int iflink;
70
71 struct net_device_stats stats;
72
73 /* dropped packets by core network, Do not use this in drivers */
74 atomic_long_t rx_dropped;
75 atomic_long_t tx_dropped;
76
77 /* Stats to monitor carrier on<->off transitions */
78 atomic_t carrier_changes;
79
80 #ifdef CONFIG_WIRELESS_EXT
81 /* List of functions to handle Wireless Extensions (instead of ioctl).
82 * See <net/iw_handler.h> for details. Jean II */
83 const struct iw_handler_def * wireless_handlers;
84 /* Instance data managed by the core of Wireless Extensions. */
85 struct iw_public_data * wireless_data;
86 #endif
87 /* Management operations */
88 const struct net_device_ops *netdev_ops;
89 const struct ethtool_ops *ethtool_ops;
90 const struct forwarding_accel_ops *fwd_ops;
91
92 /* Hardware header description */
93 const struct header_ops *header_ops;
94
95 unsigned int flags; /* interface flags (a la BSD) */
96 unsigned int priv_flags; /* Like 'flags' but invisible to userspace.
97 * See if.h for definitions. */
98 unsigned short gflags;
99 unsigned short padded; /* How much padding added by alloc_netdev() */
100
101 unsigned char operstate; /* RFC2863 operstate */
102 unsigned char link_mode; /* mapping policy to operstate */
103
104 unsigned char if_port; /* Selectable AUI, TP,..*/
105 unsigned char dma; /* DMA channel */
106
107 unsigned int mtu; /* interface MTU value */
108 unsigned short type; /* interface hardware type */
109 unsigned short hard_header_len; /* hardware hdr length */
110
111 /* extra head- and tailroom the hardware may need, but not in all cases
112 * can this be guaranteed, especially tailroom. Some cases also use
113 * LL_MAX_HEADER instead to allocate the skb.
114 */
115 unsigned short needed_headroom;
116 unsigned short needed_tailroom;
117
118 /* Interface address info. */
119 unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
120 unsigned char addr_assign_type; /* hw address assignment type */
121 unsigned char addr_len; /* hardware address length */
122 unsigned short neigh_priv_len;
123 unsigned short dev_id; /* Used to differentiate devices
124 * that share the same link
125 * layer address
126 */
127 unsigned short dev_port; /* Used to differentiate
128 * devices that share the same
129 * function
130 */
131 spinlock_t addr_list_lock;
132 struct netdev_hw_addr_list uc; /* Unicast mac addresses */
133 struct netdev_hw_addr_list mc; /* Multicast mac addresses */
134 struct netdev_hw_addr_list dev_addrs; /* list of device
135 * hw addresses
136 */
137 #ifdef CONFIG_SYSFS
138 struct kset *queues_kset;
139 #endif
140
141 bool uc_promisc;
142 unsigned int promiscuity;
143 unsigned int allmulti;
144
145
146 /* Protocol specific pointers */
147
148 #if IS_ENABLED(CONFIG_VLAN_8021Q)
149 struct vlan_info __rcu *vlan_info; /* VLAN info */
150 #endif
151 #if IS_ENABLED(CONFIG_NET_DSA)
152 struct dsa_switch_tree *dsa_ptr; /* dsa specific data */
153 #endif
154 #if IS_ENABLED(CONFIG_TIPC)
155 struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */
156 #endif
157 void *atalk_ptr; /* AppleTalk link */
158 struct in_device __rcu *ip_ptr; /* IPv4 specific data */
159 struct dn_dev __rcu *dn_ptr; /* DECnet specific data */
160 struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */
161 void *ax25_ptr; /* AX.25 specific data */
162 struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
163 assign before registering */
164
165 /*
166 * Cache lines mostly used on receive path (including eth_type_trans())
167 */
168 unsigned long last_rx; /* Time of last Rx */
169
170 /* Interface address info used in eth_type_trans() */
171 unsigned char *dev_addr; /* hw address, (before bcast
172 because most packets are
173 unicast) */
174
175
176 #ifdef CONFIG_SYSFS
177 struct netdev_rx_queue *_rx;
178
179 /* Number of RX queues allocated at register_netdev() time */
180 unsigned int num_rx_queues;
181
182 /* Number of RX queues currently active in device */
183 unsigned int real_num_rx_queues;
184
185 #endif
186
187 rx_handler_func_t __rcu *rx_handler;
188 void __rcu *rx_handler_data;
189
190 struct netdev_queue __rcu *ingress_queue;
191 unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
192
193
194 /*
195 * Cache lines mostly used on transmit path
196 */
197 struct netdev_queue *_tx ____cacheline_aligned_in_smp;
198
199 /* Number of TX queues allocated at alloc_netdev_mq() time */
200 unsigned int num_tx_queues;
201
202 /* Number of TX queues currently active in device */
203 unsigned int real_num_tx_queues;
204
205 /* root qdisc from userspace point of view */
206 struct Qdisc *qdisc;
207
208 unsigned long tx_queue_len; /* Max frames per queue allowed */
209 spinlock_t tx_global_lock;
210
211 #ifdef CONFIG_XPS
212 struct xps_dev_maps __rcu *xps_maps;
213 #endif
214 #ifdef CONFIG_RFS_ACCEL
215 /* CPU reverse-mapping for RX completion interrupts, indexed
216 * by RX queue number. Assigned by driver. This must only be
217 * set if the ndo_rx_flow_steer operation is defined. */
218 struct cpu_rmap *rx_cpu_rmap;
219 #endif
220
221 /* These may be needed for future network-power-down code. */
222
223 /*
224 * trans_start here is expensive for high speed devices on SMP,
225 * please use netdev_queue->trans_start instead.
226 */
227 unsigned long trans_start; /* Time (in jiffies) of last Tx */
228
229 int watchdog_timeo; /* used by dev_watchdog() */
230 struct timer_list watchdog_timer;
231
232 /* Number of references to this device */
233 int __percpu *pcpu_refcnt;
234
235 /* delayed register/unregister */
236 struct list_head todo_list;
237 /* device index hash chain */
238 struct hlist_node index_hlist;
239
240 struct list_head link_watch_list;
241
242 /* register/unregister state machine */
243 enum { NETREG_UNINITIALIZED=0,
244 NETREG_REGISTERED, /* completed register_netdevice */
245 NETREG_UNREGISTERING, /* called unregister_netdevice */
246 NETREG_UNREGISTERED, /* completed unregister todo */
247 NETREG_RELEASED, /* called free_netdev */
248 NETREG_DUMMY, /* dummy device for NAPI poll */
249 } reg_state:8;
250
251 bool dismantle; /* device is going do be freed */
252
253 enum {
254 RTNL_LINK_INITIALIZED,
255 RTNL_LINK_INITIALIZING,
256 } rtnl_link_state:16;
257
258 /* Called from unregister, can be used to call free_netdev */
259 void (*destructor)(struct net_device *dev);
260
261 #ifdef CONFIG_NETPOLL
262 struct netpoll_info __rcu *npinfo;
263 #endif
264
265 #ifdef CONFIG_NET_NS
266 /* Network namespace this network device is inside */
267 struct net *nd_net;
268 #endif
269
270 /* mid-layer private */
271 union {
272 void *ml_priv;
273 struct pcpu_lstats __percpu *lstats; /* loopback stats */
274 struct pcpu_sw_netstats __percpu *tstats;
275 struct pcpu_dstats __percpu *dstats; /* dummy stats */
276 struct pcpu_vstats __percpu *vstats; /* veth stats */
277 };
278 /* GARP */
279 struct garp_port __rcu *garp_port;
280 /* MRP */
281 struct mrp_port __rcu *mrp_port;
282
283 /* class/net/name entry */
284 struct device dev;
285 /* space for optional device, statistics, and wireless sysfs groups */
286 const struct attribute_group *sysfs_groups[4];
287 /* space for optional per-rx queue attributes */
288 const struct attribute_group *sysfs_rx_queue_group;
289
290 /* rtnetlink link ops */
291 const struct rtnl_link_ops *rtnl_link_ops;
292
293 /* for setting kernel sock attribute on TCP connection setup */
294 #define GSO_MAX_SIZE 65536
295 unsigned int gso_max_size;
296 #define GSO_MAX_SEGS 65535
297 u16 gso_max_segs;
298
299 #ifdef CONFIG_DCB
300 /* Data Center Bridging netlink ops */
301 const struct dcbnl_rtnl_ops *dcbnl_ops;
302 #endif
303 u8 num_tc;
304 struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
305 u8 prio_tc_map[TC_BITMASK + 1];
306
307 #if IS_ENABLED(CONFIG_FCOE)
308 /* max exchange id for FCoE LRO by ddp */
309 unsigned int fcoe_ddp_xid;
310 #endif
311 #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
312 struct netprio_map __rcu *priomap;
313 #endif
314 /* phy device may attach itself for hardware timestamping */
315 struct phy_device *phydev;
316
317 struct lock_class_key *qdisc_tx_busylock;
318
319 /* group the device belongs to */
320 int group;
321
322 struct pm_qos_request pm_qos_req;
323 };

struct net_device

其中主要的成员有

1、全局的信息
name

2、硬件信息

定义设备所使用的共享内存的内存信息和中断等。
unsigned long mem_start
unsigned long mem_end

unsigned long base_addr
unsigned char irq
unsigned char if_port

其中if_port 为多端口设备使用。

3、接口信息
hard_header_len 硬件头长度
type 接口硬件类型
mtu
flags 接口特性标志,部分由内核使用
4、设备操作函数netdev_ops (驱动的重点实现部分),驱动有时还需要实现一部分网络工具需要的接口函数。放在这个结构体的net_device->ethtool_ops (非必须,常见有设置设备MAC地址等)

这里重要先看一下网络设备操作接口,定义如下:

struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
void (*ndo_uninit)(struct net_device *dev);
int (*ndo_open)(struct net_device *dev);
int (*ndo_stop)(struct net_device *dev);
netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb,
struct net_device *dev);
u16 (*ndo_select_queue)(struct net_device *dev,
struct sk_buff *skb,
void *accel_priv,
select_queue_fallback_t fallback);
void (*ndo_change_rx_flags)(struct net_device *dev,
int flags);
void (*ndo_set_rx_mode)(struct net_device *dev);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
int (*ndo_do_ioctl)(struct net_device *dev,
struct ifreq *ifr, int cmd);
int (*ndo_set_config)(struct net_device *dev,
struct ifmap *map);
int (*ndo_change_mtu)(struct net_device *dev,
int new_mtu);
int (*ndo_neigh_setup)(struct net_device *dev,
struct neigh_parms *);
void (*ndo_tx_timeout) (struct net_device *dev); struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
struct rtnl_link_stats64 *storage);
struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); int (*ndo_vlan_rx_add_vid)(struct net_device *dev,
__be16 proto, u16 vid);
int (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
__be16 proto, u16 vid);
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
int (*ndo_netpoll_setup)(struct net_device *dev,
struct netpoll_info *info);
void (*ndo_netpoll_cleanup)(struct net_device *dev);
#endif
#ifdef CONFIG_NET_RX_BUSY_POLL
int (*ndo_busy_poll)(struct napi_struct *dev);
#endif
int (*ndo_set_vf_mac)(struct net_device *dev,
int queue, u8 *mac);
int (*ndo_set_vf_vlan)(struct net_device *dev,
int queue, u16 vlan, u8 qos);
int (*ndo_set_vf_rate)(struct net_device *dev,
int vf, int min_tx_rate,
int max_tx_rate);
int (*ndo_set_vf_spoofchk)(struct net_device *dev,
int vf, bool setting);
int (*ndo_get_vf_config)(struct net_device *dev,
int vf,
struct ifla_vf_info *ivf);
int (*ndo_set_vf_link_state)(struct net_device *dev,
int vf, int link_state);
int (*ndo_set_vf_port)(struct net_device *dev,
int vf,
struct nlattr *port[]);
int (*ndo_get_vf_port)(struct net_device *dev,
int vf, struct sk_buff *skb);
int (*ndo_setup_tc)(struct net_device *dev, u8 tc);
#if IS_ENABLED(CONFIG_FCOE)
int (*ndo_fcoe_enable)(struct net_device *dev);
int (*ndo_fcoe_disable)(struct net_device *dev);
int (*ndo_fcoe_ddp_setup)(struct net_device *dev,
u16 xid,
struct scatterlist *sgl,
unsigned int sgc);
int (*ndo_fcoe_ddp_done)(struct net_device *dev,
u16 xid);
int (*ndo_fcoe_ddp_target)(struct net_device *dev,
u16 xid,
struct scatterlist *sgl,
unsigned int sgc);
int (*ndo_fcoe_get_hbainfo)(struct net_device *dev,
struct netdev_fcoe_hbainfo *hbainfo);
#endif #if IS_ENABLED(CONFIG_LIBFCOE)
#define NETDEV_FCOE_WWNN 0
#define NETDEV_FCOE_WWPN 1
int (*ndo_fcoe_get_wwn)(struct net_device *dev,
u64 *wwn, int type);
#endif #ifdef CONFIG_RFS_ACCEL
int (*ndo_rx_flow_steer)(struct net_device *dev,
const struct sk_buff *skb,
u16 rxq_index,
u32 flow_id);
#endif
int (*ndo_add_slave)(struct net_device *dev,
struct net_device *slave_dev);
int (*ndo_del_slave)(struct net_device *dev,
struct net_device *slave_dev);
netdev_features_t (*ndo_fix_features)(struct net_device *dev,
netdev_features_t features);
int (*ndo_set_features)(struct net_device *dev,
netdev_features_t features);
int (*ndo_neigh_construct)(struct neighbour *n);
void (*ndo_neigh_destroy)(struct neighbour *n); int (*ndo_fdb_add)(struct ndmsg *ndm,
struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr,
u16 flags);
int (*ndo_fdb_del)(struct ndmsg *ndm,
struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr);
int (*ndo_fdb_dump)(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
int idx); int (*ndo_bridge_setlink)(struct net_device *dev,
struct nlmsghdr *nlh);
int (*ndo_bridge_getlink)(struct sk_buff *skb,
u32 pid, u32 seq,
struct net_device *dev,
u32 filter_mask);
int (*ndo_bridge_dellink)(struct net_device *dev,
struct nlmsghdr *nlh);
int (*ndo_change_carrier)(struct net_device *dev,
bool new_carrier);
int (*ndo_get_phys_port_id)(struct net_device *dev,
struct netdev_phys_port_id *ppid);
void (*ndo_add_vxlan_port)(struct net_device *dev,
sa_family_t sa_family,
__be16 port);
void (*ndo_del_vxlan_port)(struct net_device *dev,
sa_family_t sa_family,
__be16 port); void* (*ndo_dfwd_add_station)(struct net_device *pdev,
struct net_device *dev);
void (*ndo_dfwd_del_station)(struct net_device *pdev,
void *priv); netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb,
struct net_device *dev,
void *priv);
int (*ndo_get_lock_subclass)(struct net_device *dev);
};

很多也很复杂但也是实现必要的部分就可以了。具体的每个函数的作用后面分析驱动实例时候在全部看这里暂时记录一部部分自己现在理解的。当实现好一个网络设备并填充绑定了必须的接口信息之后就可以将网络设备注册到内核了。

网络设备的初始化(ndo_init成员)

在这个接口一般完成硬件的准备工作,检查硬件,并获取记录硬件资源。软件接口的准备工作。初始化私有成员并绑定到设备。

网络设备打开和关闭(ndo_open 和ndo_stop)

使能设备的硬件资源如中断申请,DMA 使能和配置。调用netif_start_queque()激活设备发送队列。关闭过程就是释放和关闭前面申请的资源调用netif_stop_queque()停止设备数据包传输。

数据发送过程
网络设备的数据传输过程依赖内核的一个数据结构struct sk_buff网络层打包一个完全的数据包,由下层一层层使用去除各层信息最后到达物理设备完成数据在电路上的传输。
int xxx_tx(struct sk_buff*sk_buff,struct net_device* dev)
{
   执行软件操作逻辑的处理,如等待队列---阻塞调用进程等。
   记录信息和超时的处理
   操作硬件设备寄存器等完成数据到硬件设备。
   最后有硬件设备将数据合适时间完成发送。
  发送完成后还要唤醒组册的队列中的进程。
}

数据接收过程
数据的接受一般都是由中断触发的,硬件完成数据的接收和校验后将调用网络设备的接收接口函数,将接收到的数据封成一个struct sk_buff 结构体然后通过
void xxx_rx(struct net_device* dev)
向上层递交数据。除此之外有些网络设备是NAPI兼容设备,就是对数据接收支持轮询的方式,此时这个轮询函数也封装在设备操作中,并且由指定的接口启动和停止轮询一般都是数据的第一包到来后进入中断在中断中启动轮询调度。当受到数据时
他将调用netif_receive_skb(struct sk_buff* sk_buff)提交数据给上层协议。详细具体的信息后面在学习。具体的设备连接状态信息统计等等详细的内容这里也暂时不详细看,后续用到来继续】
深入具体的学习,这里还是前面的话重在走粗线条,太细后面不用也记不住。

网络设备注册

网络设备成员实现完成后就需要通过对应的接口完成注册使用接口
int register_netdev(struct net_device* dev)
同时还有注销接口
void unregister_netdevice(struct net_device* dev)
Linux 还提供了一些宏完成网络设备的内存申请和成员的部分初始化。其最后都是通过调用
struct net_device* net_dev_mqs(int sizeof_priv,const char* name,void(*setup)(struct net_device*),unsigned int txgs,unsigned int txgs);
来分配内存和初始化网络设备。网络设备的注册和普通设备的注册没有太大的区别不在详细看。

Linux 驱动框架---net驱动框架的更多相关文章

  1. 【Linux高级驱动】input子系统框架【转】

    转自:http://www.cnblogs.com/lcw/p/3802617.html [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架?    1) 通过网 ...

  2. (转)S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析 (By liukun321 咕唧咕唧)

    作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...

  3. S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析

    作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...

  4. linux设备驱动程序--串行通信驱动框架分析

    linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...

  5. 【Linux开发】V4L2驱动框架分析学习

    Author:CJOK Contact:cjok.liao#gmail.com SinaWeibo:@廖野cjok 1.概述 Video4Linux2是Linux内核中关于视频设备的内核驱动框架,为上 ...

  6. Linux 驱动框架---i2c驱动框架

    i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...

  7. Linux 驱动框架---platform驱动框架

    Linux系统的驱动框架主要就是三个主要部分组成,驱动.总线.设备.现在常见的嵌入式SOC已经不是单纯的CPU的概念了,它们都会在片上集成很多外设电路,这些外设都挂接在SOC内部的总线上,不同与IIC ...

  8. 【Linux高级驱动】input子系统框架

    [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架?    1) 通过网络搜索    2) 自己想办法跟内核代码!         2.1 定位此驱动是属于哪种类 ...

  9. 【Linux高级驱动】I2C驱动框架分析

    1.i2c-dev.c(i2c设备驱动组件层) 功能:1)给用户提供接口 i2c_dev_init  //入口函数 /*申请主设备号*/ register_chrdev(I2C_MAJOR(), &q ...

随机推荐

  1. python爬虫如何提高效率

    开启线程池: 线程池 asyncio 特殊的函数 协程 任务对象 任务对象绑定 事件循环 from multiprocessing.dummy import Pool map(func,alist): ...

  2. 超精讲-逐例分析 CSAPP:实验2-Bomb!(下)

    好了话不多说我们书接上文继续来做第二个实验下面是前半部分实验的连接 5. 第五关 首先感觉应该是个递归问题 /* Round and 'round in memory we go, where we ...

  3. 前端面试之CSS常用的选择器!

    前端面试之CSS常用的选择器! 标签选择器 <style> /* <!-- 标签选择器 :写上标签名 -->*/ p { color: green; } div { color ...

  4. Manachar’s Algorithm

    Manachar's Algorithm Longest palindromic substring - Wikipedia  https://en.wikipedia.org/wiki/Longes ...

  5. 在不同情况下connect失败和ping不通的数据分析

  6. 从URL输入到页面展现到底发生什么?

    目录 前言 一.URL 到底是啥 二.域名解析(DNS) 1.IP 地址 2.什么是域名解析 3. 浏览器如何通过域名去查询 URL 对应的 IP 呢 4. 小结 三.TCP 三次握手 1.TCP 三 ...

  7. Form表单的知识点汇总

    分享学习到的Form知识点,希望给同样有所需要的朋友共同学习..愿我的分享,可以成为您的厚爱.. 简单的知识收到简单的回报,未来的努力造就优秀的自己... <!--<form> -- ...

  8. 利用Javascript制作网页特效(窗口特效)

    全屏显示窗口 利用fullscreen=yes可以制作全屏显示窗口. ①:在body标签内输入以下代码: <div align="center"> <input ...

  9. Spring框架——事务管理方式搭建一个小的项目

    学习Spring框架,通过事务管理的方式搭建一个小的项目,该项目可以查询对数据库中的图书库存数量进行修改. 首先,使用MVC分层的设计模式思想搭建项目目录结构. 此部分代码源码之中都有相关注释,所以尽 ...

  10. 封装SpringJdbcTemplate

    package com.jy.modules.cms.query; import java.util.List; import java.util.Map; public interface quer ...