cclinuxer / cclinuxer_bak.github.io Goto Github PK
View Code? Open in Web Editor NEWAbandoned
Abandoned
之前做项目的时候,由于需要对内存进行全方位的评估,所以就研究了一下linux的内存管理相关知识,之前用markdown写文档的时候没有做配置,导致markdown文档已经不存在。
本人水平有限,如果遇到文章中有小的错误点,请指出。
扩展阅读请参考文章中的参考文档以及内核官方文档,以及lwn中相关的内容
最近准备在团队内部做一次网络转发性能排查的技术分享,想来想去还是应该把二三层转发流程以及偏硬件相关的知识做下整理,方便大家理解。后续会在本issua中记录这个过程
本文为转载:原文地址:https://blog.csdn.net/dog250/article/details/45788497
原文作者应该是一名一线的技术大牛,我本人阅读过博主很多文章,收益匪浅
虽然和网络相关,但是它却不是网络协议栈的一部分,这就是netpoll。它只是一个出入口的处理框架。所谓的网络,它的终端节点就是主机,数据从主机的网卡发出,经过一个出口处理过程,网卡接收到一个数据包,经过一个入口处理过程,这一出一入的过程处理分为两种方式:
出口处理过程-数据排入发送队列,读取特定寄存器值,待网卡状态适合发送式,发送,等待发送后的中断通知,继续。
入口处理过程-数据被网卡收到,网卡中断CPU,CPU进而处理数据接收的过程。
网络协议栈下接的就是这种中断的出入口处理方式。
出口处理过程-数据排入发送队列,读取特定寄存器值,待网卡状态适合发送式,发送,不等待发送后的中断通知,继续读取寄存器以及根据队列情况权衡是否适合发送。
入口处理过程-数据被网卡收到,等待poll逻辑在适当的时候去主动poll网卡,若有数据,则将其从特定的网卡缓存读出。
Linux netpoll就是利用的这种方式。这种方式完全不依赖中断。
事实总是比说起来更麻烦。
要讲清楚这个有点混乱的主题,不得不引入第三种出入口处理方式,那就是中断和poll结合的方式,这就是NAPI方式。我把三种方式的图示先给出:
a.中断方式
c.NAPI方式
理解了这个,剩下的就都理解了。至于为何会有NAPI,在本文中只能简单说一句:在高速高带宽网络中,数据包持续到来,每一个包中断一次CPU的话,CPU有点吃不消,反而耽误了CPU处理这些数据包,如果之前的数据包还没有处理完,最好的办法就是将数据包排入一个队列,然后沉默,不要打扰CPU,等CPU空下来的时候,自己去poll这些队列里面的数据包,这就是NAPI。
纯中断的方式我们都很熟悉,也是最直接的方式。然而为何要有纯poll的方式呢?使用纯poll的场合在中断完全不起作用的情况下。举一个例子,系统panic之后。此时中断控制器将可能被disable掉,无论如何,此时的机器已经和外界失联了,然而如果此时必须需要一个方式对外界通告自己的死因的话,这种netpoll的方式就派上用场了,因为它是纯手工的,完全不依赖系统的中断机制。另外一种场合比panic好一些,那就是协议栈故障,如果使用中断或者NAPI的方式,由于它上接的就是协议栈,netif_receive_skb中又没有什么HOOK点,此时使用netpoll可以改变数据包的处理路径,通过一个agent可以实现远程debug。
不要把中断想象的太神秘。它无非也就是一个通知机制,告诉CPU,现在请查询我的状态,该干啥就干啥。事实上,当CPU收到网卡中断的时候,它也不知道该干啥,它只会调用中断处理函数,其内部会去读取一写寄存器的状态,然后才能知道现在该干什么,比如可以发送数据包,比如收到一个数据包等。既然如此,即使在关中断的情形下,如果不依靠中断,CPU择机主动调用一下网卡的中断处理函数,读取一写寄存器的状态,是不是也能知道该干什么呢?答案当然是肯定的了!这就是netpoll的逻辑,它使用两步完成任务:
1.主动调用网卡的中断处理函数,获取当前该发送数据包还是接收到一个数据包;
2.直接hard_xmit数据包或者使用NAPI的接口去poll网卡的数据。
Linux netpoll的总体图示如下:
这个图示中附带了netconsole的原理,没想到他是如此的简单。我记得我曾经写过一个模块,将panic后的信息发到远端,这个是受到了一个xtables-addons模块的启发,起初失败了,但是最后我仔细debug了内核代码后,成功了。在成功的过程中,发现了很多以前不知道的东西。但是现在看看netconsole吧,它什么复杂的东西都不需要,只需要两步:
1.注册一个console,此后内核buffer的信息就会发到这个console;
2.该console下接netpoll的netpoll_send_skb,此后由netpoll逻辑来处理。
即便在panic后,中断已经被关了,甚至中断控制器都关闭的情况下,只要网卡没有进水,数据依然可以收发,它完全不依赖中断和协议栈。这简直太棒了!关于netconsole,我写多少都不如内核的Document来的好:$kernel/Documentation/networking/netconsole.txt.
netpoll是Linux内核中的一种在协议栈不可用或者中断机制异常的情况下与外界通讯的手段,当然它也是一种绕开协议栈的方法。这个位置足够底层,写出来的东西也肯定比基于Netfilter的更好玩。Netfilter是在协议栈的特殊点捕获数据包的,而netpoll却可以在网卡之上直接捕获数据包,它们甚至连协议栈的最底端都到不了。以后,如果想在内核态直接发包,再也不用PACKET套接字从用户态开始了,构造一个数据包,直接通过netpoll接口发出。问题是,它采用手工触发中断处理函数的方式,效率如何待测试。因此这种机制最好还是限制于调试和少量内核审计信息的发送吧。用它做VPN,我觉得悬...
————————————————
版权声明:本文为CSDN博主「dog250」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dog250/article/details/45788497
iptables调试方法:
1、对指定数据包先用iptable进行标记:
例如:下面表示对来自192.168.0.100 在prerouting链进行打标记操作,或者修改ip的tos:
iptables -t mangle -A PREROUTING -p icmp -s 192.168.0.100 -j TOS --set-tos 0x10
iptables -t mangle -A PREROUTING -p icmp -s 192.168.0.100 -j MARK --set-mark 100
2、对在定链进行匹配,看数据包是否增加
iptables -t filter -I INPUT 2 -m mark --mark 100 -j ACCEPT
3、通过iptables -nxvL来查看我们指定的规则数据包是否有增加,如果有增加,说明数据包到了这个规则。
这种技巧在排查数据或者数据流向时候很重要,可以缩小问题范围,然后再到具体的函数,或者hook点中进一步排查问题
这里分享下ftrace的作者 Steven Rostedt之前的一个介绍ftrace的文档
之前做项目的时候,在启动过程中出现
Unable to handle kernel NULL pointer dereference at virtual address 00000004
[ 90.967706] CPU: 1 PID: 0 Comm: swapper/1 Tainted: P 3.14.77 #1
[ 90.967714] task: cf88c4c0 ti: cf8b2000 task.ti: cf8b2000
[ 90.967757] PC is at hyfi_netfilter_forwarding_hook+0x124/0x1b8 [hyfi_bridging]
[ 90.967778] LR is at hyfi_netfilter_forwarding_hook+0x11c/0x1b8 [hyfi_bridging]
[ 90.967788] pc : [<bf5cc250>] lr : [<bf5cc248>] psr: 20000113
[ 90.967788] sp : cf8b3d00 ip : 00003a89 fp : c94b8e40
[ 90.967793] r10: bf5df6f0 r9 : cd5aa000 r8 : bf5de610
[ 90.967800] r7 : c94dc000 r6 : c697e000 r5 : 00000000 r4 : cdcf4500
[ 90.967806] r3 : 00000003 r2 : cdcf4500 r1 : 00000000 r0 : 00000001
[ 90.967812] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
[ 90.967819] Control: 10c5387d Table: 8ca4406a DAC: 00000015
[ 90.967824] Process swapper/1 (pid: 0, stack limit = 0xcf8b2238)
首先找到hyfi_netfilter_forwarding_hook的源文件对应的目标文件,使用toolchain的gdb打开,然后执行list即可:
$ /opt/toolchain-arm_cortex-a7_gcc-4.8-linaro_uClibc-1.0.14_eabi/bin/arm-openwrt-linux-gdb hyfi_netfilter.o
GNU gdb (Linaro GDB) 7.6-2013.05
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-openwrt-linux-uclibcgnueabi".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /work/router/qca/ipq4018/build_dir/target-arm-openwrt-linux-uclibcgnueabi/linux-ipq806x/qca-hyfi-bridge-g/hyfi-netfilter/hyfi_netfilter.o...done.
(gdb) list *(hyfi_netfilter_forwarding_hook+0x124)
0x124 is in hyfi_netfilter_forwarding_hook (/work/router/qca/ipq4018/build_dir/target-arm-openwrt-linux-uclibcgnueabi/linux-ipq806x/qca-hyfi-bridge-g/./hyfi-netfilter/hyfi_netfilter.c:177).
出问题的代码是177行。
本文介绍利用linux的jprobe工具,对内核中的函数进行插桩,动态获取内核函数的入口参数,从而分析函数执行流,直接编译模块加载即可,无需刷机,也不需要更改原来的代码。这个技巧在系统出现问题的时候,但是这个问题又比较难复现,我们没办法重新刷机的时候,可以使用。
内核文档地址:
\Documentation\kprobes.txt
这个文档里面有现成的例子,告诉你如何进行内核模块的hook
值得说一下的是内核Documentation中有很多文档,都写得比较好懂,我们在进行一些linux中的工具学习,或者是一些模块学习的时候:例如内存、网络等,应该先去读一读相关模块在Documentation的文档
在网络问题的排查中,我们经常遇到,某个数据包导致异常发生,或者说这个导致异常的数据包是谁发出的,具体的报文格式是怎么样的,这里可以通过在内核中讲整个数据包dump出来,然后用wireshark再来具体分析是哪一个主机发出的数据包导致路由器异常。
1、在内核中dump出异常代码段的数据包
printk("------fix--me--drop-package--in--dst_outputl\n");
if (skb)
{
char *buf = skb->data;
int len = skb->len;
int i;
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\n\n");
}
dump_stack();
2、同时用tcpdump抓取对应接口的数据包,通过在wireshark中搜索包含异常数据包的16进制的数据包。从而匹配出异常数据包。从而做进一步分析。
3、定位异常,并打印调用栈进一步分析。
国内的翻译lwn上linux最新的研究进展的公众号: <Linux News搬运工>
lwn: https://lwn.net/Kernel/
公众号<泰晓科技>
公众号<Linux阅码场>
https://www.elinux.org/Main_Page
内核官网的一些文档 https://www.kernel.org/doc/html/latest/networking/index.html
https://www.kernel.org/
内核邮件列表
https://marc.info/?l=netfilter&r=1&b=202006&w=2
1、在分析网络协议栈的问题的时候,经常出现钩子函数丢包的情况,特别是我们自己在内核中注册了大量钩子函数的时候,然而钩子函数是通过遍历链表的方式执行,这个时候我们无法知道是哪一个函数丢弃了数据包,这个时候我们可以先打印出函数指针的地址,然后通过addr2line工具讲该地址转换为字符串
1、先打印出函数地址:
printk("-----debug_nf------address=0x%p\n",(*elemp)->hook);
2、根据函数地址找到具体函数
/opt/toolchain-aarch64_cortex-a53_gcc-5.2.0_musl-1.1.16/bin/aarch64-openwrt-linux-addr2line 0xffffffc0005d5864 -f -e vmlinux.debug
-e后面的参数vmlinux.debug 可以替换成其他带符号表的文件,如果文件较多,可以写一个shell脚本遍历出来
和jprobe不同的是, systemtap可以不用编写C语言内核模块,直接使用systemtap提供的脚本语言语法,由systemtap进行翻译成C语言内核模块,然后加载到内核中去。从而完成hook内核函数的功能:
关于systemtap. 可以参考官方文档:
https://sourceware.org/systemtap/documentation.html
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.