【操作系统】Linux网络包收发

276 阅读6分钟

网络性能指标

性能衡量指标

  • 带宽: 链路的最大传输速率,单位是 b/s (比特 / 秒)。
  • 延时: 请求数据包发送后,收到对端响应,所需要的时间延迟。不同的场景有着不同的含义,比如可以表示建立 TCP 连接所需的时间延迟,或一个数据包往返所需的时间延迟。
  • 吞吐率: 单位时间内成功传输的数据量,单位是 b/s(比特 / 秒)或者 B/s(字节 / 秒),吞吐受带宽限制,带宽越大,吞吐率的上限才可能越高。
  • PPS: Packet Per Second(包 / 秒),表示以网络包为单位的传输速率,一般用来评估系统对于网络的转发能力。
  • 网络的可用性: 网络能否正常通信;
  • 并发连接数: TCP 连接数量;
  • 丢包率: 所丢失数据包数量占所发送数据组的比率;
  • 重传率: 重传网络包的比例;
# 查看网络配置
ifconfig eth0
ip -s addr show dev rth0
# socket 信息查看
netstat -nlp (性能低)
ss -ltnp
# 包含了 socket 的状态(State)、接收队列(Recv-Q)、发送队列(Send-Q)、本地地址(Local Address)、远端地址(Foreign Address)、进程 PID 和进程名称(PID/Program name)
# 当 socket 状态处于 Established时:
    # Recv-Q 表示 socket 缓冲区中还没有被应用程序读取的字节数;
    # Send-Q 表示 socket 缓冲区中还没有被远端主机确认的字节数;
# 而当 socket 状态处于 Listen 时:
    # Recv-Q 表示全连接队列的长度;
    # Send-Q 表示全连接队列的最大长度;
    
# 协议栈的统计信息
netstat -s
ss -s

# 查看吞吐率和 PPS
sar -n DEV #显示网口的统计数据;
sar -n EDEV#显示关于网络错误的统计数据;
sar -n TCP #显示 TCP 的统计数据
# rxpck/s 和 txpck/s 分别是接收和发送的 PPS,单位为包 / 秒。
# rxkB/s 和 txkB/s 分别是接收和发送的吞吐率,单位是 KB/ 秒。
# rxcmp/s 和 txcmp/s 分别是接收和发送的压缩数据包数,单位是包 / 秒。

# 带宽
ethtool eth0 | grep Speed
# 连通性和延时
ping 
# icmp_seq(ICMP 序列号)
# TTL(生存时间,或者跳数)
# time (往返延时)
# 最后会汇总本次测试的情况,如果网络没有丢包,packet loss 的百分比就是 0

Linux网络包收发

网络模型

  • 七层:

    • 应用层:给应用程序提供统一的接口;
    • 表示层:把数据转换成兼容另一个系统能识别的格式;
    • 会话层:建立、管理和终止表示层实体之间的通信会话;
    • 传输层:端到端的数据传输;
    • 网络层:数据的路由、转发、分片;
    • 数据链路层:数据的封帧和差错检测,以及 MAC 寻址;
    • 物理层:在物理网络中传输数据帧;
  • 四层:

    • 应用层:向用户提供一组应用程序,HTTP、DNS、FTP 等;
    • 传输层:端到端的通信,比如 TCP、UDP 等;
    • 网络层:网络包的封装、分片、路由、转发, IP、ICMP 等;
    • 网络接口层:网络包在物理网络中的传输,比如网络包的封帧、 MAC 寻址、差错检测,以及通过网卡传输网络帧等;

Linux 网络协议栈

  • 物理链最大传输单元(MTU:1500 字节,网络包超过 MTU 的大小,就会在网络层分片。

Linux 接收网络包的流程

  • 当网卡接收到一个网络包后,会通过 DMA 技术,将网络包放入到 Ring Buffer,这个是一个环形缓冲区,该缓冲区在内核内存中的网卡驱动里。

Why?

那接收到网络包后,应该怎么告诉操作系统这个网络包已经到达了呢?

How?

  • 触发中断,也就是每当网卡收到一个网络包,就触发一个中断告诉操作系统

    • 效率低
  • Linux 内核在 2.6 版本中引入了 NAPI 机制:混合「中断和轮询」的方式来接收网络包

    • 采用中断唤醒数据接收的服务程序,然后 poll 的方法来轮询数据。

比如,当有网络包到达时,网卡发起硬件中断,于是会执行网卡硬件中断处理函数,中断处理函数处理完需要「暂时屏蔽中断」,然后唤醒「软中断」来轮询处理数据,直到没有新数据时才恢复中断,这样一次中断处理多个网络包,于是就可以降低网卡中断带来的性能开销。

软中断是怎么处理网络包的呢?

  • 从 Ring Buffer 中拷贝数据到内核 struct sk_buff 缓冲区中,作为一个网络包交给网络协议栈进行逐层处理。
  1. 会先进入到网络接口层,检查报文的合法性,如果不合法则丢弃,合法则会找出该网络包的上层协议的类型,比如是 IPv4,还是 IPv6,接着再去掉帧头和帧尾,然后交给网络层。
  2. 到了网络层,则取出 IP 包,判断网络包下一步的走向,比如是交给上层处理还是转发出去。当确认这个网络包要发送给本机后,就会从 IP 头里看看上一层协议的类型是 TCP 还是 UDP,接着去掉 IP 头,然后交给传输层。
  3. 传输层取出 TCP 头或 UDP 头,根据四元组「源 IP、源端口、目的 IP、目的端口」 作为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓冲区。
  4. 应用层程序调用 Socket 接口,从内核的 Socket 接收缓冲区读取新到来的数据到应用层。

Linux 发送网络包的流程

  1. 应用程序会调用 Socket 发送数据包的接口,由于这个是系统调用,所以会从用户态陷入到内核态中的 Socket 层,Socket 层会将应用层数据拷贝到 Socket 发送缓冲区中。
  2. 网络协议栈从 Socket 发送缓冲区中取出数据包,并按照 TCP/IP 协议栈从上到下逐层处理。
  3. 如果使用的是 TCP 传输协议发送数据,那么会在传输层增加 TCP 包头,然后交给网络层,网络层会给数据包增加 IP 包,然后通过查询路由表确认下一跳的 IP,并按照 MTU 大小进行分片。
  4. 分片后的网络包,就会被送到网络接口层,在这里会通过 ARP 协议获得下一跳的 MAC 地址,然后增加帧头和帧尾,放到发包队列中。
  5. 触发软中断告诉网卡驱动程序,这里有新的网络包需要发送。
  6. 驱动程序通过 DMA,从发包队列中读取网络包,放入硬件网卡的队列,物理网卡再将它发送出去。