集線器和交換機是兩種典型的網絡設備,集線器 位於 物理層,而 交換機 位於於 數據鏈路層 ,行爲明顯不一樣。本節準備了兩個簡單實驗,旨在經過實踐加深對理論知識的理解,逐步掌握 Linux 主機網絡操做。docker
本實驗將 3 臺 Linux 主機連到一個集線器上,以此觀察集線器的工做行爲,網絡拓撲圖以下:編程
實驗環境以 docker 容器的形式提供,執行這個 docker 命令便可一鍵打開:bash
docker run --name hub-lab --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h hub-lab fasionchan/netbox:0.5 bash /script/hub-lab.sh
實驗環境打開後,能夠看到 3 個窗口,各自表明一臺主機:網絡
這是用 tmux 命令實現的窗口劃分,按下_ Ctrl-B_ 後再按方向鍵,便可在不一樣主機窗口間切換。tcp
請特別注意,按下 Ctrl-B 後要鬆手,而後再按方向鍵,才能切到想要操做的主機窗口。
還有一種更快捷的切換方法,先按下 Ctrl-B ,鬆手後再按 Q 。這時,每一個窗口都會顯示一個數字。接着,按下對應的數字便可切到想要的窗口:工具
咱們先切到主機 ant ,觀察它的網卡信息, ifconfig 或 ip 命令都可:oop
root@ant [ ~ ] ➜ ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 ether 32:90:b9:9f:35:56 txqueuelen 1000 (Ethernet) RX packets 6 bytes 540 (540.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3 bytes 270 (270.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
root@ant [ ~ ] ➜ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd :: 6: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 32:90:b9:9f:35:56 brd ff:ff:ff:ff:ff:ff link-netnsid 0
接着,切到主機 bee 和 cicada ,繼續觀察它們的網卡信息:學習
root@bee [ ~ ] ➜ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd :: 8: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether a2:17:41:bb:cd:98 brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@cicada [ ~ ] ➜ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd :: 10: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether ee:76:f2:37:5e:69 brd ff:ff:ff:ff:ff:ff link-netnsid 0
通過觀察, 3 臺主機網卡及 MAC 地址信息整理以下:spa
主機 | 網卡 | MAC地址 |
---|---|---|
ant | eth0 | 32:90:b9:9f:35:56 |
bee | eth0 | a2:17:41:bb:cd:98 |
cicada | eth0 | ee:76:f2:37:5e:69 |
如今,咱們從主機 ant 向主機 bee 發送一句話,看主機 bee 是否能夠收到這個信息,於此同時觀察主機 cicada 是否也能夠收到。開始發送以前,咱們先在 bee 和 cicada 執行抓包工具 tcpdump 命令,嗅探網絡流量:code
root@bee [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
root@cicada [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
tcpdump 命令 -i 選項指定嗅探網卡,這裏咱們嗅探每臺主機 eth0 網卡上的流量。
一切準備就緒,咱們在主機 ant 上執行自制工具 sendether 給 bee 發一段文本:
root@ant [ ~ ] ➜ sendether -i eth0 -t a2:17:41:bb:cd:98 -T 0x0900 -d 'hello, world!'
sendether 是一個自制命令,用於發送以太網幀。其中, -i 指定發送網卡, -t 指定目的地址, -T 指定數據類型, -d 指定要發送的數據。後續的編程環節,咱們會講解 sendether 是如何封裝、發送以太網幀的。
咱們立馬看到主機 bee 上的 tcpdump 抓到一個以太網幀,它就是 ant 發出來的 hello, world!
:
root@bee [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:37:27.254658 32:90:b9:9f:35:56 > a2:17:41:bb:cd:98, ethertype Unknown (0x0900), length 27: 0x0000: 6865 6c6c 6f2c 2077 6f72 6c64 21 hello,.world!
注意到,主機 cicada 也收到這個幀,這符合集線器的行爲:
root@cicada [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:37:27.254624 32:90:b9:9f:35:56 > a2:17:41:bb:cd:98, ethertype Unknown (0x0900), length 27: 0x0000: 6865 6c6c 6f2c 2077 6f72 6c64 21 hello,.world!
因爲這個幀的目的主機並非 cicada , cicada 協議棧將丟棄它。
本實驗將 3 臺 Linux 主機連到一個交換機上,以此觀察交換機的工做行爲,網絡拓撲圖以下:
實驗環境一樣經過 docker 容器提供,執行如下命令便可一鍵打開:
docker run --name switch-lab --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h switch fasionchan/netbox:0.5 bash /script/switch-lab.sh
實驗環境啓動後,能夠看到 4 個由 tmux 命令劃分的窗口,分別表明 3 臺主機以及交換機。
爲了方便觀察交換機 MAC 地址學習的過程,咱們爲每臺主機設置了一個很好分辨的 MAC 地址:
主機 | 網卡 | MAC地址 | 交換機端口 |
---|---|---|---|
ant | eth0 | 40:aa:aa:aa:aa:aa | 1 |
bee | eth0 | 40:bb:bb:bb:bb:bb | 2 |
cicada | eth0 | 40:cc:cc:cc:cc:cc | 3 |
實驗環境中的交換機由 bridge 虛擬設備模擬,設備名爲 switch0
:
root@switch [ ~ ] ➜ ip link show switch0 4: switch0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 4a:9e:f8:3c:75:40 brd ff:ff:ff:ff:ff:ff
執行 brctl 命令,能夠查看交換機當前的 MAC 地址表:
root@switch [ ~ ] ➜ brctl showmacs switch0 port no mac addr is local? ageing timer 3 4a:9e:f8:3c:75:40 yes 0.00 3 4a:9e:f8:3c:75:40 yes 0.00 2 6a:64:44:0d:d1:55 yes 0.00 2 6a:64:44:0d:d1:55 yes 0.00 1 be:24:47:bd:f2:52 yes 0.00 1 be:24:47:bd:f2:52 yes 0.00
噫?怎麼 MAC 地址表已經有一些條目了?咱們明明尚未在任何主機上發數據,地址表按理說應該是空的呀!
其實,這些 MAC 地址是交換機本身的, is local
列值都是 yes
。若是將該列值爲 yes
的記錄過濾掉,就能夠確認 MAC 地址表確實爲空(暫未學習到任何地址):
root@switch [ ~ ] ➜ brctl showmacs switch0 | grep -v yes port no mac addr is local? ageing timer
如今,咱們在主機 ant 上往主機 bee 發送一個以太網幀,來觀察交換機行爲。開始以前,咱們先在主機 bee 和 cicada 上運行 tcpdump 命令來嗅探網絡流量。
root@bee [ ~ ] ➜ tcpdump -ni eth0
root@cicada [ ~ ] ➜ tcpdump -ni eth0
root@ant [ ~ ] ➜ sendether -i eth0 -t 40:bb:bb:bb:bb:bb -d 'hello, bee!'
這個幀成功發出去後,咱們同時在主機 bee 和 cicada 上觀察它。緣由在於,交換機還沒學到主機 bee 的 MAC 地址,只能將這個幀轉發到其餘全部端口,所以 cicada 也會收到它。
root@bee [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:40:34.437330 40:aa:aa:aa:aa:aa > 40:bb:bb:bb:bb:bb, ethertype Unknown (0x0900), length 25: 0x0000: 6865 6c6c 6f2c 2062 6565 21 hello,.bee!
root@cicada [ ~ ] ➜ tcpdump -ni eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:40:34.437152 40:aa:aa:aa:aa:aa > 40:bb:bb:bb:bb:bb, ethertype Unknown (0x0900), length 25: 0x0000: 6865 6c6c 6f2c 2062 6565 21 hello,.bee!
交換機從端口 0 接到主機 ant 發送的以太網幀,源地址是 40:aa:aa:aa:aa:aa
,便知道之後發給這個地址的幀應該轉發給端口 0 。這樣一來,交換機機智地學習到主機 ant 的 MAC 地址:
root@switch [ ~ ] ➜ brctl showmacs switch0 | grep -v yes port no mac addr is local? ageing timer 1 40:aa:aa:aa:aa:aa no 1.97
接着,咱們在主機 bee 向 ant 回覆一個信息:
root@bee [ ~ ] ➜ sendether -i eth0 -t 40:aa:aa:aa:aa:aa -d 'how are you?'
因爲交換機已經學習到 ant 的地址,知道去往 40:aa:aa:aa:aa:aa
的幀應該轉發到端口 0 ,位於端口 3 的 cicada 主機便不會收到這個幀了。
同理,在這個過程當中,交換機學習到主機 bee 的 MAC 地址 40:bb:bb:bb:bb:bb
:
root@switch [ ~ ] ➜ brctl showmacs switch0 | grep -v yes port no mac addr is local? ageing timer 1 40:aa:aa:aa:aa:aa no 60.17 2 40:bb:bb:bb:bb:bb no 50.14
這樣一來,主機 ant 再給 bee 發數據, cicada 一樣也不會收到了:
root@ant [ ~ ] ➜ sendether -i eth0 -t 40:bb:bb:bb:bb:bb -d 'fine, thank you!'
【小菜學網絡】系列文章首發於公衆號【小菜學編程】,敬請關注: