eBPF技术介绍

最近在看cilium和calico关于eBPF功能,发现有许多不理解的地方,比如概念原理等,因此花费了一定的时间进行了学习和整理,翻了不少文档和博客,最后发现还是cilium社区的这篇文章讲解的最通透,希望后来人可以静下心来把这篇文章慢慢读下来并理解。开始方向错了,其实主要两条线,一个是基于llvm的c语言编写eBPF程序,涉及到一些宏,段定义,maps定义,btf等,llvm按照一定规范为我们编译和生成elf格式的文件,另一个是iproute2/bpftool等加载器将eBPF程序加载到内核,加载工具会读取elf中的各种段信息,将其加载到内核中,此处也会涉及段名称的约定,加载工具与编译器对于btf之间的约定。明白这两块之后再看内核提供的相关辅助函数和不同的map就可以做一些特定功能的bpf程序开发了。 简介 BPF(Berkeley Packet Filter ),中文翻译为伯克利包过滤器,是类 Unix 系统上数据链路层的一种原始接口,提供原始链路层封包的收发。1992 年,Steven McCanne 和 Van Jacobson 写了一篇名为《BSD数据包过滤:一种新的用户级包捕获架构》的论文。在文中,作者描述了他们如何在 Unix 内核实现网络数据包过滤,这种新的技术比当时最先进的数据包过滤技术快 20 倍。BPF 在数据包过滤上引入了两大革新: 一个新的虚拟机 (VM) 设计,可以有效地工作在基于寄存器结构的 CPU 之上; 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息。这样可以最大程度地减少BPF 处理的数据; 由于这些巨大的改进,所有的 Unix 系统都选择采用 BPF 作为网络数据包过滤技术,直到今天,许多 Unix 内核的派生系统中(包括 Linux 内核)仍使用该实现。 2014 年初,Alexei Starovoitov 实现了 eBPF(extended Berkeley Packet Filter)。经过重新设计,eBPF 演进为一个通用执行引擎,可基于此开发性能分析工具、网络数据包过滤、系统调用过滤,系统观测和分析等诸多场景。eBPF 最早出现在 3.18 内核中,此后原来的 BPF 就被称为经典 BPF,缩写 cBPF(classic BPF),cBPF 现在已经基本废弃。现在,Linux 内核只运行 eBPF,内核会将加载的 cBPF 字节码透明地转换成 eBPF 再执行。 eBPF 新的设计针对现代硬件进行了优化,所以 eBPF 生成的指令集比旧的 BPF 解释器生成的机器码执行得更快。扩展版本也增加了虚拟机中的寄存器数量,将原有的 2 个 32 位寄存器增加到 10…

kubernetes网络 – linux网络基础设施

在介绍之前,先来熟悉一下linux给我们提供的一些基础设备。回顾一下之前cni与pod网络中的测试用例。 [root@localhost ~]# ip link add name testbr type bridge [root@localhost ~]# ip link add name veth1 type veth peer name br-veth1 [root@localhost ~]# ip link add name veth2 type veth peer name br-veth2 [root@localhost ~]# ip netns add test1 [root@localhost ~]# ip netns add test2 [root@localhost ~]# ip link set netns test1 dev veth1 [root@localhost ~]# ip link set netns test2 dev veth2 [root@localhost ~]# ip link set master…

linux配置多级服务器登录和隧道映射

通常,办公环境的电脑无法直接连接到开发测试服务器,往往需要进行多次ssh跳转。这时可通过配置ssh支持自动跳转登录功能。假设有2台服务器A和B在我们的开发测试环境中,本地我们只能连接到A服务器,而A服务器可以连接到B服务器。编辑~/.ssh/config文件,输入下列内容: Host serverA User root HostName 10.1.2.3 IdentityFile /home/myusername/.ssh/id_rsa Port 22 Host serverB User root HostName 192.168.1.3 IdentityFile /home/myusername/.ssh/id_rsa port 22 ProxyJump serverA 此时,在本地即可通过ssh serverB直接连接到服务器B的ssh服务。如果要使用免密方式进行登录。则需要执行ssh-copy-id root@serverA和ssh-copy-id root@serverB进行配置免密。 在进行了这样的配置之后,我们也可以更加方便的建立隧道来使用了。比如在服务器上有一个8080的http服务,想要在本地浏览器里访问。那么,可以执行下列命令建立隧道: ssh -Nf -Llocalhost:8080:192.168.1.3:8080 serverB 此命令会将serverB上的8080端口映射到本地的8080端口上,在浏览器中我们只需要输入http://localhost:8080可以访问到serverB上的web服务。 同样,也可以通过-R选项将本地端口映射到serverB的某个端口上,比如在微信公众号开发测试的时候,可以将配置在公众平台的服务器地址上的服务映射到本地。 为了避免网络连接中断导致隧道断开连接,可以使用systemd来保活,隧道进程退出后自动将其拉起: # cat /lib/systemd/system//my-http-proxy.service [Unit] Describe=my nginx agent After=network.target [Service] LimitNOFILE=10000 Type=simple User=root Group=root ExecStart=/usr/bin/ssh -oExitOnForwardFailure=yes -oPubkeyAuthentication=yes -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oServerAliveInterval=5 -oServerAliveCountMax=3 -Llocalhost:8080:localhost:8080 -N root@serverB Restart = always RestartSec = 1s StartLimitInterval = 0 [Install] WantedBy=network.target 执行systemctl…

linux下tcp keepalive相关参数调整测试

首先说明下面三个和keepalive相关的内核参数以及默认的值 # sysctl -a | grep keepalive # 在会后一次发送数据包后多久向对方发起探测 net.ipv4.tcp_keepalive_time = 7200 # 在没有收到对方确认时,会按照这个时间间隔再次探测 net.ipv4.tcp_keepalive_intvl = 75 # 在没有收到对方确认时,进行探测的次数 net.ipv4.tcp_keepalive_probes = 9 下面通过在本地环境上测试这些参数,首先将本地的默认keepalive参数进行修改 # sysctl -a | grep keepalive net.ipv4.tcp_keepalive_intvl = 5 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_time = 20 下载并编译带keepalive功能支持的netcat命令行工具 git clone https://github.com/cyberelf/netcat-keepalive.git cd netcat-keepalive/ make linux 运行tcpdump进行抓包 tcpdump -iany port 18888 启动服务端监听 ./nckl-linux -v4K -l 18888 使用nc去连接 nc -v -p55666 localhost 18888 可以看到抓包内容如下 root@debian:/home/blue# tcpdump -iany port 18888 tcpdump: verbose…

sed命令详解

个人工作之中经常使用sed,但是比较简单的命令,并没有仔细的研究过sed详细用法,所以参考man手册进行了详细的整理。 sed是一个流式文本编辑器,可用来过滤和转换文本。基本用法如下: [source,shell] ---- sed [OPTION]... {script-only-if-no-other-script} [input-file]... ---- 其中的“[OPTION]”是可选的命令行参数,“{script-only-if-no-other-script}”是要执行的sed命令(如果没有用-e或-f指定别的命令的话,否则会视为输入文件路径),“[input-file]”是输入文件的路径。 sed的命令格式为:[地址]命令。地址是可选的,根据具体的命令而定。如‘/^hostname/aip=8.8.8.8’,‘p’等,地址格式和具体的命令可参下文。 == 选项及其含义 -n:: --quiet:: --silent:: 禁用自动打印模式空间,也就是禁止打印匹配的内容 -e script, --expression=script:: 添加要执行的sed命令 -f script-file, --file=script-file:: 将文件中的内容添加到要执行的命令中 --follow-symlinks:: 在in-place(如下)模式下,追踪符号链接 -i[SUFFIX], --in-place[=SUFFIX]:: 对文件进行直接更改,如果提供了SUFFIX,会使用SUFFIX作为扩展名进行备份 -l N, --line-length=N:: 指定行的长度 --posix:: 禁用所有的GNU扩展 -E, -r, --regexp-extended:: 在命令中使用posix扩展正则表达式(考虑到兼容性,应使用-E) -s, --separate:: 将各个文件单独对待,而不是一个长的连续的文本流。 --sandbox:: 在沙箱模式下运行 -u, --unbuffered:: 每次加载较小数量的数据,并加快刷新输入缓存的频率。 -z, --null-data:: 采用NUL字符(ascii 0)分割行 --help:: 显示帮助信息 --version:: 打印版本信息 如果没有指定-e,--expression,-f或--file选项,那么第一个非选项参数(及位置参数)将被作为命令来对待,剩下的所有参数都将作为文件名处理,如果没有指定文件名,则在标准输出中读取数据。 == 命令列表 === 无地址命令 : label:: *b*和*t*的标号 #comment:: 注释持续到换行符(或-e参数的结尾) }:: {}区块的闭合括号 === 0或1个地址的命令…

malloc分配不同大小内存的效率

分别对64B,1K, 4K, 16K, 256K, 4M, 64M,512M,2G大小进行测试,测试程序如下: [source,c] —- #include #include #include #include long long count = 0; void alarm_handler(int sig) { printf(“%lld\n”, count); count = 0; alarm(1); } int main() { signal(SIGALRM, alarm_handler); alarm(1); while(1) { void *data = malloc(8589934592); if (!data) printf(“alloc error\n”); free(data); count++; } } —- 机器配置: 内存:8GB,1600MHz CPU:Intel Core I5,2 Core,4 Thread,2500MHz 测试时机器内存占用(足够各个大小): [source,shell] —- blue@debian:/tmp$ free -g total used free shared buff/cache available Mem: 7…

tcpdump使用方法介绍

tcpdump是一个网络抓包工具,依赖于libpcap实现。libpcap是一个网络抓包库,支持ether,fddi,tr,wlan,ip,ip6,arp,rarp,decnet,tcp和udp协议。 tcpdump的基本是用方法为: [source,shell] ---- tcpdump options expression ---- options指定程序运行选项,expression是一个逻辑表达式,只抓取满足expressionn表达式的包。例如`tcpdump -i eth0 tcp and host 192.168.1.101`抓取eth0接口到192.168.1.101主机的所有tcp包。`-i eth0`是运行选项,`tcp and host 192.168.1.101`是表达式,表示抓取所有到192.168.1.101主机的tcp包。tcpdump支持的详细参数可参考`man tcpdump`,表达式的详细信息可参考`man pcap-filter`。 == 常用的选项 -A:: 采用ASCII码打印出包内容,抓取网页时很方便。 -F file:: 使用file文件中的内容作为表达式,命令行中的表达式将被忽略。 -i interface:: 要抓取的网络接口,如果未指定,则使用序号最小的接口,如eth0。也可以使用any来使用任意接口。 -l:: 设置stdout的输出模式为行缓冲,当想一边抓包一遍查看数据的时候有用。如`tcpdump -l | tee dat`和`tcpdump -l dat & tail -f dat`。 -e:: 打印数据链路层包头。 -Q direction:: 设置要抓取发送还是接收的数据,可能的值为in,out和inout。 -r file:: 从文件中读取数据包(有tcpdump -w生成,或其他pcap兼容格式)。 -v:: -vv:: -vvv:: 打印详细信息。 -w file:: 将原始包信息输出到文件中,之后可以通过-r来打印。 -x:: 除了打印包头,同样以十六进制方式打印包内容,不包括链路层的包头。 -xx:: 除了打印包头,同样以十六进制方式打印包内容。 -X:: 除了打印包头,同样以十六进制和ASCII码方式打印包内容,不包括链路层的包头。 -XX:: 除了打印包头,同样以十六进制和ASCII码方式打印包内容。 == 表达式语法…

libvirt虚拟化开发简介

libvirt是一个虚拟化开发的工具库,提供了底层的kvm,xen,vmware esx等虚拟化的统一封装。可以通过libvirt提供的api对不同的底层实现进行同一的管理。除了原生的c api,还有c#, go, java, ocaml. perl, python, php, ruby的api,用户可自主选择自己熟悉的语言。 要使用libvirt首先要安装libvirtd,这是一个后台守护进程,负责管理虚拟机系统以及和客户端交互。libvirt还包含了virsh命令行工具,供用户通过shell手动管理。另外,还可以通过图形界面方式进行管理,该工具是virt-manager,如果您想要通过python的api进行开发,需要安装python3-libvirt或python-libvirt。在debian下,可通过下列指令安装这些包: apt-get install libvirt-daemon libvirt-daemon-system libvirt-clients python3-libvirt virt-manager 启动libvirtd: systemctl start libvirtd 接下来我们就可以通过virt-manager创建一个虚拟机。熟悉vmware或者virtualbox的同学,可以看到virt-manager和这些软件很类似,安装系统就不再介绍了。 系统安装完成之后,我们就可以通过virsh工具进行基本的操作了。运行virsh,回车,进入virsh的命令行,可通过help查看virsh支持的操作。 virsh # help Grouped commands: Domain Management (help keyword 'domain'): attach-device attach device from an XML file attach-disk attach disk device attach-interface attach network interface autostart autostart a domain blkdeviotune Set or query a block device I/O tuning parameters. blkiotune Get or set blkio parameters blockcommit…