2020-08-20 12:01:17 -07:00
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2020 Facebook */
# ifndef _TEST_TCP_HDR_OPTIONS_H
# define _TEST_TCP_HDR_OPTIONS_H
struct bpf_test_option {
__u8 flags ;
__u8 max_delack_ms ;
__u8 rand ;
} __attribute__ ( ( packed ) ) ;
enum {
OPTION_RESEND ,
OPTION_MAX_DELACK_MS ,
OPTION_RAND ,
__NR_OPTION_FLAGS ,
} ;
# define OPTION_F_RESEND (1 << OPTION_RESEND)
# define OPTION_F_MAX_DELACK_MS (1 << OPTION_MAX_DELACK_MS)
# define OPTION_F_RAND (1 << OPTION_RAND)
# define OPTION_MASK ((1 << __NR_OPTION_FLAGS) - 1)
# define TEST_OPTION_FLAGS(flags, option) (1 & ((flags) >> (option)))
# define SET_OPTION_FLAGS(flags, option) ((flags) |= (1 << (option)))
/* Store in bpf_sk_storage */
struct hdr_stg {
bool active ;
bool resend_syn ; /* active side only */
bool syncookie ; /* passive side only */
bool fastopen ; /* passive side only */
} ;
struct linum_err {
unsigned int linum ;
int err ;
} ;
# define TCPHDR_FIN 0x01
# define TCPHDR_SYN 0x02
# define TCPHDR_RST 0x04
# define TCPHDR_PSH 0x08
# define TCPHDR_ACK 0x10
# define TCPHDR_URG 0x20
# define TCPHDR_ECE 0x40
# define TCPHDR_CWR 0x80
# define TCPHDR_SYNACK (TCPHDR_SYN | TCPHDR_ACK)
# define TCPOPT_EOL 0
# define TCPOPT_NOP 1
selftests/bpf: tests for using dynptrs to parse skb and xdp buffers
Test skb and xdp dynptr functionality in the following ways:
1) progs/test_cls_redirect_dynptr.c
* Rewrite "progs/test_cls_redirect.c" test to use dynptrs to parse
skb data
* This is a great example of how dynptrs can be used to simplify a
lot of the parsing logic for non-statically known values.
When measuring the user + system time between the original version
vs. using dynptrs, and averaging the time for 10 runs (using
"time ./test_progs -t cls_redirect"):
original version: 0.092 sec
with dynptrs: 0.078 sec
2) progs/test_xdp_dynptr.c
* Rewrite "progs/test_xdp.c" test to use dynptrs to parse xdp data
When measuring the user + system time between the original version
vs. using dynptrs, and averaging the time for 10 runs (using
"time ./test_progs -t xdp_attach"):
original version: 0.118 sec
with dynptrs: 0.094 sec
3) progs/test_l4lb_noinline_dynptr.c
* Rewrite "progs/test_l4lb_noinline.c" test to use dynptrs to parse
skb data
When measuring the user + system time between the original version
vs. using dynptrs, and averaging the time for 10 runs (using
"time ./test_progs -t l4lb_all"):
original version: 0.062 sec
with dynptrs: 0.081 sec
For number of processed verifier instructions:
original version: 6268 insns
with dynptrs: 2588 insns
4) progs/test_parse_tcp_hdr_opt_dynptr.c
* Add sample code for parsing tcp hdr opt lookup using dynptrs.
This logic is lifted from a real-world use case of packet parsing
in katran [0], a layer 4 load balancer. The original version
"progs/test_parse_tcp_hdr_opt.c" (not using dynptrs) is included
here as well, for comparison.
When measuring the user + system time between the original version
vs. using dynptrs, and averaging the time for 10 runs (using
"time ./test_progs -t parse_tcp_hdr_opt"):
original version: 0.031 sec
with dynptrs: 0.045 sec
5) progs/dynptr_success.c
* Add test case "test_skb_readonly" for testing attempts at writes
on a prog type with read-only skb ctx.
* Add "test_dynptr_skb_data" for testing that bpf_dynptr_data isn't
supported for skb progs.
6) progs/dynptr_fail.c
* Add test cases "skb_invalid_data_slice{1,2,3,4}" and
"xdp_invalid_data_slice{1,2}" for testing that helpers that modify the
underlying packet buffer automatically invalidate the associated
data slice.
* Add test cases "skb_invalid_ctx" and "xdp_invalid_ctx" for testing
that prog types that do not support bpf_dynptr_from_skb/xdp don't
have access to the API.
* Add test case "dynptr_slice_var_len{1,2}" for testing that
variable-sized len can't be passed in to bpf_dynptr_slice
* Add test case "skb_invalid_slice_write" for testing that writes to a
read-only data slice are rejected by the verifier.
* Add test case "data_slice_out_of_bounds_skb" for testing that
writes to an area outside the slice are rejected.
* Add test case "invalid_slice_rdwr_rdonly" for testing that prog
types that don't allow writes to packet data don't accept any calls
to bpf_dynptr_slice_rdwr.
[0] https://github.com/facebookincubator/katran/blob/main/katran/lib/bpf/pckt_parsing.h
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230301154953.641654-11-joannelkoong@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-01 07:49:53 -08:00
# define TCPOPT_MSS 2
2020-08-20 12:01:17 -07:00
# define TCPOPT_WINDOW 3
# define TCPOPT_EXP 254
# define TCP_BPF_EXPOPT_BASE_LEN 4
# define MAX_TCP_HDR_LEN 60
# define MAX_TCP_OPTION_SPACE 40
# ifdef BPF_PROG_TEST_TCP_HDR_OPTIONS
# define CG_OK 1
# define CG_ERR 0
# ifndef SOL_TCP
# define SOL_TCP 6
# endif
struct tcp_exprm_opt {
__u8 kind ;
__u8 len ;
__u16 magic ;
union {
__u8 data [ 4 ] ;
__u32 data32 ;
} ;
} __attribute__ ( ( packed ) ) ;
struct tcp_opt {
__u8 kind ;
__u8 len ;
union {
__u8 data [ 4 ] ;
__u32 data32 ;
} ;
} __attribute__ ( ( packed ) ) ;
struct {
__uint ( type , BPF_MAP_TYPE_HASH ) ;
__uint ( max_entries , 2 ) ;
__type ( key , int ) ;
__type ( value , struct linum_err ) ;
} lport_linum_map SEC ( " .maps " ) ;
static inline unsigned int tcp_hdrlen ( const struct tcphdr * th )
{
return th - > doff < < 2 ;
}
static inline __u8 skops_tcp_flags ( const struct bpf_sock_ops * skops )
{
return skops - > skb_tcp_flags ;
}
static inline void clear_hdr_cb_flags ( struct bpf_sock_ops * skops )
{
bpf_sock_ops_cb_flags_set ( skops ,
skops - > bpf_sock_ops_cb_flags &
~ ( BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG ) ) ;
}
2020-10-01 18:34:54 -07:00
static inline void set_hdr_cb_flags ( struct bpf_sock_ops * skops , __u32 extra )
2020-08-20 12:01:17 -07:00
{
bpf_sock_ops_cb_flags_set ( skops ,
skops - > bpf_sock_ops_cb_flags |
BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
2020-10-01 18:34:54 -07:00
BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
extra ) ;
2020-08-20 12:01:17 -07:00
}
static inline void
clear_parse_all_hdr_cb_flags ( struct bpf_sock_ops * skops )
{
bpf_sock_ops_cb_flags_set ( skops ,
skops - > bpf_sock_ops_cb_flags &
~ BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG ) ;
}
static inline void
set_parse_all_hdr_cb_flags ( struct bpf_sock_ops * skops )
{
bpf_sock_ops_cb_flags_set ( skops ,
skops - > bpf_sock_ops_cb_flags |
BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG ) ;
}
# define RET_CG_ERR(__err) ({ \
struct linum_err __linum_err ; \
int __lport ; \
\
__linum_err . linum = __LINE__ ; \
__linum_err . err = __err ; \
__lport = skops - > local_port ; \
bpf_map_update_elem ( & lport_linum_map , & __lport , & __linum_err , BPF_NOEXIST ) ; \
clear_hdr_cb_flags ( skops ) ; \
clear_parse_all_hdr_cb_flags ( skops ) ; \
return CG_ERR ; \
} )
# endif /* BPF_PROG_TEST_TCP_HDR_OPTIONS */
# endif /* _TEST_TCP_HDR_OPTIONS_H */