网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配 sk_buffer 数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用 netif_rx() 函数将 sk_buffer 传递给上层协议。下面是完成这个过程的函数模板。

/*

* 网络设备驱动中的中断处理函数模板

*/

1 static void xxx_interrupt(int irq, void *dev_id)2 {3 struct net_device *dev = (struct net_device *)dev_id;4 ···5 switch (status &ISQ_EVENT_MASK) {6 caseISQ_RECEIVER_EVENT:7 /*获取数据包*/

8 xxx_rx(dev);9 break;10 /*其他类型的中断*/

11 }12 }13

14

15 static void xxx_rx(struct xxx_device *dev)16 {17 ···18 length =get_rev_len(···);19 /*分配新的套接字缓冲区*/

20 skb = dev_alloc_skb(length + 2);21

22 skb_reserve(skb, 2); /*对齐*/

23 skb->dev =dev;24

25 /*读取硬件上接收到的数据*/

26 insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1);27 if (length & 1)28 skb->data[length - 1] = inw(ioaddr, +RX_FRAME_PORT);29

30 /*获取上层协议类型*/

31 skb->protocol=eth_type_trans(skb, dev);32

33 /*把数据包交给上层*/

34 netif_rx(skb);35

36 /*记录接收时间戳*/

37 dev->last_rx =jiffies;38 ···39 }

从上述代码的5 ~ 8行可以看出,当设备的中断处理程序判断中断类型为数据包接收中断时,它调用15 ~ 39行定义的 xxx_rx( ) 函数完成更深入的数据包接收工作。 xxx_rx( ) 函数代码中的第 18 行从硬件读取到接收数据包有效数据的长度,第19 ~ 22行分配 sk_buff 和数据缓冲区,第 25 ~ 28行读取硬件上接收到的数据并放入数据缓冲区, 第30 ~ 31行解析接收数据包上层协议的类型,最后,第33 ~ 34行代码将数据包上交给上层协议。

如果是 NAPI 兼容的设备驱动,则可以通过 poll 方式接收数据包。在这种情况下,我们需要为该设备驱动提供作为 netif_napi_add( ) 参数的 xxx_poll( ) 函数,代码如下所示:

1 /*

2 * 网络设备驱动的 xxx_poll() 函数模板3 */

4

5 static int xxx_poll(struct napi_struct *napi, intbudget)6 {7 int npackets = 0;8 struct sk_buff *skb;9 struct xxx_priv *priv = container_of(napi, structxxx_priv, napi);10 struct xxx_packet *pkt;11

12 while (npackets < budget && priv->rx_queue) {13 /*从队列中取出数据包*/

14 pkt =xxx_dequeue_buf(dev);15

16 /*接下来的处理和中断触发的数据包接收一致*/

17 skb = dev_alloc_skb(pkt->datalen + 2);18 ···19 skb_reserve(skb, 2);20 memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);21 skb->dev =dev;22 skb->protocol =eth_type_trans(skb, dev);23 /*调用 netif_receive_skb,而不是 net_rx,将数据包交给上层协议*/

24 netif_receive_skb(skb);25

26 /*更改统计数据*/

27 priv->stats.rx_packets++;28 priv->stats.rx_bytes += pkt->datalen;29 xxx_release_buffer(pkt);30 npackets++;31 }32 if (npackets

35 }36 returnnpackets;37 }

上述代码中的 budget 是在初始化阶段分配给接口的 weight 值,从 xxx_poll() 函数每次只能接收最多 budget 个数据包。第 12 行的 while() 循环读取设备的接收缓冲区,同时读取数据包并提交给上层。这个过程和中断触发的数据包接收过程一致,但是最后使用的是 netif_receive_skb( ) 函数而不是 netif_rx( ) 函数将数据包提交给上层。这里体现出了 中断处理机制 和 轮询机制之间的差别。

当一个轮询过程结束时,第 33 行代码调用 napi_complete( ) 宣布这一消息,而第 34 行代码则再次启动网络设备的接收中断。

虽然 NAPI 兼容的设备驱动以 xxx_poll( ) 方式接收数据包,但是仍然需要首次数据包接收中断来触发这个过程。与数据包的中断接收方式不同的是,以轮询方式接收数据包时,当第一次中断发生后,中断处理程序要禁止设备的数据包接收中断并调度 NAPI,如以下代码所示:

1 /*

2 * 网络设备驱动的 poll 中断处理3 */

4

5 static void xxx_interrupt(int irq, void *dev_id)6 {7 switch (status &ISQ_EVENT_MASK) {8 caseISQ_RECEIVER_EVENT:9 ··· /*获取数据包*/

10 xxx_disable_rx_int(···); /*禁止接收中断*/

11 napi_schedule(&priv->napi);12 break;13 ··· /*其他类型的中断*/

14 }15 }

上述代码第 11 行的 napi_schedule( ) 函数被轮询方式驱动的中断程序调用,将设备的 poll 方法添加到网络层的 poll 处理队列中,排队并且准备接收数据包,最终触发一个 NET_RX_SOFTIRQ 软中断,从而通知网络层接收数据包。下图为 NAPI 驱动程序各部分的调用关系。

在支持 NAPI 的网络设备驱动中,通常还会进行如下与 NAPI 相关的工作。

1. 在私有数据结构体 (如 xxx_priv)中增加一个成员:

struct napi_struct napi;

在代码中就可以方便地使用 container_of( ) 通过 NAPI 成员反向获得对应的 xxx_priv 指针。

2. 通常会在设备驱动初始化时调用:

netif_napi_add(dev, napi, xxx_poll, XXX_NET_NAPI_WEIGHT);

3. 通常会在 net_device 结构体的 open( ) 和 stop( ) 成员函数中分别调用 napi_enable( ) 和 napi_disable( )。

原文:https://www.cnblogs.com/wanglouxiaozi/p/13381648.html

linux接收网络数据并存存储,Linux网络设备驱动之数据接收流程(六)相关推荐

  1. linux接收网络数据并存存储,linux网络数据包数据结构 Socket Buffer

    Linux网络核心数据结构是套接字缓存(socket buffer),简称skb.它代表一个要发送或处理的报文,并贯穿于整个协议栈.1.套接字缓存skb由两部分组成:(1)报文数据:它保存了实际在网络 ...

  2. linux启动网络服务的命令,linux重启服务命令

    linux重启服务命令 重启:service 服务名 restart 或systemctl restart 服务名 service和systemctl 1.service命令 service命令其实是 ...

  3. linux内核网络协议栈--监控和调优:发送数据(三十)

    译者序 本文翻译自 2017 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Sending Data.如果能看懂英文,建议阅读原 ...

  4. linux内核网络钩子函数使用,Linux内核IOCTL网络控制框架实现实例分析

    4.6.inet_ioctl函数 由于inet_ioctl函数内容分支很多,但功能.处理不难理解,所以我把一些不常见的内容都省去,挑简单重要的说,完全在于抛砖引玉: static int inet_i ...

  5. 应用服务器与数据库之间是长连接,要接收多个 tcp 长连接不断发送的数据并存储,哪些数据库或数据存储方案比较合适?...

    在服务器建立服务端,与多个 tcp 连接保持长连接,服务端会根据客户端发送的 token 验证确定是否保持长连接建立"session"缓存, 在某个状态开启时(我称为存储状态),要 ...

  6. 惠普安装linux网卡,网络无人职守安装linux PXE

    网络无人职守安装linux Writen BY HPLJ-2007.12.4 1配置启动安装服务器 1)install and configure dhcp service /etc/dhcpd.co ...

  7. linux c 网络编程与信号量,linux网络编程-----线程同步--信号量

    开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因:资 ...

  8. Linux修改网络支持巨型帧,linux – KVM来宾和主机之间的巨型帧?

    我正在尝试为KVM来宾和主机系统之间的存储通信实现9000字节MTU.主机有一个桥接器(br1),其MTU为9000字节: host# ip link show br1 8: br1: mtu 900 ...

  9. linux有关网络服务的接口,linux系统有关网络服务接口定义是哪个?

    浮云间 (1)网络接口的命名 这里并不存在一定的命名规范,但网络接口名字的定义一般都是要有意义的.例如: eth0: ethernet的简写,一般用于以太网接口. wifi0:wifi是无线局域网,因 ...

最新文章

  1. 飞书与德勤管理咨询达成战略合作,赋能企业实现智慧运营与管理
  2. dedecms二级菜单中判断子菜单标签的方法
  3. numpy.ma详解
  4. 双栈排序java_双栈排序(Java)
  5. 看来美国的霸道不仅仅是针对Lenovo的,SONY也被威胁--索尼被判侵犯专利,PlayStation游戏机销售面临威胁【ZZ】...
  6. c语言题目集-田队写长单词
  7. 现代软件工程讲义 11 项目管理 - 事后诸葛亮会议
  8. 伸缩轨道_深度解析——伸缩喷漆房为什么这么受欢迎!
  9. 计算机目标导学方法,计算机教学计划
  10. java8 json转xml_2019-08-17java对象与json,xml互转
  11. Jsoup设置元素的文本内容
  12. SVM支持向量机:分类、回归和核函数
  13. S1304第一本书内测测试分析
  14. 《恋上数据结构第1季》队列、双端队列、循环队列、循环双端队列
  15. windows 通过 bat 脚本后台启动 jar 包,通过 jps 找到 pid,然后停止指定 jar 包,附 linux shell 脚本启停脚本
  16. 安装arcgis的时候应用程序无法正常启动0xc000007b解决方法
  17. Win10重装系统/迁移系统,教你如何简单快速删除原系统文件
  18. AMD 3600+ X2 CPU配合昂达A69T主板超频教程
  19. oracle试算平衡表查询,介绍一下余额试算平衡表的计算方法
  20. WinEdt编译提示pdf文件打不开,Cannot Run pdf

热门文章

  1. mysql amd.dll 后门_DLL后门清除完全篇
  2. html前沿技术网页,html页面标签元素总结
  3. UE3 贴图支持及设置
  4. 苹果新Metal API实测:四倍完爆OpenGL ES
  5. 【转】iOS编译OpenSSL静态库(使用脚本自动编译)
  6. Server's Revolution
  7. MYSQL基础之centos 6下二进制安装mariadb
  8. 误区30日谈21-24
  9. gem install 和 bundle 区别
  10. 面试中几个基本的重要问题总结