• Linux内核网络报文简单流程


    转:http://blog.csdn.net/adamska0104/article/details/45397177

    Linux内核网络报文简单流程 2014-08-12 10:05:09

    分类: Linux

    linux下的网卡驱动中通常会提供类似XXX_rx的接收函数

    该函数处理与具体硬件相关的寄存器操作

    包括中断检查,数据状态检查,错误检查等

    在确认有数据抵达后读取数据或从DMA的接收环中获取数据地址

    XXX_rx函数以skb为元数据结构组织报文数据

    随后调用内核接口函数netif_rx或netif_receive_skb

    这里会涉及到软中断的处理,NAPI的接收方式

    但是最后都会走netif_receive_skb函数

    现在内核中使用了RPS机制

    将报文分散到各个cpu的接收队列中进行负载均衡处理

    在netif_receive_skb函数中进行了封装

    真正的数据处理从__netif_receive_skb_core函数开始

    现在可以将该函数视为协议栈的入口函数

    首先进行skb中报文头元数据的调整

    如果是vlan报文则先从数据中提取至vlan_tci字段

    将vlan标签的4个字节从数据移除

    即在调用deliver_skb向上层传递报文数据时不含vlan标签

    ptype_all链表的处理主要用于抓包

    在应用程序中注册PF_PACKET族ETH_P_ALL的socket便可以得到所有的输入报文

    也可以用于实现自定义的协议类型报文收发

    随后内核会丢弃无法识别的报文

    也可以在内核模块中使用dev_add_pack向ptype_all注册自定义的处理函数

    如果接口上配置了输入流控

    则根据具体的队列和分类规则决定继续处理或丢弃报文

    对于vlan数据报文

    将skb记录的输入接口修改为vlan虚接口

    比如使用vconfig配置的eth0.100虚接口

    再重复上述处理

    内核提供了netdev_rx_handler_register接口函数向接口注册rx_handler

    比如为网桥下的接口注册br_handle_frame函数

    为bonding接口注册bond_handle_frame函数

    这相对于老式的网桥处理更灵活

    有了这个机制也可以在模块中自行注册处理函数

    网桥的处理包括向上层提交和转发

    发往本地的报文会修改入接口为网桥虚接口如br0

    调用netif_receive_skb重新进入协议栈处理

    对于上层协议栈见到的只有桥虚接口

    需要转发的报文根据转发表进行单播或广播发送

    netfilter在网桥的处理路径中从br_handle_frame到br_dev_queue_push_xmit设置了5个hook点

    根据nf_call_iptables的配置还会经过NFPROTO_IPV4的hook点等

    内核注册的由br_nf_ops数组中定义

    可在模块中自行向NFPROTO_BRIDGE族的几个hook点注册函数

    ebtables在netfilter框架NFPROTO_BRIDGE中实现了桥二层过滤机制

    配合应用程序ebtables可在桥下自定义相关规则

    处理完接口上的rx_handler后便根据具体的3层协议类型在ptype_base中寻找处理函数

    比如ETH_P_IP则调用ip_rcv,ETH_P_IPV6则调用ipv6_rcv

    这些函数都由dev_add_pack注册

    可在模块中自定义协议类型处理函数

    如果重复定义相同协议的处理函数则要注意报文的修改对后续流程的影响

    IP报文进入ip_rcv后进行简单的检查便进入路由选择

    根据路由查找结果调用ip_local_deliver向上层提交或调用ip_forward进行转发

    向上层提交前会进行IP分片的重组

    在ip_local_deliver_finish中会根据报文中4层协议类型调用对应的处理函数

    处理函数由接口函数inet_add_protocol注册

    针对TCP或UDP进行不同处理,最后唤醒应用程序接收数据

    向外发送和转发数据经由ip_output函数

    包括IP的分片,ARP学习,MAC地址的修改或填充等

    netfilter在从ip_rcv到ip_output间设置了5个hook点

    向各个点的链表中注册处理函数或使用iptables工具自定义规则

    实现报文处理的行为控制

    报文的发送最后汇聚到队列发送函数dev_queue_xmit

    在接口up的时候dev_activate会创建默认的队列规则

    这里也涉及到接口驱动初始化的时候软件多队列与硬件多队列

    配合tc工具可以在报文发送前进行流量控制等

    最终报文发送到dev_hard_start_xmit调用接口注册的动作函数ndo_start_xmit

    发送前会检查ptype_all链表,支持抓包处理等

    如果是虚拟接口则通常调用其对应物理接口的发送函数

    到这里内核对报文的控制便结束了

    根据不同网卡驱动的实现,操作寄存器等由物理层将数据发送出去

    整个调用链相对较长

    每个点都包含大量的细节

    主线都是围绕元数据结构skb的处理

  • 相关阅读:
    转来的:Diablo中的七大套装背景
    我的单元测试认识之路(下)
    《You can do it!》的chapter 2笔记
    一个枚举的简单应用
    仿百度的搜索下拉提示
    简单的 菜单当前选中 解决思路
    单元测试框架NUnit 之 Attributes特性(一)
    单元测试框架NUnit 之 constraints 约束
    分享个自己的ajax封装
    开源单元测试工具 Nunit
  • 原文地址:https://www.cnblogs.com/newjiang/p/7428125.html
Copyright © 2020-2023  润新知