iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Software Development

教練我想玩eBPF系列 第 27

Day27 - BCC sockmap (上)

  • 分享至 

  • xImage
  •  

完成了昨天對cgroups的介紹,今天我們正式來介紹examples/networking/sockmap.py這隻程式。(原始碼)

首先我們一樣先來了解一下sockmap的功能。這邊我們拿Cilium CNI介紹的一張圖來說明。

圖中是一個使用envoy sidecar的kubernetes pod網路連線示意圖,簡單來說kubernetes上面容器(Pod)服務(Service)的網路流量會透過iptables的機制全部重新導向到跑在同一個容器內的sidecar,透過sidecar當作中介完成網路監控、服務發現等功能後才會真正離開容器。進入容器的流量同樣先都重導向到sidecar處理。

這樣的好處是可以完全不對service本身修改,完全由獨立的sidecar來提供附加的網路功能,但是也有一個很明顯的問題,一個封包在傳輸的過程中,要經過3次Linux kernel的network stack處理,大大降低了封包的傳輸效率。

其中由於都是在同一台設備的同一個網路空間內傳輸,因此TPC/IP/ethernet等底層網路完全可以省略。


因此我們可以透過eBPF的socket redirect技術來簡化這個封包的傳輸過程,簡單來說,在同一個設備的兩個socket間的傳輸,我們完全可以直接跳過底層的網路堆疊,直接在socket layer將封包內容從一個socket搬到另外一個socket,跳過底層TCP/IP/ethernet處理。

讓我們回到bcc的sockmap.py,他提供的就是socket redirect的功能,他會監聽機器上的所有socket,將local to local的tcp連線資料封包直接透過socket redirect的方式進行搬運。

socket redirect機制好像同時也節省了packet在userspace和kernel space之間複製搬運的過程,不過這件事情沒有完全確定。

我們一樣先看看執行起來怎麼樣,我們透過python建立一個http server並透過curl來測試

python3 -m http.server &
curl 127.0.0.1:8000

接著是eBPF程式的執行解果

python3 sockmap.py -c /sys/fs/cgroup/unified/
b'curl-3043    [000] d...1  7164.673950: bpf_trace_printk: remote-port: 8000, local-port: 46246'
b'curl-3043    [000] dN..1  7164.673973: bpf_trace_printk: Sockhash op: 4, port 46246 --> 8000'
b'curl-3043    [000] dNs11  7164.673985: bpf_trace_printk: remote-port: 46246, local-port: 8000'
b'curl-3043    [000] dNs11  7164.673988: bpf_trace_printk: Sockhash op: 5, port 8000 --> 46246'
b'curl-3043    [000] d...1  7164.674643: bpf_trace_printk: try redirect port 46246 --> 8000'
b'python3-3044    [000] d...1  7164.675211: bpf_trace_printk: try redirect port 8000 --> 46246'
b'python3-3044    [000] d...1  7164.675492: bpf_trace_printk: try redirect port 8000 --> 46246'

這邊可以看到sockmap要指定一個-c的參數,後面是指定一個cgroup,sockmap只會監控在這個cgroup節點上的socket連線。這邊unified是cgroup v2的hierarchy,在cgroup v2只有unified一個hierarchy,所有subsystem都在這個hierarchy上。

首先是 curl remote-port: 8000, local-port: 46246' Sockhash op: 4, port 46246 --> 8000',這兩條是curl發起連線時,記錄下來的socket連線請求。

接著curl remote-port: 46246, local-port: 8000' Sockhash op: 5, port 8000 --> 46246',是curl跟http server之間連線建立成功後,返回給curl的socket通知。

接著可以看到3條try redirect是curl傳遞http request和http server返回http response的msg,直接透過socket redirect的方式在兩個socket之間交互。

這邊我們使用tcpdump去監聽lo interface的方式來驗證socket redirect有真的運作到。同樣是透過curl 127.0.0.1:8000發起連線傳輸資料。在沒有啟用sockmap的情況下tcpdump捕捉到12個封包。而開啟socketmap後只會捕捉到6個封包。

透過封包內容會發現,在socketmap啟動後,只能夠捕捉到帶SYNFIN等flag的TCP控制封包,不會捕捉到中間純粹的資料交換封包。

完成驗證後,我們接著來介紹這次用到的兩種eBPG program type,分別是BPF_PROG_TYPE_SOCK_OPSBPF_PROG_TYPE_SK_MSG

BPF_PROG_TYPE_SOCK_OPS可以attach在一個cgroup節點上,當該節點上任意process的socket發生特定事件時,該eBPF program會被觸發。可能的事件定義在bpf.h。其中CB結尾的表示特定事件完成後觸發,例如BPF_SOCK_OPS_TCP_LISTEN_CB表示在socket tcp連線轉乘LISTEN狀態後觸發。有些則是觸發來透過回傳值設置一些控制項,BPF_SOCK_OPS_TIMEOUT_INIT是在TCP Timeout後觸發,透過eBPF 的return value設置RTO,-1表示使用系統預設。

enum {
	BPF_SOCK_OPS_VOID,
	BPF_SOCK_OPS_TIMEOUT_INIT,	
	BPF_SOCK_OPS_RWND_INIT,	
	BPF_SOCK_OPS_TCP_CONNECT_CB,
	BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB,	
	BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB,
	BPF_SOCK_OPS_NEEDS_ECN,	
	BPF_SOCK_OPS_BASE_RTT,
	BPF_SOCK_OPS_RTO_CB,
	BPF_SOCK_OPS_RETRANS_CB,
	BPF_SOCK_OPS_STATE_CB,	
	BPF_SOCK_OPS_TCP_LISTEN_CB,
	BPF_SOCK_OPS_RTT_CB,
	BPF_SOCK_OPS_PARSE_HDR_OPT_CB,	
	BPF_SOCK_OPS_HDR_OPT_LEN_CB,
	BPF_SOCK_OPS_WRITE_HDR_OPT_CB,	
};

這邊要特別介紹的是BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CBBPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB分別是在主動建立連線時(發送SYN,tcp三手交握第一手),和被動建立連線時(發送SYN+ACK,tcp三手交握第二手)觸發。

觸發後會拿到bpf_sock_ops上下文,並根據事件不同,eBPF回傳值也代表不同的意義。其中bpf_sock_ops->op對應到上述的事件類型。args則是不同op可能帶的一些特殊參數。

struct bpf_sock_ops {
	__u32 op;
	union {
		__u32 args[4];		/* Optionally passed to bpf program */
		__u32 reply;		/* Returned by bpf program	    */
		__u32 replylong[4];	/* Optionally returned by bpf prog  */
	};
	__u32 family;
	__u32 remote_ip4;	/* Stored in network byte order */
	__u32 local_ip4;	/* Stored in network byte order */
	__u32 remote_ip6[4];	/* Stored in network byte order */
	__u32 local_ip6[4];	/* Stored in network byte order */
	__u32 remote_port;	/* Stored in network byte order */
	__u32 local_port;	/* stored in host byte order */
	__u32 is_fullsock;
	...

今天我們介紹了socket redirect的概念還有用到的其中一個program type,明天我們會介紹另外一個program type BPF_PROG_TYPE_SK_MSG並實際看sockmap的程式碼實作。

本系列30天鐵人文章同步發表在我的個人部落格


上一篇
Day26 - Cgroups
下一篇
Day28 - BCC sockmap (下)
系列文
教練我想玩eBPF30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言