1.十年码农内功:网络篇
2.ping命令全链路分析(2)
3.LWIP分析(三)——启动流程
4.Linux虚拟网络中的虚拟虚拟macvlan设备源码分析
5.二十分钟了解K8S网络模型原理
6.go-iptables功能与源码详解
十年码农内功:网络篇
十年码农修炼内功,全新篇章《程序员进阶之路:缓存、网卡网网络、源码源码内存与案例》已升级发布。虚拟虚拟本书不仅修正了前作的网卡网错误,还扩充了网络部分,源码源码asp 源码 用户特别针对服务器端开发者,虚拟虚拟旨在提升专业技能,网卡网打破“CRUD boy”标签。源码源码深入剖析TCP/IP协议栈,虚拟虚拟从网络接口层的网卡网以太网开始,讲解理论与实践,源码源码包括MTU、虚拟虚拟MSS等概念。网卡网
网络分层讲解中,源码源码OSI七层模型和TCP/IP四层结构对比,详述IP与ICMP的作用,展示Linux中IP和ICMP头部结构,以及抓包实例。接着探讨传输层的TCP和UDP,包括套接字编程,如bind、listen、accept等函数的实战应用和阻塞/非阻塞模式的设置。
虚拟网卡(Tun/Tap)的使用,如网络层的Tun和接口层的Tap,以及创建和配置方法,以及网络抓包工具tcpdump和Wireshark的使用技巧,包括过滤规则和复杂抓包组合。此外,还介绍了网络工具如ethtool、ifconfig和伪文件的使用,以及网络调优的高级策略,如Ring Buffer优化和RSS/RPS/RFS/aRFS等技术。
网络收发过程的深入解析,包括数据包接收的多个阶段,以及丢包排查和eBPF技术的实践。最后,文章提供了丰富的参考资料,涵盖了Linux源码、网络编程实战教程和专业博客等内容,旨在为读者提供全面的网络编程学习路径。
ping命令全链路分析(2)
本文使用 Zhihu On VSCode 创作并发布
上篇文章对开源网络协议栈实现 tapip 触发进行了分析,pthread create源码探讨了执行 ping 命令时,数据包是如何到达网络协议栈的。本文将继续探讨 ping 命令与网络协议栈的联系。目前广泛使用的网络协议栈是五层协议划分:应用层、传输层、网络层、链路层和物理层。ping 命令采用的 ICMP 协议位于网络层,但特别之处在于 ICMP 报文是封装在 IP 报文之内的。下文将从 ICMP 协议开始分析。
ICMP 协议
ping 命令的执行过程实际上包含了源端向目的端发送 ICMP 请求报文和目的端向源端发送 ICMP 回复报文的过程。ICMP 报文头包含了 ICMP type、code、id、seq 等字段,报文头部为 字节,payload 部分数据长度为可变长度。
ICMP 报文头部包含 8bit 类型码 type、8bit 代码 code 和 bit 校验和 checksum,其余部分内容和类型码 type 相关。ICMP 报文中定义 type 字段包含以下几种,type 字段与 code 的详细对应关系见附录 1:
其中,ping 命令使用的报文类型为响应请求和响应应答,其报文格式如图:
ICMP 响应请求
在 tapip 中,ICMP 响应请求报文构造是在 ping.c:send_packet() 函数中完成的。ICMP 报文填充构建代码如下:
根据上一篇文章的分析,tapip 采用一个 tap 设备作为虚拟网卡,ICMP 数据报文最终通过 wirte() 接口写入 tap 设备文件中,最终被 Linux 内核中的网络协议栈处理。这里还是先从 tapip 出发,研究下网络协议栈中如何处理 ICMP 响应请求报文。在 tapip 源码中,处理 ICMP 响应请求报文在函数 icmp_echo_request() 中,其函数调用栈如下:
在 Linux 系统中,数据包到达网络设备后会触发中断,网卡驱动程序将对应数据包传递到内核网络协议栈处理,处理结果通过系统调用接口返回给应用程序(ping 应用)。
tapip 作为一种用户态实现,网络设备 net device 是通过 tap 设备模拟的,tap 设备文件描述符中被写入数据包就相当于网卡设备接收到网络数据包;
网卡驱动程序的工作对应 tapip 中 netdev_interrupt() 到 veth_rx() 之间的过程:首先在中断处理函数中调用 veth_poll() 函数采用轮询的方式检查 tap 设备的文件描述符是否有写入事件;当发生写入事件时,veth_rx() 函数被调用,从文件描述符中读取数据包,destoon 加盟源码并传递到网络协议栈中处理,此时,网络协议栈处理的入口 net_in() 被调用。
网络协议栈按照网络分层模型进行处理:
ICMP 响应回复
ICMP 响应回复的处理过程与接收侧处理 ICMP 响应请求的流程基本一致,不同点在于最后 icmp 报文响应的处理,其 type 为 0,对应的处理函数为 icmp_echo_reply(),具体函数调用栈如下:
总结
本文主要分析了用户态网络协议栈 tapip 处理 ping 命令对应的 ICMP 报文的过程,后续将结合 Linux 内核分析这个过程在内核中是如何处理的,另外还会分析下 ARP 协议的实现。
学海无涯,感觉 tapip 的实现逻辑清晰,读起来非常舒服,非常推荐对网络感兴趣的同学学习参考。
(最近特别水逆,希望能早日走出困境,迎来光明吧。)
附录 1: ICMP 报文类型表
markdown
| 类型 Type | 代码 Code | 描述 |
| :------: | :------: | :--------------------------: |
| 0 | 0 | 回显应答(ping 应答) |
| 3 | 0 | 网络不可达 |
| 3 | 1 | 主机不可达 |
| 3 | 2 | 协议不可达 |
| 3 | 3 | 端口不可达 |
| ... | ... | ... |
TODO:
LWIP分析(三)——启动流程
LWIP分析(三)——启动流程
深入分析LWIP启动流程之前,需回顾前文对物理层结构与内存管理底层原理的铺垫。LWIP协议栈在设计上不仅涵盖多种网络硬件接口,如以太网、WiFi和NBIOT等,以实现对多样化联网硬件的支持。为了统一管理多接口,引入了“虚拟网卡”的概念。虚拟网卡实通过操作系统的网络驱动程序或LWIP自身驱动程序实现,与LWIP协议栈交互。
虚拟网卡的主要功能包括建立链表管理多个网卡、配置输出和输入回调函数接口,并能在链表中增删网卡。每张网卡由netif结构体抽象,多网卡链接形成单向链表,此源码关键参数有指针next用于链表连接、output和input函数作为物理层与IP层间数据交换的回调指针。
在虚拟网卡管理中,可实现网卡动态增减、配置及数据处理。网络数据包作为TCP/IP协议的基础处理对象,LWIP高效管理机制通过pbuf结构实现。pbuf管理多样化的数据包,从几百到几千字节不等,且支持在RAM或ROM中存储。chsize s 源码
pbuf结构体如下,基于单链表设计,type字段决定不同pbuf结构。
包括PBUF_RAM、PBUF_POOL、PBUF_ROM和PBUF_REF等类型,提供高效数据包管理,适配数据传输需求。
硬件接口初始化,实现LWIP协议栈启动的关键步骤。初始化以太网硬件接口,需配置系统时钟、工作模式和速度,通过MDIO接口管理PHY寄存器实现。接着初始化引脚并记录TX/RX FIFO位置,此流程贯穿硬件配置、驱动实现与数据传输的初始化阶段。
Linux虚拟网络中的macvlan设备源码分析
Linux虚拟网络中的macvlan设备源码分析
macvlan是Linux内核提供的一种新特性,用于在单个物理网卡上创建多个独立的虚拟网卡。支持macvlan的内核版本包括v3.9-3.和4.0+,推荐使用4.0+版本。macvlan通常作为内核模块实现,可通过以下命令检测系统是否支持: 1. modprobe macvlan - 加载模块 2. lsmod | grep macvlan - 确认是否已加载 对于学习和资源分享,可以加入Linux内核源码交流群获取相关学习资料,前名成员可免费领取价值的内核资料包。 macvlan的工作原理与VLAN不同,macvlan子接口拥有独立的MAC地址和IP配置,每个子接口可以视为一个独立的网络环境。通过子接口,macvlan可以实现流量隔离,根据包的目的MAC地址决定转发给哪个虚拟网卡。macvlan的网络模式包括private、vepa、bridge和passthru,分别提供不同的通信和隔离策略。 与传统VLAN相比,macvlan在子接口独立性和广播域共享上有所不同。macvlan的子接口使用独立MAC地址,而VLAN共享主接口的MAC。此外,macvlan可以直接接入到VM或network namespace,而VLAN通常通过bridge连接。cmake查看源码 总的来说,macvlan是Linux网络配置中的强大工具,理解其源码有助于深入掌握其内部机制。对于网络配置和性能优化的探讨,可以参考以下文章和视频:Linux内核性能优化实战演练(一)
理解网络数据在内核中流转过程
Linux服务器数据恢复案例分析
虚拟文件系统操作指南
Linux共享内存同步方法
最后,关于macvlan与VLAN的详细对比,以及mactap技术,可以参考相关技术社区和文章,如内核技术中文网。二十分钟了解K8S网络模型原理
掌握K8S网络模型无需神秘,只需分钟,本文将带你轻松理解。首先,让我们预习一些基础网络知识:Linux网络命名空间:虚拟化网络栈,如同登录Linux服务器时的默认Host网络栈。
网桥设备:内核中的虚拟端口,用于转发网络数据。
Veth Pair:一对虚拟网卡,常用于连接不同网络命名空间。
VXLAN:扩展局域网,将L2数据包封装到UDP报文中,用于跨主机通信。
BGP:边界网关协议,实现自治系统间的路由可达性。
理解了这些,我们转向单机容器网络模型,这是Docker的基本架构。然后,我们进入K8S网络模型的探索,包括Flannel和Calico两种常见模型:Flannel:两种实现(UDP和VXLAN),分别涉及TUN设备或VXLAN隧道,以及Host-gw的三层解决方案。
Calico:非IPIP模式利用BGP维护路由,无网桥的直接路由规则;IPIP模式通过IP隧道解决跨子网通信问题。
最后,CNI网络插件是K8S的核心组件,负责在Pod创建时设置网络环境,如网络命名空间的配置和路由规则的设定。 通过本文,你将对K8S网络模型有深入理解,进一步实践将使理论更加扎实。详细教程和源代码可以参考相关资源。现在,你已经准备好了深入研究K8S网络的旅程。go-iptables功能与源码详解
介绍iptables之前我们先搬出他的父亲netfilter,netfilter是基于 Linux 2.4.x或更新的内核,提供了一系列报文处理的能力(过滤+改包+连接跟踪),具体来讲可以包含以下几个功能:
其实说白了,netfilter就是操作系统实现了网络防火墙的能力(连接跟踪+过滤+改包),而iptables就是用户态操作内核中防火墙能力的命令行工具,位于用户空间。快问快答,为啥计算机系统需要内核态和用户态(狗头)。
既然netfilter是对报文进行处理,那么我们就应该先了解一下内核是如何进行收发包的,发生报文大致流程如下:
netfilter框架就是作用于网络层中,在一些关键的报文收发处理路径上,加一些hook点,可以认为是一个个检查点,有的在主机外报文进入的位置(PREROUTING ),有的在经过路由发觉要进入本机用户态处理之前(INPUT ),有的在用户态处理完成后发出的地方(OUTPUT ),有的在报文经过路由并且发觉不是本机决定转发走的位置(FOWARD ),有的在路由转发之后出口的位置(POSTROUTING ),每个检查点有不同的规则集合,这些规则会有一定的优先级顺序,如果报文达到匹配条件(五元组之类的)且优先级最高的规则(序号越小优先级越高),内核会执行规则对应的动作,比如说拒绝,放行,记录日志,丢弃。
最后总结如下图所示,里面包含了netfilter框架中,报文在网络层先后经过的一些hook点:
报文转发视角:
iptables命令行工具管理视角:
规则种类:
流入本机路径:
经过本机路径:
流出本机路径:
由上一章节我们已经知道了iptables是用户态的命令行工具,目的就是为了方便我们在各个检查点增删改查不同种类的规则,命令的格式大致如下,简单理解就是针对具体的哪些流(五元组+某些特定协议还会有更细分的匹配条件,比如说只针对tcp syn报文)进行怎样的动作(端口ip转换或者阻拦放行):
2.1 最基本的增删改查
增删改查的命令,我们以最常用的filter规则为例,就是最基本的防火墙过滤功能,实验环境我先准备了一个centos7的docker跑起来(docker好啊,实验完了直接删掉,不伤害本机),并通过iptables配置一些命令,然后通过主机向该docker发生ping包,测试增删改查的filter规则是否生效。
1.查询
如果有规则会把他的序号显示出来,后面插入或者删除可以用 iptables -nvL -t filter --line
可以看出filter规则可以挂载在INPUT,FORWARD,OUTPUT检查点上,并且兜底的规则都是ACCEPT,也就是没有匹配到其他规则就全部放行,这个兜底规则是可以修改的。 我们通过ifconfig查看出docker的ip,然后主机去ping一波:
然后再去查一下,会发现 packets, bytes ---> 对应规则匹配到的报文的个数/字节数:
2. 新增+删除 新增一条拒绝的报文,我们直接把docker0网关ip给禁了,这样就无法通过主机ping通docker容器了(如果有疑问,下面有解答,会涉及docker的一些小姿势): iptables -I INPUT -s ..0.1 -j DROP (-I不指定序号的话就是头插) iptables -t filter -D INPUT 1
可见已经生效了,拦截了ping包,随后我删除了这条规则,又能够ping通了
3. 修改 通过-R可以进行规则修改,但能修改的部分比较少,只能改action,所以我的建议是先通过编号删除规则,再在原编号位置添加一条规则。
4. 持久化 当我们对规则进行了修改以后,如果想要修改永久生效,必须使用service iptables save保存规则,当然,如果你误操作了规则,但是并没有保存,那么使用service iptables restart命令重启iptables以后,规则会再次回到上次保存/etc/sysconfig/iptables文件时的模样。
再使用service iptables save命令保存iptables规则
5. 自定义链 我们可以创建自己的规则集,这样统一管理会非常方便,比如说,我现在要创建一系列的web服务相关的规则集,但我查询一波INPUT链一看,妈哎,条规则,这条规则有针对mail服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,我这看一遍下来头都大了,所以就产生了一个非常合理的需求,就是我能不能创建自己的规则集,然后让这些检查点引用,答案是可以的: iptables -t filter -N MY_WEB
iptables -t filter -I INPUT -p tcp --dport -j MY_WEB
这就相当于tcp目的端口的报文会被送入到MY_WEB规则集中进行匹配了,后面有陆续新规则进行增删时,完全可以只针对MY_WEB进行维护。 还有不少命令,详见这位大佬的总结:
回过头来,讲一个关于docker的小知识点,就是容器和如何通过主机通讯的?
这就是veth-pair技术,一端连接彼此,一端连接协议栈,evth—pair 充当一个桥梁,连接各种虚拟网络设备的。
我们在容器内和主机敲一下ifconfig:
看到了吧,容器内的eth0和主机的vetha9就是成对出现的,然后各个主机的虚拟网卡通过docker0互联,也实现了容器间的通信,大致如下:
我们抓个包看一哈:
可以看出都是通过docker0网关转发的:
最后引用一波 朱老板总结的常用套路,作为本章结尾:
1、规则的顺序非常重要。
如果报文已经被前面的规则匹配到,IPTABLES则会对报文执行对应的动作,通常是ACCEPT或者REJECT,报文被放行或拒绝以后,即使后面的规则也能匹配到刚才放行或拒绝的报文,也没有机会再对报文执行相应的动作了(前面规则的动作为LOG时除外),所以,针对相同服务的规则,更严格的规则应该放在前面。
2、当规则中有多个匹配条件时,条件之间默认存在“与”的关系。
如果一条规则中包含了多个匹配条件,那么报文必须同时满足这个规则中的所有匹配条件,报文才能被这条规则匹配到。
3、在不考虑1的情况下,应该将更容易被匹配到的规则放置在前面。
4、当IPTABLES所在主机作为网络防火墙时,在配置规则时,应着重考虑方向性,双向都要考虑,从外到内,从内到外。
5、在配置IPTABLES白名单时,往往会将链的默认策略设置为ACCEPT,通过在链的最后设置REJECT规则实现白名单机制,而不是将链的默认策略设置为DROP,如果将链的默认策略设置为DROP,当链中的规则被清空时,管理员的请求也将会被DROP掉。
3. go-iptables安装
go-iptables是组件库,直接一波import " github.com/coreos/go-ip...",然后go mod tidy一番,就准备兴致冲冲的跑一波自带的测试用例集,没想到上来就是4个error:
这还了得,我直接去go-iptables的仓库issue上瞅瞅有没有同道中人,果然发现一个类似问题:
虽然都是test failures,但是错的原因是不一样的,但是看他的版本是1.8的,所以我怀疑是我的iptables的版本太老了,一个iptables -v看一眼:
直接用yum update好像不能升级,yum search也没看到最新版本,看来只能下载iptables源码自己编译了,一套连招先打出来:
不出意外的话,那就得出点意外了:
那就继续下载源码安装吧,然后发现libmnl 又依赖libnftnl ,所以直接一波大招,netfilter全家桶全安装:
Finally,再跑一次测试用例就成功了,下面就可以愉快的阅读源码了:
4. 如何使用go-iptables
5. go-iptables源码分析
关键结构体IPTables
初始化函数func New(opts ...option) (*IPTables, error) ,流程如下:
几个重要函数的实现:
其他好像也米有什么,这里面就主要介绍一下,他的命令行执行是怎么实现的:
6. Reference
图解并茂|Linux中常用的虚拟网卡
在Linux的网络架构中,虚拟网卡(如tun, ifb)是内核提供的强大工具,随着虚拟化技术的发展,Linux源代码库不断扩展对网络虚拟化的支持。这不仅限于支持虚拟机,而是为用户和开发者提供了更多选择,适应了多样的网络应用场景。
网络虚拟化的技术种类繁多,从重量级的虚拟机技术,如支持每个虚拟机独立的协议栈,到轻量级的net namespace,它提供了独立的协议栈和网卡,适用于模拟多客户端网络连接,操作简便。例如,net namespace技术,虽然在去年已经有所实践,但学习过程中的探索精神和遇到新知识的惊喜感是持续的动力源泉。
本文将通过图形化的方式,介绍Linux中几种常见的与网络虚拟化相关的虚拟网卡,包括但不限于VETH、MACVLAN和IPVLAN。VETH,作为一对虚拟以太网卡,可以用于内核容器间通信,或通过桥接连接外部网络。MACVLAN则通过一个物理网卡虚拟出多个MAC地址,实现二层隔离,有bridge、VEPA和private模式。IPVLAN则在IP层进行流量分隔,支持L2或L3隔离。
对于MACVTAP,它是为了解决用户态虚拟机或协议栈模拟网卡的问题而设计,通过修改宿主机网卡的rx_handler,将数据直接发送到用户态设备,避免了传统TAP+Bridge的复杂性。
每个技术都有其适用的场景,选择哪种取决于具体的需求和环境。通过理解这些虚拟网卡的工作原理,开发者可以更好地利用Linux的网络虚拟化能力,提升网络管理和隔离的灵活性。