if you have a program that uses kq (or libevent) to wait for bytes to
read off an idle network interface via /dev/bpf and that interface
goes away, the program doesnt get woken up. this is because the kq
read filter in bpf only checks if there ares bytes available. because a
detached interface never gets packets (how very zen), this condition
never changes and the program will never know something happened.

this has the bpf filter check if the interface is detached too. with
this change my test program wakes up, tries to read, and gets EIO. which
is great.

note that in the middle of this is the vdevgone machinery. when an
interface is detached, bpfdetach gets called, which ends up calling
vdevgone. vdevgone sort of swaps out bpf on the currently open vdev with
some dead operations, part of which involves calling bpfclose() to try
and clean up the existing state associated with the vdev. bpfclose tries
to wake up any waiting listeners, which includes kq handlers. that's how
the kernel goes from an interface being detached to the bpf kq filter
being run. the bpf kq filter just has to check that the interface is
still attached.

ok?

Index: bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.203
diff -u -p -r1.203 bpf.c
--- bpf.c       21 Jan 2021 12:33:14 -0000      1.203
+++ bpf.c       21 Apr 2021 00:03:15 -0000
@@ -1222,6 +1222,7 @@ int
 filt_bpfread(struct knote *kn, long hint)
 {
        struct bpf_d *d = kn->kn_hook;
+       struct bpf_if *bp;
 
        KERNEL_ASSERT_LOCKED();
 
@@ -1229,9 +1230,11 @@ filt_bpfread(struct knote *kn, long hint
        kn->kn_data = d->bd_hlen;
        if (d->bd_immediate)
                kn->kn_data += d->bd_slen;
+
+       bp = d->bd_bif; /* check that the interface is still attached */
        mtx_leave(&d->bd_mtx);
 
-       return (kn->kn_data > 0);
+       return (kn->kn_data > 0 || bp == NULL);
 }
 
 /*

Reply via email to