集线器和交换机是两种典型的网络设备,集线器 位于 物理层 ,而 交换机 位于于 数据链路层,行为显著不同。本节筹备了两个简略试验,旨在通过实际加深对理论知识的了解,逐渐把握 Linux 主机网络操作。
试验一:察看以太网集线器
本试验将 3 台 Linux 主机连到一个集线器上,以此察看集线器的工作行为,网络拓扑图如下:
试验环境以 docker 容器的模式提供,执行这个 docker 命令即可一键关上:
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_ 后再按方向键,即可在不同主机窗口间切换。
请特地留神,按下 Ctrl-B 后要松手,而后再按方向键,能力切到想要操作的主机窗口。
还有一种更快捷的切换办法,先按下 Ctrl-B,松手后再按 Q。这时,每个窗口都会显示一个数字。接着,按下对应的数字即可切到想要的窗口:
咱们先切到主机 ant,察看它的网卡信息,ifconfig 或 ip 命令均可:
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 地址信息整顿如下:
主机 | 网卡 | 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 命令,嗅探网络流量:
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!'
【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注: