net_device结构体实例可以通过动态申请:
#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1)
#define alloc_netdev_mq(sizeof_priv, name, name_assign_type, setup, count) \
alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, count, \
count)
这两个宏底层调用的函数都是alloc_netdev_mqs,原型如下:
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
unsigned char name_assign_type,
void (*setup)(struct net_device *),
unsigned int txqs, unsigned int rxqs);
参数意义如下:
释放net_device结构体的API如下:
void free_netdev(struct net_device *dev);
网络驱动注册与注销使用如下两个API,定义在文件include/linux/netdevice.h中:
int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);
一般的,在驱动模块初始化的时候注册网卡设备到内核,在驱动模块卸载的时候,从内核注销网卡设备。
网络设备初始化主要完成以下工作:
网络设备的打开函数需要完成以下工作:
网络设备的释放函数需要完成以下工作:
Linux内核提供的两个API如下:
/**
* netif_start_queue - allow transmit
* @dev: network device
*
* Allow upper layers to call the device hard_start_xmit routine.
*/
static inline void netif_start_queue(struct net_device *dev)
{
netif_tx_start_queue(netdev_get_tx_queue(dev, 0));
}
/**
* netif_stop_queue - stop transmitted packets
* @dev: network device
*
* Stop upper layers calling the device hard_start_xmit routine.
* Used for flow control when transmit resources are unavailable.
*/
static inline void netif_stop_queue(struct net_device *dev)
{
netif_tx_stop_queue(netdev_get_tx_queue(dev, 0));
}
Linux网络子系统在发送数据包时,会调用驱动程序提供的ndo_start_xmit函数,用于启动数据包的发送,所以底层只需要实现该函数指针即可。
发送流程如下:
Linux内核提供的唤醒上层传递数据包的API如下:
/**
* netif_wake_queue - restart transmit
* @dev: network device
*
* Allow upper layers to call the device hard_start_xmit routine.
* Used for flow control when transmit resources are available.
*/
static inline void netif_wake_queue(struct net_device *dev)
{
netif_tx_wake_queue(netdev_get_tx_queue(dev, 0));
}
网络设备接收数据的主要方法时由中断引发设备的中断处理函数,中断处理函数中判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。
参考文章:26.Linux-网卡驱动介绍以及制作虚拟网卡驱动(详解)
该博文写的很不错,博主在此基础上,更新了驱动适配到4.14内核。
编写一个虚拟网卡设备,可以添加到内核中,并写一个虚拟的发包收包设备,使得该网卡可以ping通任何ip。
https://github.com/Mculover666/linux_driver_study/
加载模块之前,查看当前系统中存在的网卡:

加载虚拟网卡驱动模块:

加载之后再查看系统网卡,可以看到多了virt_eth0:

再使用ifconfig查看:

设置网卡ip:

查看路由表:

ping网段内任意ip测试:

可以看到发包数量和收包数量被统计:
