【TCP/IP】【调试】丢包、流不通、错包等问题查证手段系列之一——日志方式

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【TCP/IP】【调试】丢包、流不通、错包等问题查证手段系列之一——日志方式

前言


在进行TCP/IP相关的开发过程中,经常需要查证丢包、错包、流不通等问题。由于TCP/IP转发面涉及软件和硬件、并且软件流程上函数多、分支多,无论是增加打印或是分析流程,都比较困难。


本系列文章会将常用的定位手段,做一简单的总结和说明,各位可根据问题的情况,选取一种或结合使用。


日志方式简介


  • 虽然打印这种方式比较Low,但在有的情况下反而是最直接和有效的方式,有的情况下更是开发人员的杀手锏。


直接打印报文


  • 直接在需要的地方调用类似下面的print_skb的函数即可。


void print_skb(struct sk_buff *skb)
{
    if (skb) {
        char *buf = skb->data;
        int len = skb->len;
        int i = 0;
        printk("[%s:%d]Packet length = %#4x\n", __FUNCTION__, __LINE__, len);
        for (i = 0; i < len; i++){
            if (i % 16 == 0) printk("%#4.4x", i);
            if (i % 2 == 0) printk(" ");
            printk("%2.2x", ((unsigned char *)buf)[i]);
            if (i % 16 == 15) printk("\n");
        }
        printk("\n\n");
    }
}


值得一提的是,在有的内核版本中,上述代码打印不全,skb->data需要换成skb->mac_header。


另外,这种打印方式,如报文太多,会刷屏,可能将系统打宕机。


条件打印


  • 根据报文中特定字段进行打印,需要在skb结构体中增加一个字段:


struct sk_buff {
  unsigned int dbg_flag;
}


具体在某个位置,首先判断某skb是否需要被打印,比如要跟踪DHCP报文,则在某个入口或点的位置识别DHCP报文并将该标志位置上,具体可参考下面的代码段:


struct ethhdr *mh = (struct ethhdr *)(skb->mac_header);
if(mh->h_proto != htons(ETH_P_IP)) {
    return;
}
struct iphdr *iph = (struct iphdr *)ip_hdr(skb);
if(iph && iph->protocol != IPPROTO_UDP) {
    return ;
}
    // ip header --> iph->ihl*4;
struct udphdr *udph = (struct udphdr *) ((char *)iph + iph->ihl*4);
if(udph && udph->source == htons(68) && udph->dest == htons(67)) {
    skb->dbg_flag = 1;


之后,在后续其他点上,就可以直接根据这个flag来控制打印:


if (1 == skb->dbg_flag) {
    print_skb(skb);
}


开关控制打印


  • 通过某proc文件修改内核某变量,然后根据该变量来控制打印。


echo 1>/proc/net/logctl //假设logctl文件对应g_logctl变量


代码中的具体控制:


if (1 == g_logctl) {
        print_skb(skb);
    }


ratelimit限速打印


  • 限速判断函数可以用net_ratelimit或printk_ratelimit;


 if (net_ratelimit()) {
     print_skb(skb);
 }
  if (printk_ratelimit()) {
     print_skb(skb);
 }


这种打印,有个缺陷,有可能会被限速抑制掉而打印不出来,此时会有下面这种打印出现:


__ratelimit: 250 callbacks suppressed


具体的限速参数,可使用下面方式修改:


[qxhgd@localhost ~]$ cat /proc/sys/kernel/printk_ratelimit
5
[qxhgd@localhost ~]$ cat /proc/sys/kernel/printk_ratelimit_burst
10
# printk_ratelimit默认允许在5s内最多打印10条消息出来: /proc/sys/kernel/printk_ratelimit (多长时间)和 /proc/sys/kernel/printk_ratelimit_burst (在上述时间段内最多允许的消息数量)


自定义限速打印


  • 也可以根据需要,使用系统时间来自行控制打印,比如下面代码段可控制每秒最多打印一个报文:


unsigned long g_lastTime = 0; #全局变量
if (jiffies - g_lastTime > 1 * HZ)  {
    print_skb(skb);
    g_lastTime = jiffies;
}
相关实践学习
日志服务之数据清洗与入湖
本教程介绍如何使用日志服务接入NGINX模拟数据,通过数据加工对数据进行清洗并归档至OSS中进行存储。
相关文章
|
2月前
|
机器学习/深度学习 人工智能 网络协议
TCP/IP五层(或四层)模型,IP和TCP到底在哪层?
TCP/IP五层(或四层)模型,IP和TCP到底在哪层?
54 4
|
2月前
|
Java 开发工具 Windows
Windows环境下面启动jar包,输出的日志出现乱码的解决办法
Windows环境下面启动jar包,输出的日志出现乱码的解决办法
|
9月前
|
网络协议 应用服务中间件 nginx
nginx配置tcp协议代理的日志
nginx配置tcp协议代理的日志
175 0
|
22天前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
31 3
|
26天前
|
消息中间件 Kafka Go
go语言并发实战——日志收集系统(五) 基于go-ini包读取日志收集服务的配置文件
go语言并发实战——日志收集系统(五) 基于go-ini包读取日志收集服务的配置文件
|
26天前
|
存储 监控 算法
go语言并发实战——日志收集系统(四) 利用tail包实现对日志文件的实时监控
go语言并发实战——日志收集系统(四) 利用tail包实现对日志文件的实时监控
|
26天前
|
消息中间件 算法 Java
go语言并发实战——日志收集系统(三) 利用sarama包连接KafKa实现消息的生产与消费
go语言并发实战——日志收集系统(三) 利用sarama包连接KafKa实现消息的生产与消费
|
2月前
|
机器学习/深度学习 Shell Perl
logcat 只打印符合包名的log
logcat 只打印符合包名的log
21 1
|
2月前
|
Java 开发工具 开发者
dashvector的SDK包内含log4j2.xml,坑
对公SDK自带`log4j2.xml`配置,引发本地配置冲突。建议SDK开发者移除内置日志配置,避免影响用户设置。
72 0
|
2月前
|
域名解析 网络协议 应用服务中间件
nginx-ingress通过ipv6暴露服务,并在nginx ingress日志中记录客户端真实ipv6的ip地址
本文主要通过阿里云提供的clb和nlb来实现,建议是提前创建好双栈的vpc和vsw(使用clb可以不用双栈vpc和vsw)
333 1