Subject: Re: [PATCH net-next 0/9] net: Kernel side filtering for route dumps

From: Sowmini Varadhan <[email-masked]>
Date: Thu, 11 Oct 2018 11:46:24 -0400

On (10/11/18 08:26), Stephen Hemminger wrote:
> You can do the something like this already with BPF socket filters.
> But writing BPF for multi-part messages is hard.

Indeed. And I was just experimenting with this for ARP just last week.
So to handle the caes of "ip neigh show a.b.c.d" without walking through
the entire arp table and filtering in userspace, you could add a sk_filter()
hook like this:

@@ -2258,6 +2260,24 @@ static int neigh_fill_info(struct sk_buff *skb, struct ne
                goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
+
+       /* XXX skb->sk can be null in the neigh_timer_handler->__neigh_notify 
+        * path. Revisit..
+        */
+       if (!skb->sk)
+               return 0;
+
+       /* pull/push skb->data pointers so that sk_filter only sees the
+        * most recent nlh that wasjust added.
+        */
+       len = skb->len - nlh->nlmsg_len;
+       skb_pull(skb, len);
+       ret = sk_filter(skb->sk, skb);
+       skb_push(skb, len);
+       if (ret)
+               nlmsg_cancel(skb, nlh);
        return 0;
 
Writing the cBPF filter is not horrible, due to the nla extension. e.g.,
to pass a filter that matches on if_index and ipv4 address, the bpf_asm
src below will do the job. The benefit of using cBPF is that we can 
use this older kernels as well

        /*
         * Generated from the bpf_asm src
         * ldb [20]     ; len(nlmsghdr) + offsetof(ndm_ifindex)
         * jne sll->sll_ifindex, skip
         * ld #28       ; A <- len(nlmsghdr) + len(ndmsg), payload offset
         * ldx #1       ; X <-  NDA_DST
         * ld #nla      ; A <- offset(NDA_DST)
         * jeq #0, skip
         * tax
         * ld [x + 4]   ; A <- value(NDA_DST)
         * jneq htonl(addr), skip
         * ret #-1
         * skip: ret #0
         */
        struct sock_filter bpf_filter[] = {
                { 0x30,  0,  0, 0x00000014 },
                { 0x15,  0,  1, sll->sll_ifindex },
                { 0000,  0,  0, 0x0000001c },
                { 0x01,  0,  0, 0x00000001 },
                { 0x20,  0,  0, 0xfffff00c },
                { 0x15,  4,  0, 0000000000 },
                { 0x07,  0,  0, 0000000000 },
                { 0x40,  0,  0, 0x00000004 },
                { 0x15,  0,  1, htonl(addr) },
                { 0x06,  0,  0, 0xffffffff },
                { 0x06,  0,  0, 0000000000 },
                { 0x06,  0,  0, 0xffffffff },
                { 0x06,  0,  0, 0000000000 },
        };