Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says: ==================== pull-request: bpf 2021-06-23 The following pull-request contains BPF updates for your *net* tree. We've added 14 non-merge commits during the last 6 day(s) which contain a total of 13 files changed, 137 insertions(+), 64 deletions(-). Note that when you merge net into net-next, there is a small merge conflict between9f2470fbc4("skmsg: Improve udp_bpf_recvmsg() accuracy") from bpf withc49661aa6f("skmsg: Remove unused parameters of sk_msg_wait_data()") from net-next. Resolution is to: i) net/ipv4/udp_bpf.c: take udp_msg_wait_data() and remove err parameter from the function, ii) net/ipv4/tcp_bpf.c: take tcp_msg_wait_data() and remove err parameter from the function, iii) for net/core/skmsg.c and include/linux/skmsg.h: remove the sk_msg_wait_data() implementation and its prototype in header. The main changes are: 1) Fix BPF poke descriptor adjustments after insn rewrite, from John Fastabend. 2) Fix regression when using BPF_OBJ_GET with non-O_RDWR flags, from Maciej Żenczykowski. 3) Various bug and error handling fixes for UDP-related sock_map, from Cong Wang. 4) Fix patching of vmlinux BTF IDs with correct endianness, from Tony Ambardar. 5) Two fixes for TX descriptor validation in AF_XDP, from Magnus Karlsson. 6) Fix overflow in size calculation for bpf_map_area_alloc(), from Bui Quang Minh. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -126,8 +126,6 @@ int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from,
|
|||||||
struct sk_msg *msg, u32 bytes);
|
struct sk_msg *msg, u32 bytes);
|
||||||
int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
|
int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
|
||||||
struct sk_msg *msg, u32 bytes);
|
struct sk_msg *msg, u32 bytes);
|
||||||
int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags,
|
|
||||||
long timeo, int *err);
|
|
||||||
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
||||||
int len, int flags);
|
int len, int flags);
|
||||||
|
|
||||||
|
|||||||
@@ -147,11 +147,16 @@ static inline bool xp_desc_crosses_non_contig_pg(struct xsk_buff_pool *pool,
|
|||||||
{
|
{
|
||||||
bool cross_pg = (addr & (PAGE_SIZE - 1)) + len > PAGE_SIZE;
|
bool cross_pg = (addr & (PAGE_SIZE - 1)) + len > PAGE_SIZE;
|
||||||
|
|
||||||
if (pool->dma_pages_cnt && cross_pg) {
|
if (likely(!cross_pg))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pool->dma_pages_cnt) {
|
||||||
return !(pool->dma_pages[addr >> PAGE_SHIFT] &
|
return !(pool->dma_pages[addr >> PAGE_SHIFT] &
|
||||||
XSK_NEXT_PG_CONTIG_MASK);
|
XSK_NEXT_PG_CONTIG_MASK);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
/* skb path */
|
||||||
|
return addr + len > pool->addrs_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 xp_aligned_extract_addr(struct xsk_buff_pool *pool, u64 addr)
|
static inline u64 xp_aligned_extract_addr(struct xsk_buff_pool *pool, u64 addr)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ static struct hlist_head *dev_map_create_hash(unsigned int entries,
|
|||||||
int i;
|
int i;
|
||||||
struct hlist_head *hash;
|
struct hlist_head *hash;
|
||||||
|
|
||||||
hash = bpf_map_area_alloc(entries * sizeof(*hash), numa_node);
|
hash = bpf_map_area_alloc((u64) entries * sizeof(*hash), numa_node);
|
||||||
if (hash != NULL)
|
if (hash != NULL)
|
||||||
for (i = 0; i < entries; i++)
|
for (i = 0; i < entries; i++)
|
||||||
INIT_HLIST_HEAD(&hash[i]);
|
INIT_HLIST_HEAD(&hash[i]);
|
||||||
@@ -143,7 +143,7 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
|
|||||||
|
|
||||||
spin_lock_init(&dtab->index_lock);
|
spin_lock_init(&dtab->index_lock);
|
||||||
} else {
|
} else {
|
||||||
dtab->netdev_map = bpf_map_area_alloc(dtab->map.max_entries *
|
dtab->netdev_map = bpf_map_area_alloc((u64) dtab->map.max_entries *
|
||||||
sizeof(struct bpf_dtab_netdev *),
|
sizeof(struct bpf_dtab_netdev *),
|
||||||
dtab->map.numa_node);
|
dtab->map.numa_node);
|
||||||
if (!dtab->netdev_map)
|
if (!dtab->netdev_map)
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
|
|||||||
return PTR_ERR(raw);
|
return PTR_ERR(raw);
|
||||||
|
|
||||||
if (type == BPF_TYPE_PROG)
|
if (type == BPF_TYPE_PROG)
|
||||||
ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
|
ret = bpf_prog_new_fd(raw);
|
||||||
else if (type == BPF_TYPE_MAP)
|
else if (type == BPF_TYPE_MAP)
|
||||||
ret = bpf_map_new_fd(raw, f_flags);
|
ret = bpf_map_new_fd(raw, f_flags);
|
||||||
else if (type == BPF_TYPE_LINK)
|
else if (type == BPF_TYPE_LINK)
|
||||||
|
|||||||
@@ -11459,7 +11459,7 @@ static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adjust_poke_descs(struct bpf_prog *prog, u32 len)
|
static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
|
||||||
{
|
{
|
||||||
struct bpf_jit_poke_descriptor *tab = prog->aux->poke_tab;
|
struct bpf_jit_poke_descriptor *tab = prog->aux->poke_tab;
|
||||||
int i, sz = prog->aux->size_poke_tab;
|
int i, sz = prog->aux->size_poke_tab;
|
||||||
@@ -11467,6 +11467,8 @@ static void adjust_poke_descs(struct bpf_prog *prog, u32 len)
|
|||||||
|
|
||||||
for (i = 0; i < sz; i++) {
|
for (i = 0; i < sz; i++) {
|
||||||
desc = &tab[i];
|
desc = &tab[i];
|
||||||
|
if (desc->insn_idx <= off)
|
||||||
|
continue;
|
||||||
desc->insn_idx += len - 1;
|
desc->insn_idx += len - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11487,7 +11489,7 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
|
|||||||
if (adjust_insn_aux_data(env, new_prog, off, len))
|
if (adjust_insn_aux_data(env, new_prog, off, len))
|
||||||
return NULL;
|
return NULL;
|
||||||
adjust_subprog_starts(env, off, len);
|
adjust_subprog_starts(env, off, len);
|
||||||
adjust_poke_descs(new_prog, len);
|
adjust_poke_descs(new_prog, off, len);
|
||||||
return new_prog;
|
return new_prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -399,29 +399,6 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter);
|
EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter);
|
||||||
|
|
||||||
int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags,
|
|
||||||
long timeo, int *err)
|
|
||||||
{
|
|
||||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!timeo)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
add_wait_queue(sk_sleep(sk), &wait);
|
|
||||||
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
|
||||||
ret = sk_wait_event(sk, &timeo,
|
|
||||||
!list_empty(&psock->ingress_msg) ||
|
|
||||||
!skb_queue_empty(&sk->sk_receive_queue), &wait);
|
|
||||||
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
|
||||||
remove_wait_queue(sk_sleep(sk), &wait);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(sk_msg_wait_data);
|
|
||||||
|
|
||||||
/* Receive sk_msg from psock->ingress_msg to @msg. */
|
/* Receive sk_msg from psock->ingress_msg to @msg. */
|
||||||
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
||||||
int len, int flags)
|
int len, int flags)
|
||||||
@@ -601,6 +578,12 @@ static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
|
|||||||
return sk_psock_skb_ingress(psock, skb);
|
return sk_psock_skb_ingress(psock, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sock_drop(struct sock *sk, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
sk_drops_add(sk, skb);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
static void sk_psock_backlog(struct work_struct *work)
|
static void sk_psock_backlog(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct sk_psock *psock = container_of(work, struct sk_psock, work);
|
struct sk_psock *psock = container_of(work, struct sk_psock, work);
|
||||||
@@ -640,7 +623,7 @@ start:
|
|||||||
/* Hard errors break pipe and stop xmit. */
|
/* Hard errors break pipe and stop xmit. */
|
||||||
sk_psock_report_error(psock, ret ? -ret : EPIPE);
|
sk_psock_report_error(psock, ret ? -ret : EPIPE);
|
||||||
sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
|
sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
|
||||||
kfree_skb(skb);
|
sock_drop(psock->sk, skb);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
off += ret;
|
off += ret;
|
||||||
@@ -731,7 +714,7 @@ static void __sk_psock_zap_ingress(struct sk_psock *psock)
|
|||||||
|
|
||||||
while ((skb = skb_dequeue(&psock->ingress_skb)) != NULL) {
|
while ((skb = skb_dequeue(&psock->ingress_skb)) != NULL) {
|
||||||
skb_bpf_redirect_clear(skb);
|
skb_bpf_redirect_clear(skb);
|
||||||
kfree_skb(skb);
|
sock_drop(psock->sk, skb);
|
||||||
}
|
}
|
||||||
__sk_psock_purge_ingress_msg(psock);
|
__sk_psock_purge_ingress_msg(psock);
|
||||||
}
|
}
|
||||||
@@ -847,7 +830,7 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sk_psock_msg_verdict);
|
EXPORT_SYMBOL_GPL(sk_psock_msg_verdict);
|
||||||
|
|
||||||
static void sk_psock_skb_redirect(struct sk_buff *skb)
|
static int sk_psock_skb_redirect(struct sk_psock *from, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct sk_psock *psock_other;
|
struct sk_psock *psock_other;
|
||||||
struct sock *sk_other;
|
struct sock *sk_other;
|
||||||
@@ -857,8 +840,8 @@ static void sk_psock_skb_redirect(struct sk_buff *skb)
|
|||||||
* return code, but then didn't set a redirect interface.
|
* return code, but then didn't set a redirect interface.
|
||||||
*/
|
*/
|
||||||
if (unlikely(!sk_other)) {
|
if (unlikely(!sk_other)) {
|
||||||
kfree_skb(skb);
|
sock_drop(from->sk, skb);
|
||||||
return;
|
return -EIO;
|
||||||
}
|
}
|
||||||
psock_other = sk_psock(sk_other);
|
psock_other = sk_psock(sk_other);
|
||||||
/* This error indicates the socket is being torn down or had another
|
/* This error indicates the socket is being torn down or had another
|
||||||
@@ -866,26 +849,30 @@ static void sk_psock_skb_redirect(struct sk_buff *skb)
|
|||||||
* a socket that is in this state so we drop the skb.
|
* a socket that is in this state so we drop the skb.
|
||||||
*/
|
*/
|
||||||
if (!psock_other || sock_flag(sk_other, SOCK_DEAD)) {
|
if (!psock_other || sock_flag(sk_other, SOCK_DEAD)) {
|
||||||
kfree_skb(skb);
|
skb_bpf_redirect_clear(skb);
|
||||||
return;
|
sock_drop(from->sk, skb);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
spin_lock_bh(&psock_other->ingress_lock);
|
spin_lock_bh(&psock_other->ingress_lock);
|
||||||
if (!sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) {
|
if (!sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) {
|
||||||
spin_unlock_bh(&psock_other->ingress_lock);
|
spin_unlock_bh(&psock_other->ingress_lock);
|
||||||
kfree_skb(skb);
|
skb_bpf_redirect_clear(skb);
|
||||||
return;
|
sock_drop(from->sk, skb);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_queue_tail(&psock_other->ingress_skb, skb);
|
skb_queue_tail(&psock_other->ingress_skb, skb);
|
||||||
schedule_work(&psock_other->work);
|
schedule_work(&psock_other->work);
|
||||||
spin_unlock_bh(&psock_other->ingress_lock);
|
spin_unlock_bh(&psock_other->ingress_lock);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sk_psock_tls_verdict_apply(struct sk_buff *skb, struct sock *sk, int verdict)
|
static void sk_psock_tls_verdict_apply(struct sk_buff *skb,
|
||||||
|
struct sk_psock *from, int verdict)
|
||||||
{
|
{
|
||||||
switch (verdict) {
|
switch (verdict) {
|
||||||
case __SK_REDIRECT:
|
case __SK_REDIRECT:
|
||||||
sk_psock_skb_redirect(skb);
|
sk_psock_skb_redirect(from, skb);
|
||||||
break;
|
break;
|
||||||
case __SK_PASS:
|
case __SK_PASS:
|
||||||
case __SK_DROP:
|
case __SK_DROP:
|
||||||
@@ -909,20 +896,21 @@ int sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb)
|
|||||||
ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
|
ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
|
||||||
skb->sk = NULL;
|
skb->sk = NULL;
|
||||||
}
|
}
|
||||||
sk_psock_tls_verdict_apply(skb, psock->sk, ret);
|
sk_psock_tls_verdict_apply(skb, psock, ret);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sk_psock_tls_strp_read);
|
EXPORT_SYMBOL_GPL(sk_psock_tls_strp_read);
|
||||||
|
|
||||||
static void sk_psock_verdict_apply(struct sk_psock *psock,
|
static int sk_psock_verdict_apply(struct sk_psock *psock, struct sk_buff *skb,
|
||||||
struct sk_buff *skb, int verdict)
|
int verdict)
|
||||||
{
|
{
|
||||||
struct sock *sk_other;
|
struct sock *sk_other;
|
||||||
int err = -EIO;
|
int err = 0;
|
||||||
|
|
||||||
switch (verdict) {
|
switch (verdict) {
|
||||||
case __SK_PASS:
|
case __SK_PASS:
|
||||||
|
err = -EIO;
|
||||||
sk_other = psock->sk;
|
sk_other = psock->sk;
|
||||||
if (sock_flag(sk_other, SOCK_DEAD) ||
|
if (sock_flag(sk_other, SOCK_DEAD) ||
|
||||||
!sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
|
!sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
|
||||||
@@ -945,18 +933,25 @@ static void sk_psock_verdict_apply(struct sk_psock *psock,
|
|||||||
if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
|
if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
|
||||||
skb_queue_tail(&psock->ingress_skb, skb);
|
skb_queue_tail(&psock->ingress_skb, skb);
|
||||||
schedule_work(&psock->work);
|
schedule_work(&psock->work);
|
||||||
|
err = 0;
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&psock->ingress_lock);
|
spin_unlock_bh(&psock->ingress_lock);
|
||||||
|
if (err < 0) {
|
||||||
|
skb_bpf_redirect_clear(skb);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case __SK_REDIRECT:
|
case __SK_REDIRECT:
|
||||||
sk_psock_skb_redirect(skb);
|
err = sk_psock_skb_redirect(psock, skb);
|
||||||
break;
|
break;
|
||||||
case __SK_DROP:
|
case __SK_DROP:
|
||||||
default:
|
default:
|
||||||
out_free:
|
out_free:
|
||||||
kfree_skb(skb);
|
sock_drop(psock->sk, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sk_psock_write_space(struct sock *sk)
|
static void sk_psock_write_space(struct sock *sk)
|
||||||
@@ -988,7 +983,7 @@ static void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb)
|
|||||||
sk = strp->sk;
|
sk = strp->sk;
|
||||||
psock = sk_psock(sk);
|
psock = sk_psock(sk);
|
||||||
if (unlikely(!psock)) {
|
if (unlikely(!psock)) {
|
||||||
kfree_skb(skb);
|
sock_drop(sk, skb);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
prog = READ_ONCE(psock->progs.stream_verdict);
|
prog = READ_ONCE(psock->progs.stream_verdict);
|
||||||
@@ -1109,7 +1104,7 @@ static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb,
|
|||||||
psock = sk_psock(sk);
|
psock = sk_psock(sk);
|
||||||
if (unlikely(!psock)) {
|
if (unlikely(!psock)) {
|
||||||
len = 0;
|
len = 0;
|
||||||
kfree_skb(skb);
|
sock_drop(sk, skb);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
prog = READ_ONCE(psock->progs.stream_verdict);
|
prog = READ_ONCE(psock->progs.stream_verdict);
|
||||||
@@ -1123,7 +1118,8 @@ static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb,
|
|||||||
ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
|
ret = sk_psock_map_verd(ret, skb_bpf_redirect_fetch(skb));
|
||||||
skb->sk = NULL;
|
skb->sk = NULL;
|
||||||
}
|
}
|
||||||
sk_psock_verdict_apply(psock, skb, ret);
|
if (sk_psock_verdict_apply(psock, skb, ret) < 0)
|
||||||
|
len = 0;
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return len;
|
return len;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
|
|||||||
bpf_map_init_from_attr(&stab->map, attr);
|
bpf_map_init_from_attr(&stab->map, attr);
|
||||||
raw_spin_lock_init(&stab->lock);
|
raw_spin_lock_init(&stab->lock);
|
||||||
|
|
||||||
stab->sks = bpf_map_area_alloc(stab->map.max_entries *
|
stab->sks = bpf_map_area_alloc((u64) stab->map.max_entries *
|
||||||
sizeof(struct sock *),
|
sizeof(struct sock *),
|
||||||
stab->map.numa_node);
|
stab->map.numa_node);
|
||||||
if (!stab->sks) {
|
if (!stab->sks) {
|
||||||
|
|||||||
@@ -163,6 +163,28 @@ static bool tcp_bpf_stream_read(const struct sock *sk)
|
|||||||
return !empty;
|
return !empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags,
|
||||||
|
long timeo, int *err)
|
||||||
|
{
|
||||||
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!timeo)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
add_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||||
|
ret = sk_wait_event(sk, &timeo,
|
||||||
|
!list_empty(&psock->ingress_msg) ||
|
||||||
|
!skb_queue_empty(&sk->sk_receive_queue), &wait);
|
||||||
|
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||||
|
remove_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||||
int nonblock, int flags, int *addr_len)
|
int nonblock, int flags, int *addr_len)
|
||||||
{
|
{
|
||||||
@@ -188,7 +210,7 @@ msg_bytes_ready:
|
|||||||
long timeo;
|
long timeo;
|
||||||
|
|
||||||
timeo = sock_rcvtimeo(sk, nonblock);
|
timeo = sock_rcvtimeo(sk, nonblock);
|
||||||
data = sk_msg_wait_data(sk, psock, flags, timeo, &err);
|
data = tcp_msg_wait_data(sk, psock, flags, timeo, &err);
|
||||||
if (data) {
|
if (data) {
|
||||||
if (!sk_psock_queue_empty(psock))
|
if (!sk_psock_queue_empty(psock))
|
||||||
goto msg_bytes_ready;
|
goto msg_bytes_ready;
|
||||||
|
|||||||
@@ -1798,11 +1798,13 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|||||||
if (used <= 0) {
|
if (used <= 0) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
copied = used;
|
copied = used;
|
||||||
|
kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
} else if (used <= skb->len) {
|
} else if (used <= skb->len) {
|
||||||
copied += used;
|
copied += used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
if (!desc->count)
|
if (!desc->count)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,45 @@ static int sk_udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|||||||
return udp_prot.recvmsg(sk, msg, len, noblock, flags, addr_len);
|
return udp_prot.recvmsg(sk, msg, len, noblock, flags, addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool udp_sk_has_data(struct sock *sk)
|
||||||
|
{
|
||||||
|
return !skb_queue_empty(&udp_sk(sk)->reader_queue) ||
|
||||||
|
!skb_queue_empty(&sk->sk_receive_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool psock_has_data(struct sk_psock *psock)
|
||||||
|
{
|
||||||
|
return !skb_queue_empty(&psock->ingress_skb) ||
|
||||||
|
!sk_psock_queue_empty(psock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define udp_msg_has_data(__sk, __psock) \
|
||||||
|
({ udp_sk_has_data(__sk) || psock_has_data(__psock); })
|
||||||
|
|
||||||
|
static int udp_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags,
|
||||||
|
long timeo, int *err)
|
||||||
|
{
|
||||||
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!timeo)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
add_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||||
|
ret = udp_msg_has_data(sk, psock);
|
||||||
|
if (!ret) {
|
||||||
|
wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
|
||||||
|
ret = udp_msg_has_data(sk, psock);
|
||||||
|
}
|
||||||
|
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||||
|
remove_wait_queue(sk_sleep(sk), &wait);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||||
int nonblock, int flags, int *addr_len)
|
int nonblock, int flags, int *addr_len)
|
||||||
{
|
{
|
||||||
@@ -34,8 +73,7 @@ static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|||||||
if (unlikely(!psock))
|
if (unlikely(!psock))
|
||||||
return sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
return sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
||||||
|
|
||||||
lock_sock(sk);
|
if (!psock_has_data(psock)) {
|
||||||
if (sk_psock_queue_empty(psock)) {
|
|
||||||
ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -47,9 +85,9 @@ msg_bytes_ready:
|
|||||||
long timeo;
|
long timeo;
|
||||||
|
|
||||||
timeo = sock_rcvtimeo(sk, nonblock);
|
timeo = sock_rcvtimeo(sk, nonblock);
|
||||||
data = sk_msg_wait_data(sk, psock, flags, timeo, &err);
|
data = udp_msg_wait_data(sk, psock, flags, timeo, &err);
|
||||||
if (data) {
|
if (data) {
|
||||||
if (!sk_psock_queue_empty(psock))
|
if (psock_has_data(psock))
|
||||||
goto msg_bytes_ready;
|
goto msg_bytes_ready;
|
||||||
ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -62,7 +100,6 @@ msg_bytes_ready:
|
|||||||
}
|
}
|
||||||
ret = copied;
|
ret = copied;
|
||||||
out:
|
out:
|
||||||
release_sock(sk);
|
|
||||||
sk_psock_put(sk, psock);
|
sk_psock_put(sk, psock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,12 +128,15 @@ static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr)
|
|||||||
static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool,
|
static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool,
|
||||||
struct xdp_desc *desc)
|
struct xdp_desc *desc)
|
||||||
{
|
{
|
||||||
u64 chunk;
|
u64 chunk, chunk_end;
|
||||||
|
|
||||||
if (desc->len > pool->chunk_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
chunk = xp_aligned_extract_addr(pool, desc->addr);
|
chunk = xp_aligned_extract_addr(pool, desc->addr);
|
||||||
|
if (likely(desc->len)) {
|
||||||
|
chunk_end = xp_aligned_extract_addr(pool, desc->addr + desc->len - 1);
|
||||||
|
if (chunk != chunk_end)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (chunk >= pool->addrs_cnt)
|
if (chunk >= pool->addrs_cnt)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -655,6 +655,9 @@ static int symbols_patch(struct object *obj)
|
|||||||
if (sets_patch(obj))
|
if (sets_patch(obj))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Set type to ensure endian translation occurs. */
|
||||||
|
obj->efile.idlist->d_type = ELF_T_WORD;
|
||||||
|
|
||||||
elf_flagdata(obj->efile.idlist, ELF_C_SET, ELF_F_DIRTY);
|
elf_flagdata(obj->efile.idlist, ELF_C_SET, ELF_F_DIRTY);
|
||||||
|
|
||||||
err = elf_update(obj->efile.elf, ELF_C_WRITE);
|
err = elf_update(obj->efile.elf, ELF_C_WRITE);
|
||||||
|
|||||||
@@ -1610,6 +1610,7 @@ static void udp_redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
int c0, c1, p0, p1;
|
int c0, c1, p0, p1;
|
||||||
unsigned int pass;
|
unsigned int pass;
|
||||||
|
int retries = 100;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
int err, n;
|
int err, n;
|
||||||
u64 value;
|
u64 value;
|
||||||
@@ -1686,9 +1687,13 @@ static void udp_redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||||||
if (pass != 1)
|
if (pass != 1)
|
||||||
FAIL("%s: want pass count 1, have %d", log_prefix, pass);
|
FAIL("%s: want pass count 1, have %d", log_prefix, pass);
|
||||||
|
|
||||||
|
again:
|
||||||
n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1);
|
n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1);
|
||||||
if (n < 0)
|
if (n < 0) {
|
||||||
|
if (errno == EAGAIN && retries--)
|
||||||
|
goto again;
|
||||||
FAIL_ERRNO("%s: read", log_prefix);
|
FAIL_ERRNO("%s: read", log_prefix);
|
||||||
|
}
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
FAIL("%s: incomplete read", log_prefix);
|
FAIL("%s: incomplete read", log_prefix);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user