/* Copyright (c) 2017 Facebook
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*/
/* This program shows clang/llvm is able to generate code pattern
* like :
* _ tcp_send_active_reset :
* 0 : bf 16 00 00 00 00 00 00 r6 = r1
* . . . . . .
* 335 : b7 01 00 00 0 f 00 00 00 r1 = 15
* 336 : 05 00 48 00 00 00 00 00 goto 72
*
* LBB0_3 :
* 337 : b7 01 00 00 01 00 00 00 r1 = 1
* 338 : 63 1 a d0 ff 00 00 00 00 * ( u32 * ) ( r10 - 48 ) = r1
* 408 : b7 01 00 00 03 00 00 00 r1 = 3
*
* LBB0_4 :
* 409 : 71 a2 fe ff 00 00 00 00 r2 = * ( u8 * ) ( r10 - 2 )
* 410 : bf a7 00 00 00 00 00 00 r7 = r10
* 411 : 07 07 00 00 b8 ff ff ff r7 + = - 72
* 412 : bf 73 00 00 00 00 00 00 r3 = r7
* 413 : 0 f 13 00 00 00 00 00 00 r3 + = r1
* 414 : 73 23 2 d 00 00 00 00 00 * ( u8 * ) ( r3 + 45 ) = r2
*
* From the above code snippet , the code generated by the compiler
* is reasonable . The " r1 " is assigned to different values in basic
* blocks " _ tcp_send_active_reset " and " LBB0_3 " , and used in " LBB0_4 " .
* The verifier should be able to handle such code patterns .
*/
#include <string.h>
#include <linux/bpf.h>
#include <linux/ipv6.h>
#include <linux/version.h>
#include <sys/socket.h>
#include <bpf/bpf_helpers.h>
#define _(P) ({typeof(P) val = 0 ; bpf_probe_read_kernel(&val, sizeof (val), &P); val;})
#define TCP_ESTATS_MAGIC 0 xBAADBEEF
/* This test case needs "sock" and "pt_regs" data structure.
* Recursively , " sock " needs " sock_common " and " inet_sock " .
* However , this is a unit test case only for
* verifier purpose without bpf program execution .
* We can safely mock much simpler data structures , basically
* only taking the necessary fields from kernel headers .
*/
typedef __u32 __bitwise __portpair;
typedef __u64 __bitwise __addrpair;
struct sock_common {
unsigned short skc_family;
union {
__addrpair skc_addrpair;
struct {
__be32 skc_daddr;
__be32 skc_rcv_saddr;
};
};
union {
__portpair skc_portpair;
struct {
__be16 skc_dport;
__u16 skc_num;
};
};
struct in6_addr skc_v6_daddr;
struct in6_addr skc_v6_rcv_saddr;
};
struct sock {
struct sock_common __sk_common;
#define sk_family __sk_common.skc_family
#define sk_v6_daddr __sk_common.skc_v6_daddr
#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
};
struct inet_sock {
struct sock sk;
#define inet_daddr sk.__sk_common.skc_daddr
#define inet_dport sk.__sk_common.skc_dport
__be32 inet_saddr;
__be16 inet_sport;
};
struct pt_regs {
long di;
};
static inline struct inet_sock *inet_sk(const struct sock *sk)
{
return (struct inet_sock *)sk;
}
/* Define various data structures for state recording.
* Some fields are not used due to test simplification .
*/
enum tcp_estats_addrtype {
TCP_ESTATS_ADDRTYPE_IPV4 = 1 ,
TCP_ESTATS_ADDRTYPE_IPV6 = 2
};
enum tcp_estats_event_type {
TCP_ESTATS_ESTABLISH,
TCP_ESTATS_PERIODIC,
TCP_ESTATS_TIMEOUT,
TCP_ESTATS_RETRANSMIT_TIMEOUT,
TCP_ESTATS_RETRANSMIT_OTHER,
TCP_ESTATS_SYN_RETRANSMIT,
TCP_ESTATS_SYNACK_RETRANSMIT,
TCP_ESTATS_TERM,
TCP_ESTATS_TX_RESET,
TCP_ESTATS_RX_RESET,
TCP_ESTATS_WRITE_TIMEOUT,
TCP_ESTATS_CONN_TIMEOUT,
TCP_ESTATS_ACK_LATENCY,
TCP_ESTATS_NEVENTS,
};
struct tcp_estats_event {
int pid;
int cpu;
unsigned long ts;
unsigned int magic;
enum tcp_estats_event_type event_type;
};
/* The below data structure is packed in order for
* llvm compiler to generate expected code .
*/
struct tcp_estats_conn_id {
unsigned int localaddressType;
struct {
unsigned char data[16 ];
} localaddress;
struct {
unsigned char data[16 ];
} remaddress;
unsigned short localport;
unsigned short remport;
} __attribute__((__packed__));
struct tcp_estats_basic_event {
struct tcp_estats_event event;
struct tcp_estats_conn_id conn_id;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024 );
__type(key, __u32);
__type(value, struct tcp_estats_basic_event);
} ev_record_map SEC(".maps" );
struct dummy_tracepoint_args {
unsigned long long pad;
struct sock *sock;
};
static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
enum tcp_estats_event_type type)
{
event->magic = TCP_ESTATS_MAGIC;
event->ts = bpf_ktime_get_ns();
event->event_type = type;
}
static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
{
to[0 ] = _(from[0 ]);
to[1 ] = _(from[1 ]);
to[2 ] = _(from[2 ]);
to[3 ] = _(from[3 ]);
}
static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
__be32 *saddr, __be32 *daddr)
{
conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
}
static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
__be32 *saddr, __be32 *daddr)
{
conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
unaligned_u32_set(conn_id->localaddress.data + sizeof (__u32),
(__u8 *)(saddr + 1 ));
unaligned_u32_set(conn_id->localaddress.data + sizeof (__u32) * 2 ,
(__u8 *)(saddr + 2 ));
unaligned_u32_set(conn_id->localaddress.data + sizeof (__u32) * 3 ,
(__u8 *)(saddr + 3 ));
unaligned_u32_set(conn_id->remaddress.data,
(__u8 *)(daddr));
unaligned_u32_set(conn_id->remaddress.data + sizeof (__u32),
(__u8 *)(daddr + 1 ));
unaligned_u32_set(conn_id->remaddress.data + sizeof (__u32) * 2 ,
(__u8 *)(daddr + 2 ));
unaligned_u32_set(conn_id->remaddress.data + sizeof (__u32) * 3 ,
(__u8 *)(daddr + 3 ));
}
static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
struct sock *sk)
{
conn_id->localport = _(inet_sk(sk)->inet_sport);
conn_id->remport = _(inet_sk(sk)->inet_dport);
if (_(sk->sk_family) == AF_INET6)
conn_id_ipv6_init(conn_id,
sk->sk_v6_rcv_saddr.s6_addr32,
sk->sk_v6_daddr.s6_addr32);
else
conn_id_ipv4_init(conn_id,
&inet_sk(sk)->inet_saddr,
&inet_sk(sk)->inet_daddr);
}
static __always_inline void tcp_estats_init(struct sock *sk,
struct tcp_estats_event *event,
struct tcp_estats_conn_id *conn_id,
enum tcp_estats_event_type type)
{
tcp_estats_ev_init(event, type);
tcp_estats_conn_id_init(conn_id, sk);
}
static __always_inline void send_basic_event(struct sock *sk,
enum tcp_estats_event_type type)
{
struct tcp_estats_basic_event ev;
__u32 key = bpf_get_prandom_u32();
memset(&ev, 0 , sizeof (ev));
tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
}
SEC("tp/dummy/tracepoint" )
int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
{
if (!arg->sock)
return 0 ;
send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
return 0 ;
}
char _license[] SEC("license" ) = "GPL" ;
Messung V0.5 in Prozent C=99 H=100 G=99
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland