記錄開發(fā)ebpf 遇到的問題

1、內(nèi)核態(tài)和用戶態(tài)傳遞信息的結(jié)構(gòu)定義,數(shù)據(jù)結(jié)構(gòu)要對齊,數(shù)據(jù)結(jié)構(gòu)成員的大小要確定;
這里定義了一個perf map,用戶態(tài)用golang實現(xiàn)。
C的對其方式很多,按照類型長度從大大小排序,不足的地方增加pad即可。

struct event_t {
    u64 saddr[2];
    u64 daddr[2];
    u64 ipt_delay;
    u64 kernel_ip;
    //time
    u64 start_ns;
    u64 test;
    void *skb;


    u32  netns;
    u32 len;

    u32 hook;
    u32 verdict;

    int kernel_stack_id;     // call stack
    u16 tot_len;
    u16 icmpid;

    u16 icmpseq;
    u16 sport;
    u16 dport;
    u16 tcpflags;

    u8 flags;
    u8 cpu;
    u8 dir;
    u8 ip_version;
    u8 l4_proto;
    u8 icmptype;
    u8 pf;
    u8 pkt_type; //skb->pkt_type
    u8 dest_mac[6];
    char func_name[FUNCNAME_MAX_LEN];
    char ifname[IFNAMSIZ];
    char tablename[XT_TABLE_MAXNAMELEN];
};
BPF_PERF_OUTPUT(route_event);

go代碼:

type traceEvent struct {
    SAddr    [2]uint64
    DAddr    [2]uint64
    IptDelay uint64
    KernelIp uint64
    StartNs  uint64
    Test     uint64
    Skb      uint64

    NetNs         uint32
    Len           uint32
    Hook          uint32
    Verdict       uint32
    KernalStackId uint32
    TotolLen      uint16
    IcmpId        uint16
    IcmpSeq       uint16
    SPort         uint16
    DPort         uint16
    TcpFlags      uint16
    Flags         uint8
    Cpu           uint8
    Dir           uint8
    IpVersion     uint8
    L4Proto       uint8
    IcmpType      uint8
    Pf            uint8
    PktType       uint8 //skb->pkt_type
    Dmac          [6]uint8

    // call stack
    FuncName  [FUNCNAME_MAX_LEN]byte
    IfName    [IFNAME_MAX_LEN]byte
    TableName [XT_TABLE_MAXNAMELEN]byte
    Pad       [10]byte
}

其中有個細(xì)節(jié),上面C的定義中有個 int 類型的“int kernel_stack_id”,如果在go中也定義int類型會報錯,需要使用uint32代替,按道理大小應(yīng)該一樣的。

failed to decode received data: binary.Read: invalid type *main.traceEvent

2、kprobe跟蹤內(nèi)核函數(shù)的時候,基本上有符號表的都能跟蹤,但內(nèi)核是模塊化的,可能由于未加載模塊導(dǎo)致kprobe加載失敗。
如,在加載ebt_do_table的時候,報錯:

Failed to load kprobe__ebt_do_table: Module: unable to find kprobe__ebt_do_table

這個函數(shù)不是內(nèi)連函數(shù),也沒有static 修飾是可以跟蹤的,但看不到符號表:

[root@172-25-116-187 ~]# cat /proc/kallsyms | grep do_table
ffffffffc03c9030 r __ksymtab_ipt_do_table   [ip_tables]
ffffffffc03c93c8 r __kstrtab_ipt_do_table   [ip_tables]
ffffffffc03c6020 T ipt_do_table [ip_tables]

加載一下ebtables 模塊就ok了。

[root@172-25-116-166 perf]# lsmod | grep ebtable
ebtable_filter         16384  1
ebtables               36864  1 ebtable_filter
[root@172-25-116-166 perf]# cat /proc/kallsyms | grep do_table
ffffffffc0407030 r __ksymtab_ebt_do_table   [ebtables]
ffffffffc0407f22 r __kstrtab_ebt_do_table   [ebtables]
ffffffffc04038f0 T ebt_do_table [ebtables]
ffffffffc02d5030 r __ksymtab_ipt_do_table   [ip_tables]
ffffffffc02d53c8 r __kstrtab_ipt_do_table   [ip_tables]
ffffffffc02d2020 T ipt_do_table [ip_tables]

3、[]byte 轉(zhuǎn) string
C語言使用char數(shù)組存儲字符串,go在使用的時候要轉(zhuǎn)一下。

    event.funcName = C.GoString((*C.char)(unsafe.Pointer(&event.FuncName)))
    event.tableName = C.GoString((*C.char)(unsafe.Pointer(&event.TableName)))
    event.ifName = C.GoString((*C.char)(unsafe.Pointer(&event.IfName)))

使用string強(qiáng)轉(zhuǎn)會有問題,舉個例子,如下,在C語言中為空的情況,轉(zhuǎn)成go string之后,len為64,無法使用go的字符串為空判斷。

    var IfName [64]byte
    // 輸出: ifName:[][64]
    fmt.Printf("ifName:[%s][%d]\n", string(IfName[:]), len(string(IfName[:])))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容