有需要參考網絡基礎知識的,參見https://www.cnblogs.com/shuiguizi/p/12518086.html
1,GRE:是一種協議封裝的格式。注意是約束格式的,他的具體要求是這樣的。
在GRE中,需要被傳輸和封裝的報文稱之為payload packet,而用於封裝和傳輸的協議則成為delivery protocol。GRE在封裝的時候,除了payload和delivery協議的header外,會生成一個GRE header。
GRE header + payload一起被delivery協議封裝用於傳輸。
例如:要建立VPN的時候,需要建立隧道,那么此時就要求三大類協議:乘客協議,隧道協議,承載協議。
GRE是在路由器上進行封裝解封裝,能夠封和解的路由器(即靠近源和目的的路由器)設怎么做到封和解的呢?
答:在這些路由器上有特殊的路由條目,如果是要被封裝的數據則讓他的下一跳時隔特殊的東東叫做Tunnel0(可以認為是隧道的起點),於是他負責封
到了目的路由器,同樣是這個叫做tunnel的東東,會把附加的封裝去除,得到真正的payload。
需要注意的是,GRE是點對點的,為什么這么說,
因為tunnel0是要配置的,會在tunnel0上配置tunnel的終點時誰(即目的ip),所以一個tunnel0只負責一條隧道。想要多播那就再建立隧道。
想要組播是不支持的,想要廣播那就是向這個節點上的所有隧道(即所有tunnel0s);另外很多防火牆或者三層網絡設備不支持GRE,即不能解析明白被封裝的包是什么也就無從做過濾或者符再均衡之類的行為。
2,vxlan:
他的封包特點有如下幾點:
1)不同於GRE是(第)三層外面套(第)三層,而是二層外面套四層,三層, 二層,所以這就說明封裝后的包可以精准到達目的地的四層
(注意,雖然是四層不能說就是一個用戶態應用,着要看具體用什么實現的vtep,有的內核就支持那么就不用切換到用戶態了,有的是硬件支持有的是軟件支持)
並且,因為封裝的是二層網絡,也就是已經細化到局域網了,所以才叫VxLAN
2)也有一個類似tunnel0的東西,叫做VTEP(VxLAN Tunnel Endpoint)是用來做封裝解封裝的
3)應用場景:因為封裝的是二層包,所以應用的場景是宿主機A上的虛擬機m和另一個宿主機B上的虛擬機n之間的通信,因為可以將宿主機上的虛擬機們看作是類局域網。
在通信的時候,是有arp的,因為m並不知道n所屬的主機地址到底是哪個,所以發arp問下宿主機們,m在誰那里。
4)具體的工作過程
(1)當一個VTEP啟動的時候,他會通過IGMP協議加入一個組播組,於是此時A,B,C都在一個組中了,制定了VXLAN ID為100
(2)然后A上的m虛擬機啟動了,他具有的VXLAN就是100,同樣n也是100,他們可以認為是在一個lan中(因為是一個二層的封裝啊)
(3)當m想要ping n的時候,發現他並不知道如何找到n,具體的說是不知道他的mac地址,還是因為是一個局域網中,所以於是封裝並發送arp包,vtep在組中廣播看看誰有n的mac地址 ,
於是vtep B回復了n的mac,然后vtep A就開始封裝包 :內層ip和mac是虛擬機n的地址,外層是vtep B的地址
(4)最后,宿主機B上的vtep B程序獲取到了這個四層包,然后解包,得到就是一個內部局域網的二層包,最后發送給寄宿在自己身上的虛擬機n。
這里要說一下,這個包之所以能組播出去,正是IGMP協議的工作。
VxLAN包:
Virtual Extensible LAN,虛擬化可擴展局域網,基於IP網絡,采用 MAC in UDP封裝形式的二層VPN技術,一個簡單拓撲和報文結構圖來感性認識下
幾個關鍵名詞:
VNI:VXLAN Network Identifier,即虛擬出來的網絡id
VTEP:VxLAN隧道的EndPoint,代表隧道的始端或者終端實體。負責對VxLAN報文進行封裝/解封裝,包括ARP請求報文和數據報文。VTEP可由硬件設備或軟件去實現。
結合報文格式解讀一下:學過TCP/IP的我們都知道,協議棧可以分成5層,從最上層的應用出來的數據會經過協議棧一層層封裝:應用層--->傳輸層TCP/UDP頭--->三層(網絡層)IP頭--->二層(鏈路層)MAC頭-->物理層,從物理網卡出去。
VxLAN是其在封裝到二層的時候,由VTEP進行再一次的封裝叫做VxLAN封裝,即又增加了UDP頭->IP頭->MAC頭,所以叫"MAC in UDP"。這就非常適用於容器的應用場景,一方面滿足了網絡隔離的要求(比如多租戶等),另一方面VNI是個24-bit的值,即支持2^24個vxlan網絡,遠高於vlan。這樣的好處是用一張圖就能看出來:
水鬼子:其實里面還有很多知識點沒有融會貫通,先記錄這些,之后隨着遇到問題,應該就會慢慢豁然開朗
==========================================================
linux 內核從3.7之后就內部集成了vxlan功能,所以可以使用linux內核提供的vxlan功能,經過配置創建vxlan網絡。
而從Docker自Docker Engine 1.9之后,就自帶overlay網絡的驅動了,也才有了可以直接使用docker create network命令創建overlay類型的網絡
在這里我們除了創建單純的vxlan網絡,我們可以手動模擬overlay驅動,利用namespace自己創建overlay網絡,這里會遇到很多坑,但對於學習vxlan甚至是linux網絡知識都很有幫助。
另外,受環境所限這里我只試驗了點對點類型的vxlan網絡,但對於理解vxlan往還是夠用啦
大綱:
1,環境准備,
2,最基本的點對點vxlan網
3,多namespace下的點對點vxlan網
3.1入坑
3.2爬坑
3.3結論
環境准備
0,在某兩家雲服務供應商上買了2台計算雲,centos 7,這樣的環境稍顯復雜,因為計算雲的機器都是綁定的VIP,其自身接口的ip都是小網ip,互相不認識的小網ip......
master節點 minion節點
VIP: 188.x.x.113 ---中間網絡------ 106.y.y.3
IP(eth0): 172.21.0.3 172.16.0.4
MAC(eth0): 52:54:00:6b:df:04 fa:16:3e:a8:1f:98
1,linux內核版本越高越好,如果不夠,可以用如下命令進行升級
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml -y
2, 安裝必要的工具,比如
ln -s /var/run/docker/netns/ /var/run/netns
最基本的點對點vxlan網
所謂點對點網絡,表示每個vtep只有一個伙伴,它只與這個伙伴建立一個隧道。
【實操】
master:
//創建一個vxlan類型的接口作為vtep,vxlan id即VNI為200,指定隧道的另一端ip為minion的VIP,建立隧道的物理接口為eth0
ip link add vxlan20 type vxlan id 200 dstport 4789 remote 106.y.y.3 dev eth0
ip addr add 10.20.1.2/24 dev vxlan20
ip link set vxlan20 up
minion:
ip link add vxlan20 type vxlan id 200 remote 188.x.x.113 dstport 4789 dev eth0 ip addr add 10.20.1.3/24 dev vxlan20 ip link set vxlan20 up
【驗證】#ping 10.20.1.3 OK的,抓包也可以看到經過vxlan封裝的報文
【解析】:
此種情況屬於vtep之間的直接通信,arp包和icmp包都被vtep即vxlan20進行了vxlan封裝。
這部分的實驗是很有必要的,因為可以說明我的linux內核是支持vxlan。這很重要,因為在開始我使用的是namespace + veth pair方式搭建環境,但總是不通,查了好多資料都說是版本問題,所以我這才舍棄自己的虛擬機花錢購買了計算雲,然后又是升級內核版本等等....
直到這種最簡單方式的情況下發現是OK的,我才意識到,我解決問題的方向早就偏了....
多namespace下的點對點vxlan網
【配置】
master:
ip link add vxlan20 type vxlan id 100 remote 106.y.y.3 dstport 4789 dev eth0
ip link add br-vx2 type bridge //創建網橋
ip link add veth20 type veth peer name veth21 //創建一對veth pair
//br-vx網橋左手一只vxlan10接口,右手一只veth10接口,然后將網橋up起來
ip link set vxlan20 master br-vx2
ip link set vxlan20 up
ip link set dev veth20 master br-vx2
ip link set dev veth20 up
ip link set br-vx2 up
//創建一個新的namespace名叫ns100,將之前創建的veth pair中的另一端veth11,添加到該ns100中,並添加ip以及up起來
ip netns add ns200
ip link set dev veth11 netns ns200
ip netns exec ns200 ip addr add 10.20.0.20/24 dev veth21
ip netns exec ns200 ip link set dev veth21 up
ip netns exec ns200 ip link set lo up
minion:
ip link add vxlan20 type vxlan id 200 remote 188.x.x.113 dstport 4789 dev eth0
ip link add br-vx2 type bridge
ip link add veth20 type veth peer name veth21
ip link set vxlan20 master br-vx2
ip link set vxlan20 up
ip link set dev veth20 master br-vx2
ip link set dev veth20 up
ip link set br-vx2 up
ip netns add ns200
ip link set dev veth21 netns ns200
ip netns exec ns200 ip addr add 10.20.0.21/24 dev veth21
ip netns exec ns200 ip link set veth21 up
ip netns exec ns200 ip link set lo up
入坑>>>>>>>>>
【操作】:為什么不通能,為什么?
#ip netns exec ns200 ping 10.20.0.21 -c 3
PING 10.20.0.21 (10.20.0.21) 56(84) bytes of data.
--- 10.20.0.21 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2030ms
爬坑>>>>>>>>
【解析round1】:
根據目前學到的理論,我們知道數據的方向會如下圖中紅色箭頭所示,於是我開始一步一步抓包
1,vxlan20接口抓包如下,arp有發出去且有收到應答,但是icmp包卻有去無回
2,再次檢查收發包情況,對比執行ping前后得到如下
[root@master ~]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
br-vx2 1450 341 0 0 0 0 0 0 0 BMRU
veth20 1500 998 0 0 0 278 0 0 0 BMRU
vxlan20 1450 279 0 0 0 204 0 0 0 BMRU
執行完ping操作, 即從ns200的veth21接口會發出來3個icmp包 + 1個arp包
[root@master ~]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
br-vx2 1450 346 0 0 0 0 0 0 0 BMRU
veth20 1500 1002 0 0 0 279 0 0 0 BMRU
vxlan20 1450 280 0 0 0 205 0 0 0 BMRU
解析:
veth20:接收4個包,其中3個icmp + 1個arp,發送1個arp請求
br-vx2:接收5個包 發送0個包
vxlan20:接收1個包,發送1個包,均為arp包,一個請求一個應答
水鬼子:不知道這里你有沒有和我一樣有個疑問,看過linux轉發原理都知道,橋的一個接口接收到包之后會轉發給橋上的其他接口,那么上面的發送接收到底表示什么含義呢,比如vxlan20接收的1個包是指接收來自veth20的轉發,還是來自外網的應答?還有tcpdump這個工具,它到底抓的是哪個方向的數據包,他和netstat統計時打點的地方一樣的么?接下來我會一步一步驗證,非常繁瑣,寫下來只是為了給自己的記錄,大家可以略過此段直接看結論。
0,預備知識:
http://ebtables.netfilter.org/br_fw_ia/br_fw_ia.html
很好的文章,看看在linu bridge中,ebtables和iptables都扮演了什么角色,這里截取核心的部分,如下圖:
說明:
藍色:ebtbales, 綠色:ibtables
橋上的接口收到數據后,進行bridge decision,如果目的地是給自己,上送走filter表的input鏈;否則橋內部洪泛,洪泛之前要走ebtables:filter的forward表,iptables:mangle表的forward表和filter表的forward表。
操作1:br-vx2接口是用來和上層協議棧交互的,掐斷上報的路,看看什么結果
[root@master ~]# ebtables -L
Bridge table: filter
Bridge chain: INPUT, entries: 1, policy: ACCEPT
-j DROP //上送的數據都drop掉,即阻斷上送的路
再ping,得到如下:
[root@master ~]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
br-vx2 1450 346 0 0 0 0 0 0 0 BMRU
veth20 1500 1006 0 0 0 280 0 0 0 BMRU
vxlan20 1450 281 0 0 0 206 0 0 0 BMRU
小小結1:br-vx2確實表示用於上報,這個和網橋同名的接口可以看做是通向內核協議棧的接口。
操作2:我刪除ebtables中的配置,然后ping一個未知的ip,讓其得不到arp應答
# ip netns exec ns200 ping 10.20.0.22 -c 3
PING 10.20.0.22 (10.20.0.22) 56(84) bytes of data.
[root@master ~]# tcpdump -i br-vx2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-vx2, link-type EN10MB (Ethernet), capture size 262144 bytes
20:02:41.886373 ARP, Request who-has 10.20.0.22 tell 10.20.0.20, length 28
20:02:42.931276 ARP, Request who-has 10.20.0.22 tell 10.20.0.20, length 28
20:02:43.955364 ARP, Request who-has 10.20.0.22 tell 10.20.0.20, length 28
br-vx2 1450 349 0 0 0 0 0 0 0 BMRU
vxlan20 1450 281 0 0 0 209 0 0 0 BMRU
解析:為什么是ping -c 3的時候br-vx2 接收到5個包呢?其中3(icmp)+1(arp請求)是veth20通過橋內部轉發給我的,那一個是什么?我猜測是接收過來的arp應答
為了驗證這個結論,經過上述操作發現netstat的數據中,br-vx2只增加了3個(arp請求)
小小結:反向證明上面多出的1個包是arp應答。另外netstat統計時,RX-OK表示的是接口收到的數據包,這個數據包既可以是請求也可以是應答,只要是我接收到的。
小結:
結合上述實驗加上我又看了linux的bridge部分的源碼,以及netstat工具的源碼,可以得到如下結論:
1,每一個bridge都有一個同名接口,可以將該接口看做是內核協議棧對外(網橋)的出入口。
2,netstat -i命令統計的數據是驅動層面的,將驅動中記錄的數據提取出來進行顯示,rx表示ingress,rx表示egress
---數據本來就在那里,我去取
3,tcpdump -i x是應用層面的,根據指令在不同模塊上注冊socket,數據在流動過程中發現有tcpdump的注冊則deliver一份給他
4,二者的區別,netstat的統計更底層,所以當你發現netstat的統計數據和tcpdump不同的時候,就可以大概猜出來數據是在哪里被丟掉的。
【解析round2】:
在上面的例子可以看出來arp可以接收到應答,但是icmp報文為什么就不行呢?有兩條線索
1,tcpdump -i vxlan20有看到請求發出來
2,netstat -i 發現,數據沒有從vxlan10接口真的出去
那么數據肯定再這中間被drop掉了,然后看看這中間經歷了什么,沒錯,就是iptables和ebtables一共經歷了6個鏈,那好,我一個一個表查,通過向鏈里添加匹配條件來跟蹤數據包都走到哪里。
最終,我發現原來這里給drop掉了
[root@master ~]# iptables -LFORWARD -v
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 icmp -- any any anywhere 10.20.0.21 ----這個是我后加的匹配條件,原先是沒有的
開始ping
[root@master ~]# iptables -LFORWARD -v
Chain FORWARD (policy DROP 3 packets, 252 bytes) ----是的,被drop掉了
pkts bytes target prot opt in out source destination
3 252 icmp -- any any anywhere 10.20.0.21
986 82824 DOCKER-USER all -- any any anywhere anywhere
986 82824 DOCKER-ISOLATION-STAGE-1 all -- any any anywhere anywhere
0 0 ACCEPT all -- any docker0 anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- any docker0 anywhere anywhere
0 0 ACCEPT all -- docker0 !docker0 anywhere anywhere
0 0 ACCEPT all -- docker0 docker0 anywhere anywhere
0 0 ACCEPT all -- any docker_gwbridge anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 DOCKER all -- any docker_gwbridge anywhere anywhere
結論>>>>>>>>
仔細看,filter表的FORWARD鏈,除了docker相關的鏈匹配上了(這兩個鏈直接return的,這里就不展示了)但都是什么也沒做,也就是說走的是缺省策略?
excuse me?DROP?是的,該鏈的缺省策略時DROP,想死的心都有了,馬上改
[root@master ~]# iptables -P FORWARD ACCEPT
[root@minion ~]# iptables -P FORWARD ACCEPT
[root@master ~]# ip netns exec ns200 ping 10.20.0.21 -c 3
PING 10.20.0.21 (10.20.0.21) 56(84) bytes of data.
64 bytes from 10.20.0.21: icmp_seq=1 ttl=64 time=16.5 ms
64 bytes from 10.20.0.21: icmp_seq=2 ttl=64 time=8.49 ms
64 bytes from 10.20.0.21: icmp_seq=3 ttl=64 time=8.43 ms
--- 10.20.0.21 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 8.438/11.156/16.534/3.802 ms
[root@master ~]#
注:頻繁操作網橋,要設置如下命令,即讓網橋的記憶為0,否則會因為有記憶讓配置的策略暫時不生效(缺省5分鍾才生效)
]# brctl setageing br-vx2 0
水鬼子:網上說在試驗前要關閉防火牆,然后我就用如下命令關閉了,還關閉了selinux,但是事實證明iptables還是生效的,也許這里面又什么原理等待我去研究,但是已經管不了那么多了TOT
[root@master ~]# systemctl stop firewalld.service
[root@master ~]# systemctl disable firewalld.service
[root@master ~]# firewall-cmd --state
not running
-------------------------------end---------------------------------------------------