1、內(nèi)核態(tài)和用戶態(tài)傳遞信息的結(jié)構(gòu)定義,數(shù)據(jù)結(jié)構(gòu)要對齊宿饱,數(shù)據(jù)結(jié)構(gòu)成員的大小要確定肠阱;
這里定義了一個(gè)perf map蔚携,用戶態(tài)用golang實(shí)現(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
}
其中有個(gè)細(xì)節(jié)盖矫,上面C的定義中有個(gè) int 類型的“int kernel_stack_id”,如果在go中也定義int類型會(huì)報(bào)錯(cuò)击奶,需要使用uint32代替辈双,按道理大小應(yīng)該一樣的。
failed to decode received data: binary.Read: invalid type *main.traceEvent
2柜砾、kprobe跟蹤內(nèi)核函數(shù)的時(shí)候湃望,基本上有符號表的都能跟蹤,但內(nèi)核是模塊化的痰驱,可能由于未加載模塊導(dǎo)致kprobe加載失敗证芭。
如,在加載ebt_do_table的時(shí)候萄唇,報(bào)錯(cuò):
Failed to load kprobe__ebt_do_table: Module: unable to find kprobe__ebt_do_table
這個(gè)函數(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ù)組存儲(chǔ)字符串诅挑,go在使用的時(shí)候要轉(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)會(huì)有問題,舉個(gè)例子拔妥,如下忿危,在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[:])))