Cumulus NVUE 5.16。下圖是本實驗的環境一台交換器和兩台 Server,主要目的是了解交換器 ACL 的資料平面和控制平面設定以及原理。

數據平面和控制平面 ACL 定義,透過以下表格呈現
| 流量類型 | 處理位置 | iptables 鏈 | 說明 |
|---|---|---|---|
| 數據平面 (Transit) | 硬體 (ASIC) | FORWARD | 穿越交換器的流量,以範例來說是 Server01 存取 Server02。 |
| 控制平面 (Local) | 軟體 (CPU) | INPUT | 目的地為交換器本身的流量,以範例來說是 Server01 SSH 進入 Leaf01。 |
當執行 nv config apply 之後,定義的 NVUE YAML 內容系統會將高階抽象配置轉換為底層 Linux 核心的 iptables 規則,接著再透過底層的 switchd 行程,將這些規則寫至 Spectrum ASIC 的硬體記憶體中,以實現線速轉發與阻擋。
要確認這些寫入規則是否已經成功載入到 Linux 核心的記憶體中,使用 Cumulus 專屬的 cl-acltool,它能確保看到的是與硬體加速同步的規則。執行 cl-acltool -L ip 指令來檢視 IPv4 的規則。
如果在套用配置後發現規則沒有生效,可以檢查 /var/log/syslog 或 /var/log/switchd.log。如果底層的 TCAM / ATCAM 硬體資源已經耗盡,會在日誌中看到 error: hw sync failed (sync_acl hardware installation failed) 或是 No More Resources 之類的硬體寫入錯誤。
- set:
system:
hostname: leaf01
interface:
swp1:
vrf: blue
ipv4:
address:
192.168.1.254/24: {}
swp2:
vrf: red
ipv4:
address:
192.168.2.254/24: {}
vrf:
blue:
router:
static:
192.168.2.0/24:
via:
swp2: {}
red:
router:
static:
192.168.1.0/24:
via:
swp1: {}
應用至底層
cumulus@cumulus:mgmt:~$ nv config patch nvue.yaml
created [rev_id: 3]
cumulus@cumulus:mgmt:~$ nv config apply
network:
version: 2
ethernets:
enp2s0:
match:
macaddress: "0c:48:5a:2b:00:00"
dhcp4: false
dhcp6: false
set-name: "enp2s0"
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.254
network:
version: 2
ethernets:
enp2s0:
match:
macaddress: "0c:74:2f:2a:00:00"
dhcp4: false
dhcp6: false
set-name: "enp2s0"
addresses:
- 192.168.2.100/24
routes:
- to: default
via: 192.168.2.254
配置完後,透過 server01 到 server02 或是反向都是可以通訊。其資料流會貫穿交換器至另外的 Server,因此屬於資料平面的設定。
~$ ping 192.168.2.100 -c 2
PING 192.168.2.100 (192.168.2.100) 56(84) bytes of data.
64 bytes from 192.168.2.100: icmp_seq=1 ttl=63 time=1.07 ms
64 bytes from 192.168.2.100: icmp_seq=2 ttl=63 time=0.796 ms
--- 192.168.2.100 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.796/0.931/1.067/0.135 ms
我們透過新增一條 ACL,來讓 server01 和 server02 無法互相存取 。leaf01 新增下面配置
- set:
acl:
BLOCK_PING:
type: ipv4
rule:
'10':
action:
deny: {}
match:
ip:
protocol: icmp
source-ip: 192.168.1.0/24
dest-ip: 192.168.2.0/24
interface:
swp1:
acl:
BLOCK_PING:
inbound: {}
配置完成後 server01 無法連到 server02。反之。
$ ping 192.168.2.100 -c 2
PING 192.168.2.100 (192.168.2.100) 56(84) bytes of data.
對於 NVUE 建立的 ACL,預設會存放在 /etc/cumulus/acl/policy.d/50_nvue.rules。
$ sudo cat /etc/cumulus/acl/policy.d/50_nvue.rules
# Auto-generated by NVUE!
# Any local modifications will prevent NVUE from re-generating this file.
# md5sum: cd9bd588dc5d6149c71c07985d50603c
[iptables]
## ACL BLOCK_PING in dir inbound on interface swp1 ##
# rule-id #10: #
-t mangle -A PREROUTING -i swp1 -m comment --comment rule_id:10,acl_name:BLOCK_PING,dir:inbound,interface_id:swp1 -s 192.168.1.0/24 -d 192.168.2.0/24 -p icmp -j DROP
[ip6tables]
[ebtables]
從內容來看,因將規則套用於 swp1 的 inbound (入站方向),在 Cumulus 5.0 之後的版本,這會被翻譯成套用於 mangle 表的 PREROUTING 鏈。這代表封包從 swp1 進入且在進行路由判斷之前(PREROUTING),只要符合 ICMP 協定以及指定的來源與目的網段,就會被丟棄 (DROP)。
執行 cl-acltool -L ip 指令來檢視 IPv4 的規則。在輸出的 TABLE mangle 將會看到剛才那條阻擋 ICMP 互 Ping 的規則已經在系統中生效。
$ sudo cl-acltool -L ip
warning: Detected platform is Cumulus VX
warning: Running in no-hw-sync mode. No rules will be programmed in hw
-------------------------------
Listing rules of type iptables:
-------------------------------
TABLE filter :
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- swp+ any 240.0.0.0/5 anywhere
0 0 DROP all -- swp+ any loopback/8 anywhere
0 0 DROP all -- swp+ any 224.0.0.0/4 anywhere
0 0 DROP all -- swp+ any 255.255.255.255 anywhere
7783 513K ACCEPT all -- any any loopback/8 loopback/8
7 2296 ACCEPT all -- lo any anywhere anywhere
0 0 DROP all -- !lo any anywhere loopback/8
0 0 DROP icmp -- any any anywhere anywhere icmp timestamp-request
0 0 ACCEPT all -- any any anywhere anywhere /* rule_id:30,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ ctstate RELATED,ESTABLISHED
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:40,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ tcp flags:FIN,SYN,RST,ACK/ACK ctstate NEW
0 0 DROP all -f any any anywhere anywhere /* rule_id:50,
...
TABLE mangle :
Chain PREROUTING (policy ACCEPT 7849 packets, 543K bytes)
pkts bytes target prot opt in out source destination
4 336 DROP icmp -- swp1 any 192.168.1.0/24 192.168.2.0/24 /* rule_id:10,acl_name:BLOCK_PING,dir:inbound,interface_id:swp1 */
Chain INPUT (policy ACCEPT 7811 packets, 535K bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 10 packets, 840 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 7734 packets, 510K bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 7744 packets, 511K bytes)
pkts bytes target prot opt in out source destination
TABLE raw :
Chain PREROUTING (policy ACCEPT 8001 packets, 553K bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 7882 packets, 520K bytes)
pkts bytes target prot opt in out source destination
0 0 CT udp -- any any anywhere anywhere udp dpt:tftp CT helper tftp
TABLE nat :
Chain PREROUTING (policy ACCEPT 1 packets, 84 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 34 packets, 2332 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 211 packets, 12952 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 178 packets, 10704 bytes)
pkts bytes target prot opt in out source destination
場景上,可以應用在交換器本身服務的存取控管。這邊範例呈現是,僅允許特定管理主機 SSH 進入 Leaf01,其餘全部拒絕。以下配置顯示我們的範例不允許 Server02 遠端 Leaf01 交換器。
- set:
acl:
BLOCK_SSH:
type: ipv4
rule:
'10':
action:
deny: {}
match:
ip:
protocol: tcp
tcp:
dest-port:
'22': {}
source-ip: 192.168.2.0/24
system:
control-plane:
acl:
BLOCK_SSH:
inbound: {}
欄位定義:
acl: BLOCK_SSH: 宣告建立一個名為 BLOCK_SSH 的存取控制串列 (ACL)。這是一個容器,用來群組化與管理內部的多筆規則。type: ipv4: 指定這個 ACL 的協定類型為 IPv4,這決定了它底層會被轉換為 iptables 規則(若為 IPv6 則是 ip6tables,MAC 則是 ebtables)。rule: '10': 定義規則的序號 (Sequence ID)。ACL 的運作邏輯是由上而下依序比對 (Sequential Match),封包一旦配對到最先符合的規則,就會執行動作並結束後續比對。設定為 10 是一種 Best Practice,方便未來若有需要,可在其前後安插新規則(如 rule 5 或 rule 20)。action: deny: 指定當封包符合底下的條件時的處置動作。deny 代表拒絕,封包會被直接丟棄 (對應底層的 DROP)。match: ip: 開始定義 IP 封包的特徵比對條件。protocol: tcp: 指定只比對傳輸層協定為 TCP 的封包。tcp: dest-port: '22': 進一步指定 TCP 的目的埠號 (Destination Port) 必須是 22 (即 SSH 服務)。source-ip: 192.168.2.0/24: 指定封包的來源 IP 網段必須是 192.168.2.0/24。接著執行遠端,其結果是被拒絕的。
$ ssh cumulus@192.168.2.254
再透過 NVUE 檢視控制層統計資訊,只要你看到 Rule 10 的 In Packet (入站命中封包數) 與 In Byte (入站命中位元組數) 在你嘗試 SSH 登入時有持續增加,這就代表封包已經成功被這條 ACL 規則匹配並丟棄。
$ nv show system control-plane acl BLOCK_SSH statistics
Rule In Packet In Byte Out Packet Out Byte Action Match
---- ---------- --------------- ---------- --------------- -------------------------------------------- ----------------------------
10 13 780 Bytes deny ip
protocol : tcp
source-ip : 192.168.2.0/24
tcp
dest-port : 22
另外可透過底層 cl-acltool 檢視 iptables,pkts 和 bytes 欄位代表命中此規則的封包數量與大小。當從 Server02 不斷嘗試 SSH 時,這個數字會隨之遞增。target DROP 代表動作為拒絕。後方的註解 /* rule_id:10,acl_name:BLOCK_SSH... */ 則清楚標示這條底層 iptables 規則是由 NVUE 的 BLOCK_SSH 所生成的。定義的這條規則會被安插進 INPUT 鏈 (送往交換器本機 CPU 處理前的過濾階段)。
$ sudo cl-acltool -L ip
[sudo] password for cumulus:
warning: Detected platform is Cumulus VX
warning: Running in no-hw-sync mode. No rules will be programmed in hw
-------------------------------
Listing rules of type iptables:
-------------------------------
TABLE filter :
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
...
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:80,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ ctstate INVALID
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:90,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ tcpmss match !536:65535 ctstate NEW
14 840 tcp -- any any anywhere anywhere /* rule_id:100,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ tcp dpt:ssh ctstate NEW recent: SET name: acl_test side: source mask: 255.255.255.255
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:110,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ tcp dpt:ssh ctstate NEW recent: UPDATE seconds: 60 hit_count: 100 name: acl_test side: source mask: 255.255.255.255
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:120,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ tcp flags:RST/RST limit: above 5/min burst 2 mode srcip htable-expire 30000
0 0 DROP tcp -- any any anywhere anywhere /* rule_id:130,acl_name:acl-default-dos,dir:inbound,interface_id:control-plane */ ctstate NEW limit: above 50/sec burst 30 mode srcip htable-expire 30000
13 780 DROP tcp -- any any 192.168.2.0/24 anywhere /* rule_id:10,acl_name:BLOCK_SSH,dir:inbound,interface_id:control-plane */ tcp dpt:ssh
...
檢查 ASIC 硬體寫入狀態與命中統計 (Data Plane)
可以使用以下 NVUE 指令來監看該介面上的 ACL 命中統計
$ nv show interface swp1 acl BLOCK_PING statistics 10
operational applied
------------- -------------- -------
match
ip
source-ip 192.168.1.0/24
dest-ip 192.168.2.0/24
protocol icmp
action deny
inbound
packet 4
byte 336 Bytes
如果在 Server01 嘗試 Ping Server02 時,你看到此指令輸出中的 In Packet (入站命中封包數) 與 In Byte (入站命中位元組數) 不斷增加,那就代表硬體層級已經成功攔截並丟棄了這些流量。
檢查寫入狀態與命中統計 (Control Plane)
$ nv show system control-plane acl BLOCK_SSH statistics