乙太網交換裝置驅動程式模型 (switchdev)¶
版權所有 © 2014 Jiri Pirko <jiri@resnulli.us>
版權所有 © 2014-2015 Scott Feldman <sfeldma@gmail.com>
乙太網交換裝置驅動程式模型 (switchdev) 是一種核心驅動程式模型,用於將轉發(資料)平面從核心中分流的交換裝置。
圖 1 是一個框圖,顯示了 switchdev 模型在使用資料中心級交換 ASIC 晶片的示例設定中的元件。其他使用 SR-IOV 或軟交換(如 OVS)的設定也是可能的。
User-space tools
user space |
+-------------------------------------------------------------------+
kernel | Netlink
|
+--------------+-------------------------------+
| Network stack |
| (Linux) |
| |
+----------------------------------------------+
sw1p2 sw1p4 sw1p6
sw1p1 + sw1p3 + sw1p5 + eth1
+ | + | + | +
| | | | | | |
+--+----+----+----+----+----+---+ +-----+-----+
| Switch driver | | mgmt |
| (this document) | | driver |
| | | |
+--------------+----------------+ +-----------+
|
kernel | HW bus (eg PCI)
+-------------------------------------------------------------------+
hardware |
+--------------+----------------+
| Switch device (sw1) |
| +----+ +--------+
| | v offloaded data path | mgmt port
| | | |
+--|----|----+----+----+----+---+
| | | | | |
+ + + + + +
p1 p2 p3 p4 p5 p6
front-panel ports
Fig 1.
包含檔案¶
#include <linux/netdevice.h>
#include <net/switchdev.h>
配置¶
在驅動程式的 Kconfig 中使用“depends NET_SWITCHDEV”以確保為驅動程式構建 switchdev 模型支援。
交換機埠¶
在 switchdev 驅動程式初始化時,驅動程式將為每個列舉的物理交換機埠分配並註冊一個 struct net_device(使用 register_netdev()),該埠稱為埠 netdev。埠 netdev 是物理埠的軟體表示,為控制器(核心)和網路之間的控制流量提供通路,也是橋接、繫結、VLAN、隧道和 L3 路由器等更高階構造的錨點。使用標準 netdev 工具(iproute2、ethtool 等),埠 netdev 還可以向用戶提供對交換機埠物理屬性的訪問,例如 PHY 鏈路狀態和 I/O 統計資訊。
除了埠 netdev 之外,目前沒有更高層次的核心物件用於交換機。所有的 switchdev 驅動程式操作都是 netdev 操作或 switchdev 操作。
交換機管理埠超出了 switchdev 驅動程式模型的範圍。通常,管理埠不參與解除安裝資料平面,並在管理埠裝置上載入不同的驅動程式,例如 NIC 驅動程式。
交換機 ID¶
switchdev 驅動程式必須為每個埠 netdev 實現 net_device 操作 ndo_get_port_parent_id,為交換機的每個埠返回相同的物理 ID。在同一系統上的交換機之間,該 ID 必須是唯一的。在不同系統上的交換機之間,該 ID 不需要是唯一的。
交換機 ID 用於定位交換機上的埠,並判斷聚合埠是否屬於同一交換機。
埠 Netdev 命名¶
埠 netdev 命名應使用 Udev 規則,以埠的某個唯一屬性作為鍵,例如埠 MAC 地址或埠 PHYS 名稱。不鼓勵在驅動程式中硬編碼核心 netdev 名稱;讓核心選擇預設的 netdev 名稱,並讓 udev 根據埠屬性設定最終名稱。
使用埠 PHYS 名稱 (ndo_get_phys_port_name) 作為鍵對於動態命名的埠特別有用,其中裝置根據外部配置命名其埠。例如,如果一個物理 40G 埠邏輯上拆分為 4 個 10G 埠,從而產生 4 個埠 netdev,裝置可以使用埠 PHYS 名稱為每個埠提供一個唯一的名稱。udev 規則將是
SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}=="<phys_switch_id>", \
ATTR{phys_port_name}!="", NAME="swX$attr{phys_port_name}"
建議的命名約定是“swXpYsZ”,其中 X 是交換機名稱或 ID,Y 是埠名稱或 ID,Z 是子埠名稱或 ID。例如,sw1p1s0 將是交換機 1 上埠 1 的子埠 0。
埠特性¶
dev->netns_immutable
如果 switchdev 驅動程式(和裝置)僅支援解除安裝預設網路名稱空間 (netns),則驅動程式應設定此私有標誌,以防止埠 netdev 移出預設 netns。一個感知 netns 的驅動程式/裝置不會設定此標誌,並將負責劃分硬體以保持 netns 隔離。這意味著硬體不能將流量從一個名稱空間中的埠轉發到另一個名稱空間中的另一個埠。
埠拓撲¶
表示物理交換機埠的埠 netdev 可以組織成更高級別的交換構造。預設構造是獨立的路由器埠,用於解除安裝 L3 轉發。兩個或更多埠可以繫結在一起形成一個 LAG。兩個或更多埠(或 LAG)可以橋接以橋接 L2 網路。VLAN 可用於細分 L2 網路。L2-over-L3 隧道可以在埠上構建。這些構造是使用標準 Linux 工具構建的,例如網橋驅動程式、繫結/團隊驅動程式和基於 netlink 的工具(如 iproute2)。
switchdev 驅動程式可以透過監視 NETDEV_CHANGEUPPER 通知來了解特定埠在拓撲中的位置。例如,移動到繫結中的埠將看到其上層主控發生變化。如果該繫結被移動到網橋中,則繫結的上層主控將發生變化。依此類推。驅動程式將透過註冊 netdevice 事件並響應 NETDEV_CHANGEUPPER 來跟蹤此類移動,以瞭解埠在整體拓撲中的位置。
L2 轉發解除安裝¶
核心思想是透過將網橋 FDB 條目映象到 switchdev 裝置來將 L2 資料轉發(交換)路徑從核心解除安裝到 switchdev 裝置。FDB 條目是 {port, MAC, VLAN} 元組轉發目的地。
要解除安裝 L2 橋接,switchdev 驅動程式/裝置應支援
安裝在網橋埠上的靜態 FDB 條目
裝置學習/遺忘源 MAC/VLAN 的通知
埠上的 STP 狀態更改
組播/廣播和未知單播資料包的 VLAN 泛洪
靜態 FDB 條目¶
實現 ndo_fdb_add、ndo_fdb_del 和 ndo_fdb_dump 操作的驅動程式能夠支援下面的命令,該命令新增一個靜態網橋 FDB 條目
bridge fdb add dev DEV ADDRESS [vlan VID] [self] static
(“static”關鍵字是必選的:如果未指定,則條目預設為“local”,這意味著不應轉發)
“self”關鍵字(可選,因為它是隱式的)的作用是指示核心透過 DEV 裝置本身的 ndo_fdb_add 實現來完成操作。如果 DEV 是一個網橋埠,這將繞過網橋,從而導致軟體資料庫與硬體資料庫不同步。
為避免這種情況,可以使用“master”關鍵字
bridge fdb add dev DEV ADDRESS [vlan VID] master static
上述命令指示核心搜尋 DEV 的主介面,並透過該主介面的 ndo_fdb_add 方法完成操作。此時,網橋會生成一個 SWITCHDEV_FDB_ADD_TO_DEVICE 通知,埠驅動程式可以處理並使用它來程式設計其硬體表。這樣,軟體和硬體資料庫都將包含此靜態 FDB 條目。
注意:對於解除安裝 Linux 網橋的新 switchdev 驅動程式,強烈不建議實現 ndo_fdb_add 和 ndo_fdb_del 網橋繞過方法:所有靜態 FDB 條目都應使用“master”標誌在網橋埠上新增。ndo_fdb_dump 是一個例外,如果裝置沒有中斷來通知作業系統新學習/遺忘的動態 FDB 地址,則可以實現它來視覺化硬體表。在這種情況下,硬體 FDB 最終可能包含軟體 FDB 中不存在的條目,並且實現 ndo_fdb_dump 是檢視它們的唯一方法。
注意:預設情況下,網橋不對 VLAN 進行過濾,只橋接未標記的流量。要啟用 VLAN 支援,請開啟 VLAN 過濾
echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering
已學習/遺忘源 MAC/VLAN 的通知¶
交換裝置將在入口資料包上學習/遺忘源 MAC 地址/VLAN,並通知交換機驅動程式 mac/vlan/port 元組。交換機驅動程式反過來將使用 switchdev 通知程式呼叫來通知網橋驅動程式
err = call_switchdev_notifiers(val, dev, info, extack);
其中 val 在學習時為 SWITCHDEV_FDB_ADD,在遺忘時為 SWITCHDEV_FDB_DEL,info 指向 struct switchdev_notifier_fdb_info。在 SWITCHDEV_FDB_ADD 上,網橋驅動程式會將 FDB 條目安裝到網橋的 FDB 中,並將該條目標記為 NTF_EXT_LEARNED。iproute2 bridge 命令會將這些條目標記為“offload”
$ bridge fdb
52:54:00:12:35:01 dev sw1p1 master br0 permanent
00:02:00:00:02:00 dev sw1p1 master br0 offload
00:02:00:00:02:00 dev sw1p1 self
52:54:00:12:35:02 dev sw1p2 master br0 permanent
00:02:00:00:03:00 dev sw1p2 master br0 offload
00:02:00:00:03:00 dev sw1p2 self
33:33:00:00:00:01 dev eth0 self permanent
01:00:5e:00:00:01 dev eth0 self permanent
33:33:ff:00:00:00 dev eth0 self permanent
01:80:c2:00:00:0e dev eth0 self permanent
33:33:00:00:00:01 dev br0 self permanent
01:00:5e:00:00:01 dev br0 self permanent
33:33:ff:12:35:01 dev br0 self permanent
應使用 bridge 命令停用埠上的學習功能
bridge link set dev DEV learning off
應啟用裝置埠上的學習功能,以及 learning_sync
bridge link set dev DEV learning on self
bridge link set dev DEV learning_sync on self
learning_sync 屬性啟用將已學習/遺忘的 FDB 條目同步到網橋的 FDB。在裝置埠和網橋埠上同時啟用學習功能,並停用 learning_sync,這是可能的,但不是最佳選擇。
為支援學習,驅動程式為 SWITCHDEV_ATTR_PORT_ID_{PRE}_BRIDGE_FLAGS 實現了 switchdev 操作 switchdev_port_attr_set。
FDB 老化¶
網橋將跳過標記為 NTF_EXT_LEARNED 的 FDB 條目的老化,埠驅動程式/裝置負責使這些條目老化。如果埠裝置支援老化,當 FDB 條目過期時,它將通知驅動程式,驅動程式反過來將使用 SWITCHDEV_FDB_DEL 通知網橋。如果裝置不支援老化,驅動程式可以使用垃圾回收計時器模擬老化來監控 FDB 條目。過期條目將使用 SWITCHDEV_FDB_DEL 通知網橋。有關執行老化計時器的驅動程式示例,請參見 rocker 驅動程式。
為了使 NTF_EXT_LEARNED 條目“保持活動”,驅動程式應透過呼叫 call_switchdev_notifiers(SWITCHDEV_FDB_ADD, ...) 來重新整理 FDB 條目。該通知將把 FDB 條目的最後使用時間重置為當前時間。驅動程式應對重新整理通知進行速率限制,例如,每秒不超過一次。(最後使用時間可以使用 bridge -s fdb 選項檢視)。
埠上的 STP 狀態更改¶
在內部或使用第三方 STP 協議實現(例如 mstpd),網橋驅動程式維護埠的 STP 狀態,並使用 switchdev 操作 switchdev_attr_port_set(針對 SWITCHDEV_ATTR_PORT_ID_STP_UPDATE)通知交換機驅動程式埠上的 STP 狀態更改。
狀態是 BR_STATE_* 之一。交換機驅動程式可以使用 STP 狀態更新來更新埠的入口資料包過濾列表。例如,如果埠處於 DISABLED 狀態,則不應有資料包透過;但如果埠移動到 BLOCKED 狀態,則 STP BPDU 和其他 IEEE 01:80:c2:xx:xx:xx 鏈路本地組播資料包可以透過。
請注意,STP BPDU 是未標記的,並且 STP 狀態適用於埠上的所有 VLAN,因此資料包過濾器應在埠上的一致應用於未標記和已標記的 VLAN。
L2 域泛洪¶
對於給定的 L2 VLAN 域,如果埠的當前 STP 狀態允許,交換裝置應將組播/廣播和未知單播資料包泛洪到域中的所有埠。交換機驅動程式知道哪些埠屬於哪個 VLAN L2 域,可以對交換裝置進行程式設計以進行泛洪。資料包可能會發送到埠 netdev,以便由網橋驅動程式處理。網橋不應將資料包重新泛洪到裝置已泛洪的相同埠,否則線上路上將出現重複資料包。
為避免重複資料包,交換機驅動程式應透過設定 skb->offload_fwd_mark 位將資料包標記為已轉發。網橋驅動程式將使用入口網橋埠的標記來標記 skb,並阻止其透過任何具有相同標記的網橋埠轉發。
交換裝置可能不處理泛洪,而是將資料包推送到網橋驅動程式進行泛洪。這並不理想,因為隨著 L2 域中埠數量的增加,裝置在泛洪資料包方面比軟體效率高得多。
如果裝置支援,泛洪控制可以解除安裝到裝置上,從而防止某些 netdev 泛洪沒有 FDB 條目的單播流量。
IGMP 偵聽¶
為了支援 IGMP 偵聽,埠 netdev 應將所有 IGMP 加入和離開訊息捕獲到網橋驅動程式。網橋多播模組將在每個多播組更改時通知埠 netdev,無論是靜態配置還是動態加入/離開。硬體實現應僅將所有註冊的多播流量組轉發到配置的埠。
L3 路由解除安裝¶
解除安裝 L3 路由要求裝置使用核心中的 FIB 條目進行程式設計,由裝置執行 FIB 查詢和轉發。裝置對匹配路由字首的 FIB 條目進行最長字首匹配 (LPM),並將資料包轉發到匹配的 FIB 條目的下一跳出埠。
要對裝置進行程式設計,驅動程式必須使用 register_fib_notifier 註冊一個 FIB 通知處理程式。以下事件可用:
FIB_EVENT_ENTRY_ADD |
用於向裝置新增新 FIB 條目,或修改裝置上現有條目。 |
FIB_EVENT_ENTRY_DEL |
用於刪除 FIB 條目 |
FIB_EVENT_RULE_ADD, |
|
FIB_EVENT_RULE_DEL |
用於傳播 FIB 規則更改 |
FIB_EVENT_ENTRY_ADD 和 FIB_EVENT_ENTRY_DEL 事件傳遞
struct fib_entry_notifier_info {
struct fib_notifier_info info; /* must be first */
u32 dst;
int dst_len;
struct fib_info *fi;
u8 tos;
u8 type;
u32 tb_id;
u32 nlflags;
};
用於在表 tb_id 上新增/修改/刪除 IPv4 dst/dest_len 字首。*fi 結構包含有關路由和路由下一跳的詳細資訊。*dev 是路由下一跳列表中提到的埠 netdev 之一。
解除安裝到裝置的路由在 ip route 列表中標記為“offload”
$ ip route show
default via 192.168.0.2 dev eth0
11.0.0.0/30 dev sw1p1 proto kernel scope link src 11.0.0.2 offload
11.0.0.4/30 via 11.0.0.1 dev sw1p1 proto zebra metric 20 offload
11.0.0.8/30 dev sw1p2 proto kernel scope link src 11.0.0.10 offload
11.0.0.12/30 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload
12.0.0.2 proto zebra metric 30 offload
nexthop via 11.0.0.1 dev sw1p1 weight 1
nexthop via 11.0.0.9 dev sw1p2 weight 1
12.0.0.3 via 11.0.0.1 dev sw1p1 proto zebra metric 20 offload
12.0.0.4 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15
如果至少有一個裝置解除安裝了 FIB 條目,則設定“offload”標誌。
XXX: 新增/修改/刪除 IPv6 FIB API
下一跳解析¶
FIB 條目的下一跳列表包含下一跳元組(閘道器,裝置),但為了交換裝置能夠使用正確的目的 MAC 地址轉發資料包,必須將下一跳閘道器解析為鄰居的 MAC 地址。鄰居 MAC 地址發現透過 ARP(或 ND)過程進行,並透過 arp_tbl 鄰居表可用。為了解析路由的下一跳閘道器,驅動程式應觸發核心的鄰居解析過程。有關示例,請參閱 rocker 驅動程式的 rocker_port_ipv4_resolve()。
驅動程式可以使用 netevent 通知器 NETEVENT_NEIGH_UPDATE 監控 arp_tbl 的更新。裝置可以根據 arp_tbl 的更新,為路由程式設計已解析的下一跳。驅動程式實現 ndo_neigh_destroy 以瞭解 arp_tbl 鄰居條目何時從埠中清除。
裝置驅動程式的預期行為¶
以下是啟用 switchdev 的網路裝置必須遵守的一組定義行為。
無配置狀態¶
驅動程式啟動後,網路裝置必須完全執行,並且支援驅動程式必須配置網路裝置,使其能夠向該網路裝置傳送和接收流量,並與其他網路裝置/埠正確分離(例如:這在交換機 ASIC 中很常見)。實現這一點在很大程度上取決於硬體,但一個簡單的解決方案是使用每埠 VLAN 識別符號,除非有更好的機制可用(例如每個網路埠的專有元資料)。
網路裝置必須能夠執行完整的 IP 協議棧,包括組播、DHCP、IPv4/6 等。如有必要,它應程式設計適當的 VLAN、組播、單播等過濾器。底層裝置驅動程式必須有效地配置,其方式與在這些 switchdev 網路裝置上啟用 IP 組播的 IGMP 偵聽時所做的方式類似,並且必須儘可能早在硬體中過濾掉未經請求的組播。
在網路裝置之上配置 VLAN 時,所有 VLAN 都必須正常工作,無論其他網路裝置的狀態如何(例如:其他埠作為 VLAN 感知網橋的一部分執行入口 VID 檢查)。詳細資訊請參見下文。
如果裝置實現例如 VLAN 過濾,將介面置於混雜模式應允許接收所有 VLAN 標籤(包括過濾器中不存在的標籤)。
橋接交換機埠¶
當一個啟用 switchdev 的網路裝置作為網橋成員新增時,它不應中斷非橋接網路裝置的任何功能,它們應繼續作為正常的網路裝置執行。根據下面的網橋配置旋鈕,預期行為已記錄在案。
網橋 VLAN 過濾¶
Linux 網橋允許配置 VLAN 過濾模式(靜態地,在裝置建立時;以及動態地,在執行時),底層 switchdev 網路裝置/硬體必須遵守該模式。
關閉 VLAN 過濾時:網橋嚴格不感知 VLAN,其資料路徑將處理所有乙太網幀,就像它們是未標記 VLAN 一樣。網橋 VLAN 資料庫仍然可以修改,但在 VLAN 過濾關閉時,這些修改不應產生任何效果。以未程式設計到網橋/交換機 VLAN 表中的 VID 進入裝置的幀必須被轉發,並且可以使用 VLAN 裝置進行處理(參見下文)。
開啟 VLAN 過濾時:網橋是 VLAN 感知的,並且以未程式設計到網橋/交換機 VLAN 表中的 VID 進入裝置的幀必須被丟棄(嚴格的 VID 檢查)。
當在作為網橋埠成員的 switchdev 網路裝置之上配置了 VLAN 裝置(例如:sw0p1.100)時,必須保留軟體網路堆疊的行為,如果不可能,則必須拒絕配置。
關閉 VLAN 過濾時,網橋將處理埠的所有入口流量,除了標記有 VLAN ID 且目標是 VLAN 上層的流量。VLAN 上層介面(消耗 VLAN 標籤)甚至可以新增到第二個網橋中,該網橋包括其他交換機埠或軟體介面。確保屬於 VLAN 上層介面的流量轉發域得到妥善管理的一些方法:
如果轉發目的地可以按 VLAN 管理,則可以將硬體配置為將所有流量(除了帶有屬於 VLAN 上層介面的 VID 的資料包)對映到一個與未標記資料包對應的內部 VID。這個內部 VID 覆蓋了所有不感知 VLAN 的網橋埠。與 VLAN 上層介面對應的 VID 覆蓋了該 VLAN 介面的物理埠,以及可能與其橋接的其他埠。
將帶有 VLAN 上層介面的網橋埠視為獨立埠,並讓轉發在軟體資料路徑中處理。
開啟 VLAN 過濾時,只要網橋在任何網橋埠上都沒有具有相同 VID 的現有 VLAN 條目,就可以建立這些 VLAN 裝置。這些 VLAN 裝置不能被橋接,因為它們與網橋的 VLAN 資料路徑處理功能/用例重複。
相同交換結構中的非橋接網路埠不應受到網橋裝置上啟用 VLAN 過濾的任何干擾。如果 VLAN 過濾設定對整個晶片是全域性的,則獨立埠應透過在 ethtool 特性中設定“rx-vlan-filter: on [fixed]”來指示網路堆疊需要 VLAN 過濾。
由於 VLAN 過濾可以在執行時開啟/關閉,因此 switchdev 驅動程式必須能夠即時重新配置底層硬體,以遵循該選項的切換並採取適當的行為。如果不可能,switchdev 驅動程式也可以拒絕在執行時支援 VLAN 過濾旋鈕的動態切換,並要求銷燬現有網橋裝置並建立具有不同 VLAN 過濾值的新網橋裝置,以確保 VLAN 感知能力被下推到硬體。
即使網橋中的 VLAN 過濾已關閉,底層交換硬體和驅動程式仍然可以配置自身為 VLAN 感知模式,前提是遵守上述行為。
網橋的 VLAN 協議在決定資料包是否被視為已標記方面起著作用:使用 802.1ad 協議的網橋必須將未標記 VLAN 的資料包以及帶有 802.1Q 頭的資料包都視為未標記。
裝置必須以與未標記資料包相同的方式處理 802.1p (VID 0) 標記的資料包,因為網橋裝置不允許在其資料庫中操作 VID 0。
當網橋啟用了 VLAN 過濾且入口埠未配置 PVID 時,未標記和 802.1p 標記的資料包必須被丟棄。當網橋啟用了 VLAN 過濾且入口埠存在 PVID 時,未標記和優先順序標記的資料包必須被接受並根據網橋在 PVID VLAN 中的埠成員資格進行轉發。當網橋停用了 VLAN 過濾時,PVID 的存在與否不應影響資料包轉發決策。
網橋 IGMP 偵聽¶
Linux 網橋允許配置 IGMP 偵聽(靜態地,在介面建立時;或動態地,在執行時),底層 switchdev 網路裝置/硬體必須以以下方式遵守:
當 IGMP 偵聽關閉時,組播流量必須泛洪到同一網橋中所有 mcast_flood=true 的埠。CPU/管理埠理想情況下不應泛洪(除非入口介面具有 IFF_ALLMULTI 或 IFF_PROMISC),並繼續透過網路棧通知學習組播流量。如果硬體無法做到這一點,則 CPU/管理埠也必須泛洪,並且組播過濾在軟體中進行。
當 IGMP 偵聽開啟時,組播流量必須選擇性地流向適當的網路埠(包括 CPU/管理埠)。未知組播的泛洪應僅流向連線到組播路由器的埠(本地裝置也可以充當組播路由器)。
交換機必須遵守 RFC 4541 並相應地泛洪組播流量,因為 Linux 網橋實現就是這樣做的。
由於 IGMP 偵聽可以在執行時開啟/關閉,因此 switchdev 驅動程式必須能夠即時重新配置底層硬體,以遵循該選項的切換並採取適當的行為。
switchdev 驅動程式也可以拒絕在執行時支援多播偵聽旋鈕的動態切換,並要求銷燬現有網橋裝置並建立具有不同多播偵聽值的新網橋裝置。