Commit cd86d1fd authored by Lawrence Brakmo's avatar Lawrence Brakmo Committed by David S. Miller

bpf: Adding helper function bpf_getsockops

Adding support for helper function bpf_getsockops to socket_ops BPF
programs. This patch only supports TCP_CONGESTION.
Signed-off-by: default avatarVlad Vysotsky <vlad@cs.ucla.edu>
Acked-by: default avatarLawrence Brakmo <brakmo@fb.com>
Acked-by: default avatarAlexei Starovoitov <ast@fb.com>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e6546ef6
...@@ -613,12 +613,22 @@ union bpf_attr { ...@@ -613,12 +613,22 @@ union bpf_attr {
* int bpf_setsockopt(bpf_socket, level, optname, optval, optlen) * int bpf_setsockopt(bpf_socket, level, optname, optval, optlen)
* Calls setsockopt. Not all opts are available, only those with * Calls setsockopt. Not all opts are available, only those with
* integer optvals plus TCP_CONGESTION. * integer optvals plus TCP_CONGESTION.
* Supported levels: SOL_SOCKET and IPROTO_TCP * Supported levels: SOL_SOCKET and IPPROTO_TCP
* @bpf_socket: pointer to bpf_socket * @bpf_socket: pointer to bpf_socket
* @level: SOL_SOCKET or IPROTO_TCP * @level: SOL_SOCKET or IPPROTO_TCP
* @optname: option name * @optname: option name
* @optval: pointer to option value * @optval: pointer to option value
* @optlen: length of optval in byes * @optlen: length of optval in bytes
* Return: 0 or negative error
*
* int bpf_getsockopt(bpf_socket, level, optname, optval, optlen)
* Calls getsockopt. Not all opts are available.
* Supported levels: IPPROTO_TCP
* @bpf_socket: pointer to bpf_socket
* @level: IPPROTO_TCP
* @optname: option name
* @optval: pointer to option value
* @optlen: length of optval in bytes
* Return: 0 or negative error * Return: 0 or negative error
* *
* int bpf_skb_adjust_room(skb, len_diff, mode, flags) * int bpf_skb_adjust_room(skb, len_diff, mode, flags)
...@@ -721,7 +731,8 @@ union bpf_attr { ...@@ -721,7 +731,8 @@ union bpf_attr {
FN(sock_map_update), \ FN(sock_map_update), \
FN(xdp_adjust_meta), \ FN(xdp_adjust_meta), \
FN(perf_event_read_value), \ FN(perf_event_read_value), \
FN(perf_prog_read_value), FN(perf_prog_read_value), \
FN(getsockopt),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
...@@ -3273,7 +3273,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, ...@@ -3273,7 +3273,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
static const struct bpf_func_proto bpf_setsockopt_proto = { static const struct bpf_func_proto bpf_setsockopt_proto = {
.func = bpf_setsockopt, .func = bpf_setsockopt,
.gpl_only = true, .gpl_only = false,
.ret_type = RET_INTEGER, .ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX, .arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING, .arg2_type = ARG_ANYTHING,
...@@ -3282,6 +3282,48 @@ static const struct bpf_func_proto bpf_setsockopt_proto = { ...@@ -3282,6 +3282,48 @@ static const struct bpf_func_proto bpf_setsockopt_proto = {
.arg5_type = ARG_CONST_SIZE, .arg5_type = ARG_CONST_SIZE,
}; };
BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock,
int, level, int, optname, char *, optval, int, optlen)
{
struct sock *sk = bpf_sock->sk;
int ret = 0;
if (!sk_fullsock(sk))
goto err_clear;
#ifdef CONFIG_INET
if (level == SOL_TCP && sk->sk_prot->getsockopt == tcp_getsockopt) {
if (optname == TCP_CONGESTION) {
struct inet_connection_sock *icsk = inet_csk(sk);
if (!icsk->icsk_ca_ops || optlen <= 1)
goto err_clear;
strncpy(optval, icsk->icsk_ca_ops->name, optlen);
optval[optlen - 1] = 0;
} else {
goto err_clear;
}
} else {
goto err_clear;
}
return ret;
#endif
err_clear:
memset(optval, 0, optlen);
return -EINVAL;
}
static const struct bpf_func_proto bpf_getsockopt_proto = {
.func = bpf_getsockopt,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
.arg3_type = ARG_ANYTHING,
.arg4_type = ARG_PTR_TO_UNINIT_MEM,
.arg5_type = ARG_CONST_SIZE,
};
static const struct bpf_func_proto * static const struct bpf_func_proto *
bpf_base_func_proto(enum bpf_func_id func_id) bpf_base_func_proto(enum bpf_func_id func_id)
{ {
...@@ -3460,6 +3502,8 @@ static const struct bpf_func_proto * ...@@ -3460,6 +3502,8 @@ static const struct bpf_func_proto *
switch (func_id) { switch (func_id) {
case BPF_FUNC_setsockopt: case BPF_FUNC_setsockopt:
return &bpf_setsockopt_proto; return &bpf_setsockopt_proto;
case BPF_FUNC_getsockopt:
return &bpf_getsockopt_proto;
case BPF_FUNC_sock_map_update: case BPF_FUNC_sock_map_update:
return &bpf_sock_map_update_proto; return &bpf_sock_map_update_proto;
default: default:
......
...@@ -67,6 +67,9 @@ static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = ...@@ -67,6 +67,9 @@ static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
int optlen) = int optlen) =
(void *) BPF_FUNC_setsockopt; (void *) BPF_FUNC_setsockopt;
static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval,
int optlen) =
(void *) BPF_FUNC_getsockopt;
static int (*bpf_sk_redirect_map)(void *map, int key, int flags) = static int (*bpf_sk_redirect_map)(void *map, int key, int flags) =
(void *) BPF_FUNC_sk_redirect_map; (void *) BPF_FUNC_sk_redirect_map;
static int (*bpf_sock_map_update)(void *map, void *key, void *value, static int (*bpf_sock_map_update)(void *map, void *key, void *value,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment