韩国保姆2_少女伦理电影_HD中文字幕在线观看,玩偶姐姐在线观看高清,8090新视觉电影免费播放在线观看,98蜜桃

沃趣科技技術(shù)社區(qū)
行業(yè)前沿信息一網(wǎng)打盡
技術(shù)社區(qū) > 數(shù)據(jù)庫(kù)技術(shù)a|技術(shù)干貨 | cilium 原理之sock_connect

數(shù)據(jù)庫(kù)技術(shù)a|技術(shù)干貨 | cilium 原理之sock_connect

2023年08月11日

1.背景


在集群網(wǎng)絡(luò)使用cilium之后,最明顯的情況就是:服務(wù)暴露vip+port,在集群內(nèi)怎么測(cè)試都正常,但集群外訪問(wèn)可能是有問(wèn)題的。而這就在于cilium所使用的ebpf科技。


2.引子:curl請(qǐng)求的路程

相對(duì)底層一點(diǎn)的語(yǔ)言,比如c語(yǔ)言,在創(chuàng)建一個(gè)tcp連接時(shí),主要分兩步(其它語(yǔ)言可能會(huì)更簡(jiǎn)單):


    int socket_desc;
    struct sockaddr_in server;
  
  //Create socket
  socket_desc = socket(AF_INET , SOCK_STREAM , 0);
 
  server.sin_addr.s_addr = inet_addr("1.1.1.1");
  server.sin_family = AF_INET;
  server.sin_port = htons( 80 );
 
  //Connect to remote server
  if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)


一個(gè)連接的創(chuàng)建,主要分兩個(gè)步驟:

  1. 創(chuàng)建socket對(duì)象

  2. 發(fā)起connect連接

而實(shí)際上,在內(nèi)核層,它經(jīng)歷的步驟會(huì)非常多??梢酝ㄟ^(guò)perf工具來(lái)查看:


perf trace  -e 'net:*' -e 'sock:*' -e 'syscalls:*'  curl 1.1.1.1 -s >& /dev/stdout


上面的輸出很多,而syscalls:sys_enter_socket前面的很長(zhǎng)一段,是curl程序打開本身加載動(dòng)態(tài)鏈接庫(kù)需要的系統(tǒng)調(diào)用。


而本次需要關(guān)心的是以下這部分(截取的部分內(nèi)容):


   108.294 curl/15819 syscalls:sys_enter_socket(family: INET, type: STREAM)
   108.351 curl/15819 syscalls:sys_exit_socket(__syscall_nr: 41, ret: AX25)
   108.939 curl/15819 syscalls:sys_enter_connect(fd: 3, uservaddr: { .family: UNSPEC }, addrlen: 16)
   108.991 curl/15819 sock:inet_sock_set_state(skaddr: 0xffff902527424c80, oldstate: 7, newstate: 2, dport: 80, family: 2, protocol: 6, saddr: 0x7f176658943b, daddr: 0x7f176658943f, saddr_v6: 0x7f1766589443, daddr_v6: 0x7f1766589453)
   109.090 curl/15819 net:net_dev_queue(skbaddr: 0xffff9024f0a2d4e8, len: 74, name: "enp1s0")
   109.140 curl/15819 net:net_dev_start_xmit(name: "enp1s0", skbaddr: 0xffff9024f0a2d4e8, protocol: 2048, ip_summed: 3, len: 74, network_offset: 14, transport_offset_vali
d: 1, transport_offset: 34, gso_segs: 1, gso_type: 1)


從上面可以看出,在定義socket后,接著就是connect連接,而在sock:inet_sock_set_state這一步,有輸出地址相關(guān)信息,但輸出的是內(nèi)存地址,無(wú)法直接查看。能通過(guò)bcc工具集中的tcplife來(lái)查看。


# 一個(gè)終端中運(yùn)行:
tcplife -D 12345
# 另一個(gè)終端中運(yùn)行:
curl 1.1.1.1:12345


雖然訪問(wèn)的是不存在的地址,但內(nèi)核也會(huì)基于默認(rèn)路由,走默認(rèn)網(wǎng)關(guān),將報(bào)文發(fā)送到enp1s0網(wǎng)卡上。而在sock:inet_sock_set_state可以抓取到源地址與目的地址信息。 既然我們能在sock:inet_sock_set_state點(diǎn)掛載程序,抓取報(bào)文信息,那我們是否可以在掛載點(diǎn),修改socket的目的地址與目的端口信息?


答案是肯定的。但cilium是在cgroup/connect4進(jìn)行修改的(和上面從perf查出來(lái)的不同,但可以通過(guò)bcc的工具來(lái)驗(yàn)證。cgroup是高版本內(nèi)核才有的特殊,具體可參考鏈接,里面有標(biāo)識(shí)內(nèi)核版本的特性。


那么,這是如何查到的呢?


[root@c7-1 ~]# bpftool prog |grep sock
1653: type 18  name sock6_connect  tag d526fd1cb49a372e  gpl
1657: cgroup_sock  name sock6_post_bind  tag e46a7916c9c72e67  gpl
1661: type 18  name sock6_sendmsg  tag 19094f9c26d4dddf  gpl
1665: type 18  name sock6_recvmsg  tag 282bf4c10eff7f73  gpl
1669: type 18  name sock4_connect  tag 57eae2cf019378cc  gpl
1673: cgroup_sock  name sock4_post_bind  tag ddd7183184f2e6e9  gpl
1677: type 18  name sock4_sendmsg  tag 570ef9d580ce0589  gpl
1681: type 18  name sock4_recvmsg  tag 0bdebe7409ceb49f  gpl
[root@c7-1 ~]# bpftool prog |grep connect
1653: type 18  name sock6_connect  tag d526fd1cb49a372e  gpl
1669: type 18  name sock4_connect  tag 57eae2cf019378cc  gpl


在有運(yùn)行cilium的機(jī)器上,使用bpftool工具查詢掛載的程序,發(fā)現(xiàn)與socket相關(guān)的就是這些。


再到cilium的源代碼中,查看對(duì)應(yīng)的代碼段定義:


github.com/cilium/cilium/bpf$ grep -i "__section(" *.c
bpf_host.c:__section("from-netdev")
bpf_host.c:__section("from-host")
bpf_host.c:__section("to-netdev")
bpf_host.c:__section("to-host")
bpf_lxc.c:__section("from-container")
bpf_lxc.c:__section("mydebug1")
bpf_lxc.c:__section("mydebug2")
bpf_lxc.c:__section("to-container")
bpf_network.c:__section("from-network")
bpf_overlay.c:__section("from-overlay")
bpf_overlay.c:__section("to-overlay")
bpf_sock.c:__section("cgroup/connect4")
bpf_sock.c:__section("cgroup/post_bind4")
bpf_sock.c:__section("cgroup/bind4")
bpf_sock.c:__section("cgroup/sendmsg4")
bpf_sock.c:__section("cgroup/recvmsg4")
bpf_sock.c:__section("cgroup/getpeername4")
bpf_sock.c:__section("cgroup/post_bind6")
bpf_sock.c:__section("cgroup/bind6")
bpf_sock.c:__section("cgroup/connect6")
bpf_sock.c:__section("cgroup/sendmsg6")
bpf_sock.c:__section("cgroup/recvmsg6")
bpf_sock.c:__section("cgroup/getpeername6")
bpf_xdp.c:__section("from-netdev")


由此,cilium使用的科技就很明顯了。


3. 手寫ebpf

1. ebpf程序?qū)崿F(xiàn)

在看cilium源碼實(shí)現(xiàn)之前,先手寫一個(gè)最簡(jiǎn)單的修改目的地址與端口的程序。因?yàn)閏ilium本身框架很復(fù)雜,代碼也有相關(guān),所以先以最簡(jiǎn)單的(寫死的)程序入手。代碼可以參考cilium源碼。


#include <bpf/ctx/unspec.h>
#include <bpf/api.h>
 
#define SKIP_POLICY_MAP 1
#define SKIP_CALLS_MAP  1
 
#define SYS_REJECT      0
#define SYS_PROCEED     1
 
# define printk(fmt, ...)                                       \
                ({                                              \
                        const char ____fmt[] = fmt;             \
                        trace_printk(____fmt, sizeof(____fmt),  \
                                     ##__VA_ARGS__);            \
                })
 
__section("cgroup/connect4")
int sock4_connect(struct bpf_sock_addr *ctx )
{
        if (ctx->user_ip4 != 0x04030201) {  // des ip is 1.2.3.4
            return SYS_PROCEED;
        }
        printk("aa %x ", ctx->user_ip4);
        ctx->user_ip4=0x19280a0a;  // set to 10.10.40.25
        printk("set ok %x,%x", ctx->user_ip4, ctx->user_port);
        return SYS_PROCEED;
}
 
BPF_LICENSE("Dual BSD/GPL");



程序說(shuō)明:

  1. 判斷目標(biāo)ip是1.2.3.4才處理(對(duì)應(yīng)16進(jìn)制順序相反,是因?yàn)橄到y(tǒng)為小端模式)。

  2. 輸出目的ip,方便debug。

  3. 修改目的ip為指定的ip。

  4. 輸出設(shè)置的結(jié)果。


入?yún)?span style="background-color: rgb(219, 229, 241);">bpf_sock_addr,可從cilium的源碼中找到相關(guān)定義。

mysock.c


/* User bpf_sock_addr struct to access socket fields and sockaddr struct passed
 * by user and intended to be used by socket (e.g. to bind to, depends on
 * attach type).
 */
struct bpf_sock_addr {
  __u32 user_family;  /* Allows 4-byte read, but no write. */
  __u32 user_ip4;    /* Allows 1,2,4-byte read and 4-byte write.
         * Stored in network byte order.
         */
  __u32 user_ip6[4];  /* Allows 1,2,4,8-byte read and 4,8-byte write.
         * Stored in network byte order.
         */
  __u32 user_port;  /* Allows 1,2,4-byte read and 4-byte write.
         * Stored in network byte order
         */
  __u32 family;    /* Allows 4-byte read, but no write */
  __u32 type;    /* Allows 4-byte read, but no write */
  __u32 protocol;    /* Allows 4-byte read, but no write */
  __u32 msg_src_ip4;  /* Allows 1,2,4-byte read and 4-byte write.
         * Stored in network byte order.
         */
  __u32 msg_src_ip6[4];  /* Allows 1,2,4,8-byte read and 4,8-byte write.
         * Stored in network byte order.
         */
  __bpf_md_ptr(struct bpf_sock *, sk);
};


2. 程序加載

基于k8s部署cilium后,cilium會(huì)在容器中初始化好環(huán)境,我們可以直接使用,省去編譯環(huán)境、cgroupv2配置的麻煩。

將上面的文件,復(fù)制到cilium的容器中(本樣例中使用的cilium版本為1.12.7)。


file=./mysock.c
 
clang -O2 -target bpf -std=gnu89 -nostdinc -emit-llvm -g -Wall -Wextra -Werror -Wshadow -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-gnu-variable-sized-type-not-at-end -Wdeclaration-after-statement -Wimplicit-int-conversion -Wenum-conversion -I. -I/run/cilium/state/globals -I/var/lib/cilium/bpf -I/var/lib/cilium/bpf/include -D__NR_CPUS__=8 -DENABLE_ARP_RESPONDER=1 -DCALLS_MAP=cilium_calls_lb -c $file -o - | llc -march=bpf -mcpu=v2 -mattr=dwarfris -filetype=obj -o mysock.o
 
bpftool cgroup detach /run/cilium/cgroupv2 connect4 pinned /sys/fs/bpf/tc/globals/mytest
rm -f /sys/fs/bpf/tc/globals/mytest
 
tc exec bpf pin /sys/fs/bpf/tc/globals/mytest obj mysock.o type sockaddr attach_type connect4 sec cgroup/connect4
bpftool cgroup attach /run/cilium/cgroupv2 connect4 pinned /sys/fs/bpf/tc/globals/mytest


3.測(cè)試

開啟四個(gè)終端,分別執(zhí)行如下命令(直接在主機(jī)上執(zhí)行):


# command 1
cat /sys/kernel/debug/tracing/trace_pipe
# command 2
tcpconnect -P 80
# command 3
tcplife -D 80
# command 4
curl 1.2.3.4:80


因?yàn)槲覀儠?huì)變更目的ip,所以就基于端口來(lái)抓包。

  1. 用tcplife抓包,抓的是上面perf的sock:inet_sock_set_state時(shí)的狀態(tài)。

  2. 用tcpconnect抓的是connect() syscall時(shí)的狀態(tài)。


4. 自己搭建ebpf環(huán)境

1. 掛載cgroup2

mkdir -p /run/cilium/cgroupv2
mount -t cgroup2  none /run/cilium/cgroupv2/


2. 加載ebp程序

因?yàn)閏entos8自帶的tc與bpftool版本有點(diǎn)低,所以使用cilium中已經(jīng)適配好的版本。


docker run -it --name=mytest --network=host --privileged -v $PWD:/hosts/ -v /sys/fs/bpf:/sys/fs/bpf -v /run/cilium/cgroupv2/:/run/cilium/cgroupv2 cilium:v1.12.7 bash
 
cd /hosts/
# 可以直接用之前編譯好的文件
tc exec bpf pin /sys/fs/bpf/tc/globals/mytest obj mysock.o type sockaddr attach_type connect4 sec cgroup/connect4
bpftool cgroup attach /run/cilium/cgroupv2 connect4 pinned /sys/fs/bpf/tc/globals/mytest


很香!你會(huì)發(fā)現(xiàn),功能已經(jīng)實(shí)現(xiàn)了。



5. cilium邏輯講解


  • 框架已定型,通過(guò)在ebpf中,獲取目的ip與目的端口,然后基于映射規(guī)則將目的ip與端口進(jìn)行修改,從而實(shí)現(xiàn)vip到目的地址的轉(zhuǎn)換。

  • 由于它是在connect階段做的轉(zhuǎn)換,類似在調(diào)用connect函數(shù)時(shí)注冊(cè)一個(gè)回調(diào)函數(shù),和dnat是不同的,所以不需要在回包時(shí)轉(zhuǎn)換還原。


cilium service list


這個(gè)命令可以查看cilium基于service配置的映射規(guī)則,ebpf程序再?gòu)倪@個(gè)規(guī)則中找到合適的bacend,并修改目的地址,然后完成轉(zhuǎn)換。


6.展望

1. 這個(gè)功能可以做什么?

服務(wù)暴露關(guān)心的主要是兩點(diǎn):1. vip的高可用。2.負(fù)載均衡。而這兩點(diǎn),通過(guò)本文所介紹的方式都是可以實(shí)現(xiàn)的。

1.vip的高可用

  • vip的高可用,其本質(zhì)就是在服務(wù)異常時(shí),可以切換到服務(wù)b(這里暫不考慮有狀態(tài)服務(wù)分主備的情況)。

  • 當(dāng)我們?cè)诳蛻舳诉\(yùn)行ebpf程序時(shí),就不需要這個(gè)vip了。在應(yīng)用時(shí)可以配置一個(gè)虛擬的地址,比如1.2.3.4,由ebpf程序來(lái)決定轉(zhuǎn)換到哪個(gè)實(shí)際的后端服務(wù)。而且當(dāng)服務(wù)a異常后,可以變更映射規(guī)則,切換到服務(wù)b。這一切對(duì)應(yīng)用都是透明的。

2.負(fù)載均衡

  • 既然可以將目的地址映射到服務(wù)a,那么基于服務(wù)a,b,c之間做負(fù)載均衡也是可行的。包括設(shè)置權(quán)重、熔斷等。

  • 如istio,需要在客戶端注入sidecar,運(yùn)行envoy程序,其實(shí)也是相類似的邏輯,只不過(guò)它是通過(guò)代理實(shí)現(xiàn)。除了解析目的地址外,它還支持解析數(shù)據(jù)包,比如解析http協(xié)議,在異常時(shí)自動(dòng)重試,實(shí)現(xiàn)服務(wù)切換應(yīng)用無(wú)感知。相對(duì)于應(yīng)用來(lái)說(shuō),只是卡頓了一下。

  • ebpf程序能夠滿足大部分場(chǎng)景,而且很高效。




作者:

沃趣科技產(chǎn)品研發(fā)部



讓數(shù)據(jù)庫(kù)基礎(chǔ)設(shè)施更簡(jiǎn)單
加速企業(yè)數(shù)字化轉(zhuǎn)型建設(shè)及落地
立即咨詢

沃趣科技

中立的企業(yè)級(jí)數(shù)據(jù)庫(kù)云
十年磨一劍十年來(lái)始終如一的專注數(shù)據(jù)庫(kù)生態(tài)領(lǐng)域
夯實(shí)技術(shù)底蘊(yùn)打造最適合時(shí)代的數(shù)據(jù)庫(kù)基礎(chǔ)設(shè)施
業(yè)績(jī)持續(xù)領(lǐng)先目前已累計(jì)服務(wù)超3000家企業(yè)客戶

留言咨詢

完善信息,我們第一時(shí)間跟您聯(lián)系
姓名
手機(jī)
公司
所在地區(qū)
咨詢問(wèn)題