History

bpf, sockmap: Improved check for empty queue

We noticed some rare sk_buffs were stepping past the queue when system was under memory pressure. The general theory is to skip enqueueing sk_buffs when its not necessary which is the normal case with a system that is properly provisioned for the task, no memory pressure and enough cpu assigned. But, if we can't allocate memory due to an ENOMEM error when enqueueing the sk_buff into the sockmap receive queue we push it onto a delayed workqueue to retry later. When a new sk_buff is received we then check if that queue is empty. However, there is a problem with simply checking the queue length. When a sk_buff is being processed from the ingress queue but not yet on the sockmap msg receive queue its possible to also recv a sk_buff through normal path. It will check the ingress queue which is zero and then skip ahead of the pkt being processed. Previously we used sock lock from both contexts which made the problem harder to hit, but not impossible. To fix instead of popping the skb from the queue entirely we peek the skb from the queue and do the copy there. This ensures checks to the queue length are non-zero while skb is being processed. Then finally when the entire skb has been copied to user space queue or another socket we pop it off the queue. This way the queue length check allows bypassing the queue only after the list has been completely processed. To reproduce issue we run NGINX compliance test with sockmap running and observe some flakes in our testing that we attributed to this issue.

John Fastabend committed 3 years ago

Commit 405df891 parent bce22552 files · +8 −25Browse files

Unified · Split

2 files
  1. include/linux/skmsg.h +0 −1
  2. net/core/skmsg.c +8 −24
include/linux/skmsg.h+0−1
@@ -71,7 +71,6 @@ struct sk_psock_link { · 70 unmodified lines
71};71};
72 72
73struct sk_psock_work_state {73struct sk_psock_work_state {
74 struct sk_buff *skb;
75 u32 len;74 u32 len;
76 u32 off;75 u32 off;
77};76};
net/core/skmsg.c+8−24
@@ -622,16 +622,12 @@ static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb, · 621 unmodified lines
622 622
623static void sk_psock_skb_state(struct sk_psock *psock,623static void sk_psock_skb_state(struct sk_psock *psock,
624 struct sk_psock_work_state *state,624 struct sk_psock_work_state *state,
625 struct sk_buff *skb,
626 int len, int off)625 int len, int off)
627{626{
628 spin_lock_bh(&psock->ingress_lock);627 spin_lock_bh(&psock->ingress_lock);
629 if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {628 if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
630 state->skb = skb;
631 state->len = len;629 state->len = len;
632 state->off = off;630 state->off = off;
633 } else {
634 sock_drop(psock->sk, skb);
635 }631 }
636 spin_unlock_bh(&psock->ingress_lock);632 spin_unlock_bh(&psock->ingress_lock);
637}633}
@@ -642,23 +638,17 @@ static void sk_psock_backlog(struct work_struct *work) · 4 unmodified lines
642 struct sk_psock *psock = container_of(dwork, struct sk_psock, work);638 struct sk_psock *psock = container_of(dwork, struct sk_psock, work);
643 struct sk_psock_work_state *state = &psock->work_state;639 struct sk_psock_work_state *state = &psock->work_state;
644 struct sk_buff *skb = NULL;640 struct sk_buff *skb = NULL;
641 u32 len = 0, off = 0;
645 bool ingress;642 bool ingress;
646 u32 len, off;
647 int ret;643 int ret;
648 644
649 mutex_lock(&psock->work_mutex);645 mutex_lock(&psock->work_mutex);
650 if (unlikely(state->skb)) {646 if (unlikely(state->len)) {
651 spin_lock_bh(&psock->ingress_lock);
652 skb = state->skb;
653 len = state->len;647 len = state->len;
654 off = state->off;648 off = state->off;
655 state->skb = NULL;
656 spin_unlock_bh(&psock->ingress_lock);
657 }649 }
658 if (skb)
659 goto start;
660 650
661 while ((skb = skb_dequeue(&psock->ingress_skb))) {651 while ((skb = skb_peek(&psock->ingress_skb))) {
662 len = skb->len;652 len = skb->len;
663 off = 0;653 off = 0;
664 if (skb_bpf_strparser(skb)) {654 if (skb_bpf_strparser(skb)) {
@@ -667,7 +657,6 @@ static void sk_psock_backlog(struct work_struct *work) · 2 unmodified lines
667 off = stm->offset;657 off = stm->offset;
668 len = stm->full_len;658 len = stm->full_len;
669 }659 }
670start:
671 ingress = skb_bpf_ingress(skb);660 ingress = skb_bpf_ingress(skb);
672 skb_bpf_redirect_clear(skb);661 skb_bpf_redirect_clear(skb);
673 do {662 do {
@@ -677,8 +666,7 @@ start: · 3 unmodified lines
677 len, ingress);666 len, ingress);
678 if (ret <= 0) {667 if (ret <= 0) {
679 if (ret == -EAGAIN) {668 if (ret == -EAGAIN) {
680 sk_psock_skb_state(psock, state, skb,669 sk_psock_skb_state(psock, state, len, off);
681 len, off);
682 670
683 /* Delay slightly to prioritize any671 /* Delay slightly to prioritize any
684 * other work that might be here.672 * other work that might be here.
@@ -690,15 +678,16 @@ start: · 5 unmodified lines
690 /* Hard errors break pipe and stop xmit. */678 /* Hard errors break pipe and stop xmit. */
691 sk_psock_report_error(psock, ret ? -ret : EPIPE);679 sk_psock_report_error(psock, ret ? -ret : EPIPE);
692 sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);680 sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
693 sock_drop(psock->sk, skb);
694 goto end;681 goto end;
695 }682 }
696 off += ret;683 off += ret;
697 len -= ret;684 len -= ret;
698 } while (len);685 } while (len);
699 686
700 if (!ingress)687 skb = skb_dequeue(&psock->ingress_skb);
688 if (!ingress) {
701 kfree_skb(skb);689 kfree_skb(skb);
690 }
702 }691 }
703end:692end:
704 mutex_unlock(&psock->work_mutex);693 mutex_unlock(&psock->work_mutex);
@@ -791,11 +780,6 @@ static void __sk_psock_zap_ingress(struct sk_psock *psock) · 86 unmodified lines
791 skb_bpf_redirect_clear(skb);780 skb_bpf_redirect_clear(skb);
792 sock_drop(psock->sk, skb);781 sock_drop(psock->sk, skb);
793 }782 }
794 kfree_skb(psock->work_state.skb);
795 /* We null the skb here to ensure that calls to sk_psock_backlog
796 * do not pick up the free'd skb.
797 */
798 psock->work_state.skb = NULL;
799 __sk_psock_purge_ingress_msg(psock);783 __sk_psock_purge_ingress_msg(psock);
800}784}
801 785
@@ -814,7 +798,6 @@ void sk_psock_stop(struct sk_psock *psock) · 12 unmodified lines
814 spin_lock_bh(&psock->ingress_lock);798 spin_lock_bh(&psock->ingress_lock);
815 sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);799 sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
816 sk_psock_cork_free(psock);800 sk_psock_cork_free(psock);
817 __sk_psock_zap_ingress(psock);
818 spin_unlock_bh(&psock->ingress_lock);801 spin_unlock_bh(&psock->ingress_lock);
819}802}
820 803
@@ -829,6 +812,7 @@ static void sk_psock_destroy(struct work_struct *work) · 8 unmodified lines
829 sk_psock_done_strp(psock);812 sk_psock_done_strp(psock);
830 813
831 cancel_delayed_work_sync(&psock->work);814 cancel_delayed_work_sync(&psock->work);
815 __sk_psock_zap_ingress(psock);
832 mutex_destroy(&psock->work_mutex);816 mutex_destroy(&psock->work_mutex);
833 817
834 psock_progs_drop(&psock->progs);818 psock_progs_drop(&psock->progs);