i.MX6ULL驱动开发 | 32 - 手动编写一个虚拟网卡设备
Posted Mculover666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了i.MX6ULL驱动开发 | 32 - 手动编写一个虚拟网卡设备相关的知识,希望对你有一定的参考价值。
一、Linux内核网络驱动处理流程
1. net_device结构体的申请与释放
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);
参数意义如下:
- sizeof_priv:设备私有成员的大小
- name:设备名
- name_assign_type:名称对齐类型
- setup:函数指针
- txqs:要分配的发送队列的数量
- rxqs:要分配的接收队列的数量
释放net_device结构体的API如下:
void free_netdev(struct net_device *dev);
2. 网络设备驱动的注册与注销
网络驱动注册与注销使用如下两个API,定义在文件include/linux/netdevice.h
中:
int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);
一般的,在驱动模块初始化的时候注册网卡设备到内核,在驱动模块卸载的时候,从内核注销网卡设备。
3. 网络设备的初始化
网络设备初始化主要完成以下工作:
- 进行硬件准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源;
- 进行软件准备工作,分配net_device结构体并对其数据和函数指针成员赋值;
- 获得设备的私有信息指针并初始化各成员的值;
4. 网络设备的打开与释放
网络设备的打开函数需要完成以下工作:
- 使能设备所使用的硬件资源,申请I/O区域、中断、DMA通道等
- 调用Linux内核提供的API,激活设备发送队列
网络设备的释放函数需要完成以下工作:
- 调用Linux内核提供的API,停止设备传输包
- 释放设备所使用的I/O区域、中断、DMA通道等
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));
5. 数据发送流程
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));
6. 数据接收流程
网络设备接收数据的主要方法时由中断引发设备的中断处理函数,中断处理函数中判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。
二、实例——编写一个虚拟网卡设备
参考文章:26.Linux-网卡驱动介绍以及制作虚拟网卡驱动(详解)
该博文写的很不错,博主在此基础上,更新了驱动适配到4.14内核。
1. 目的
编写一个虚拟网卡设备,可以添加到内核中,并写一个虚拟的发包收包设备,使得该网卡可以ping通任何ip。
2. 代码实现
https://github.com/Mculover666/linux_driver_study/
3. 效果
3.1. 加载虚拟网卡驱动模块
加载模块之前,查看当前系统中存在的网卡:
加载虚拟网卡驱动模块:
加载之后再查看系统网卡,可以看到多了virt_eth0:
再使用ifconfig查看:
3.2.ping测试
设置网卡ip:
查看路由表:
ping网段内任意ip测试:
可以看到发包数量和收包数量被统计:
以上是关于i.MX6ULL驱动开发 | 32 - 手动编写一个虚拟网卡设备的主要内容,如果未能解决你的问题,请参考以下文章
i.MX6ULL驱动开发 | 37 - FT5426电容触摸屏幕调试并修复驱动问题(基于linux 5.4.32内核)
i.MX6ULL驱动开发 | 01-Linux内核模块的编写与使用
i.MX6ULL驱动开发 | 21 - 按键驱动使用 input 子系统上报事件
i.MX6ULL驱动开发 | 21 - 按键驱动使用 input 子系统上报事件