4889软件园:电脑手机软件下载大全,热门手机游戏免费下载

4889软件园 > 资讯文章 > 金山贝壳arp防火墙(win10怎么开启arp防火墙系统天地)

金山贝壳arp防火墙(win10怎么开启arp防火墙系统天地)

作者:佚名 来源:4889软件园 时间:2023-03-27 02:05:28

金山贝壳arp防火墙(win10怎么开启arp防火墙系统天地)

金山贝壳arp防火墙文章列表:

金山贝壳arp防火墙(win10怎么开启arp防火墙系统天地)

win10怎么开启arp防火墙系统天地

相信很多电脑用户都知道arp防火墙有着拦截攻击、拦截ip冲突等多种保护系统的用途,从而保证网络通畅,保证用户使用的电脑不受第三方或者黑客们的攻击,最近有位win10系统用户使用电脑的时候想要开启arp防火墙,但是却不知道怎么操作,为此非常苦恼,那么win10怎么开启arp防火墙呢?今天为大家分享win10开启arp防火墙的操作方法。

开启arp防火墙操作方法:

1、右键点击Win10 开始菜单,然后选择“运行”;或者使用快捷键系统图标键或者是win键 然后按着不松手在按下r键。如图所示:


  
2、然后会打开运行的界面。然后在运行中输入 “Services.msc”回车。如图所示:


  
3、回车后会打开 本地服务。如图所示:


  
4、然后在服务中找到“Windows Firewall”服务,该项就是防火墙的主服务了;顺序是按照字体排列的,大家可以按照字母排列找,会方便很多的。如图所示:


  
5、双击打开该服务后,将驱动类型设置为“自动”,然后点击应用。如图所示:


  
6、最后点击“启动”按钮,来启动防火墙服务。如图所示:


  
7、启动服务驱动后,点击应用或者确定,一切就都好了,Win10防火墙启动成功。如图所示:


  
关于win10开启arp防火墙的操作步骤就为小伙伴们详细分享到这里了,如果用户们使用电脑的时候不知道怎么开启arp防火墙,可以参考以上方法步骤进行操作哦,希望本篇教程对大家有所帮助
本文来源于http://www.xitongtiandi.net/,转载请注明出处。

黑客攻防对付arp攻击让你断网的人!

ARP攻击危害:众说周知,ARP攻击变得日益猖狂,局域网内频繁性区域或整体掉线、IP地址冲突;网速时快时慢。极其不稳定,严重影响了网络的正常通讯。

用“arp -d”命令,只能临时解决上网问题,要从根本上解决问题,就得找到病毒主机。通过上面的arp -a命令,可以判定改变了的网关MAC地址或多个ip指向的物理地址,就是病毒机的MAC地址。哪么对应这个MAC地址的主机又是哪一台呢,windows中有ipconfig /all命令查看每台的信息,但如果电脑数目多话,一台台查下去不是办法,因此可以下载一个叫“NBTSCAN”的软件,它可以扫描到PC的真实IP地址和MAC地址。

早上起来上网,本来上着好好的,看完一段视频后,居然打不开网站了,以为是路由器出问题了(垃圾的tplink老是出这种问题的),ping了下网关,嘿,居然是通的,没问题啊,在ping下百度,域名能解析,但是不能返回数据,显示超时了,一下子就猜到估计是有人在arp我了,打开cmd,arp -a ,果然,arp缓存表里有一个可疑的ip/mac对应表。

法克,哪个2货,一大早,闲没事干来arp限速,我这是租的房子,唉,穷苦百姓,路由共享上网的。打开鸟360的arp防火墙,稍微设置下,靠,毛用处都没用,照样被断网,垃圾360,忽悠人倒是一套一套的,虽然俺也装了360安全卫士,不过哥只用他来打补丁。说实话,其他的功能用处真不大,可有可无。

看来得换防火墙,记忆中,就彩影防火墙好用,有效果,打开百度,准备搜索下下载地址,法克,忘记自己不能上网了,咋办捏,入侵它,用公司的漏洞扫描器扫描了下,没漏洞,唉,xp打完补丁的玩意,对我这种菜鸟真不能入侵。木法子了。。。

一段时间的等待,还是打不开网页,哥急了,奶奶的,兔子急了还咬人呢,再说哥是人,你不让我上网,哥也不让你上,反正哥不能上网了,操起p2p终结者,扫描下,对着那个192.168.0.114,右键选择控制规则,直接选择断网。一段时间后,嘿嘿,貌似可以上网了,ping baidu.com时能返回数据不再超时了,估计那个人以为是自己使用p2p终结者之类的软件,导致自己也不能上网了,把软件关闭了,我怕他一段时间后,又会开启限速软件,这样我又不能上网了。然后我趁这段时间空隙,赶紧下载了彩影防火墙antiarp,安装好后,直接运行。果然,一段时间后,那个2货再次开动限速软件,进行arp欺骗,还是antiarp这个防火墙好用,效果很明显,但是,上网是能上,这个网速还是慢啊,还对网速有影响,看来哥得给他点color to see see。

当一个普通人能以“数据”为切入点,可以轻而易举的更改世界财富的时候,说明这个世界可以随时被打乱重组。

于是,无论你是一个什么样的既得利益者,都不会一直坐享其成。

这个世界,根本不会有阶层固化,只会越来越激荡。

上升的通只会越来越多,越来越多元化。

努力吧,少年。

如果有一天,你误入了世界秘密的中央。

请记住,你的初衷是做一个好人。

我们面对的是一个越来越复杂和动荡的世界

没有一种商业模式是长存的

没有一种竞争力是永恒的

没有一种资产是稳固的

再次操起p2p终结者,果断对他进行断网,不过,在使用p2p之前要对antiarp防火墙进行设置下,不然会拦截的。

请点击此处输入图片描述

总结:

本人装备: p2p终结者 彩影antiarp防火墙

对方装备: p2p终结者之类的网管软件

pk结果 : 本人完胜

建议对局域网的每一台电脑尽量作用固定IP,路由器不启用DHCP,对给网内的每一台电脑编一个号,每一个号对应一个唯一的IP,这样有利用以后故障的查询也方便管理。并利用“NBTSCAN”软件查出每一IP对应的MAC地址,建立一个“电脑编号-IP地址-MAC地址”一一对应的数据库。

详解HCIE-Security防火墙NAT技术

作者:腾科IT教育 李廣

导语:通过案例详细剖析

随着Internet的快速发展,IPv4的公网地址资源已非常匮乏,NAT(Network Address Translation)技术通过对IP报文中的地址或端口进行转换,可以使大量的私网IP地址通过共享少量的公网IP地址来访问公网,从而有效减少了对公网地址的需求,减缓IP地址空间枯竭的速度。

针对NAT的类型可分为以下三种;

1、源NAT

a) 地址池方式,转换源IP信息,适用大量私网用户访问Internet的场景。

b) 出接口地址方式(Easy IP),适用于公网接口IP地址是动态获取的情况。

2、服务器映射

a) 静态映射(NAT Server),适用于公网用户访问私网内部服务器的场景。

b) 服务器负载均衡,适用于多个内网服务器提供相同的服务,对外虚拟成一个服务器。

3、目的NAT

主要应用在转换手机用户WAP网关地址,使手机用户可以正常上网的场景。

NAT基本概念:在USG系列防火墙上,还有Server-map用于存放关于地址转换的映射关系,设备根据这种映射关系对报文的地址进行转换,并转发。

NAT生成Server-map的两种情况:

l 配置NAT Server成功后生成静态表项。

l 配置NAT No-PAT后,需要由流量触发建立Server-map表。

NAT ALG基本概念:NAT ALG(Application Level Gateway,应用级网关)是特定的应用协议的转换代理,可以完成应用层数据中携带的地址及端口号信息的转换。

l FTP应用就由数据连接和控制连接共同完成,而且数据连接的建立动态地由控制连接中的载荷字段信息决定,这就需要ALG来完成载荷字段信息的转换,以保证后续数据连接的正确建立。

l ASPF功能的主要目的是通过对应用层协议的报文分析,为其开放相应的包过滤规则,而NAT ALG的主要目的,是为其开放相应的NAT规则。由于两者通常都是结合使用的,所以使用同一条命令就可以将两者同时开启。

华为HCIE-Security认证针对以上类型展开分析,由技术的原理开始,再到使用的场景,到最后场景的故障分析,完整地解析地址转换技术相关知识。

首先我们将带大家了解在出口部署源NAT地址池方式的大致框架及逻辑,如下图:

如上图内网用户群(10.1.10.2-10.1.10.100)最初都在一个区域内,有两个公网IP(210.1.1.11和210.1.1.12)可用于做NAT转换,由于无需对这些用户进行区分,所以可将两个公网IP放在同一地址池内。上网流量到达防火墙后,将从地址池中随机选取一个公网IP做NAT转换。这个过程看似很简单,但是一些相对复杂的环境还是会难倒部分技术人员,下面通过案例为大家分享下。

例如有道这样的安全竞赛题:LAB2有部分需求如下,其中FW1的G1/0/1地址为10.1.10.254/24,ISP1的G0/0/1地址为10.1.10.10/24,问题需求是:

1、在FW1部署NAT双出口为内网设备访问外部数据,在出口ISP1或ISP2路由设备故障进行切换,其中ISP1申请地址池范围为10.1.10.9/29,向ISP2申请地址范围为10.1.22.9/29,并配置相应安全策略允许内向流通通过。

2、考虑在FW1出口的两个ISP可能会出现的潜在环路或ARP广播问题,该如何解决?

通过分析发现这个LAB2的需求并不是难,无非是是基础知识组合在一起。但大部分工程师并没有能提交完整的答案。反馈的问题是在FW1设备无法将流量访问到ISP1的G0/0/1接口直连。(其中ISP1设备G0/0/1地址为10.1.10.10/24,FW1设备G1/0/1地址为10.1.10.254/24)

询问大家在这个位置做了什么操作时,有人说到在NAT地址池与出口处于同网段时可能引起ARP广播问题,NAT地址池与出口处于不同网段时可能引起环路问题。

登录防火墙,此时FW1上的路由条目如下:

在FW上查会话如下:

产生ARP广播条件:向FW1的G1/0/1口发送目的为10.1.10.13的数据包:

在FW1的G1/0/1接口抓包如下:

此处ARP广播产生的原因是因为防火墙收到报文后,发现报文的目的地址和自己的接口在同一网段,直接发送ARP请求报文(第2个ARP报文),寻找该地址的MAC地址(防火墙依然没有意识到该报文的目的地址是自己的NAT地址池地址)。如果公网上的不法分子发起大量访问时,防火墙将发送大量的ARP请求报文,也会消耗系统资源。

解决的办法是在FW1上针对NAT地址池写黑洞路由,随即在FW1上配置了如下命令"ip route-static 10.1.10.9/29 NULL 0",此时FW1路由表如下:

接着在FW1上查的会话也老化消失:

之后就出现经过FW1访问ISP1直连不通的现象,甚至有人在此排查了半个多小时。在针对直连链路访问失败问题,我们可在FW1执行“display ip routing-table 10.1.10.10”就会得到你想要的结果,发现数据都丢NULL 0 接口。原因是:根据路由匹配原则,路由器会优先选择掩码最长的条目,导致数据无法从FW1的G1/0/1口发送出来,ISP1设备不能收到请求报文。

解决此场景"在NAT地址池与出口处于同网段时可能引起ARP广播问题",可写关于地址池的明细路由(排除已配置的IP)指向NULL 0接口,或者规划好IP地址的使用,避开NAT地址池的范围10.1.10.9/29,使用其他地址配置物理接口。

通过上述案例可以发现,很多的场景并不复杂,只是我们忘了原本基础的内容。包括很多高级学员参加HCIE考试,经常会忘记基础的内容。排错是技术工程师务必掌握的内容,而排错这个技能往往离不开平时的实验练习与基础理论部分。

通过此篇文章,你是否有了解到关于NAT技术的内容?更多关于NAT ALG及Server map表项的场景及注意事项,我们后续继续介绍哦。

OPENWRT明白纸

本内容来源于@什么值得买apP,观点仅代表作者本人 |作者:DMG宝藏大萌哥



小学生openwrt路由器固件学习笔记,给对网络设置一知半解的人看的扫盲文水准!浅显解读,大神莫喷,只是想把ow用的更充分,如果能藉此帮助同样水平的朋友,更是极好的。有些描述不准确请观者担待。

【OPENWRT百度百科解读】:

OpenWrt :一个开源的嵌入项目,linux写的一个完全可写的文件系统,根据硬件配置和功能需要,开发人员自定义的一套固件。简单讲,不是厂商做什么给我用我就用什么,二是我要用什么功能,在OPENWRT构架下挂载我想要的功能,以方便应用实践。

但是OW并不限于路由器,可以广泛的应用于各种领域,比如工控设备、智能家居、机器人等。

在这篇文章的语境下,OW是作为路由器固件出现,基于R21.10.1 / LuCI Master (git-21.280.14233-9b796b1)版本,这应该是最新的OW版本,2021年10月15日发布。

OW一共有状态、系统、服务、网络存储、VPN、网络、带宽监控七个主要模块。藉此对对路由器做监控、设置和插件应用。

状态栏包含:概览、防火墙、路由表、系统日志、内核日志、系统进程、实时信息、WireGuard 、状态负载、均衡释放内存十个子项,分别解读如下:

概览:包含系统、内存、网络、DHCP分配、DHCPv6分配、无线。都是路由器的基本数据。

系统

主机名:这个无线路由器的名称。

型号:路由器的原生型号,一般是固化在路由器芯片里的厂商命名型号。

架构:厂商采用的芯片、方案,可以复制下来搜索看看这个方案的优缺点,网友的评价等;再就是你有硬改的手艺,想硬改一下路由器,比如给路由器加个USB3接口,可以搜索看看你手里的路由器有没有这个可能之类的。

固件、内核版本:OPENWRT的固件版本和内核版本。

本地时间:就是本地时间,一般从时间服务器上得到的数据。

运行时间:路由器上次重启后开始算起的时间。

平均负载:有三个数字,分别表示系统在过去1分钟、5分钟、15分钟内的路由器负载,满负载就是1,大过载会导致错误、丢包、卡顿等现象,路由器也会严重发热。所以这个数值还有点用,就是看你路由器能力能不能承担你家里所有网络设备的负载,所以你可以通过一些方法给路由加负载(类似于打开路由器上的一些吃资源的插件功能、下载软件一次下50个种子吃满宽带,局域网内终端互相拷贝),观察这个数值的大小,如果你网络设置没有问题,这个数值持续过高,就说明你得换个更劲的路由了;你说我花2000大元刚买的牛叉闪闪WIFI6,那肯定你组网有设置的不合适的地方。

我家这个是极路由的b70,wifi5里还算体质可以的一款老路由器;移动百兆宽带,OW上的功能基本能开的都开了,组网感觉也比较合理,身兼路由、交换、ap三职,基本平均负载最大也就是0.5-0.7,所以这个数值还说明一个事,如果你没有房子太大,WIFI覆盖不行的烦恼的话,WIFI5依然抗打,WIFI6意义不大!

CPU使用率:基本和平均负载配套的。

内存:

看看就行了,没啥解释头

网络:

IPV4 WAN状态和ipv6 WAN状态:就是wan口传过来的你家宽带的IP,一个ipV4和一个IPV6;极路由我之前就用的原生的固件,没有刷OW,我还以为刷完之后还需要再设置一下IPV6,等连上OW后台,发现都自动设置好了。应该是你只要改了光猫桥接,在光猫里允许IPV6,OW这边就自动设置好。以后你设置一些功能的时候,需要看ip什么的就来这找吧。

在线用户数:这个我觉得应该是通过DHCP客户端分配列表统计的,所以这玩意能看出来你有没有被蹭网,如果几十个手机连你宽带,而你只是图个清静赶走就行,不追究谁蹭的话,最简单的就改个WIFI密码吧,最好再改个WIFI名字:“蹭网的,我是嫩爹!”之类的。

活动链接:这个数一般也是和你路由器负载是一套活,一般家用不会占满65535,你不开bt下载不挖矿,这个数一般20%以内,占满的话你家肯定网卡的要死。

DHCP分配、DHCPv6分配:

DHCP(动态主机配置协议)是一个局域网的网络协议。指的是由服务器(在这也就是你的路由器)控制一段IP地址范围,终端登录服务器时就可以自动获得服务器分配的IP地址和子网掩码。形象点讲就是,国家建好社区修好道(网络运营商),然后给小区分地址:某某某省-市-区-社区-小区;开发商(路由器)分小区内的地址,南区北区-哪栋-哪个单元-哪一层-哪一户?这个玩法就是DHCP,只不过他是抽签抓阄随机定的。

这个列表就是罗列了局域网内所有通过这个路由器联网的设备以及DHCP分给他的地址,上半部分是IPV4,下半部分是IPV6的,我这个4个IPV4主机,3个IPV6主机,是因为有个设备不支持IPV6。

当然你也可以不用DHCP自动分配地址,手动指定,那个叫静态IP,后边有地方可以改这个东西。

无线

这个更好理解了,就是这个路由器的无线网络,一个2.4G一个5G的,后面的无线板块里设置的一些东西会在这体现出来。

SSID和BSSSID:无线的名字,SSID是给人看的,就是你手机、网卡搜出来的名字,“蹭网的,我是嫩爹!”也从这改。BSSID是给设备看的二进制标识符。

信道:就是你家这信息高速公路走哪条车道,原则是你身处的的环境有好多的话,分开设置避免干扰。这些东西一般让路由器自己管理就行了,瞎鼓捣的意义不大,。

传输速率:这个要注意后边的单位Mbit/s,别看这个就觉得你买个1200m的路由器怎么才200m,单位不一样,1200是Mbp/s,1Mbit/s=8Mbp/s.

这里只是显示防火墙的状态,一个ipv4一个ipv6的,能鼓捣的也就是重启防火墙功能,路由器防火墙默认行为已经可以满足路由器的需要,一般情况下也无需修改,没点计算机水平你也不会改,但是不代表这个完全没用,有些时候你设置一些东西的时候死活就是不通,可以来这看看是不是防火墙挡住了,是的话在后边防火墙设置里可以设置一些规则,来绕开防火墙。专业设置,不懂别瞎鼓捣。

路由表里也是只能看不能设置,是为你一些网络设置提供信息。

ARP:即地址解析协议, 用于实现从 IP 地址(应用层)到 MAC 地址(硬件层)的映射,即询问目标IP对应的MAC地址,大白话描述就是有些设备需要ip地址,有些设备需要MAC地址,这俩种设备对话的话需要一个协议互相翻译。这个列表基本就是把局域网里存在设备的IP地址和mac地址对应的表现了出来。

往下就是IPV4和 IPV6的路由表,以及IPV6网上邻居,展开说几本书说不完,总之就是需要的时候来查阅就好

记录路由器行为,可以通过日志判断一些网络问题

两个日志,记录路由器行为,可以通过日志判断一些网络问题

系统进程类似于windows的进程管理,路由器上运行的所有模块和服务都会在这里显示出来,还有cpu和内存的占用信息,还可以关闭和挂起,openwrt还可以加一些用户自编的脚本,运行的话也会在这显示出来

就是把负载、流量、无线、连接的数量统计图表化了。

WireGuard是个利用了最新加密技术的开源VPN,简单讲就是让你翻墙科学上网的,这里是设置正确工作后的状态监控页面,所以说OPENWRT是个操作性很强的能真金白银给你省钱儿的东西,之后的章节会有wireguard的教程,这里只是运行这个wG的监控页面。

均衡负载的监控页面,均衡负载前边的词叫双线多拨、一线多拨、一号多拨。双线多拨就是两条入户的宽带线路接在一起用实现带宽叠加;一线多拨是同一个运营商的两个宽带账号在一条先路上实现带宽叠加;一号多拨是运营商不封锁这个的前提下,你用一条线路一个账号多次拨号实现带宽叠加。这样进到你家的宽带来源就复杂了起来,你需要给他指定个规则等和平共处,这个规则就是均衡负载。这个页面就是监控此功能的,设置后会在这里体现出来。

这个OW版本这里选上会回到状态页,估计是没有做上,基本等同于360一键释放内存这种功能吧,其实意义不大,够用的路由器不需要这个,有足够的内存冗余。

这就是OPENWRT第一部分的释读,可以调整的的东西很少,主要都是监控页面。下一篇:状态栏。



#值得买才是双十一#

一文理解 K8s 容器网络虚拟化

本文需要读者熟悉 Ethernet(以太网)的基本原理和 Linux 系统的基本网络命令,以及 TCP/IP 协议族并了解传统的网络模型和协议包的流转原理。文中涉及到 Linux 内核的具体实现时,均以内核 v4.19.215 版本为准。

一 内核网络包接收流程

1 从网卡到内核协议栈

如图[1],网络包到达 NC(Network Computer,本文指物理机)时,由 NIC(Network Interface Controller,网络接口控制器,俗称网卡)设备处理,NIC 以中断的方式向内核传递消息。Linux 内核的中断处理分为上半部(Top Half)和下半部(Bottom Half)。上半部需要尽快处理掉和硬件相关的工作并返回,下半部由上半部激活来处理后续比较耗时的工作。

具体到 NIC 的处理流程如下:当 NIC 收到数据时,会以 DMA 方式将数据拷贝到 Ring Buffer (接收队列) 里描述符指向的映射内存区域,拷贝完成后会触发中断通知 CPU 进行处理。这里可以使用 ethtool -g {设备名,如eth0} 命令查看 RX/TX (接收/发送)队列的大小。CPU 识别到中断后跳转到 NIC 的中断处理函数开始执行。此时要区分 NIC 的工作模式,在早先的非 NAPI(New API)[2]模式下,中断上半部更新相关的寄存器信息,查看接收队列并分配 sk_buff 结构指向接收到的数据,最后调用 netif_rx() 把 sk_buff 递交给内核处理。在 netif_rx() 的函数的流程中,这个分配的 sk_buff 结构被放入 input_pkt_queue队列后,会把一个虚拟设备加入poll_list 轮询队列并触发软中断 NET_RX_SOFTIRQ 激活中断下半部。此时中断上半部就结束了,详细的处理流程可以参见 net/core/dev.c 的 netif_rx() -> netif_rx_internal() -> enqueue_to_backlog() 过程。下半部 NET_RX_SOFTIRQ 软中断对应的处理函数是 net_rx_action(),这个函数会调用设备注册的 poll() 函数进行处理。非 NAPI 的情况下这个虚拟设备的 poll() 函数固定指向 process_backlog() 函数。这个函数将 sk_buff 从 input_pkt_queue 移动到 process_queue 中,调用 __netif_receive_skb() 函数将其投递给协议栈,最后协议栈相关代码会根据协议类型调用相应的接口进行后续的处理。特别地,这里的 enqueue_to_backlog() 以及 process_backlog() 函数也用于和启用了 RPS 机制后的相关逻辑。

非 NAPI(New API)模式下每个网络包的到达都会触发一次中断处理流程,这么做降低了整体的处理能力,已经过时了。现在大多数 NIC 都支持 NAPI 模式了。NAPI 模式下在首包触发 NIC 中断后,设备就会被加入轮询队列进行轮询操作以提升效率,轮询过程中不会产生新的中断。为了支持 NAPI,每个 CPU 维护了一个叫 softnet_data 的结构,其中有一个 poll_list 字段放置所有的轮询设备。此时中断上半部很简单,只需要更新 NIC 相关的寄存器信息,以及把设备加入poll_list 轮询队列并触发软中断 NET_RX_SOFTIRQ就结束了。中断下半部的处理依旧是 net_rx_action() 来调用设备驱动提供的 poll() 函数。只是 poll() 此时指向的就是设备驱动提供的轮询处理函数了(而不是非 NAPI 模式下的内核函数 process_backlog())。这个设备驱动提供的轮询 poll() 函数最后也会调用 __netif_receive_skb() 函数把 sk_buff 提交给协议栈处理。

非 NAPI 模式和 NAPI 模式下的流程对比如下(其中灰色底色是设备驱动要实现的,其他都是内核自身的实现):

关于 NAPI 模式网络设备驱动的实现以及详细的 NAPI 模式的处理流程,这里提供一篇文章和其译文作为参考[3](强烈推荐)。这篇文章很详细的描述了 Intel Ethernet Controller I350 这个 NIC 设备的收包和处理细节(其姊妹篇发包处理过程和译文[4])。另外收包这里还涉及到多网卡的 Bonding 模式(可以在/proc/net/bonding/bond0 里查看模式)、网络多队列(sudo lspci -vvv 查看 Ethernet controller 的 Capabilities信息里有 MSI-X: Enable Count=10 字样说明 NIC 支持,可以在 /proc/interrupts 里查看中断绑定情况)等机制。这些本文都不再赘述,有兴趣的话请参阅相关资料[5]。

2 内核协议栈网络包处理流程

前文说到 NIC 收到网络包构造出的 sk_buff 结构最终被 __netif_receive_skb() 提交给了内核协议栈解析处理。这个函数首先进行 RPS[5] 相关的处理,数据包会继续在队列里转一圈(一般开启了 RSS 的网卡不需要开启 RPS)。如果需要分发包到其他 CPU 去处理,则会使用 enqueue_to_backlog() 投递给其他 CPU 的队列,并在 process_backlog()) 中触发 IPI(Inter-Processor Interrupt,处理器间中断,于 APIC 总线上传输,并不通过 IRQ)给其他 CPU 发送通知(net_rps_send_ipi()函数)。

最终,数据包会由 __netif_receive_skb_core() 进行下一阶段的处理。这个处理函数主要的功能有:

处理ptype_all 上所有的 packet_type->func(),典型场景是 tcpdump 等工具的抓包回调(paket_type.type 为 ETH_P_ALL,libcap 使用 AF_PACKET Address Family)

处理 VLAN(Virtual Local Area Network,虚拟局域网)报文 vlan_do_receive() 以及处理网桥的相关逻辑(skb->dev->rx_handler() 指向了 br_handle_frame())

处理 ptype_base上所有的 packet_type->func() , 将数据包传递给上层协议层处理,例如指向 IP 层的回调 ip_rcv() 函数

截至目前,数据包仍旧在数据链路层的处理流程中。这里复习下 OSI 七层模型与 TCP/IP 五层模型:

在网络分层模型里,后一层即为前一层的数据部分,称之为载荷(Payload)。一个完整的 TCP/IP 应用层数据包的格式如下[6]:

__netif_receive_skb_core() 的处理逻辑中需要关注的是网桥和接下来 IP 层以及 TCP/UDP 层的处理。首先看 IP 层,__netif_receive_skb_core() 调用 deliver_skb(),后者调用具体协议的 .func() 接口。对于 IP 协议,这里指向的是 ip_rcv() 函数。这个函数做了一些统计和检查之后,就把包转给了 Netfilter [7]框架并指定了函数 ip_rcv_finish() 进行后续的处理(如果包没被 Netfilter 丢弃)。经过路由子系统检查处理后,如果包是属于本机的,那么会调用 ip_local_deliver() 将数据包继续往上层协议转发。这个函数类似之前的逻辑,依旧是呈递给 Netfilter 框架并指定函数 ip_local_deliver_finish() 进行后续的处理,这个函数最终会检查和选择对应的上层协议接口进行处理。

常见的上层协议比如 TCP 或者 UDP 协议的流程不在本文讨论的范围内,仅 TCP 的流程所需要的篇幅足以超过本文所有的内容。这里给出 TCP 协议(v4)的入口函数 tcp_v4_rcv() 以及 UDP 协议的入口函数 udp_rcv() 作为指引自行研究,也可以阅读其他的资料进行进一步的了解[9]。

3 Netfilter/iptables 与 NAT(网络地址转换)

关于 Netfilter 框架需要稍微着重的强调一下,因为后文要提到的网络策略和很多服务透出的实现都要使用 Netfilter 提供的机制。

Netfilter 是内核的包过滤框架(Packet Filtering Framework)的实现。简单说就是在协议栈的各个层次的包处理函数中内置了很多的 Hook 点来支持在这些点注册回调函数。

图片来自 Wikimedia,可以点开参考文献[8]查看大图(svg 矢量图,可以调大网页显示百分比继续放大)。

Linux 上最常用的防火墙 iptables 即是基于 Netfilter 来实现的(nftables 是新一代的防火墙)。iptables 基于表和链(Tables and Chains)的概念来组织规则。注意这里不要被“防火墙”这个词误导了,iptables 所能做的不仅仅是对包的过滤(Filter Table),还支持对包进行网络地址转换(NAT Table)以及修改包的字段(Mangle Table)。在网络虚拟化里,用的最多的便是 NAT 地址转换功能。通常此类功能一般在网关网络设备或是负载均衡设备中很常见。当 NC 需要在内部进行网络相关的虚拟化时,也是一个类似网关以及负载均衡设备了。

在设置 iptables 的 NAT 规则前,还需要打开内核的包转发功能 echo "1" > /proc/sys/net/ipv4/ip_forward 才可以。另外建议也打开 echo "1" /proc/sys/net/Bridge/bridge-nf-call-iptables 开关(可能需要 modprobe br_netfilter)。bridge-nf-call-iptables 从上面的源码分析就能理解,网桥的转发处理是在 Netfilter 规则之前的。所以默认情况下二层网桥的转发是不会受到三层 iptables 的限制的,但是很多虚拟化网络的实现需要 Netfilter 规则生效,所以内核也支持了让网桥的转发逻辑也调用一下 Netfilter 的规则。这个特性默认情况不开启,所以需要检查开关。至于具体的 iptables 命令,可以参考这篇文章和其译文[10]进行了解,本文不再讨论。

这里强调下,Netfilter 的逻辑运行在内核软中断上下文里。如果 Netfilter 添加了很多规则,必然会造成一定的 CPU 开销。下文在提到虚拟化网络的性能降低时,很大一部分开销便是源自这里。

二 虚拟网络设备

在传统的网络认知里,网络就是由带有一个或多个 NIC 的一组 NC 使用硬件介质和 switch(交换机)、Router(路由器)所组成的一个通信集合(图片来自 [11],下同):

网络虚拟化作为 SDN(Software?Defined?Network,软件定义网络)的一种实现,无非就是虚拟出 vNIC(虚拟网卡)、vSwitch(虚拟交换机)、vRouter(虚拟路由器)等设备,配置相应的数据包流转规则而已。其对外的接口必然也是符合其所在的物理网络协议规范的,比如 Ethernet 和 TCP/IP 协议族。

随着 Linux 网络虚拟化技术的演进,有了若干种虚拟化网络设备,在虚拟机和虚拟容器网络中得到了广泛的应用。典型的有 Tap/Tun/Veth、Bridge 等:

Tap/Tun 是 Linux 内核实现的一对虚拟网络设备,Tap/Tun 分别工作在二层/三层。Linux 内核通过 Tap/Tun 设备和绑定该设备的用户空间之间交换数据。基于 Tap 驱动即可实现虚拟机 vNIC 的功能,Tun 设备做一些其他的转发功能。

Veth 设备总是成对创建(Veth Pair),一个设备收到内核发送的数据后,会发送到另一个设备上去,可以把 Veth Pair 可以想象成一对用网线连接起来的 vNIC 设备。

Bridge 是工作在二层的虚拟网桥。这是虚拟设备,虽然叫网桥,但其实类似 vSwitch 的设计。当 Bridge 配合 Veth 设备使用时,可以将 Veth 设备的一端绑定到一个Bridge 上,相当于真实环境把一个 NIC 接入一个交换机里。

虚拟机和容器的网络在传输流程上有些区别,前者比如 KVM 一般是使用 Tap 设备将虚拟机的 vNIC 和宿主机的网桥 Bridge 连接起来。而容器的 Bridge 网络模式是将不同 Namespace 里的 Veth Pair 连接网桥 Bridge 来实现通信(其他方式下文讨论)。

Linux Bridge 配合桥接或者 NAT 模式很容易可以实现同主机或跨主机的虚拟机/容器之间通信,而且 Bridge 本身也支持 VLAN 的配置,可以实现一些三层交换机的能力。但是很多厂商都在研发功能更丰富的虚拟交换机,流行的有 Cisco Nexus 1000V、 VMware Virtual Switch 以及广泛使用的开源的 Open vSwitch[12] 等。利用 vSwitch,可以构建出支持更多封装协议、更高级的虚拟网络:

1 Linux Bridge Veth Pair 转发

VRF(Virtual Routing and Forwarding,虚拟路由转发)在网络领域中是个很常见的术语。上世纪九十年代开始,很多二层交换机上就能创建出 4K 的 VLAN 广播域了。4K 是因为 VLAN 标签的格式遵循 802.1q 标准,其中定义的 VLAN ID 是 12 位的缘故(802.1q in 802.1q 可以做到 4094*4094 个,0 和 4095 保留)。如今 VRF 概念被引入三层,单个物理设备上也可以有多个虚拟路由/转发实例了。Linux 的 VRF 实现了对三层的网络协议栈的虚拟,而 Network Namespace(以下简称 netns)虚拟了整个网络栈。一个 netns 的网络栈包括:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。本文使用 netns 进行演示(毕竟在讨论容器),下文使用 ip[14] 命令创建和管理 netns 以及 Veth Pair 设备。

创建、查看、删除 Network Namespace

# 创建名为 qianyi-test-1 和 add qianyi-test-2 的命名 netns,可以在 /var/run/netns/ 下查看ip netns add qianyi-test-1ip netns add qianyi-test-2# 查看所有的 Network Namespaceip netns list# 删除 Network Namespaceip netns del qianyi-test-1ip netns del qianyi-test-2

执行结果如图(删除先不执行):

有兴趣的话可以使用 strace 命令跟踪这个创建过程看看 ip 命令是怎么创建的(strace ip netns add qianyi-test-1)。

在 netns 中执行命令

# 在 qianyi-test-1 这个 netns 中执行 ip addr 命令(甚至可以直接执行 bash 命令得到一个 shell)# nsenter 这个命令也很好用,可以 man nsenter 了解ip netns exec qianyi-test-1 ip addr

执行结果如下:

图片

这个新创建的 netns 里一贫如洗,只有一个孤独的 lo 网卡,还是 DOWN 状态的。下面开启它:

开启 lo 网卡,这个很重要

ip netns exec qianyi-test-1 ip link set dev lo up
ip netns exec qianyi-test-2 ip link set dev lo up

状态变成了 UNKOWN,这是正常的。这个状态是驱动提供的,但是 lo 的驱动没有做这个事情。

创建 Veth Pair 设备

# 分别创建 2 对名为 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 的 Veth Pair 设备ip link add veth-1-a type veth peer name veth-1-bip link add veth-2-a type veth peer name veth-2-b

使用 ip addr 命令可以查看:

8-9,10-11 便是上面创建出来的 2 对 Veth Pair 设备,此时它们都没有分配 IP 地址且是 DOWN 状态。

将 Veth Pair 设备加入 netns

# 将 veth-1-a 设备加入 qianyi-test-1 这个 netnsip link set veth-1-a netns qianyi-test-1# 将 veth-1-b 设备加入 qianyi-test-2 这个 netnsip link set veth-1-b netns qianyi-test-2# 为设备添加 ip 地址/子网掩码并开启ip netns exec qianyi-test-1 ip addr add 10.0.0.101/24 dev veth-1-aip netns exec qianyi-test-1 ip link set dev veth-1-a upip netns exec qianyi-test-2 ip addr add 10.0.0.102/24 dev veth-1-bip netns exec qianyi-test-2 ip link set dev veth-1-b up

此时我们分别在两个 netns 中执行 ip addr 命令,即可看到设备已经存在,且路由表(route 或 ip route 命令)也被默认创建了:

这里操作和查看设备都必须采用 ip netns exec {...} 的方式进行,如果命令很多,也可以把执行的命令换成 bash,这样可以方便的在这个 shell 里对该 netns 进行操作。

现在通过 veth-1-a/veth-1-b 这对 Veth Pair 联通了 qianyi-test-1 和 qianyi-test-2 这两个 netns,这两个 netns 之间就可以通过这两个 IP 地址相互访问了。

ping 的同时在 101 上抓包的结果如下:

可以很清楚的看到,eth-1-a(10.0.0.101)先通过 arp (Address Resolution Protocol,地址解析协议)询问 10.0.0.102 的 MAC 地址。得到回应后,就以 ICMP (Internet Control Message Protocol,Internet 报文控制协议) request 和 reply 了,这也正是 ping 使用的协议。

ARP 解析的缓存信息也可以通过 arp 命令查看:

此时的网络连接模式是这样的:

这种连接模式,就很像是现实中把两个带有 NIC 的设备用网线连接起来,然后配置了相同网段的 IP 后彼此就可以通信了。那如果超过一个设备需要建立互联呢?现实中就需要交换机等网络设备了。还记得前文中说的 Linux 自带的 Bridge 么?接下来就使用 Bridge 机制建立网络。

进行下面的试验前需要把 veth-1-a/veth-1-b 这对 Veth Pair 从 qianyi-test-1 和 qianyi-test-2 移动回宿主机的 netns 里,恢复初始的环境。

# 宿主机的 netns id 是 1(有些系统可能不是,请查询相关系统的文档)ip netns exec qianyi-test-1 ip link set veth-1-a netns 1ip netns exec qianyi-test-2 ip link set veth-1-b netns 1

创建 Linux Bridge 并配置网络

# 创建一个名为 br0 的 bridge 并启动(也可以使用 brctl 命令)ip link add br0 type bridgeip link set br0 up# 将 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 这两对 Veth Pair 的 a 端放入 qianyi-test-1 和 qianyi-test-2ip link set veth-1-a netns qianyi-test-1ip link set veth-2-a netns qianyi-test-2# 为 veth-1-a 和 veth-2-a 配置 IP 并开启ip netns exec qianyi-test-1 ip addr add 10.0.0.101/24 dev veth-1-aip netns exec qianyi-test-1 ip link set dev veth-1-a upip netns exec qianyi-test-2 ip addr add 10.0.0.102/24 dev veth-2-aip netns exec qianyi-test-2 ip link set dev veth-2-a up# 将 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 这两对 Veth Pair 的 b 端接入 br0 网桥并开启接口ip link set veth-1-b master br0ip link set dev veth-1-b upip link set veth-2-b master br0ip link set dev veth-2-b up

执行完可以查看创建好的网桥和配置好的 IP,实际上 brctl show 命令显示的结果更易懂,可以很清楚的看到 veth-1-b 和 veth-2-b 连接在了网桥的接口上。当 Veth Pair 的一端连接在网桥上时,就会从“网卡”退化成一个“水晶头”。

当下模式抓包的结果并没有什么区别,但网络连接模式不同:

按照这个模式,如果有更多的 Network Namespace 和 Veth Pair 的话,使用相同的方式添加就可以水平扩展了。

但是尝试从 qianyi-test-1 中 ping 宿主机自然是不通的,因为没有任何网络规则可以访问到宿主机的网络:

上面的截图中有个 Docker0 的网桥。当机器上安装了 Docker 之后会被自动设置好这个网桥供 Docker 使用。可能你注意到了,这个名为 docker0 的网桥居然是有 IP 地址的。现实中的网桥自然是没有 IP 的,但是 Linux Bridge 这个虚拟设备是可以设置的。当 Bridge 设置 IP 之后,就可以将其设置成这个内部网络的网关(Gateway),再配合路由规则就可以实现最简单的虚拟网络跨机通信了(类似现实中的三层交换机)。

下面继续给 br0 网桥创建地址并在 veth-1-a 和 veth-2-a 上设置其为默认的网关地址:

# 确认路由转发开启echo "1" > /proc/sys/net/ipv4/ip_forward# 为 br0 设置 IP 地址ip addr add local 10.0.0.1/24 dev br0# 为 veth-1-a 和 veth-2-a 设置默认网关ip netns exec qianyi-test-1 ip route add default via 10.0.0.1ip netns exec qianyi-test-2 ip route add default via 10.0.0.1

此时就能成功的访问宿主机地址了(宿主机上的路由表在 ip link set br0 up 这一步自动创建了):

网络模型进一步变成了这样:

如果此时,另一台宿主机上也存在另一个网段的网桥和若干个 netns 的话,怎么让他们互通呢?分别在两边宿主机上配置一条到目的宿主机的路由规则就好了。假设另一台宿主机的 IP 地址是 10.97.212.160,子网是 10.0.1.0/24 的话,那么需要在当前机器上加一条 10.0.1.0/24 via 10.97.212.160 的规则,10.97.212.160 上加一条 10.0.0.0/24 via 10.97.212.159 的规则就可以了(或者 iptables 配置 SNAT/DNAT 规则)。那如果有 N 台呢?那就会是个 N * N 条的规则,会很复杂。这就一个简单的 Underlay 模式的容器通信方案了。缺点也很明显,要求对宿主机底层网络有修改权,且比较难和底层网络解耦。那如果能在物理网络上构建出一个横跨所有宿主机的虚拟网桥,把所有相关的 netns 里面的设备都连接上去,不就可以解耦了么。这就是 Overlay Network(覆盖网络)方案,下文会进行阐述。至于本节其他虚拟网络设备的安装和配置(比如 Open vSwitch)也是比较类似的,这里不再赘述,有兴趣的话可以自行查看文档并测试。

2 Overlay 网络方案之 VXLAN

VXLAN(Virtual eXtensible Local Area Network,虚拟可扩展局域网,RFC7348)[16],VLAN 的扩展协议,是由 IETF 定义的 NVO3(Network Virtualization over Layer 3)标准技术之一(其他有代表性的还有 NVGRE、STT)。但是 VXLAN 和 VLAN 想要解决的问题是不一样的。VXLAN 本质上是一种隧道封装技术,它将数据链路层(L2)的以太网帧(Ethernet frames)封装成传输层(L4)的 UDP 数据报(Datagrams),然后在网络层(L3)中传输。效果就像数据链路层(L2)的以太网帧在一个广播域中传输一样,即跨越了三层网络却感知不到三层的存在。因为是基于 UDP 封装,只要是 IP 网络路由可达就可以构建出庞大的虚拟二层网络。也因为是基于高层协议再次封装,性能会比传统的网络低 20%~30% 左右(性能数据随着技术发展会有变化,仅代表当前水平)。

这里简要介绍下 VXLAN 的 2 个重要概念:

VTEP(VXLAN Tunnel Endpoints,VXLAN 隧道端点),负责 VXLAN 报文的封装和解封,对上层隐藏了链路层帧的转发细节

VNI(VXLAN Network Identifier,VXLAN 网络标识符),代表不同的租户,属于不同 VNI 的虚拟网络之间不能直接进行二层通信。

VXLAN 的报文格式如图[17]:

Linux kernel v3.7.0 版本开始支持 VXLAN 网络。但为了稳定性和其他功能,请尽量选择 kernel v3.10.0 及之后的版本。下面我们使用 10.97.212.159 和 11.238.151.74 这两台机器创建一个测试的 VXLAN 网络。

# 10.97.212.159 上操作# 创建名为 qianyi-test-1 和 add qianyi-test-2 的命名 netns,可以在 /var/run/netns/ 下查看ip netns add qianyi-test-1ip netns add qianyi-test-2# 开启 lo 网卡,这个很重要ip netns exec qianyi-test-1 ip link set dev lo upip netns exec qianyi-test-2 ip link set dev lo up# 创建一个名为 br0 的 bridge 并启动(也可以使用 brctl 命令)ip link add br0 type bridgeip link set br0 up# 分别创建 2 对名为 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 的 Veth Pair 设备ip link add veth-1-a type veth peer name veth-1-bip link add veth-2-a type veth peer name veth-2-b# 将 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 这两对 Veth Pair 的 a 端放入 qianyi-test-1 和 qianyi-test-2ip link set veth-1-a netns qianyi-test-1ip link set veth-2-a netns qianyi-test-2# 为 veth-1-a 和 veth-2-a 配置 IP 并开启ip netns exec qianyi-test-1 ip addr add 10.0.0.101/24 dev veth-1-aip netns exec qianyi-test-1 ip link set dev veth-1-a upip netns exec qianyi-test-2 ip addr add 10.0.0.102/24 dev veth-2-aip netns exec qianyi-test-2 ip link set dev veth-2-a up# 将 veth-1-a/veth-1-b 和 veth-2-a/veth-2-b 这两对 Veth Pair 的 b 端接入 br0 网桥并开启接口ip link set veth-1-b master br0ip link set dev veth-1-b upip link set veth-2-b master br0ip link set dev veth-2-b up# 11.238.151.74 上操作# 创建名为 qianyi-test-3 和 add qianyi-test-4 的命名 netns,可以在 /var/run/netns/ 下查看ip netns add qianyi-test-3ip netns add qianyi-test-4# 开启 lo 网卡,这个很重要ip netns exec qianyi-test-3 ip link set dev lo upip netns exec qianyi-test-4 ip link set dev lo up# 创建一个名为 br0 的 bridge 并启动(也可以使用 brctl 命令)ip link add br0 type bridgeip link set br0 up# 分别创建 2 对名为 veth-3-a/veth-3-b 和 veth-4-a/veth-4-b 的 Veth Pair 设备ip link add veth-3-a type veth peer name veth-3-bip link add veth-4-a type veth peer name veth-4-b# 将 veth-3-a/veth-3-b 和 veth-4-a/veth-4-b 这两对 Veth Pair 的 a 端放入 qianyi-test-3 和 qianyi-test-4ip link set veth-3-a netns qianyi-test-3ip link set veth-4-a netns qianyi-test-4# 为 veth-3-a 和 veth-4-a 配置 IP 并开启ip netns exec qianyi-test-3 ip addr add 10.0.0.103/24 dev veth-3-aip netns exec qianyi-test-3 ip link set dev veth-3-a upip netns exec qianyi-test-4 ip addr add 10.0.0.104/24 dev veth-4-aip netns exec qianyi-test-4 ip link set dev veth-4-a up# 将 veth-3-a/veth-3-b 和 veth-4-a/veth-4-b 这两对 Veth Pair 的 b 端接入 br0 网桥并开启接口ip link set veth-3-b master br0ip link set dev veth-3-b upip link set veth-4-b master br0ip link set dev veth-4-b up

这一长串的命令和之前的步骤完全一致,构建了一个如下图所示的网络环境:

这个环境里,10.0.0.101 和 10.0.0.102 是通的,10.0.0.103 和 10.0.0.104 也是通的,但是显然 10.0.0.101/10.0.0.102 和 10.0.0.103/10.0.0.104 是无法通信的。

接下来配置 VXLAN 环境打通这四个 netns 环境:

# 10.97.212.159 上操作(本机有多个地址时可以用 local 10.97.212.159 指定)ip link add vxlan1 type vxlan id 1 remote 11.238.151.74 dstport 9527 dev bond0ip link set vxlan1 master br0ip link set vxlan1 up# 11.238.151.74 上操作(本机有多个地址时可以用 local 11.238.151.74 指定)ip link add vxlan2 type vxlan id 1 remote 10.97.212.159 dstport 9527 dev bond0ip link set vxlan2 master br0ip link set vxlan2 up

使用 brctl show br0 命令可以看到两个 VXLAN 设备都连接上去了:

然后从 10.0.0.101 上就可以 ping 通 10.0.0.103 了:

在 10.0.0.101 上抓的包来看,就像是二层互通一样:

直接查看 arp 缓存,也是和二层互通一模一样:

使用 arp -d 10.0.0.103 删掉这个缓存项目,在宿主机上重新抓包并保存文件,然后用 WireShark 打开看看(因为上面设置的不是 VXLAN 默认端口 4789,还需要设置 WireShark 把抓到的 UDP 解析为 VXLAN 协议):

我们得到了预期的结果。此时的网络架构如图所示:

那么问题来了,这里使用 UDP 协议能实现可靠通信吗?当然可以,可靠性不是这一层考虑的事情,而是里层被包裹的协议需要考虑的。完整的通信原理其实也并不复杂,两台机器上各自有 VTEP(VXLAN Tunnel Endpoints,VXLAN 隧道端点)设备,监听着 9527 端口上发送的 UDP 数据包。在收到数据包后拆解通过 Bridge 传递给指定的设备。那 VETP 这个虚拟设备怎么知道类似 10.0.0.3 这样的地址要发送给哪台机器上的 VETP 设备呢?这可是虚拟的二层网络,底层网络上可不认识这个地址。事实上在 Linux Bridge 上维护着一个名为 FDB(Forwarding Database entry)的二层转发表,用于保存远端虚拟机/容器的 MAC 地址、远端 VTEP 的 IP,以及 VNI 的映射关系,可以通过 bridge fdb 命令来对 FDB 表进行操作:

# 新增条目bridge fdb add <remote_host_mac_addr> dev <vxlan_interface> dst <remote_host_ip_addr># 删除条目bridge fdb del <remote_host_mac_addr> dev <vxlan_interface># 替换条目bridge fdb replace <remote_host_mac_addr> dev <vxlan_interface> dst <remote_host_ip_addr># 显示条目bridge fdb show

上面这个简单的实验就 2 台机器,使用了命令的方式直接指定了彼此的 VTEP 地址,当 fdb 表查不到信息时发给对方就行了,这是最简单的互联模式。大规模 VXLAN 网络下,就需要考虑如何发现网络中其他的 VETP 地址了。解决这个问题一般有 2 种方式:一是使用组播/多播( IGMP, Internet Group Management Protocol),把节点组成一个虚拟的整体,包不清楚发给谁的话就广播给整个组了(上述实验中的创建 VETH 设备的命令修改为组播/多播地址比如 224.1.1.1 就行,remote 关键字也要改成 group,具体请参阅其他资料);二是通过外部的分布式控制中心来收集 FDB 信息并分发给同一个 VXLAN 网络的所有节点。组播/多播受限于底层网络的支持情况和大规模下的的性能问题,比如很多云网络上不一定允许这么做。所以下文在讨论和研究 K8s 的网络方案时会看到很多网络插件的实现采用的都是类似后者的实现方式。

这节就介绍到这里了。当然 Overlay 网络方案也不止 VXLAN 这一种方式,只是目前很多主流的方案都采用了这种方式。其他的 Overlay 模式看上去眼花缭乱,其实说白了,无非就是 L2 over L4,L2 over L3,L3 over L3 等等各种包装方式罢了,懂了基本原理之后都没什么大不了的。网络虚拟化的设备和机制也有很多[18],细说的话一天都说不完,但是基本的网络原理掌握之后,无非是各种协议包的流转罢了。

三 K8s 的网络虚拟化实现

1 K8s 的网络模型

每一个 Pod 都有它自己的 IP 地址,这就意味着你不需要显式地在每个 Pod 之间创建链接, 你几乎不需要处理容器端口到主机端口之间的映射。这将创建一个干净的、向后兼容的模型,在这个模型里,从端口分配、命名、服务发现、 负载均衡、应用配置和迁移的角度来看,Pod 可以被视作虚拟机或者物理主机。

Kubernetes 对所有网络设施的实施,都需要满足以下的基本要求(除非有设置一些特定的网络分段策略):

节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信

节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有 Pod 通信

备注:仅针对那些支持 Pods 在主机网络中运行的平台(比如:Linux):

那些运行在节点的主机网络里的 Pod 可以不通过 NAT 和所有节点上的 Pod 通信

这个模型不仅不复杂,而且还和 Kubernetes 的实现廉价的从虚拟机向容器迁移的初衷相兼容, 如果你的工作开始是在虚拟机中运行的,你的虚拟机有一个 IP,这样就可以和其他的虚拟机进行通信,这是基本相同的模型。

Kubernetes 的 IP 地址存在于 Pod 范围内 - 容器共享它们的网络命名空间 - 包括它们的 IP 地址和 MAC 地址。这就意味着 Pod 内的容器都可以通过 localhost 到达各个端口。这也意味着 Pod 内的容器都需要相互协调端口的使用,但是这和虚拟机中的进程似乎没有什么不同, 这也被称为“一个 Pod 一个 IP”模型。

这几段话引用自 K8s 的官方文档[19],简单概括下就是一个 Pod 一个独立的 IP 地址,所有的 Pod 之间可以不通过 NAT 通信。这个模型把一个 Pod 的网络环境近似等同于一个 VM 的网络环境。

2 K8s 的主流网络插件实现原理

K8s 中的网络是通过插件方式实现的,其网络插件有 2 种类型:

CNI 插件:遵守 CNI(Container Network Interface,容器网络接口)规范,其设计上偏重互操作性

Kubenet 插件:使用 bridge 和 host-local CNI 插件实现了基本的 cbr0

图片来自[20],本文只关注 CNI 接口插件。主流的 K8s 网络插件有这些[21],本文选出 github star 数在千以上的几个项目分析下:

Flannel:https://github.com/flannel-io/flannel

Calico:https://github.com/projectcalico/calico

Cilium:https://github.com/cilium/cilium

Flannel

CNI 是由 CoreOS 提出的规范,那就先看下 CoreOS 自己的 Flannel 项目的设计。Flannel 会在每台机宿主机上部署一个名为 flanneld 的代理进程,网段相关的数据使用 Kubernetes API/Etcd 存储。Flannel 项目本身是一个框架,真正为我们提供容器网络功能的,是 Flannel 的后端实现。

目前的 Flannel 有下面几种后端实现:VXLAN、host-gw、UDP 以及阿里云和其他大厂的支持后端(云厂商都是实验性支持),还有诸如 IPIP、IPSec 等一些隧道通信的实验性支持。按照官方文档的建议是优先使用 VXLAN 模式,host-gw 推荐给经验丰富且想要进一步提升性能的用户(云环境通常不能用,原因后面说),UDP 是 Flannel 最早支持的一种性能比较差的方案,基本上已经弃用了。

下文分别对这三种模式进行分析。

1)VXLAN

使用 Linux 内核 VXLAN 封装数据包的方式和原理上文已经介绍过了,Flannel 创建了一个名为 flannel.1 的 VETH 设备。因为 flanneld 进程的存在,所以注册和更新新的 VETH 设备关系的任务就依靠这个进程了。所以好像也没什么需要说的了,就是每个新的 K8s Node 都会创建 flanneld 这个 DeamonSet 模式的守护进程。然后注册、更新新的 VETH 设备就变得非常自然了,全局的数据自然也是保存在 Etcd 里了。这种方式图已经画过了,无非是设备名字不一样(VETH 叫 flannel.1,网桥叫 cni0)而已。

2)host-gw

顾名思义,host-gw 就是把宿主机 Host 当做 Gateway 网关来处理协议包的流动。这个方式上文其实也演示过了,至于节点的变化和路由表的增删也是依靠 flanneld 在做的。这个方案优缺点都很明显,最大的优点自然是性能,实打实的直接转发(性能整体比宿主机层面的通信低 10%,VXLAN 可是20% 起步,甚至 30%)。缺点也很明显,这种方式要求宿主机之间是二层连通的,还需要对基础设施有掌控权(编辑路由表),这个在云服务环境一般较难实现,另外规模越来越大时候的路由表规模也会随之增大。这种方式原理上比较简单,图不画了。

3)UDP

每台宿主机上的 flanneld 进程会创建一个默认名为 flannel0 的 Tun 设备。Tun 设备的功能非常简单,用于在内核和用户应用程序之间传递 IP 包。内核将一个 IP 包发送给 Tun 设备之后,这个包就会交给创建这个设备的应用程序。而进程向 Tun 设备发送了一个 IP 包,那么这个 IP 包就会出现在宿主机的网络栈中,然后根据路由表进行下一跳的处理。在由 Flannel 管理的容器网络里,一台宿主机上的所有容器都属于该宿主机被分配的一个“子网”。这个子网的范围信息,所属的宿主机 IP 地址都保存在 Etcd 里。flanneld 进程均监听着宿主机上的 UDP 8285 端口,相互之间通过 UDP 协议包装 IP 包给目的主机完成通信。之前说过这个模式性能差,差在哪里?这个方案就是一个在应用层模拟实现的 Overlay 网络似得(像不像一个用户态实现的 VETH 设备?),数据包相比内核原生支持的 VXLAN 协议在用户态多了一次进出(flanneld 进程封包/拆包过程),所以性能上损失要大一些。

Calico

Calico 是个挺有意思的项目,基本思想是把宿主机完全当成路由器,不使用隧道或 NAT 来实现转发,把所有二三层流量转换成三层流量,并通过宿主机上的路由配置完成包的转发。

Calico 和之前说的 Flannel 的 host-gw 模式区别是什么?首先 Calico 不使用网桥,而是通过路由规则在不同的 vNiC 间转发数据。另外路由表也不是靠 Etcd 存储和通知更新,而是像现实环境一样直接用 BGP(Border Gateway Protocol, 边界网关协议)进行路由表数据交换。BGP 挺复杂的,详细的阐述这个协议有点费劲(而且我也不是很懂),在本文里只需要知道这个协议使得路由设备可以相互发送和学习对方的路由信息来充实自己就可以了,有兴趣的话请查阅其他资料进一步了解。回到 Calico,宿主机上依旧有个名为 Felix 的守护进程和一个名为 BIRD的 BGP 客户端。

上文说过,Flannel 的 host-gw 模式要求宿主机二层是互通的(在一个子网),在 Calico 这里依然有这个要求。但是 Calico 为不在一个子网的环境提供了 IPIP 模式的支持。开启这个模式之后,宿主机上会创建一个 Tun 设备以 IP 隧道(IP tunnel)的方式通信。当然用了这个模式之后,包又是L3 over L3 的 Overlay 网络模式了,性能也和 VXLAN 模式相当。

全路由表的通信方式也没有额外组件,配置好 IP 路由转发规则后全靠内核路由模块的流转来做。IPIP 的架构图也是大同小异的,也不画了。

Cilium

eBPF-based Networking, Security, and Observability

光从这个介绍上就看出来 Cilium 散发出的那种与众不同的气息。这个项目目前的 Github Star 数字快过万了,直接力压前面两位。Cilium 部署后会在宿主机上创建一个名为 cilium-agent 的守护进程,这个进程的作用就是维护和部署 eBPF 脚本来实现所有的流量转发、过滤、诊断的事情(都不依赖 Netfilter 机制,kenel > v4.19 版本)。从原理图的角度画出来的架构图很简单(配图来自 github 主页):

Cilium 除了支持基本的网络连通、隔离与服务透出之外,依托 eBPF 所以对宿主机网络有更好的观测性和故障排查能力。这个话题也很大,本文就此收住。这里给两几篇写的很好的文章何其译文可以进一步了解22。

3 K8s 容器内访问隔离

上文介绍了网络插件的机制和实现原理,最终可以构建出一个二层/三层连通的虚拟网络。默认情况下 Pod 间的任何网络访问都是不受限的,但是内部网络中经常还是需要设置一些访问规则(防火墙)的。

针对这个需求,K8s 抽象了一个名为 NetworkPolicy 的机制来支持这个功能。网络策略通过网络插件来实现,要使用网络策略就必须使用支持 NetworkPolicy 的网络解决方案。为什么这么说?因为不是所有的网络插件都支持 NetworkPolicy 机制,比如 Flannel 就不支持。至于 NetworkPolicy 的底层原理,自然是使用 iptables 配置 netfilter 规则来实现对包的过滤的。NetworkPolicy 配置的方法和 iptables/Netfilter 的原理细节不在本文范围内,请参阅其他资料进行了解24。

4 K8s 容器内服务透出

在一个 K8s 集群内部,在网络插件的帮助下,所有的容器/进程可以相互进行通信。但是作为服务提供方这是不够的,因为很多时候,服务的使用方不会在同一个 K8s 集群内的。那么就需要一种机制将这个集群内的服务对外透出。K8s 使用 Service 这个对象来完成这个能力的抽象。Service 在 K8s 里是个很重要的对象,即使在 K8s 内部进行访问,往往也是需要 Service 包装的(一来 Pod 地址不是永远固定的,二来总是会有负载均衡的需求)。

一句话概括 Service 的原理就是:Service = kube-proxy iptables 规则。当一个 Service 创建时,K8s 会为其分配一个 Cluster IP 地址。这个地址其实是个 VIP,并没有一个真实的网络对象存在。这个 IP 只会存在于 iptables 规则里,对这个 VIP:VPort 的访问使用 iptables 的随机模式规则指向了一个或者多个真实存在的 Pod 地址(DNAT),这个是 Service 最基本的工作原理。那 kube-proxy 做什么?kube-proxy 监听 Pod 的变化,负责在宿主机上生成这些 NAT 规则。这个模式下 kube-proxy 不转发流量,kube-proxy 只是负责疏通管道。

K8s 官方文档比较好的介绍了 kube-proxy 支持的多种模式和基本的原理[26]。早先的 userspace 模式基本上弃用了,上面所述的 iptables 随机规则的做法在大规模下也不推荐使用了(想想为什么)。现在最推荐的当属 IPVS 模式了,相对于前两种在大规模下的性能更好。如果说 IPVS 这个词比较陌生的话,LVS 这个词恐怕是我们耳熟能详的。在这个模式下,kube-proxy 会在宿主机上创建一个名为 kube-ipvs0 的虚拟网卡,然后分配 Service VIP 作为其 IP 地址。最后 kube-proxy 使用内核的 IPVS 模块为这个地址设置后端 POD 的地址(ipvsadm 命令可以查看)。其实 IPVS 在内核中的实现也是用了 Netfilter 的 NAT 机制。不同的是,IPVS 不会为每一个地址设置 NAT 规则,而是把这些规则的处理放到了内核态,保证了 iptables 规则的数量基本上恒定,比较好的解决了之前的问题。

上面说的只是解决了负载均衡的问题,还没提到服务透出。K8s 服务透出的方式主要有 NodePort、LoadBalancer 类型的 Service(会调用 CloudProvider 在公有云上为你创建一个负载均衡服务)以及 ExternalName(kube-dns 里添加 CNAME)的方式。对于第二种类型,当 Service 繁多但是又流量很小的情况下,也可以使用 Ingress 这个 Service 的 Service 来收敛掉[27]。Ingress 目前只支持七层 HTTP(S) 转发(Service 目前只支持四层转发),从这个角度猜猜 Ingress 怎么实现的?来张图看看吧[28](当然还有很多其他的 Controller[29]):

对于这部分,本文不再进行详细阐述了,无非就是 NAT,NAT 多了就想办法收敛 NAT 条目。按照惯例,这里给出一篇特别好的 kube-proxy 原理阐述的文章供进一步了解[30]。

四 总结

网络虚拟化是个很大的话题,很难在一篇文章中完全讲清楚。尽管这篇文章尽量想把重要的知识节点编织清楚,但受限于作者本人的精力以及认知上的限制,可能存在疏忽甚至错漏。如有此类问题,欢迎在评论区讨论/指正。参考文献里给出了很多不错的资料值得进一步去学习(部分地址受限于网络环境,可能需要特定的方式才能访问)。

参考文献

1、TCP Implementation in Linux: A Brief Tutorial, Helali Bhuiyan, Mark McGinley, Tao Li, Malathi Veeraraghavan, University of Virginia:https://www.semanticscholar.org/paper/TCP-Implementation-in-Linux-:-A-Brief-Tutorial-Bhuiyan-McGinley/f505e259fb0cd8cf3f75582d46cd209fd9cb1d1a
2、NAPI, linuxfoundation, https://wiki.linuxfoundation.org/networking/napi
3、Monitoring and Tuning the Linux Networking Stack: Receiving Data, Joe Damato,译文:Linux 网络栈监控和调优:接收数据(2016):http://arthurchiao.art/blog/tuning-stack-rx-zh/
4、Monitoring and Tuning the Linux Networking Stack: Sending Data, Joe Damato, 译文:Linux 网络栈监控和调优:发送数据(2017):http://arthurchiao.art/blog/tuning-stack-tx-zh/
5、Scaling in the Linux Networking Stack, https://github.com/torvalds/linux/blob/master/Documentation/networking/scaling.rst
6、Understanding TCP internals step by step for Software Engineers and System Designers, Kousik Nath
7、Netfilter, https://www.netfilter.org/
8、Netfilter-packet-flow, https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
9、Analysis TCP in Linux, https://github.com/fzyz999/Analysis_TCP_in_Linux
10、NAT - Network Address Translation, 译文:NAT - 网络地址转换(2016):http://arthurchiao.art/blog/nat-zh/
11、Virtual networking in Linux, By M. Jones, IBM Developer:https://developer.ibm.com/tutorials/l-virtual-networking/
12、Open vSwitch, http://www.openvswitch.org/
13、Linux Namespace, https://man7.org/linux/man-pages/man7/namespaces.7.html
14、ip, https://man7.org/linux/man-pages/man8/ip.8.html
15、Veth, https://man7.org/linux/man-pages/man4/veth.4.html
16、VxLAN, https://en.wikipedia.org/wiki/Virtual_Extensible_LAN
17、QinQ vs VLAN vs VXLAN, John, https://community.fs.com/blog/qinq-vs-vlan-vs-vxlan.htm
18、Introduction to Linux interfaces for virtual networking, Hangbin Liu:https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#
19、Cluster Networking, 英文地址https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/
20、THE CONTAINER NETWORKING LANDSCAPE: CNI FROM COREOS AND CNM FROM DOCKER, Lee Calcote:https://thenewstack.io/container-networking-landscape-cni-coreos-cnm-docker/
21、CNI - the Container Network Interface, https://github.com/containernetworking/cni
22、Making the Kubernetes Service Abstraction Scale using eBPF, [译] 利用 eBPF 支撑大规模 K8s Service (LPC, 2019):https://linuxplumbersconf.org/event/4/contributions/458/
23、基于 BPF/XDP 实现 K8s Service 负载均衡 (LPC, 2020)https://linuxplumbersconf.org/event/7/contributions/674/

24、A Deep Dive into Iptables and Netfilter Architecture, Justin Ellingwood:https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture

25、Iptables Tutorial 1.2.2, Oskar Andreasson:https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html

26、Virtual IPs and service proxies, 英文地址:https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies

27、Ingress, 英文地址:https://kubernetes.io/docs/concepts/services-networking/ingress/

28、NGINX Ingress Controller, https://www.nginx.com/products/nginx-ingress-controller/

29、Ingress Controllers, 英文地址:https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/

30、Cracking kubernetes node proxy (aka kube-proxy), [译] 深入理解 Kubernetes 网络模型:自己实现 Kube-Proxy 的功能:https://cloudnative.to/blog/k8s-node-proxy/

原文链接:https://developer.aliyun.com/article/813025?utm_content=g_1000310145

本文为阿里云原创内容,未经允许不得转载。