Linux Networking - ianchen0119/Introduce-to-5GC GitHub Wiki

在核心網路中的所有訊息都可以被分成兩大類:

  • Data plane
  • Control plane

Control plane 的部分就像是之前介紹的那樣,有各式各樣的網路協定(NAS、NGAP、PFCP、GTP-C)會在核網中被用到。 而 Data plane 不像前者有這麼多協議(只使用 GTP-U),當我們撇開那些控制訊號不看,整個核心網路其實就是一個巨大的 gateway(將通訊網路與外部網路相連),所以接觸核心網路時我們總是可以看到很多處理網路封包的相關技術,對於像筆者這樣的小白來說真的是非常頭痛。

經過了一段時間的磨練後,筆者也漸漸搞懂了一些技術與觀念,為了造福大家(避免自己忘記),本篇文章會講解一些 Linux 中常見的網路觀念或是技術:

  • nic
  • xdp (ebpf)
  • dpdk
  • device driver
  • networking subsystem (tc, netfilter, etc)
  • kernel module
  • socket

進入正題

linux_net

  • nic 也就是我們常見的網卡,這邊的網卡可以是實體網卡,也可以是虛擬網卡。
  • kernel module 是經過編譯的可執行檔案,我們可以使用 insmod 或是 modprobe 將模組載入到 kernel,free5gc 的 gtp5g 專案(Data plane of UPF)就屬於 kernel module。
  • device driver 是硬體的驅動程式,它可以作為一個靜態檔案存在於 kernel,也可以像 kernel module 一樣,在作業系統運作時動態的載入模組。
  • networking subsystem 包含常見的 tc(traffic control)和 netfilter,細節會在後面補充。
  • xdp 是一項可以提高系統吞吐量的技術,細節同樣會在稍後補充。

traffic control

Traffic control 包含了幾個重要的功能:

  • SHAPING,控制輸出的傳送效率,可以用來改善 traffic burst 的問題。
  • SCHEDULING,為每個 packets transmission 排程,保證某些資料流的頻寬。
  • POLICING,與 shaping 類似,不過它只會在 ingress 上執行。
  • DROPPING,丟棄 ingress 或是 egress 的封包。

簡單來說,tc 的這些功能是透過 filter + queuing disciplines(qdisc)組成的:

圖片來源:https://www.cnblogs.com/charlieroro/p/13993695.html

上圖是一個最基本的 queuing disciplines:pfifo,我們可以看到它由多個 queue 所組成:

  • queue 是有優先權之分的(排序為從左至右)
  • 將封包放到 queue 的動作稱為 enqueue,將封包從 queue 取出為 dequeue
  • 永遠從優先權較高的 queue 取出封包

而 filter 則是決定哪些封包能夠被放入 queue,而 filter 有多個種類可供使用者挑選。

eBPF

在談 eBPF 之前,我們需要來聊聊 BPF(Berkeley Packet Filter)這項技術,BPF 最初由 berkeley 提出,是一項用於過濾封包的機制。 雖著 Linux kernel 的演進,BPF 被採納到核心中並且逐步擴充為 eBPF(Extended BPF),成為 Linux kernel 內建的內部行為分析工具,功能包含:

  • 動態追蹤
  • 靜態追蹤
  • 效能分析

圖片來源:https://speakerdeck.com/johnlin/ebpf-based-container-networking

  • 開發者能夠藉由 C 語言與 bpf 套件開發需要注入至 kernel space 的程式,在注入之前,原始碼必須經過 LLVM 編譯成 eBPF VM 能理解的 eBPF bytecode。
  • 待注入的 bytecode 都需要經過 Verifier 驗證,這麼做確保了程式的安全性。
  • 注入後的程式碼會與 kernel 的 hook 關聯,並且在特定情況(比如說:某個系統呼叫被調用時)下觸發程式。

與 user space 溝通

eBPF 提供了一種特別的資料結構:map,讓我們可以在 user space 與 kernel space 存取它:

struct bpf_map_def SEC("maps") stat_map = {
	.type        = BPF_MAP_TYPE_ARRAY,
	.key_size    = sizeof(__u32),
	.value_size  = sizeof(struct datarec),
	.max_entries = 10,
};

參考上方程式碼,它宣告了 BPF_MAP_TYPE_ARRAY 類型的 map,key 的大小為 4 bytes,每個 value 能容下一個 datarec structure。 stat_map 可容納 10 筆資料,超過以後便會出錯。

DPDK

DPDK 是由 Intel 提出的技術,它可以繞過 kernel space 的封包處理(kernel bypass),直接將封包內容透過 zero-copy 技術複製到 user space,提高系統的 throughput。

image

參考上圖,左側的架構為傳統 Linux 的封包處理流程,在一般情況下,網路封包必須經過 kernel 的 protocol stack、分配 socket buffer(代表封包本身),最後再利用系統呼叫將 socket buffer 的資料拷貝至 user space(假設有 user space application 在監聽 socket,這時候 application 會取得封包資料),這個作法會因為以下原因拖累效能:

  • Kernel 與 User space 之間的轉換
  • Driver 需要透過中斷接收來自 NIC 上的封包
  • Context-switch 的成本

而 dpdk 直接跳過 kernel space,利用 PMD(Poll Mode Driver)關注網卡的 tx/rx ring,直接將封包複製到 user space 進行處理。這樣一來,可以大大的提升系統的吞吐量,不過這也會讓系統開發者面臨一些挑戰:

  • 開發相對傳統方式困難
  • 需要特定硬體(支援 dpdk 技術的網卡)
  • 許多原本在 kernel space 處理的事情都需要從頭實作,包含:
    • IP Stack(TCP/IP, filtering, routing)
    • Packet processing(ARP, bridging)
    • Connection tracking
    • NAT

幸運的是,Intel 的開源專案:nff-go 幫助我們解決上面大部分惱人的問題,這個專案是一個 high-level 的 dpdk framework,可以幫助開發者快速的打造基於 DPDK 的 Network Function。

參考上圖,nff-go 的開發概念是讓開發者描述 flow graph,透過它提供的 hook function 綁定開發者自定義的 user-defined function,來決定封包應該被:

  • 繼續處理
  • 轉發
  • 丟棄

除此之外,它還提供了 L2 到 L4 的封包處理函式(Parsing、Encapsulate、Decapsulate),讓我們不用重複造輪子。

更多資訊請參考 Intel 開發者提供的投影片

XDP

圖片來源:https://sematext.com/blog/ebpf-and-xdp-for-processing-packets-at-bare-metal-speed/

XDP(eXpress Data Path)是以 eBPF 為基礎的高性能、可編程的網路路徑技術,它可以讓網路封包在不經過作業系統的 networking stack 的情況下完成封包的處理(轉發或是丟棄),它常見於:

補充: XDP 與 dpdk 不同,它並不是 kernel bypass 的技術,因為網路封包已經進入到 kernel space 了,只不過這些封包會在 socket buffer allocation 之前被處理掉。

除此之外,也有開發者使用 xdp 技術開發 5G UPF 並且發表了論文:

XDP 之所以能夠這麼快,最大的原因是:它能夠在作業系統分配 socket buffer 就將封包處理完畢(也可以理解是網路封包將不會經過系統的網路堆疊處理):

上圖取自 Securing Linux with a Faster and Scalable Iptables,它比較了傳統 iptables 以及 bpf-iptables 之間的效能差異。 雖然造成差異如此巨大的原因有很多(匹配演算法、連線追蹤實作),但最根本的原因仍離不開 kernel bypass。

因為這個優秀的效能表現,在 kubernetes 生態圈也能夠見到相關的應用:Cilium

image

Cilium 可以直接取代 kube-proxy,接手原本由 kube-proxy 負責的:均衡附載封包路由服務探索...等工作。