自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊Sockmap與基本原理

存儲 存儲軟件
sockmap是BPF程序的一種map類型,顧名思義,這種map類型中存儲的是對struct sock的引用。熟悉網(wǎng)絡(luò)的同學知道struct sock是套接字在網(wǎng)絡(luò)層的表示,因此利用sockmap我們可以在網(wǎng)絡(luò)層上對TCP套接字進行一些自定義處理和操縱。

 [[381394]]

本文轉(zhuǎn)載自微信公眾號「云巔論劍」,作者寒蟬。轉(zhuǎn)載本文請聯(lián)系云巔論劍公眾號。  

什么是sockmap

 

sockmap是BPF程序的一種map類型,顧名思義,這種map類型中存儲的是對struct sock的引用。熟悉網(wǎng)絡(luò)的同學知道struct sock是套接字在網(wǎng)絡(luò)層的表示,因此利用sockmap我們可以在網(wǎng)絡(luò)層上對TCP套接字進行一些自定義處理和操縱。

背景

在現(xiàn)實環(huán)境中,絕大多數(shù)的網(wǎng)絡(luò)請求并不會像如下左圖一樣直接從客戶端發(fā)送到服務(wù)端,而是由于負載均衡、安全性等原因像如下右圖一樣,客戶端發(fā)出的請求要經(jīng)過代理服務(wù)器轉(zhuǎn)發(fā)才能到達服務(wù)端。

 

 

 

很明顯,代理轉(zhuǎn)發(fā)行為拉長了網(wǎng)絡(luò)傳輸路徑,相對于直連增加了2次內(nèi)核態(tài)和用戶態(tài)之間的切換、2次內(nèi)核態(tài)和用戶態(tài)之間的數(shù)據(jù)拷貝、2次網(wǎng)絡(luò)協(xié)議棧的處理以及1次用戶態(tài)處理,因此代理轉(zhuǎn)發(fā)相比直連大大的降低了網(wǎng)絡(luò)性能(提高了時延,降低了帶寬)。

sockmap就是在這個背景下產(chǎn)生的,其目的就是提供一種加速本機內(nèi)部TCP socket之間數(shù)據(jù)轉(zhuǎn)發(fā)的機制。

機制1 socket數(shù)據(jù)轉(zhuǎn)發(fā)卸載

簡介

 

如圖2.1,通常用戶態(tài)程序(如代理程序)需要通過系統(tǒng)調(diào)用sys_read從一個socket中讀取數(shù)據(jù)到用戶態(tài),這個過程涉及到2次上下文切換(用戶態(tài)->內(nèi)核態(tài)->用戶態(tài))和1次內(nèi)核態(tài)到用戶態(tài)的數(shù)據(jù)拷貝;用戶態(tài)程序?qū)膕ocket中讀取的數(shù)據(jù)進行一系列處理后,再通過系統(tǒng)調(diào)用sys_write將處理后的數(shù)據(jù)寫入到另一個socket中去,這個過程涉及到2次上下文切換(用戶態(tài)->內(nèi)核態(tài)->用戶態(tài))和1次用戶態(tài)到內(nèi)核態(tài)的數(shù)據(jù)拷貝。

 

sockmap最初的版本提供了一種在本機TCP socket之間直接進行skb(struct sk_buff,其表示一個包含包頭的數(shù)據(jù)包,后續(xù)均簡稱為skb)轉(zhuǎn)發(fā)的機制。如圖2.2,這種機制允許將原先圖2.1中的用戶態(tài)處理部分的邏輯卸載到內(nèi)核BPF程序中進行處理,處理后的數(shù)據(jù)包skb直接在內(nèi)核態(tài)中轉(zhuǎn)發(fā)到另一個socket中去進行數(shù)據(jù)包的發(fā)送。整個過程無需的用戶態(tài)內(nèi)核態(tài)之間上下文切換,也無需任何用戶態(tài)內(nèi)核態(tài)之間的數(shù)據(jù)拷貝,大大縮短了數(shù)據(jù)轉(zhuǎn)發(fā)路徑。

關(guān)聯(lián)的BPF程序

針對本機制,sockmap提供了兩種BPF程序類型:

1. BPF_SK_SKB_STREAM_VERDICT

該類型的BPF程序根據(jù)用戶的邏輯對數(shù)據(jù)進行處理和仲裁,其返回值(有如下三種)決定了源sock中數(shù)據(jù)的具體轉(zhuǎn)發(fā)行為:

1.1 SK_PASS

該行為表示數(shù)據(jù)將按圖2.1的方式被用戶態(tài)程序接收處理并再發(fā)送到目的sock中。

1.2 SK_REDIRECT

該行為表示數(shù)據(jù)將按圖2.2的方式在內(nèi)核態(tài)中直接被BPF程序處理并發(fā)送到目的sock中。

1.3 SK_DROP

該行為表示數(shù)據(jù)將被直接丟棄。

2. BPF_SK_SKB_STREAM_PARSER

該類型的BPF程序不可單獨使用,必須與BPF_SK_SKB_STREAM_VERDICT程序搭配使用,其用于確定一條完整消息的邊界。通常數(shù)據(jù)流協(xié)議,在協(xié)議頭中會指定playload有幾個字節(jié),然后通過底層tcp讀取完協(xié)議頭header和完整的payload后,才形成一條完整的消息記錄。當BPF_SK_SKB_STREAM_VERDICT程序不能自行確定一條完整的消息長度時,就需要該BPF程序來確定是否讀取到一條完整消息的尾部。

大多數(shù)情況下,BPF_SK_SKB_STREAM_VERDICT程序要么是可以自行確定消息的邊界要么只是從skb中獲取一些元數(shù)據(jù)例如IP地址。這時,該類型的BPF程序一般就直接返回SKB長度即可,如下。在內(nèi)核5.10版本之后,這種情形的BPF_SK_SKB_STREAM_PARSER程序可以省略,僅使用BPF_SK_SKB_STREAM_VERDICT即可。

  1. SEC("stream_parser"
  2. int parser(struct __sk_buff *skb) 
  3.     return skb->len; 

實現(xiàn)原理

那么現(xiàn)在我們要實現(xiàn)機制一的效果,即從圖2.1到圖2.2,核心是兩點:

1. 用戶態(tài)對數(shù)據(jù)包的處理(圖2.1)-> 內(nèi)核態(tài)對數(shù)據(jù)包的處理(圖2.2)

2. 用戶態(tài)收發(fā)網(wǎng)絡(luò)數(shù)據(jù)包(圖2.1)-> 內(nèi)核態(tài)收發(fā)網(wǎng)絡(luò)包(圖2.2)

用戶態(tài)數(shù)據(jù)包處理轉(zhuǎn)換到內(nèi)核態(tài)數(shù)據(jù)包處理

將用戶態(tài)數(shù)據(jù)包的處理卸載到內(nèi)核態(tài)進行處理的方法很簡單,就是將用戶態(tài)的處理邏輯用BPF程序在內(nèi)核態(tài)重寫一遍即可。

用戶態(tài)收發(fā)包轉(zhuǎn)換到內(nèi)核態(tài)收發(fā)包

回想一下用戶態(tài)應(yīng)用是如何從網(wǎng)絡(luò)收發(fā)數(shù)據(jù)的。

通常用戶態(tài)應(yīng)用阻塞在系統(tǒng)調(diào)用recv/recvfrom/read上或是通過select/poll/epoll等方式監(jiān)聽socket,當socket接收緩存有數(shù)據(jù)到達時,內(nèi)核會通過回調(diào)函數(shù)sk_data_ready(sk_data_ready是結(jié)構(gòu)體struct sk的一個函數(shù)指針成員)喚醒用戶態(tài)應(yīng)用進程從socket中收包并進行用戶態(tài)的處理。

相對應(yīng)的,通常用戶態(tài)調(diào)用send/sendto/write等系統(tǒng)調(diào)用向socket的發(fā)送緩存寫入數(shù)據(jù)時,內(nèi)核會通過回調(diào)函數(shù)sk_write_space(sk_write_space也是結(jié)構(gòu)體struct sk的一個函數(shù)指針程序)喚醒內(nèi)核態(tài)進程并把數(shù)據(jù)從用戶態(tài)進程轉(zhuǎn)交到內(nèi)核協(xié)議棧。

sockmap利用了Linux內(nèi)核的一個名為Stream Parser的框架,該框架提供了在內(nèi)核中做基于tcp之上的數(shù)據(jù)流協(xié)議解析的能力,其核心原理就是替換了sk_data_ready和sk_write_space的實現(xiàn)。

 

當tcp收到數(shù)據(jù)后,通過回調(diào)函數(shù)sk_data_ready進行事件通知,將收到的數(shù)據(jù)傳遞到Stream Parser中而不是喚醒用戶態(tài)程序進行收包處理,接著Stream Parser把數(shù)據(jù)包交由前述的BPF程序進行處理。如前面所說,類型為BPF_SK_SKB_STREAM_VERDICT的程序會決定SKB的轉(zhuǎn)發(fā)行為,經(jīng)BPF程序處理后返回值為SK_REDIRECT的SKB會在內(nèi)核態(tài)直接被轉(zhuǎn)發(fā)到目的sock中發(fā)送緩存中,最后調(diào)用sk_write_space通知目的sock有數(shù)據(jù)寫入。

機制2數(shù)據(jù)發(fā)送BYPASS協(xié)議棧

簡介

 

通常從用戶態(tài)空間中創(chuàng)建的TCP socket中發(fā)送數(shù)據(jù)可以使用send/sendto/sendmsg/write等系統(tǒng)調(diào)用,而這些系統(tǒng)調(diào)用最終都將由tcp_sendmsg和tcp_sendpage來處理,tcp_sendmsg和tcp_sendpage將用戶空間的數(shù)據(jù)復(fù)制到內(nèi)核SKB中,并將其按照TCP數(shù)據(jù)段發(fā)送出去。

如圖3.1,對于位于同一臺主機的發(fā)送端和接收端來說,發(fā)送端用戶程序向發(fā)送側(cè)socket發(fā)送的數(shù)據(jù)經(jīng)tcp_sendmsg和tcp_sendpage發(fā)送后經(jīng)過網(wǎng)絡(luò)協(xié)議棧到達虛擬網(wǎng)卡Loopback后再經(jīng)過一次網(wǎng)絡(luò)協(xié)議棧到達接收端的接受側(cè)socket,最后接收端的用戶程序從接收側(cè)socket中收取數(shù)據(jù)到用戶態(tài)空間。

很明顯,在這個過程中,數(shù)據(jù)經(jīng)過了兩次網(wǎng)絡(luò)協(xié)議棧的處理。

 

因此,sockmap中又提供了一種加速機制,當發(fā)送端和接收端的socket都位于同一主機時,在發(fā)送數(shù)據(jù)時可以繞過網(wǎng)絡(luò)協(xié)議棧,直接將數(shù)據(jù)發(fā)送接收端的socket中,如圖3.2。

注:該機制下在Loopback網(wǎng)卡上將無法抓到網(wǎng)絡(luò)報文。

關(guān)聯(lián)的BPF程序

針對本機制,sockmap提供了一種BPF程序類型:

1. BPF_SK_MSG_VERDICT

該類型的BPF程序根據(jù)用戶的邏輯對用戶態(tài)發(fā)送的數(shù)據(jù)進行仲裁,其返回值(如下)決定了數(shù)據(jù)的轉(zhuǎn)發(fā)行為。

1.1 SK_PASS

該行為表示數(shù)據(jù)將重新有如圖3.1的方式發(fā)送到網(wǎng)絡(luò)協(xié)議棧中經(jīng)Loopback轉(zhuǎn)發(fā)到接收端socket中。

1.2 SK_REDIRECT

該行為表示數(shù)據(jù)將按照圖3.2的方式直接發(fā)送到接收端socket中,不經(jīng)過網(wǎng)絡(luò)協(xié)議棧和Loopback。

1.3 SK_DROP

該行為表示數(shù)據(jù)將被丟棄。

實現(xiàn)原理

為了實現(xiàn)本機制,sockmap直接替換了tcp_sendmsg和tcp_sendpage的實現(xiàn)為tcp_bpf_sendmsg和tcp_bpf_sendpage,如下。

 

在tcp_bpf_sendmsg和tcp_bpf_sendpage中會將數(shù)據(jù)的控制權(quán)交由前面提到的類型為BPF_SK_MSG_VERDICT的BPF程序仲裁決定該數(shù)據(jù)是否要經(jīng)過該機制的加速。對于BPF程序返回值為SK_REDIRECT的數(shù)據(jù)將被直接放入接收側(cè)socket的接收緩存中,無需經(jīng)過協(xié)議棧和Loopback。

總結(jié)

 

sockmap針對位于同一主機下socket的TCP數(shù)據(jù)轉(zhuǎn)發(fā)路徑的不同部分提供了兩種機制。

機制一由于BPF自身的限制(如只支持有限的循環(huán))無法重寫較為復(fù)雜的用戶態(tài)邏輯,因此在實際應(yīng)用上較為少見。

機制二目前已經(jīng)可以在一些應(yīng)用上看到了,比如社區(qū)的Cilium,以及我們團隊在service mesh的一些場景做的網(wǎng)絡(luò)優(yōu)化。但是由于其只是BYPASS內(nèi)核網(wǎng)絡(luò)協(xié)議棧,網(wǎng)絡(luò)轉(zhuǎn)發(fā)加速效果并沒有機制一那么明顯。

參考資料

https://github.com/torvalds/linux

https://lwn.net/Articles/731133/

https://lwn.net/Articles/768371/

https://www.spinics.net/lists/netdev/msg691409.html

責任編輯:武曉燕 來源: 云巔論劍
相關(guān)推薦

2020-12-15 11:37:18

語音通話網(wǎng)絡(luò)拓撲音頻

2012-01-12 14:37:34

jQuery

2009-02-24 09:43:00

IP電話原理

2011-11-29 12:17:00

2020-11-26 13:54:03

容器LinuxDocker

2016-08-18 00:04:09

網(wǎng)絡(luò)爬蟲抓取系統(tǒng)服務(wù)器

2010-08-20 13:29:33

OFDM

2020-03-21 14:57:14

手機定位智能手機APP

2013-04-07 14:09:55

Android應(yīng)用基本

2019-11-28 10:45:28

ZooKeeper源碼分布式

2016-08-17 23:53:29

網(wǎng)絡(luò)爬蟲抓取系統(tǒng)

2020-12-29 16:55:44

ZooKeeper運維數(shù)據(jù)結(jié)構(gòu)

2011-07-07 14:10:21

Cocoa 內(nèi)省 hash

2009-06-11 09:56:09

MySQL Repli原理

2010-03-17 13:35:02

2011-07-07 14:46:10

Cocoa Xcode

2010-03-18 20:13:03

Java socket

2013-09-22 14:02:09

內(nèi)存數(shù)據(jù)庫

2019-04-30 08:15:31

2010-06-18 17:28:37

Linux Anacr
點贊
收藏

51CTO技術(shù)棧公眾號