• 使用ping命令定位网络延迟问题


    一、背景

    使用ping命令发现局域网内延迟大,且变化较大。需要分析耗时在那一层。

    二、分析

    上图可以看出,本机ping延时非常低。在本机网络 IO 的过程中,流程会有一些差别。有差异的地方总共有两个,分别是路由和驱动程序。

    路由:

     对于本机网络 IO 来说,特殊之处在于在 local 路由表中就能找到路由项,对应的设备都将使用 loopback 网卡,也就是我们常见的 lO。

    驱动程序:

    网络设备子系统的入口函数是 dev_queue_xmit。对于真的有队列的物理设备,在该函数中进行了一系列复杂的排队等处理以后,才调用 dev_hard_start_xmit,从这个函数再进入驱动程序来发送。

    但是对于启动状态的回环设备来说(q->enqueue 判断为 false),就简单多了:没有队列的问题,直接进入 dev_hard_start_xmit。接着进入回环设备的“驱动”里的发送回调函数 loopback_xmit,将 skb “发送”出去。

    因此,可以从上面两层入手,排查问题!

    驱动:

    监控icmp包发送和接受的时刻,看时间是否过大。

    但有一个问题,链路上运行的不一定只有ICMP数据包。因此,我们需要在每一层对我们发送和接收的ICMP包进行过滤。

    路由:

    三、ICMP

    ICMP报文包含在IP数据报中,IP报头在ICMP报文的最前面。一个ICMP报文包括IP报头(至少20字节)、ICMP报头(至少八字节)和ICMP报文(属于ICMP报文的数据部分)。当IP报头中的协议字段值为1时,就说明这是一个ICMP报文。ICMP报头如下图所示。

    这里只讲解与ping有关的ICMP消息类型,主机发送回送消息(Type = 8),被请求主机回送响应消息(Type = 0),基本格式如下:
    回送消息[ECHO]

    回送响应消息[ECHO REPLY]

     
    •CheckSum为校验和,重点注意从ICMP的头部(即Type开始),到data结束(即到整个数据包结束)
    •Identifier为标识符,由主机设定,一般设置为进程号,回送响应消息与回送消息中identifier保持一致
    •Sequence Number为序列号,由主机设定,一般设为由0递增的序列,回送响应消息与回送消息中Sequence Number保持一致
    •data为数据,由主机设定,回送响应消息与回送消息中data保持一致

    1. ///include/uapi/linux/icmp.h
    2. struct icmphdr {
    3. __u8 type;
    4. __u8 code;
    5. __sum16 checksum;
    6. union {
    7. struct {
    8. __be16 id;
    9. __be16 sequence;
    10. } echo;
    11. __be32 gateway;
    12. struct {
    13. __be16 __unused;
    14. __be16 mtu;
    15. } frag;
    16. __u8 reserved[4];
    17. } un;
    18. };

    四、实现

    1. #ifndef _LINUX_IP_H
    2. #define _LINUX_IP_H
    3. #include
    4. #include
    5. static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
    6. {
    7. return (struct iphdr *)skb_network_header(skb);
    8. }
    9. static inline struct iphdr *inner_ip_hdr(const struct sk_buff *skb)
    10. {
    11. return (struct iphdr *)skb_inner_network_header(skb);
    12. }
    13. static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
    14. {
    15. return (struct iphdr *)skb_transport_header(skb);
    16. }
    17. #endif /* _LINUX_IP_H */
    18. struct iphdr {
    19. #if defined(__LITTLE_ENDIAN_BITFIELD)
    20. __u8 ihl:4,
    21. version:4;
    22. #elif defined (__BIG_ENDIAN_BITFIELD)
    23. __u8 version:4,
    24. ihl:4;
    25. #else
    26. #error "Please fix "
    27. #endif
    28. __u8 tos;
    29. __be16 tot_len;
    30. __be16 id;
    31. __be16 frag_off;
    32. __u8 ttl;
    33. __u8 protocol;
    34. __sum16 check;
    35. __be32 saddr;
    36. __be32 daddr;
    37. /*The options start here. */
    38. };
    1. ///include/uapi/linux/in.h
    2. enum {
    3. IPPROTO_IP = 0, /* Dummy protocol for TCP */
    4. #define IPPROTO_IP IPPROTO_IP
    5. IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
    6. #define IPPROTO_ICMP IPPROTO_ICMP
    7. IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
    8. #define IPPROTO_IGMP IPPROTO_IGMP
    9. IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
    10. #define IPPROTO_IPIP IPPROTO_IPIP
    11. IPPROTO_TCP = 6, /* Transmission Control Protocol */
    12. #define IPPROTO_TCP IPPROTO_TCP
    13. IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
    14. #define IPPROTO_EGP IPPROTO_EGP
    15. IPPROTO_PUP = 12, /* PUP protocol */
    16. #define IPPROTO_PUP IPPROTO_PUP
    17. IPPROTO_UDP = 17, /* User Datagram Protocol */
    18. #define IPPROTO_UDP IPPROTO_UDP
    19. IPPROTO_IDP = 22, /* XNS IDP protocol */
    20. #define IPPROTO_IDP IPPROTO_IDP
    21. IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */
    22. #define IPPROTO_TP IPPROTO_TP
    23. IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
    24. #define IPPROTO_DCCP IPPROTO_DCCP
    25. IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
    26. #define IPPROTO_IPV6 IPPROTO_IPV6
    27. IPPROTO_RSVP = 46, /* RSVP Protocol */
    28. #define IPPROTO_RSVP IPPROTO_RSVP
    29. IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
    30. #define IPPROTO_GRE IPPROTO_GRE
    31. IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
    32. #define IPPROTO_ESP IPPROTO_ESP
    33. IPPROTO_AH = 51, /* Authentication Header protocol */
    34. #define IPPROTO_AH IPPROTO_AH
    35. IPPROTO_MTP = 92, /* Multicast Transport Protocol */
    36. #define IPPROTO_MTP IPPROTO_MTP
    37. IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
    38. #define IPPROTO_BEETPH IPPROTO_BEETPH
    39. IPPROTO_ENCAP = 98, /* Encapsulation Header */
    40. #define IPPROTO_ENCAP IPPROTO_ENCAP
    41. IPPROTO_PIM = 103, /* Protocol Independent Multicast */
    42. #define IPPROTO_PIM IPPROTO_PIM
    43. IPPROTO_COMP = 108, /* Compression Header Protocol */
    44. #define IPPROTO_COMP IPPROTO_COMP
    45. IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
    46. #define IPPROTO_SCTP IPPROTO_SCTP
    47. IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
    48. #define IPPROTO_UDPLITE IPPROTO_UDPLITE
    49. IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */
    50. #define IPPROTO_MPLS IPPROTO_MPLS
    51. IPPROTO_RAW = 255, /* Raw IP packets */
    52. #define IPPROTO_RAW IPPROTO_RAW
    53. IPPROTO_MAX
    54. };

    驱动层如何识别ICMP报文?

    在.ndo_start_xmit = esp_hard_start_xmit,函数中,将邻居子系统传递下来的skb使用ip_hdr函数即可转换!

    1. #include
    2. #include
    3. #include
    4. struct iphdr *iph;
    5. struct icmphdr *icmpph = NULL;
    6. iph = ip_hdr(skb);
    7. if(iph->protocol==IPPROTO_ICMP ) {
    8. //如果是ICMP报文
    9. icmpph = (struct icmphdr *) ((u8 *) iph + (iph->ihl << 2));
    10. printk("ESP type:%d, code:%d\n", icmpph->type, icmpph->code);
    11. if(icmpph->type==8 && icmpph->code==0) {//ping 请求
    12. printk(KERN_ERR "ping RQ:%d\n",icmpph->un.echo.sequence);
    13. }
    14. }

    ref:

    不为人知的网络编程(十三):深入操作系统,彻底搞懂127.0.0.1本机网络通信 - 知乎

    linux内核协议栈 icmp 报文收发流程_老王不让用的博客-CSDN博客

    ping命令全链路分析(4) - 数据包内核态处理 - 知乎

    Linux内核:从skb获取udp头,udp_hdr()获取到是错误的udp头_kanguolaikanguolaik的博客-CSDN博客

    网络-ICMP协议、Ping命令实现与ICMP攻击_51CTO博客_icmp ping

    ICMP协议之ping实现_yo-yo的博客-CSDN博客

  • 相关阅读:
    如何应用 matrix3d 映射变幻
    高通道筛选出的小分子 应用到伊蚊“控制”
    JS/TS项目里的Module都是什么?
    TiUP DM
    Gin模板渲染
    文心一言 VS 讯飞星火 VS chatgpt (136)-- 算法导论11.3 2题
    关于个人考取PMP认证考试的这些关键问题
    【联合出版】2022年交通与智慧城市国际会议(ICoTSC 2022)
    多用途折叠式行李拉车设计
    Gin,Gorm实现Web计算器
  • 原文地址:https://blog.csdn.net/wwwlyj123321/article/details/127717968