From c9b1964b55839a2369ee3946d9361ebe27a607d1 Mon Sep 17 00:00:00 2001 From: bitcoffee <854182924@qq.com> Date: Sun, 20 Nov 2022 02:17:09 +0800 Subject: [PATCH 1/3] net: Implements the rewriting function of PERMANENT protos. Currently, the PERMANENT proto can not override. It is difficult to some special processes, such as delaying network link setup. Add INET_PROTOSW_PERMANENT_OVERRIDE to allow users overide the PERMANENT protocol. Signed-off-by: bitcoffee --- include/net/protocol.h | 2 ++ net/ipv4/af_inet.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/net/protocol.h b/include/net/protocol.h index 2b778e1d2d8f..fcef3c7e4b5f 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -93,6 +93,8 @@ struct inet_protosw { #define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */ #define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */ #define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? */ +/* Allows hook rewriting for loaded protos */ +#define INET_PROTOSW_PERMANENT_OVERRIDE 0x08 extern struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS]; extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS]; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4629beccd2d4..a864e786a164 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1182,6 +1182,8 @@ void inet_register_protosw(struct inet_protosw *p) /* Check only the non-wild match. */ if ((INET_PROTOSW_PERMANENT & answer->flags) == 0) break; + if (p->flags & INET_PROTOSW_PERMANENT_OVERRIDE) + break; if (protocol == answer->protocol) goto out_permanent; last_perm = lh; -- Gitee From 46451f153af526ebb349d240ebbc5018c47c8e91 Mon Sep 17 00:00:00 2001 From: bitcoffee <854182924@qq.com> Date: Sun, 20 Nov 2022 02:17:53 +0800 Subject: [PATCH 2/3] net:Add a new mechanism for delaying link A new mechanism for delaying link establishment controlled by ebpf is introduced. The sendmsg and recvmsg hooks can be rewritten to trigger the ebp program and send the flag to the ebpf program for processing. Signed-off-by: bitcoffee --- include/net/inet_sock.h | 5 ++++- net/ipv4/tcp.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 91668b1cd3d1..f7314a771df1 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -240,10 +240,13 @@ struct inet_sock { nodefrag:1; __u8 bind_address_no_port:1, recverr_rfc4884:1, - defer_connect:1; /* Indicates that fastopen_connect is set + defer_connect:1, /* Indicates that fastopen_connect is set * and cookie exists so we defer connect * until first data frame is written */ + bpf_defer_connect:1; /* Use bpf to decide whether defer + * connect + */ __u8 rcv_tos; __u8 convert_csum; int uc_index; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f1e6a819502f..3e9db9be88c9 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -590,7 +590,8 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) if (tp->urg_data & TCP_URG_VALID) mask |= EPOLLPRI; - } else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) { + } else if (state == TCP_SYN_SENT && + (inet_sk(sk)->defer_connect || inet_sk(sk)->bpf_defer_connect)) { /* Active TCP fastopen socket with defer_connect * Return EPOLLOUT so application can call write() * in order for kernel to generate SYN+data -- Gitee From cb2193906763347711b3bbce3ceb8cce44c61478 Mon Sep 17 00:00:00 2001 From: bitcoffee <854182924@qq.com> Date: Sun, 20 Nov 2022 02:18:20 +0800 Subject: [PATCH 3/3] ebpf:Add some helpers for improving ebpf capabilities Thefollowing helpers are added to imporve the character processing capablity of the ebpf program: bpf_strchr bpf_strstr bpf_strcmp bpf_strcpy bpf_strnstr bpf_strlen Two new helper functions are added to enhance the parsing capability of the ebpf on the message. Signed-off-by: bitcoffee --- include/uapi/linux/bpf.h | 71 +++++++++++++++++++++++ kernel/bpf/helpers.c | 100 +++++++++++++++++++++++++++++++++ net/core/filter.c | 40 +++++++++++++ tools/include/uapi/linux/bpf.h | 71 +++++++++++++++++++++++ 4 files changed, 282 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index bd566bfc843f..4a6f6616ba9f 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3755,6 +3755,60 @@ union bpf_attr { * Get Ipv4 origdst or replysrc. Works with IPv4. * Return * 0 on success, or a negative error in case of failure. + * void *bpf_strch(void *src, int ch) + * Description + * Finds the first match of a given character `ch` in `src` + * Return + * Returns a pointer to the first occurrence of the character in the + * string, or NULL if the character does not exist in the string. + * + * void *bpf_strstr(void *src, void *tar) + * Description + * Finds the first match of a given string `tar` in `src` + * Return + * Returns a pointer to the first occurrence of string2 in string1, + * or NULL if the string2 does not exist in the string1. + * + * int bpf_strcmp(void *s1, void *s2) + * Description + * Compares two strings and returns an integer based on the comparison + * result. + * Return + * A negative number is returned when s1 < s2. + * Return value is 0 when s1 = s2. + * A positive number is returned when s1 > s2. + * + * int bpf_strcpy(char *dst, u32 dst_size, char *src) + * Description + * Copies a string that starts with the src address and ends with the + * NULL character to the address space that starts with dst. + * Return + * Returns a apointer to dst. + * + * char *bpf_strnstr(void *s1, void *s2, u32 size) + * Description + * Search for s2 in the first position character string os s1. + * Return + * If s2 exists, returns the position of s2 in s1. If s2 is not found, + * return NULL. + * + * int bpf_strlen(char *buff) + * Description + * Obtains the length of a character string. + * Return + * Length of the string. + * + * int bpf_parse_header_msg(struct bpf_mem_ptr *msg) + * Description + * Parses the content of the msg. User can use `parse_protocol_func` + * to define the parse function. + * Return + * User-defined return value. + * + * void *bpf_get_msg_header_element(char *name) + * Description + * Reads the content of the parsed msg. User can use + * `get_protocol_element_func` to define the content. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -3915,6 +3969,14 @@ union bpf_attr { FN(redirect_peer), \ FN(get_sockops_uid_gid), \ FN(sk_original_addr), \ + FN(strchr), \ + FN(strstr), \ + FN(strcmp), \ + FN(strcpy), \ + FN(strnstr), \ + FN(strlen), \ + FN(parse_header_msg), \ + FN(get_msg_header_element), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5051,6 +5113,15 @@ struct btf_ptr { __u32 flags; /* BTF ptr flags; unused at present. */ }; +/* + * struct bpf_mem_ptr is used for pointer to the memory. It records + * the location and length of the memory. + */ +struct bpf_mem_ptr { + void *ptr; + __u32 size; +}; + /* * Flags to control bpf_snprintf_btf() behaviour. * - BTF_F_COMPACT: no formatting around type information diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 4bb5921a7d21..b3b022910d1b 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -653,6 +653,94 @@ const struct bpf_func_proto bpf_this_cpu_ptr_proto = { .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, }; +BPF_CALL_2(bpf_strchr, void *, s, int, c) +{ + return strchr(s, c); +} + +const struct bpf_func_proto bpf_strchr_proto = { + .func = bpf_strchr, + .gpl_only = false, + .ret_type = RET_PTR_TO_ALLOC_MEM_OR_NULL, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, +}; + +BPF_CALL_2(bpf_strstr, void *, s1, void *, s2) +{ + return strstr(s1, s2); +} + +const struct bpf_func_proto bpf_strstr_proto = { + .func = bpf_strstr, + .gpl_only = false, + .ret_type = RET_PTR_TO_ALLOC_MEM_OR_NULL, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, +}; + +BPF_CALL_3(bpf_strnstr, void *, s1, void *, s2, size_t, len) +{ + return strnstr(s1, s2, len); +} + +const struct bpf_func_proto bpf_strnstr_proto = { + .func = bpf_strnstr, + .gpl_only = false, + .ret_type = RET_PTR_TO_ALLOC_MEM_OR_NULL, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, +}; + +BPF_CALL_2(bpf_strcmp, void *, str1, void *, str2) +{ + return strcmp(str1, str2); +} + +BPF_CALL_3(bpf_strcpy, void *, dst, u32, dst_size, void *, src) +{ + u32 src_size; + if (!dst || !src) + return -1; + + src_size = strlen(src) + 1; + if (src_size > dst_size) + return -1; + + (void)strcpy(dst, src); + return 0; +} + +const struct bpf_func_proto bpf_strcpy_proto = { + .func = bpf_strcpy, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, +}; + +BPF_CALL_1(bpf_strlen, void *, src) +{ + return strlen(src); +} + +const struct bpf_func_proto bpf_strlen_proto = { + .func = bpf_strlen, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, +}; + +const struct bpf_func_proto bpf_strcmp_proto = { + .func = bpf_strcmp, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; @@ -697,6 +785,18 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_ringbuf_discard_proto; case BPF_FUNC_ringbuf_query: return &bpf_ringbuf_query_proto; + case BPF_FUNC_strchr: + return &bpf_strchr_proto; + case BPF_FUNC_strstr: + return &bpf_strstr_proto; + case BPF_FUNC_strnstr: + return &bpf_strnstr_proto; + case BPF_FUNC_strcmp: + return &bpf_strcmp_proto; + case BPF_FUNC_strcpy: + return &bpf_strcpy_proto; + case BPF_FUNC_strlen: + return &bpf_strlen_proto; default: break; } diff --git a/net/core/filter.c b/net/core/filter.c index 23b6820a2e28..7a27196ffd19 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6964,6 +6964,42 @@ static const struct bpf_func_proto bpf_sock_ops_reserve_hdr_opt_proto = { .arg3_type = ARG_ANYTHING, }; +typedef u32 (*bpf_parse_protocol_func)(struct bpf_mem_ptr* msg); +bpf_parse_protocol_func parse_protocol_func = NULL; +EXPORT_SYMBOL(parse_protocol_func); + +typedef struct bpf_mem_ptr* (*bpf_get_protocol_element_func)(char *key); +bpf_get_protocol_element_func get_protocol_element_func = NULL; +EXPORT_SYMBOL(get_protocol_element_func); + +BPF_CALL_1(bpf_parse_header_msg, struct bpf_mem_ptr *, msg) +{ + if (!parse_protocol_func) + return -ENOTSUPP; + return parse_protocol_func(msg); +} + +static const struct bpf_func_proto bpf_parse_header_msg_proto = { + .func = bpf_parse_header_msg, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, +}; + +BPF_CALL_1(bpf_get_msg_header_element, char *, key) +{ + if (!get_protocol_element_func) + return -ENOTSUPP; + return get_protocol_element_func(key); +} + +static const struct bpf_func_proto bpf_get_msg_header_element_proto = { + .func = bpf_get_msg_header_element, + .gpl_only = true, + .ret_type = RET_PTR_TO_ALLOC_MEM_OR_NULL, + .arg1_type = ARG_ANYTHING, +}; + #endif /* CONFIG_INET */ bool bpf_helper_changes_pkt_data(void *func) @@ -7392,6 +7428,10 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_sock_ops_reserve_hdr_opt_proto; case BPF_FUNC_tcp_sock: return &bpf_tcp_sock_proto; + case BPF_FUNC_parse_header_msg: + return &bpf_parse_header_msg_proto; + case BPF_FUNC_get_msg_header_element: + return &bpf_get_msg_header_element_proto; #endif /* CONFIG_INET */ default: return bpf_sk_base_func_proto(func_id); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4af3661414fa..4d1e0742f6f1 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3755,6 +3755,60 @@ union bpf_attr { * Get Ipv4 origdst or replysrc. Works with IPv4. * Return * 0 on success, or a negative error in case of failure. + * void *bpf_strch(void *src, int ch) + * Description + * Finds the first match of a given character `ch` in `src` + * Return + * Returns a pointer to the first occurrence of the character in the + * string, or NULL if the character does not exist in the string. + * + * void *bpf_strstr(void *src, void *tar) + * Description + * Finds the first match of a given string `tar` in `src` + * Return + * Returns a pointer to the first occurrence of string2 in string1, + * or NULL if the string2 does not exist in the string1. + * + * int bpf_strcmp(void *s1, void *s2) + * Description + * Compares two strings and returns an integer based on the comparison + * result. + * Return + * A negative number is returned when s1 < s2. + * Return value is 0 when s1 = s2. + * A positive number is returned when s1 > s2. + * + * int bpf_strcpy(char *dst, u32 dst_size, char *src) + * Description + * Copies a string that starts with the src address and ends with the + * NULL character to the address space that starts with dst. + * Return + * Returns a apointer to dst. + * + * char *bpf_strnstr(void *s1, void *s2, u32 size) + * Description + * Search for s2 in the first position character string os s1. + * Return + * If s2 exists, returns the position of s2 in s1. If s2 is not found, + * return NULL. + * + * int bpf_strlen(char *buff) + * Description + * Obtains the length of a character string. + * Return + * Length of the string. + * + * int bpf_parse_header_msg(struct bpf_mem_ptr *msg) + * Description + * Parses the content of the msg. User can use `parse_protocol_func` + * to define the parse function. + * Return + * User-defined return value. + * + * void *bpf_get_msg_header_element(char *name) + * Description + * Reads the content of the parsed msg. User can use + * `get_protocol_element_func` to define the content. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -3915,6 +3969,14 @@ union bpf_attr { FN(redirect_peer), \ FN(get_sockops_uid_gid), \ FN(sk_original_addr), \ + FN(strchr), \ + FN(strstr), \ + FN(strcmp), \ + FN(strcpy), \ + FN(strnstr), \ + FN(strlen), \ + FN(parse_header_msg), \ + FN(get_msg_header_element), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -5051,6 +5113,15 @@ struct btf_ptr { __u32 flags; /* BTF ptr flags; unused at present. */ }; +/* + * struct bpf_mem_ptr is used for pointer to the memory. It records + * the location and length of the memory. + */ +struct bpf_mem_ptr { + void *ptr; + __u32 size; +}; + /* * Flags to control bpf_snprintf_btf() behaviour. * - BTF_F_COMPACT: no formatting around type information -- Gitee