Linux内核Net子系统完全解析
·
第一部分:网络子系统总体架构
1.1 网络子系统分层结构树
Linux网络子系统 │ ├── 【用户空间层】 │ ├── 应用程序 (sockets API) │ │ ├── socket() / bind() / listen() / accept() │ │ ├── send() / recv() / sendto() / recvfrom() │ │ └── setsockopt() / getsockopt() │ │ │ └── 配置工具 │ ├── iproute2 (ip命令) │ ├── net-tools (ifconfig, route) │ ├── ethtool │ └── ss / netstat │ ├── 【系统调用接口层】net/socket.c │ ├── SYSCALL_DEFINE3(socket, ...) # socket()系统调用 │ ├── SYSCALL_DEFINE3(bind, ...) # bind()系统调用 │ ├── SYSCALL_DEFINE3(connect, ...) # connect()系统调用 │ ├── SYSCALL_DEFINE4(send, ...) # send()系统调用 │ ├── SYSCALL_DEFINE4(recv, ...) # recv()系统调用 │ └── sockfd_lookup_light() # fd→socket结构转换 │ ├── 【协议无关接口层】net/socket.c │ ├── struct socket # BSD socket抽象 │ │ ├── struct file *file # 关联的文件结构 │ │ ├── struct sock *sk # INET socket层 │ │ ├── const struct proto_ops *ops # 协议族操作 │ │ └── short type # SOCK_STREAM等 │ │ │ └── struct proto_ops # 协议族操作表 │ ├── .bind = inet_bind │ ├── .connect = inet_stream_connect │ ├── .accept = inet_accept │ ├── .sendmsg = inet_sendmsg │ └── .recvmsg = inet_recvmsg │ ├── 【INET Socket层】net/ipv4/af_inet.c │ ├── struct sock # 传输层socket抽象 │ │ ├── struct sock_common __sk_common │ │ │ ├── __be32 skc_daddr # 目标IP │ │ │ ├── __be32 skc_rcv_saddr # 源IP │ │ │ ├── __u16 skc_num # 本地端口 │ │ │ └── __u16 skc_dport # 目标端口 │ │ ├── struct sk_buff_head sk_receive_queue # 接收队列 │ │ ├── struct sk_buff_head sk_write_queue # 发送队列 │ │ ├── struct sk_buff_head sk_backlog # 后备队列 │ │ ├── struct proto *sk_prot # 传输层协议操作 │ │ └── struct socket *sk_socket # 回指BSD socket │ │ │ └── struct proto # 传输层协议操作表 │ ├── .hash = tcp_v4_hash │ ├── .connect = tcp_v4_connect │ ├── .sendmsg = tcp_sendmsg │ └── .recvmsg = tcp_recvmsg │ ├── 【传输层协议】 │ ├── TCP (net/ipv4/tcp.c, tcp_input.c, tcp_output.c) │ │ ├── tcp_v4_rcv() # TCP接收入口 │ │ ├── tcp_v4_sendmsg() # TCP发送 │ │ ├── tcp_input.c # 输入处理 │ │ │ ├── tcp_rcv_established() # 已建立连接接收 │ │ │ └── tcp_rcv_state_process() # 状态机处理 │ │ ├── tcp_output.c # 输出处理 │ │ │ ├── tcp_sendmsg() # 用户数据发送 │ │ │ └── tcp_write_xmit() # 实际发送 │ │ └── tcp_timer.c # 定时器管理 │ │ │ ├── UDP (net/ipv4/udp.c) │ │ ├── udp_rcv() # UDP接收入口 │ │ ├── udp_sendmsg() # UDP发送 │ │ └── udp_queue_rcv_skb() # 入队处理 │ │ │ └── RAW (net/ipv4/raw.c) │ ├── raw_rcv() │ └── raw_sendmsg() │ ├── 【网络层】net/ipv4/ │ ├── IP输入 (ip_input.c) │ │ ├── ip_rcv() # IP包接收入口 │ │ ├── ip_rcv_finish() # 接收完成处理 │ │ ├── ip_local_deliver() # 本地投递 │ │ └── ip_local_deliver_finish() # 本地投递完成 │ │ │ ├── IP转发 (ip_forward.c) │ │ ├── ip_forward() # 转发处理 │ │ └── ip_forward_finish() │ │ │ ├── IP输出 (ip_output.c) │ │ ├── ip_queue_xmit() # IP层发送 │ │ ├── ip_output() # 输出处理 │ │ └── ip_finish_output() # 完成输出 │ │ │ ├── IP分片 (ip_fragment.c) │ │ ├── ip_fragment() # IP分片 │ │ └── ip_defrag() # IP重组 │ │ │ └── 路由子系统 (net/ipv4/route.c) │ ├── ip_route_input() # 输入路由查找 │ ├── ip_route_output_key() # 输出路由查找 │ └── struct rtable # 路由缓存项 │ ├── 【邻居子系统】net/core/neighbour.c │ ├── struct neighbour # 邻居项 │ │ ├── u8 nud_state # NUD状态 │ │ ├── struct hh_cache hh # 硬件头缓存 │ │ └── struct net_device *dev │ ├── ARP协议 (net/ipv4/arp.c) │ │ ├── arp_rcv() # ARP接收 │ │ ├── arp_send() # ARP发送 │ │ └── arp_process() # ARP处理 │ └── neigh_resolve_output() # 邻居解析输出 │ ├── 【设备无关接口层】net/core/dev.c │ ├── 初始化: net_dev_init() │ │ ├── 注册网络软中断 │ │ │ ├── open_softirq(NET_TX_SOFTIRQ, net_tx_action) │ │ │ └── open_softirq(NET_RX_SOFTIRQ, net_rx_action) │ │ └── 初始化CPU私有数据 │ │ │ ├── 接收路径 │ │ ├── netif_rx() # 传统接收(非NAPI) │ │ ├── netif_receive_skb() # 接收核心 │ │ └── __netif_receive_skb_core() # 核心处理 │ │ │ ├── 发送路径 │ │ ├── dev_queue_xmit() # 发送入口 │ │ ├── __dev_queue_xmit() # 核心发送 │ │ └── dev_hard_start_xmit() # 硬件发送 │ │ │ └── 软中断处理 │ ├── net_rx_action() # 接收软中断 │ └── net_tx_action() # 发送软中断 │ └── 【网络设备驱动层】drivers/net/ ├── struct net_device # 网络设备抽象 │ ├── netdev_ops # 设备操作 │ │ ├── .ndo_open │ │ ├── .ndo_stop │ │ ├── .ndo_start_xmit │ │ └── .ndo_get_stats │ ├── struct device dev │ └── void *priv # 驱动私有数据 │ └── 驱动示例 ├── e1000 (Intel PRO/1000) ├── r8169 (Realtek) ├── virtio_net (虚拟化) └── veth (虚拟以太网)
第二部分:TCP/IP协议栈逐层分析
2.1 数据包接收完整流程
TCP数据包接收Pipeline │ ├── 【硬件层】网卡接收 │ ├── 1. 数据帧到达网卡PHY │ ├── 2. 网卡DMA写入内存环形缓冲区 │ ├── 3. 网卡触发硬件中断 │ └── 代码路径: drivers/net/ethernet/intel/e1000/e1000_main.c │ ├── 【中断处理】上半部 │ ├── e1000_intr() # 中断处理函数 │ │ ├── 读取中断状态寄存器 │ │ ├── 禁用中断 (或轮询模式) │ │ ├── 调度NAPI: napi_schedule() │ │ └── 返回IRQ_HANDLED │ │ │ └── 关键函数: __napi_schedule() │ └── 将napi_struct加入CPU的poll_list │ ├── 【软中断处理】下半部 │ ├── net_rx_action() # NET_RX_SOFTIRQ处理 │ │ ├── 遍历CPU的poll_list │ │ ├── 调用napi->poll()函数 │ │ └── 控制轮询时间/包数预算 │ │ │ └── e1000_clean() # NAPI poll函数 │ ├── 读取DMA描述符环 │ ├── 分配sk_buff │ ├── 将数据拷贝/映射到skb │ ├── napi_gro_receive() # GRO合并 │ └── netif_receive_skb() │ ├── 【设备无关层】netif_receive_skb() │ ├── 1. VLAN去标签 (如果存在) │ ├── 2. 递交给抓包点: ptype_all (tcpdump) │ ├── 3. 递交给协议处理 │ │ └── __netif_receive_skb_core() │ │ ├── 桥接处理 (如果启用) │ │ ├── 根据skb->protocol查找ptype_base │ │ └── 调用协议handler: ip_rcv() │ │ │ └── 关键数据结构: ptype_base哈希表 │ └── 协议类型→处理函数映射 │ ├── ETH_P_IP → ip_rcv │ ├── ETH_P_ARP → arp_rcv │ └── ETH_P_8021Q → vlan_skb_recv │ ├── 【网络层】IP层处理 (ip_input.c) │ ├── ip_rcv() │ │ ├── 1. IP头合法性检查 │ │ ├── 2. 计算校验和 │ │ ├── 3. 设置netfilter钩子 NF_INET_PRE_ROUTING │ │ └── 4. 调用 ip_rcv_finish() │ │ │ ├── ip_rcv_finish() │ │ ├── 路由查找: ip_route_input_noref() │ │ ├── 确定是本机、转发还是丢弃 │ │ └── 根据路由结果分发 │ │ │ ├── ip_local_deliver() # 本机投递 │ │ ├── IP分片重组: ip_defrag() │ │ ├── netfilter: NF_INET_LOCAL_IN │ │ └── ip_local_deliver_finish() │ │ │ └── ip_local_deliver_finish() │ └── 根据L4协议分发 │ ├── IPPROTO_TCP → tcp_v4_rcv │ ├── IPPROTO_UDP → udp_rcv │ └── IPPROTO_ICMP → icmp_rcv │ ├── 【传输层】TCP处理 (tcp_input.c) │ ├── tcp_v4_rcv() │ │ ├── 1. 查找sock: __inet_lookup() │ │ ├── 2. 校验和验证 │ │ ├── 3. 锁socket: bh_lock_sock() │ │ └── 4. 根据socket状态处理 │ │ │ ├── 接收路径分支 │ │ ├── TCP_ESTABLISHED → tcp_rcv_established() │ │ └── 其他状态 → tcp_rcv_state_process() │ │ │ ├── tcp_rcv_established() │ │ ├── 快速路径 (无选项, 无乱序) │ │ │ ├── 数据放入接收队列 │ │ │ └── 发送ACK │ │ └── 慢速路径 (有选项或有乱序) │ │ ├── tcp_data_queue() # 排队数据 │ │ ├── 处理乱序包 │ │ └── tcp_ofo_queue() # 重排序队列 │ │ │ ├── tcp_data_queue() │ │ ├── 顺序数据 → 加入sk_receive_queue │ │ ├── 乱序数据 → 加入ofo_queue │ │ └── 唤醒等待进程 │ │ │ └── 最终数据到达用户空间 │ ├── tcp_recvmsg() # 用户态read/recv │ └── skb_copy_datagram_msg() # 拷贝到用户空间 │ └── 关键数据结构流转 └── struct sk_buff (SKB) 生命周期 ├── 网卡DMA分配 ├── netif_receive_skb() ├── ip_rcv() ├── tcp_v4_rcv() ├── tcp_rcv_established() └── kfree_skb() (释放)
2.2 数据包发送完整流程
TCP数据包发送Pipeline │ ├── 【用户层】系统调用 │ ├── send() / write() │ ├── sys_sendto() → net/socket.c │ └── sock_sendmsg() │ ├── 【INET Socket层】 │ ├── inet_sendmsg() │ │ └── 调用sk->sk_prot->sendmsg │ └── tcp_sendmsg() (net/ipv4/tcp.c) │ ├── 1. 获取用户数据 │ ├── 2. 锁定socket │ ├── 3. 拷贝数据到skb │ ├── 4. 加入发送队列: tcp_send_skb() │ └── 5. 调度发送: tcp_push() │ ├── 【TCP层输出】 │ ├── tcp_write_xmit() (tcp_output.c) │ │ ├── 拥塞窗口检查 │ │ ├── 发送窗口检查 │ │ ├── tcp_transmit_skb() # 构建TCP头 │ │ └── 调用IP层发送 │ │ │ └── tcp_transmit_skb() │ ├── 克隆SKB (可能) │ ├── 构建TCP头 │ ├── 计算校验和 │ └── 调用 queue_xmit(): ip_queue_xmit() │ ├── 【网络层】IP输出 │ ├── ip_queue_xmit() (ip_output.c) │ │ ├── 1. 路由查找 (如果未缓存) │ │ ├── 2. 设置IP头 │ │ ├── 3. netfilter: NF_INET_LOCAL_OUT │ │ ├── 4. ip_local_out() │ │ └── ip_output() │ │ │ └── ip_finish_output() │ ├── 分片检查: ip_fragment() (如果超过MTU) │ ├── netfilter: NF_INET_POST_ROUTING │ └── neigh_output() → dev_queue_xmit() │ ├── 【邻居子系统】 │ ├── neigh_output() │ │ ├── 邻居状态检查 │ │ │ ├── NUD_CONNECTED → 直接发送 │ │ │ └── NUD_INCOMPLETE → 排队等待ARP │ │ └── dev_queue_xmit() │ │ │ └── ARP处理 (arp.c) │ ├── arp_send() # 发送ARP请求 │ └── arp_process() # 处理ARP响应 │ ├── 【设备无关层】发送核心 │ ├── dev_queue_xmit() │ ├── __dev_queue_xmit() │ │ ├── 1. 选择发送队列 (QoS) │ │ ├── 2. 排队规则入队: qdisc_enqueue() │ │ ├── 3. 调度: qdisc_run() │ │ └── __qdisc_run() │ │ │ └── qdisc_restart() # 从队列取包发送 │ ├── dev_hard_start_xmit() │ └── 调用 ndo_start_xmit │ ├── 【网卡驱动】实际发送 │ ├── e1000_xmit_frame() (驱动) │ │ ├── 1. 映射DMA地址 │ │ ├── 2. 填充描述符 │ │ ├── 3. 更新TDT (发送描述符尾寄存器) │ │ └── 4. 网卡DMA读取并发送 │ │ │ └── 发送完成中断 │ └── 释放SKB (DMA unmap, kfree_skb) │ └── 关键流程图 write() → sys_write() → sock_write() → tcp_sendmsg() → tcp_push() → tcp_write_xmit() → tcp_transmit_skb() → ip_queue_xmit() → ip_output() → ip_finish_output() → dev_queue_xmit() → qdisc_enqueue() → __qdisc_run() → dev_hard_start_xmit() → ndo_start_xmit() → 硬件发送 → 发送完成中断
第三部分:核心数据结构树形分析
3.1 sk_buff (SKB) 结构详解
struct sk_buff (include/linux/skbuff.h)
│
├── 【网络参数区】
│ ├── struct sock *sk # 所属socket
│ ├── struct net_device *dev # 接收/发送设备
│ ├── struct net_device *input_dev # 原始输入设备
│ ├── __be32 protocol # 协议类型 (ETH_P_IP等)
│ ├── u16 transport_header # 传输层头偏移
│ ├── u16 network_header # 网络层头偏移
│ ├── u16 mac_header # MAC层头偏移
│ └── u16 inner_*_header # 隧道内层头
│
├── 【数据指针区】 (关键偏移操作)
│ ├── unsigned char *head # 缓冲区起始
│ ├── unsigned char *data # 数据起始
│ ├── unsigned char *tail # 数据结束
│ └── unsigned char *end # 缓冲区结束
│
├── 【长度信息】
│ ├── unsigned int len # 总数据长度
│ ├── unsigned int data_len # 非线性数据长度
│ ├── unsigned int truesize # 实际分配大小
│ └── atomic_t users # 引用计数
│
├── 【控制标志】
│ ├── __u8 pkt_type # 包类型 (PACKET_HOST等)
│ ├── __u8 ip_summed # 校验和状态
│ │ ├── CHECKSUM_NONE
│ │ ├── CHECKSUM_UNNECESSARY
│ │ ├── CHECKSUM_COMPLETE
│ │ └── CHECKSUM_PARTIAL
│ ├── __u8 cloned # 是否克隆
│ ├── __u8 nofcs # 无FCS标志
│ └── __u8 ignore_df # 忽略不分片标志
│
├── 【时间戳】
│ ├── union {
│ │ __u32 tstamp
│ │ ktime_t tstamp
│ │ }
│ └── __u32 skb_mstamp_ns
│
├── 【非线性数据区】 (分页支持)
│ └── struct skb_shared_info *shinfo
│ ├── unsigned int nr_frags # 分页数量
│ ├── skb_frag_t frags[MAX_SKB_FRAGS] # 分页数组
│ ├── struct sk_buff *frag_list # 分片链
│ └── __u32 gso_size # GSO分段大小
│
└── 【私有数据区】 (各层使用)
├── cb[48] char # 控制块 (48字节)
│ └── TCP使用: struct tcp_skb_cb
│ ├── seq, end_seq
│ ├── tcp_flags
│ └── 其他控制信息
└── __u32 *data_priv
3.2 环形缓冲区实现 (网卡DMA)
网卡DMA环形缓冲区架构
│
├── 【基本原理】
│ ├── 生产者-消费者模型
│ ├── 2的幂次大小 (便于位运算)
│ └── 硬件与软件共享
│
├── 【描述符环结构】
│ struct e1000_rx_ring {
│ struct e1000_rx_desc *desc; # 描述符数组
│ dma_addr_t dma; # 物理地址
│ struct sk_buff **skb; # SKB指针数组
│ unsigned int count; # 描述符数量
│ unsigned int next_to_use; # 生产者索引
│ unsigned int next_to_clean; # 消费者索引
│ };
│
├── 【环形缓冲区操作宏】 (include/linux/circ_buf.h)
│ ├── CIRC_SPACE(head, tail, size) # 剩余空间
│ ├── CIRC_SPACE_TO_END() # 连续剩余空间
│ ├── CIRC_CNT(head, tail, size) # 已用数量
│ └── CIRC_CNT_TO_END() # 连续已用数量
│
├── 【接收环形缓冲流程】
│ ├── 1. 硬件接收中断
│ ├── 2. 驱动处理clean函数
│ │ ├── 读取last_clean索引
│ │ ├── 遍历描述符直到last_clean == next_to_use
│ │ │ ├── 检查描述符状态位 (DD)
│ │ │ ├── 获取DMA数据
│ │ │ ├── 构建SKB
│ │ │ └── 提交上层: napi_gro_receive()
│ │ ├── 更新next_to_clean
│ │ └── 分配新的SKB填充释放的描述符
│ │
│ └── 3. 硬件继续DMA写入空闲描述符
│
├── 【发送环形缓冲流程】
│ ├── 1. 驱动xmit函数
│ │ ├── 获取next_to_use索引
│ │ ├── 填充描述符 (DMA地址, 长度)
│ │ └── 更新next_to_use (写入TDT寄存器)
│ │
│ ├── 2. 硬件DMA读取描述符发送
│ ├── 3. 发送完成中断
│ │ ├── 读取next_to_clean
│ │ ├── 检查描述符完成标志
│ │ ├── 释放SKB (DMA unmap, kfree)
│ │ └── 更新next_to_clean
│ │
│ └── 4. BQL字节队列限制
│ ├── 动态限流避免缓冲区膨胀
│ └── dev_watchdog监控
│
└── 【内存屏障应用】 (Documentation/core-api/circular-buffers.rst)
├── smp_store_release() # 生产者写入head
├── smp_load_acquire() # 消费者读取head
└── 确保数据在索引更新前可见
第四部分:特殊协议族处理Pipeline
4.1 CAN总线协议 (SocketCAN)
CAN总线协议栈 (net/can/)
│
├── 【协议层架构】
│ ├── AF_CAN地址族 (PF_CAN = 29)
│ ├── 协议类型
│ │ ├── CAN_RAW (原始CAN帧)
│ │ ├── CAN_BCM (广播管理器)
│ │ ├── CAN_TP (传输协议ISO 15765-2)
│ │ └── CAN_ISOTP (ISO-TP诊断)
│ │
│ └── 协议族初始化: can_init()
│
├── 【CAN帧结构】
│ struct can_frame {
│ canid_t can_id; # CAN ID (11位或29位)
│ __u8 can_dlc; # 数据长度 (0-8)
│ __u8 __pad; # 填充
│ __u8 __res0; # 保留
│ __u8 len8_dlc; # 可选DLC
│ __u8 data[8]; # 数据 (最多8字节)
│ };
│
├── 【接收Pipeline】
│ │
│ ├── 硬件层
│ │ └── CAN控制器驱动 (如mcp251x, flexcan)
│ │
│ ├── 驱动接收
│ │ ├── 中断处理读取CAN帧
│ │ ├── 分配skb: alloc_can_skb()
│ │ ├── 填充can_frame结构
│ │ └── netif_rx() / netif_receive_skb()
│ │
│ ├── 协议层接收 (af_can.c)
│ │ ├── can_rcv()
│ │ │ ├── 过滤匹配 (CAN ID过滤)
│ │ │ ├── 查找绑定的socket
│ │ │ └── can_queue_rcv_skb()
│ │ └── 入队到socket接收队列
│ │
│ └── 用户空间
│ └── recvmsg() 读取can_frame
│
├── 【发送Pipeline】
│ ├── 用户空间sendmsg()
│ ├── raw_sendmsg() (can_raw.c)
│ │ ├── 构建can_frame
│ │ ├── 路由到网络设备
│ │ └── can_send()
│ ├── can_send()
│ │ ├── 计算CAN帧时间戳
│ │ ├── 硬件过滤配置
│ │ └── dev_queue_xmit()
│ └── CAN驱动发送
│ └── 写入控制器寄存器
│
├── 【ISO-TP协议】 (can-isotp)
│ ├── 用途: 传输超过8字节的数据 (UDS诊断)
│ ├── 内核模块: can-isotp
│ ├── 分段机制
│ │ ├── 首帧 (FF) - 包含总长度
│ │ ├── 连续帧 (CF) - 后续数据
│ │ └── 流控制 (FC) - 接收方控制
│ │
│ └── ISO-TP Socket示例
│ int s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
│ struct sockaddr_can addr;
│ addr.can_family = AF_CAN;
│ addr.can_ifindex = if_nametoindex("can0");
│ addr.can_addr.tp.rx_id = 0x123; # 接收CAN ID
│ addr.can_addr.tp.tx_id = 0x456; # 发送CAN ID
│
└── 【调试工具】
├── candump (查看CAN帧)
├── cansend (发送CAN帧)
├── isotpdump (ISO-TP调试)
└── isotpsend (ISO-TP发送)
4.2 Bluetooth协议栈 (BlueZ)
Bluetooth协议栈架构 (net/bluetooth/)
│
├── 【地址族】
│ ├── PF_BLUETOOTH (AF_BLUETOOTH = 31)
│ └── 协议类型
│ ├── BTPROTO_L2CAP
│ ├── BTPROTO_HCI
│ ├── BTPROTO_RFCOMM
│ ├── BTPROTO_BNEP
│ ├── BTPROTO_CMTP
│ └── BTPROTO_SCO
│
├── 【协议栈分层】
│ │
│ ├── 【HCI层】 (hci_sock.c)
│ │ ├── 主机控制器接口
│ │ ├── 处理与蓝牙硬件的通信
│ │ ├── HCI命令: hci_send_cmd()
│ │ ├── HCI事件: hci_event_packet()
│ │ └── 数据包: hci_send_data()
│ │
│ ├── 【L2CAP层】 (l2cap_core.c)
│ │ ├── 逻辑链路控制和适配协议
│ │ ├── 通道复用 (CID)
│ │ ├── 分段和重组 (SAR)
│ │ ├── l2cap_chan_send() # 发送
│ │ ├── l2cap_recv_frame() # 接收
│ │ └── 流控和重传
│ │
│ ├── 【RFCOMM层】 (rfcomm/core.c)
│ │ ├── 串口仿真 (9针RS-232)
│ │ ├── rfcomm_dlc_send() # DLC发送
│ │ ├── rfcomm_recv_frame() # 接收
│ │ └── TTY仿真: rfcomm_tty
│ │
│ ├── 【BNEP层】 (bnep/core.c)
│ │ └── 蓝牙网络封装 (PAN)
│ │ ├── BNEP桥接以太网
│ │ └── bnep_netdev_ops (虚拟网卡)
│ │
│ └── 【SCO层】 (sco.c)
│ └── 同步连接 (语音)
│
├── 【核心管理】 (mgmt.c)
│ ├── 蓝牙控制器管理
│ ├── 设备发现
│ ├── 配对和绑定
│ └── mgmt_sock_event()
│
├── 【数据流Pipeline】
│ │
│ ├── 接收路径
│ │ ├── 硬件接收 (USB/串口)
│ │ ├── hci_rx_work() # HCI接收工作
│ │ ├── hci_send_to_sock() # 发送到HCI socket
│ │ └── 协议分发
│ │ ├── L2CAP帧 → l2cap_recv_acldata()
│ │ ├── SCO帧 → sco_recv_scodata()
│ │ └── 事件 → mgmt_event()
│ │
│ └── 发送路径
│ ├── L2CAP发送: l2cap_chan_send()
│ ├── 分段处理: l2cap_segment_sdu()
│ ├── HCI封装: hci_send_acl()
│ └── 硬件发送: hci_send_frame()
│
├── 【Socket接口】
│ ├── 创建Bluetooth Socket
│ │ int sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
│ │ int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
│ │ int sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
│ │
│ └── 地址结构
│ struct sockaddr_hci {
│ sa_family_t hci_family;
│ unsigned short hci_dev;
│ unsigned short hci_channel;
│ };
│
└── 【用户空间】BlueZ工具
├── bluetoothd (守护进程)
├── bluetoothctl (控制工具)
├── hcitool (HCI工具)
├── hciconfig (配置)
└── rfcomm (串口绑定)
4.3 自定义协议实现框架
自定义Socket协议实现框架
│
├── 【步骤1:注册协议族】
│ │
│ ├── 定义协议族编号
│ │ #define AF_MYPROTO 46 (需要分配)
│ │ #define PF_MYPROTO AF_MYPROTO
│ │
│ ├── 实现协议族操作表
│ │ static const struct proto_ops myproto_ops = {
│ │ .family = PF_MYPROTO,
│ │ .owner = THIS_MODULE,
│ │ .release = myproto_release,
│ │ .bind = myproto_bind,
│ │ .connect = myproto_connect,
│ │ .socketpair = sock_no_socketpair,
│ │ .accept = sock_no_accept,
│ │ .sendmsg = myproto_sendmsg,
│ │ .recvmsg = myproto_recvmsg,
│ │ .mmap = sock_no_mmap,
│ │ };
│ │
│ └── 注册到net_families[]
│ static int __init myproto_init(void)
│ {
│ int err = sock_register(&myproto_family_ops);
│ if (err) return err;
│ err = proto_register(&myproto_prot, 0);
│ return err;
│ }
│
├── 【步骤2:定义socket结构】
│ │
│ └── 继承struct sock
│ struct myproto_sock {
│ struct sock sk; # 必须放在第一位
│ spinlock_t lock;
│ struct list_head rx_queue;
│ struct list_head tx_queue;
│ int state;
│ __u32 local_addr;
│ __u32 remote_addr;
│ };
│
├── 【步骤3:实现socket操作】
│ │
│ ├── myproto_create()
│ │ static int myproto_create(struct net *net, struct socket *sock,
│ │ int protocol, int kern)
│ │ {
│ │ struct myproto_sock *mp;
│ │ struct sock *sk;
│ │
│ │ if (!capable(CAP_NET_RAW))
│ │ return -EPERM;
│ │
│ │ sock->state = SS_UNCONNECTED;
│ │ sock->ops = &myproto_ops;
│ │
│ │ sk = sk_alloc(net, PF_MYPROTO, GFP_KERNEL, &myproto_prot, kern);
│ │ mp = myproto_sk(sk);
│ │
│ │ sock_init_data(sock, sk);
│ │ sk->sk_destruct = myproto_destruct;
│ │
│ │ return 0;
│ │ }
│ │
│ ├── myproto_sendmsg()
│ │ static int myproto_sendmsg(struct socket *sock,
│ │ struct msghdr *msg, size_t len)
│ │ {
│ │ struct sock *sk = sock->sk;
│ │ struct sk_buff *skb;
│ │ int err;
│ │
│ │ /* 分配SKB */
│ │ skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE,
│ │ msg->msg_flags & MSG_DONTWAIT, &err);
│ │
│ │ /* 拷贝用户数据 */
│ │ skb_put(skb, len);
│ │ err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len);
│ │
│ │ /* 设置协议头 */
│ │ skb_push(skb, MYPROTO_HLEN);
│ │ skb->protocol = htons(ETH_P_MYPROTO);
│ │
│ │ /* 发送处理 (设备无关层) */
│ │ err = dev_queue_xmit(skb);
│ │
│ │ return len;
│ │ }
│ │
│ └── myproto_recvmsg()
│ static int myproto_recvmsg(struct socket *sock,
│ struct msghdr *msg, size_t size, int flags)
│ {
│ struct sock *sk = sock->sk;
│ struct sk_buff *skb;
│ int err;
│
│ skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
│
│ /* 拷贝到用户空间 */
│ err = skb_copy_datagram_msg(skb, 0, msg, skb->len);
│
│ skb_free_datagram(sk, skb);
│ return err ?: skb->len;
│ }
│
├── 【步骤4:协议注册】
│ │
│ └── 协议族结构
│ static struct net_proto_family myproto_family_ops = {
│ .family = PF_MYPROTO,
│ .create = myproto_create,
│ .owner = THIS_MODULE,
│ };
│
└── 【步骤5:用户空间使用】
int sock = socket(AF_MYPROTO, SOCK_RAW, 0);
struct sockaddr_my addr = { .family = AF_MYPROTO, .dev = 1 };
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
send(sock, data, len, 0);
recv(sock, buf, sizeof(buf), 0);
第五部分:调试工具与性能分析
5.1 调试工具树形图
Linux网络调试工具全景
│
├── 【传统工具集】
│ ├── net-tools (已过时但常用)
│ │ ├── ifconfig # 接口配置
│ │ ├── route # 路由表
│ │ ├── netstat # 网络统计
│ │ └── arp # ARP缓存
│ │
│ └── iproute2 (现代替代)
│ ├── ip # 主命令
│ │ ├── ip link # 链路层
│ │ ├── ip addr # IP地址
│ │ ├── ip route # 路由
│ │ ├── ip neigh # 邻居
│ │ └── ip netns # 网络命名空间
│ ├── ss # socket统计
│ ├── tc # 流量控制
│ └── bridge # 桥接
│
├── 【抓包分析工具】
│ ├── tcpdump # 命令行抓包
│ │ tcpdump -i eth0 -w capture.pcap
│ │ tcpdump -i any host 192.168.1.1
│ │ tcpdump -i eth0 'tcp port 80'
│ │
│ ├── wireshark # GUI分析
│ │ └── 支持协议解析/流跟踪
│ │
│ ├── tshark # 命令行Wireshark
│ │
│ └── netsniff-ng # 高性能抓包
│ └── ifpps # top类网络统计
│
├── 【eBPF追踪工具】
│ │
│ ├── pwru (Packet Where aRe yoU)
│ │ ├── 追踪网络包在内核中的路径
│ │ ├── 高级过滤 (skb元数据, 函数名)
│ │ └── 示例: pwru --output-tuple 'host 1.1.1.1'
│ │
│ ├── bpftrace # 动态追踪
│ │ ├── 追踪kprobe/uprobe
│ │ └── 示例: bpftrace -e 'kprobe:ip_rcv { @[comm] = count(); }'
│ │
│ └── libbpf # BPF开发库
│
├── 【内核调试接口】
│ ├── /proc/net/ # 网络统计
│ │ ├── /proc/net/dev # 设备统计
│ │ ├── /proc/net/tcp # TCP连接
│ │ ├── /proc/net/udp # UDP连接
│ │ ├── /proc/net/sockstat # Socket统计
│ │ └── /proc/net/softnet_stat # 软中断统计
│ │
│ ├── /sys/class/net/ # sysfs接口
│ │ └── eth0/statistics/ # 设备统计
│ │
│ ├── netlink # 内核-用户通信
│ │ ├── NETLINK_ROUTE # 路由信息
│ │ ├── NETLINK_SOCK_DIAG # Socket诊断
│ │ └── NETLINK_NETFILTER # Netfilter
│ │
│ └── tracepoints # 静态跟踪点
│ ├── net:netif_rx
│ ├── net:net_dev_queue
│ ├── net:ip_rcv
│ ├── net:tcp_rcv_established
│ └── net:sock_rcvqueue_alloc
│
├── 【性能分析工具】
│ ├── perf # Linux性能分析
│ │ perf record -e net:netif_receive_skb
│ │ perf top
│ │
│ ├── ftrace # 函数跟踪
│ │ echo 'ip_rcv' > /sys/kernel/debug/tracing/set_ftrace_filter
│ │ echo function > current_tracer
│ │
│ └── sar # 系统活动报告
│ sar -n DEV 1
│
├── 【专用测试工具】
│ ├── netperf # 网络性能测试
│ ├── iperf3 # 带宽测试
│ ├── ping # 连通性测试
│ ├── traceroute # 路由跟踪
│ ├── ethtool # 网卡配置/统计
│ │ ethtool -S eth0 # 网卡统计
│ │ ethtool -k eth0 # 卸载功能
│ │ ethtool -i eth0 # 驱动信息
│ │
│ └── nstat # 网络统计
│
└── 【开发调试工具】
├── strace # 系统调用跟踪
│ strace -e network curl example.com
│
├── gdb # 内核调试
│ gdb vmlinux /proc/kcore
│
└── kdump # 内核崩溃转储
5.2 性能分析树形图
网络性能分析框架 │ ├── 【性能指标层次】 │ │ │ ├── 应用层指标 │ │ ├── 吞吐量 (Mbps) │ │ ├── 延迟 (RTT) │ │ ├── 并发连接数 │ │ └── 请求响应时间 │ │ │ ├── 传输层指标 │ │ ├── TCP重传率 │ │ ├── TCP窗口大小 │ │ ├── 拥塞窗口(cwnd) │ │ ├── 接收窗口(rwnd) │ │ └── 丢包率 │ │ │ ├── 网络层指标 │ │ ├── 路由缓存命中率 │ │ ├── IP分片率 │ │ ├── ICMP错误率 │ │ └── 转发速率 (pps) │ │ │ ├── 设备层指标 │ │ ├── 网卡丢包计数 │ │ ├── 中断速率 │ │ ├── DMA映射效率 │ │ ├── 描述符环利用率 │ │ └── 硬件队列深度 │ │ │ └── 系统层指标 │ ├── CPU软中断占用 │ ├── 内存使用 (SKB缓存) │ ├── 锁竞争 │ └── 缓存未命中率 │ ├── 【性能瓶颈定位流程】 │ │ │ ├── 1. 识别瓶颈层 │ │ ├── 应用层: ss -ti 查看TCP统计 │ │ ├── 协议栈: netstat -s 查看协议统计 │ │ ├── 设备层: ethtool -S eth0 │ │ └── 系统层: mpstat -P ALL 1 │ │ │ ├── 2. 细粒度分析 │ │ ├── 追踪函数调用: perf top │ │ ├── 抓包分析: tcpdump -i eth0 -w cap.pcap │ │ ├── eBPF追踪: pwru --output-tuple │ │ └── 内核追踪: trace-cmd record -e net │ │ │ └── 3. 优化建议 │ ├── 调整缓冲区大小 │ ├── 启用GRO/GSO/TSO │ ├── 调整中断亲和性 │ ├── 使用多队列网卡 │ └── 优化拥塞控制算法 │ ├── 【性能调优参数】 │ │ │ ├── 内核参数 (/proc/sys/net/) │ │ ├── core/ │ │ │ ├── netdev_max_backlog # 接收队列长度 │ │ │ ├── somaxconn # 监听队列长度 │ │ │ └── rmem_default/max # 接收缓冲区 │ │ ├── ipv4/ │ │ │ ├── tcp_rmem/tcp_wmem # TCP缓冲区 │ │ │ ├── tcp_congestion_control # 拥塞控制 │ │ │ ├── tcp_tw_reuse # TIME_WAIT复用 │ │ │ └── tcp_fastopen # TFO │ │ └── netfilter/ │ │ └── nf_conntrack_max # 连接跟踪 │ │ │ ├── 网卡卸载功能 (ethtool -k) │ │ ├── tso (TCP Segmentation Offload) │ │ ├── gro (Generic Receive Offload) │ │ ├── gso (Generic Segmentation Offload) │ │ ├── lro (Large Receive Offload) │ │ ├── rx/tx checksum │ │ └── rss (Receive Side Scaling) │ │ │ └── 中断亲和性 (smp_affinity) │ └── echo 1 > /proc/irq/xxx/smp_affinity │ └── 【性能监控命令】 ├── sar -n DEV 1 # 设备吞吐量 ├── sar -n TCP 1 # TCP统计 ├── sar -n EDEV 1 # 错误统计 ├── ss -tiepm # Socket详细信息 ├── nstat -z # 内核网络统计 ├── netstat -i # 接口统计 ├── ip -s link # 接口统计(现代) └── ifpps eth0 # top类实时统计
第六部分:总结与参考
6.1 关键源码文件索引
| 模块 | 路径 | 说明 |
|---|---|---|
| 系统调用 | net/socket.c | socket()、bind()等系统调用实现 |
| 协议族注册 | net/socket.c | net_families[]、sock_register() |
| INET层 | net/ipv4/af_inet.c | AF_INET协议族实现 |
| TCP协议 | net/ipv4/tcp.c, tcp_input.c, tcp_output.c | TCP核心实现 |
| UDP协议 | net/ipv4/udp.c | UDP实现 |
| IP层 | net/ipv4/ip_input.c, ip_output.c | IP输入输出 |
| 路由 | net/ipv4/route.c | 路由查找 |
| 邻居/ARP | net/core/neighbour.c, net/ipv4/arp.c | ARP和邻居管理 |
| 设备层 | net/core/dev.c | netif_rx、dev_queue_xmit |
| SKB | net/core/skbuff.c | sk_buff管理 |
| Socket层 | net/core/sock.c | 通用socket操作 |
| CAN总线 | net/can/ | SocketCAN实现 |
| Bluetooth | net/bluetooth/ | BlueZ协议栈 |
| 环形缓冲区 | include/linux/circ_buf.h | CIRC_*宏定义 |
| 调试工具 | tools/net/ | 网络工具源码 |
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)