bridge vlan aware

1
2
3
4
5
6
7
8
9
10
                         br0
+
vrf-h1 | vrf-h2
+ +---+----+ +
| | | |
192.0.2.1/24 + + + + 192.0.2.2/24
swp1 swp2 swp3 swp4
+ + + +
| | | |
+--------+ +--------+

地址学习

搭建环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# vrf prepare
root@debian:~# ip -4 rule add pref 32765 table local
root@debian:~# ip -4 rule del pref 0

# h1 create
root@debian:~# ip link add dev vlinux_veth0 type vrf table 1
root@debian:~# ip -4 route add table 1 unreachable default metric 4278198272
root@debian:~# ip link set dev vlinux_veth0 up
root@debian:~# ip link set dev linux_veth0 master vlinux_veth0
root@debian:~# ip link set dev linux_veth0 up
root@debian:~# ip addr add 192.0.2.1/24 dev linux_veth0

#h2 create
root@debian:~# ip link add dev vlinux_veth3 type vrf table 2
root@debian:~# ip -4 route add table 2 unreachable default metric 4278198272
root@debian:~# ip link set dev vlinux_veth3 up
root@debian:~# ip link set dev linux_veth3 master vlinux_veth3
root@debian:~# ip link set dev linux_veth3 up
root@debian:~# ip addr add 192.0.2.2/24 dev linux_veth3

# switch_create
root@debian:~# ip link add dev br0 type bridge vlan_filtering 1 ageing_time 1000 mcast_snooping 0
root@debian:~# ip link set dev linux_veth1 master br0
root@debian:~# ip link set dev linux_veth2 master br0
root@debian:~# ip link set dev br0 up
root@debian:~# ip link set dev linux_veth1 up
root@debian:~# ip link set dev linux_veth2 up

# vlan create
root@raspi:~# bridge vlan add vid 100 dev linux_veth1
root@raspi:~# bridge vlan add vid 100 dev linux_veth2

root@raspi:~# ip link add name linux_veth0.100 link linux_veth0 type vlan id 100
root@raspi:~# ip link set dev linux_veth0.100 master vlinux_veth0
root@raspi:~# ip link set dev linux_veth0.100 up
root@raspi:~# ip addr add 198.51.100.1/24 dev linux_veth0.100
root@raspi:~#
root@raspi:~#
root@raspi:~# ip link add name linux_veth3.100 link linux_veth3 type vlan id 100
root@raspi:~# ip link set dev linux_veth3.100 master vlinux_veth3
root@raspi:~# ip link set dev linux_veth3.100 up
root@raspi:~# ip addr add 198.51.100.2/24 dev linux_veth3.100

ping测试

linux_veth0和linux_veth3的mac地址:

1
2
3
4
root@debian:~# ip -j addr show dev linux_veth0 | jq -r '.[0].address'
e2:73:69:29:b1:42
root@debian:~# ip -j addr show dev linux_veth3 | jq -r '.[0].address'
82:14:44:86:cd:b6

linux_veth1没有学到linux_veth0的mac地址:

1
2
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 | jq -e ".[0] | select(.mac == \"e2:73:69:29:b1:42\")"
root@debian:~#

linux_veth2没有学到linux_veth3的mac地址:

1
2
root@debian:~# bridge -j fdb show br br0 brport linux_veth2 | jq -e ".[0] | select(.mac == \"82:14:44:86:cd:b6\")"
root@debian:~#

ping测试:

1
2
3
4
5
6
7
8
9
10
11
root@debian:~# ip vrf exec vlinux_veth0 ping 192.0.2.2 -c 4 -i 0.1 
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.059 ms
64 bytes from 192.0.2.2: icmp_seq=4 ttl=64 time=0.062 ms

--- 192.0.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 306ms
rtt min/avg/max/mdev = 0.057/0.068/0.095/0.015 ms
root@debian:~#

linux_veth1学习到了linux_veth0的mac地址:

1
2
3
4
5
6
7
8
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 | jq -e ".[0] | select(.mac == \"e2:73:69:29:b1:42\")"
{
"mac": "e2:73:69:29:b1:42",
"vlan": 1,
"flags": [],
"master": "br0",
"state": ""
}

linux_veth2学习到了linux_veth3的mac地址:

1
2
3
4
5
6
7
8
root@debian:~# bridge -j fdb show br br0 brport linux_veth2 | jq -e ".[0] | select(.mac == \"82:14:44:86:cd:b6\")"
{
"mac": "82:14:44:86:cd:b6",
"vlan": 1,
"flags": [],
"master": "br0",
"state": ""
}

一段时间后mac地址老化:

1
2
3
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 | jq -e ".[0] | select(.mac == \"e2:73:69:29:b1:42\")"
root@debian:~# bridge -j fdb show br br0 brport linux_veth2 | jq -e ".[0] | select(.mac == \"82:14:44:86:cd:b6\")"
root@debian:~#

地址学习细节

用于测试的MAC地址de:ad:be:ef:13:37

在测试前,linux_veth1不应该有目标MAC地址de:ad:be:ef:13:37的记录:

1
2
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 | jq -e ".[] | select(.mac == \"de:ad:be:ef:13:37\")"
root@debian:~#

在linux_veth1上关闭未知单播洪范,确保只有在FDB中存在匹配条目时,数据包才会被转发到该端口:

1
2
root@debian:~# bridge link set dev linux_veth1 flood off
root@debian:~#

linux_veth0进入混杂模式,基于目标MAC地址添加一个过滤器规则,丢弃发往de:ad:be:ef:13:37的数据包。

1
2
3
4
root@debian:~# ip link set linux_veth0 promisc on
root@debian:~# tc qdisc add dev linux_veth0 ingress
root@debian:~# tc filter add dev linux_veth0 ingress protocol ip pref 1 handle 101 flower dst_mac de:ad:be:ef:13:37 action drop
root@debian:~#

linux_veth3发送一个目标MAC地址为de:ad:be:ef:13:37的数据包:

1
mausezahn linux_veth3 -c 1 -p 64 -b de:ad:be:ef:13:37 -t ip

linux_veth0没有收到linux_veth3发送的数据包,这是因为linux_veth1关闭了未知单播洪范:

1
2
3
4
root@debian:~# tc -j -s filter show dev linux_veth0 ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)"
root@debian:~#

linux_veth0发起源MAC为de:ad:be:ef:13:37的广播包,linux_veth1上可以找到目标MAC地址为de:ad:be:ef:13:37的记录:

1
2
3
4
5
6
7
8
9
10
11
12
root@debian:~# mausezahn linux_veth0 -c 1 -p 64 -a de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (5291 packets per second)
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 \
| jq -e ".[] | select(.mac == \"de:ad:be:ef:13:37\")"
{
"mac": "de:ad:be:ef:13:37",
"vlan": 1,
"flags": [],
"master": "br0",
"state": ""
}
root@debian:~#

如果赶在目标MAC地址老化之前,linux_veth3发送一个目标MAC地址为de:ad:be:ef:13:37的数据包,linux_veth1会进行转发,linux_veth0会收到该数据包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
root@debian:~# mausezahn linux_veth0 -c 1 -p 64 -a de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (7519 packets per second)
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 \
| jq -e ".[] | select(.mac == \"de:ad:be:ef:13:37\")"
{
"mac": "de:ad:be:ef:13:37",
"vlan": 1,
"flags": [],
"master": "br0",
"state": ""
}
root@debian:~# mausezahn linux_veth3 -c 1 -p 64 -b de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (5882 packets per second)
root@debian:~# tc -j -s filter show dev linux_veth0 ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)"
{
"protocol": "ip",
"pref": 1,
"kind": "flower",
"chain": 0,
"options": {
"handle": 101,
"keys": {
"dst_mac": "de:ad:be:ef:13:37",
"eth_type": "ipv4"
},
"not_in_hw": true,
"actions": [
{
"order": 1,
"kind": "gact",
"control_action": {
"type": "drop"
},
"prob": {
"random_type": "none",
"control_action": {
"type": "pass"
},
"val": 0
},
"index": 1,
"ref": 1,
"bind": 1,
"installed": 1678,
"last_used": 3,
"first_used": 3,
"stats": {
"bytes": 84,
"packets": 1,
"drops": 1,
"overlimits": 0,
"requeues": 0,
"backlog": 0,
"qlen": 0
}
}
]
}
}
root@debian:~#

禁用linux_veth1的地址学习,linux_veth0发送一个源MAC地址为de:ad:be:ef:13:37的广播包,linux_veth1上没有目标MAC表项

1
2
3
4
5
6
7
8
root@debian:~# bridge link set dev linux_veth1 learning off
root@debian:~#
root@debian:~# mausezahn linux_veth0 -c 1 -p 64 -a de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (4902 packets per second)
root@debian:~#
root@debian:~# bridge -j fdb show br br0 brport linux_veth1 \
| jq -e ".[] | select(.mac == \"de:ad:be:ef:13:37\")"
root@debian:~#

拆除环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@debian:~# bridge link set dev linux_veth1 learning on
root@debian:~# tc filter del dev linux_veth0 ingress protocol ip pref 1 handle 101 flower
root@debian:~# tc qdisc del dev linux_veth0 ingress
root@debian:~# ip link set linux_veth0 promisc off
root@debian:~# bridge link set dev linux_veth1 flood on

root@debian:~# ip link set dev linux_veth1 down
root@debian:~# ip link set dev linux_veth2 down
root@debian:~# ip link del dev br0

root@debian:~# ip addr del 192.0.2.2/24 dev linux_veth3
root@debian:~# ip link set dev linux_veth3 down
root@debian:~# ip link set dev linux_veth3 nomaster
root@debian:~# ip -4 route del table 2 unreachable default metric 4278198272
root@debian:~# ip link del dev vlinux_veth3

root@debian:~# ip add del 192.0.2.1/24 dev linux_veth0
root@debian:~# ip link set dev linux_veth0 down
root@debian:~# ip link set dev linux_veth0 nomaster
root@debian:~# ip -4 route del table 1 unreachable default metric 4278198272
root@debian:~# ip link del dev vlinux_veth0

root@debian:~# ip -4 rule add pref 0 table local
root@debian:~# ip -4 rule del pref 32765
root@debian:~#

洪范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@debian:~# bridge link set dev linux_veth2 flood off
root@debian:~# ip link set linux_veth3 promisc on
root@debian:~# tc qdisc add dev linux_veth3 ingress
root@debian:~# tc filter add dev linux_veth3 ingress protocol ip pref 1 handle 101 flower dst_mac de:ad:be:ef:13:37 action drop

root@debian:~# mausezahn linux_veth0 -c 1 -p 64 -b de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (6289 packets per second)
root@debian:~# tc -j -s filter show dev linux_veth3 ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)"

root@debian:~# tc filter del dev linux_veth3 ingress protocol ip pref 1 handle 101 flower
root@debian:~# tc qdisc del dev linux_veth3 ingress
root@debian:~# ip link set linux_veth3 promisc off
root@debian:~#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
root@debian:~# bridge link set dev linux_veth2 flood on
root@debian:~# ip link set linux_veth3 promisc on
root@debian:~# tc qdisc add dev linux_veth3 ingress
root@debian:~# tc filter add dev linux_veth3 ingress protocol ip pref 1 handle 101 flower dst_mac de:ad:be:ef:13:37 action drop
root@debian:~# mausezahn linux_veth0 -c 1 -p 64 -b de:ad:be:ef:13:37 -t ip
Mausezahn will send 1 frames... 0.00 seconds (4587 packets per second)
root@debian:~# tc -j -s filter show dev linux_veth3 ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)"
{
"protocol": "ip",
"pref": 1,
"kind": "flower",
"chain": 0,
"options": {
"handle": 101,
"keys": {
"dst_mac": "de:ad:be:ef:13:37",
"eth_type": "ipv4"
},
"not_in_hw": true,
"actions": [
{
"order": 1,
"kind": "gact",
"control_action": {
"type": "drop"
},
"prob": {
"random_type": "none",
"control_action": {
"type": "pass"
},
"val": 0
},
"index": 1,
"ref": 1,
"bind": 1,
"installed": 14,
"last_used": 8,
"first_used": 8,
"stats": {
"bytes": 84,
"packets": 1,
"drops": 1,
"overlimits": 0,
"requeues": 0,
"backlog": 0,
"qlen": 0
}
}
]
}
}
root@debian:~# tc filter del dev linux_veth3 ingress protocol ip pref 1 handle 101 flower
root@debian:~# tc qdisc del dev linux_veth3 ingress
root@debian:~# ip link set linux_veth3 promisc off
root@debian:~#

mac迁移

1
2
3
4
5
6
7
8
9
10
11
12
13
root@debian:~# bridge fdb show br br0 brport linux_veth1 | grep de:ad:be:ef:13:37
root@debian:~#
root@debian:~# bridge fdb add de:ad:be:ef:13:37 dev linux_veth1 master extern_learn vlan 1
root@debian:~#
root@debian:~# bridge fdb show br br0 brport linux_veth1 | grep de:ad:be:ef:13:37
de:ad:be:ef:13:37 vlan 1 extern_learn master br0
root@debian:~#
root@debian:~# mausezahn linux_veth3 -c 1 -p 64 -a de:ad:be:ef:13:37 -t ip -q
root@debian:~# bridge fdb show br br0 brport linux_veth1 | grep de:ad:be:ef:13:37
root@debian:~# bridge fdb show br br0 brport linux_veth2 | grep de:ad:be:ef:13:37
de:ad:be:ef:13:37 vlan 1 master br0
root@debian:~# bridge fdb show br br0 brport linux_veth2 | grep de:ad:be:ef:13:37
root@debian:~#

port锁定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
root@debian:~# ip vrf exec vlinux_veth0 ping -c 4 -i 0.1 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.104 ms
64 bytes from 192.0.2.2: icmp_seq=4 ttl=64 time=0.046 ms

--- 192.0.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 310ms
rtt min/avg/max/mdev = 0.046/0.071/0.104/0.021 ms
root@debian:~# bridge link set dev linux_veth1 locked on
root@debian:~#
root@debian:~# ip vrf exec vlinux_veth0 ping -c 4 -i 0.1 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
^C
--- 192.0.2.2 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 311ms

root@debian:~# ip addr show dev linux_veth0
8: linux_veth0@linux_veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vlinux_veth0 state UP group default qlen 1000
link/ether e2:73:69:29:b1:42 brd ff:ff:ff:ff:ff:ff
inet 192.0.2.1/24 scope global linux_veth0
valid_lft forever preferred_lft forever
inet6 2001:db8:1::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::e073:69ff:fe29:b142/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
root@debian:~#
root@debian:~# bridge fdb add e2:73:69:29:b1:42 dev linux_veth1 master static
root@debian:~#
root@debian:~# ip vrf exec vlinux_veth0 ping -c 4 -i 0.1 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.096 ms
64 bytes from 192.0.2.2: icmp_seq=4 ttl=64 time=0.052 ms

--- 192.0.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 310ms
rtt min/avg/max/mdev = 0.050/0.072/0.096/0.021 ms
root@debian:~# bridge link set dev linux_veth1 locked off
root@debian:~# bridge fdb del e2:73:69:29:b1:42 dev linux_veth1 master static
root@debian:~#
root@debian:~# ip vrf exec vlinux_veth0 ping -c 4 -i 0.1 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.081 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.074 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from 192.0.2.2: icmp_seq=4 ttl=64 time=0.054 ms

--- 192.0.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 319ms
rtt min/avg/max/mdev = 0.054/0.065/0.081/0.012 ms
root@debian:~#

vlan下的port锁定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
root@debian:~# bridge vlan add vid 100 dev linux_veth1
root@debian:~# bridge vlan add vid 100 dev linux_veth2
root@debian:~# ip vrf exec vlinux_veth0 ping 198.51.100.2 -c 4 -i 0.1 -w 1
PING 198.51.100.2 (198.51.100.2) 56(84) bytes of data.
64 bytes from 198.51.100.2: icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from 198.51.100.2: icmp_seq=2 ttl=64 time=0.093 ms
64 bytes from 198.51.100.2: icmp_seq=3 ttl=64 time=0.158 ms
64 bytes from 198.51.100.2: icmp_seq=4 ttl=64 time=0.046 ms

--- 198.51.100.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 314ms
rtt min/avg/max/mdev = 0.046/0.103/0.158/0.040 ms
root@debian:~# bridge link set dev linux_veth1 locked on
root@debian:~# ip vrf exec vlinux_veth0 ping 198.51.100.2 -c 4 -i 0.1 -w 1
PING 198.51.100.2 (198.51.100.2) 56(84) bytes of data.

--- 198.51.100.2 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 943ms
root@debian:~# ip link show dev linux_veth0
8: linux_veth0@linux_veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vlinux_veth0 state UP mode DEFAULT group default qlen 1000
link/ether e2:73:69:29:b1:42 brd ff:ff:ff:ff:ff:ff
root@debian:~#
root@debian:~# bridge fdb add e2:73:69:29:b1:42 dev linux_veth1 vlan 100 master static
root@debian:~#
root@debian:~# ip vrf exec vlinux_veth0 ping 198.51.100.2 -c 4 -i 0.1 -w 1
PING 198.51.100.2 (198.51.100.2) 56(84) bytes of data.
64 bytes from 198.51.100.2: icmp_seq=1 ttl=64 time=0.120 ms
64 bytes from 198.51.100.2: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 198.51.100.2: icmp_seq=3 ttl=64 time=0.051 ms
64 bytes from 198.51.100.2: icmp_seq=4 ttl=64 time=0.039 ms

--- 198.51.100.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 315ms
rtt min/avg/max/mdev = 0.039/0.063/0.120/0.032 ms
root@debian:~#
root@debian:~# bridge link set dev linux_veth1 locked off
root@debian:~#
root@debian:~# ip vrf exec vlinux_veth0 ping 198.51.100.2 -c 4 -i 0.1 -w 1
PING 198.51.100.2 (198.51.100.2) 56(84) bytes of data.
64 bytes from 198.51.100.2: icmp_seq=1 ttl=64 time=0.103 ms
64 bytes from 198.51.100.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 198.51.100.2: icmp_seq=3 ttl=64 time=0.041 ms
64 bytes from 198.51.100.2: icmp_seq=4 ttl=64 time=0.072 ms

--- 198.51.100.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 311ms
rtt min/avg/max/mdev = 0.041/0.068/0.103/0.022 ms
root@debian:~# bridge vlan del vid 100 dev linux_veth1
root@debian:~# bridge vlan del vid 100 dev linux_veth2
root@debian:~#