[zebra:linux] Filter out unwanted netlink messages by PID

2008-08-16 Stephen Hemminger <stephen.hemminger@vyatta.com>

	* zebra/rt_netlink.c: Update the netlink socket BPF to cancel out
	  unwanted ACKs on the listen socket by matching on the PID.

Signed-off-by: Paul Jakma <paul@quagga.net>
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 395f1ca..592dfe2 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -285,7 +285,7 @@
   req.nlh.nlmsg_len = sizeof req;
   req.nlh.nlmsg_type = type;
   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
-  req.nlh.nlmsg_pid = 0;
+  req.nlh.nlmsg_pid = nl->snl.nl_pid;
   req.nlh.nlmsg_seq = ++nl->seq;
   req.g.rtgen_family = family;
 
@@ -367,13 +367,6 @@
           return -1;
         }
       
-      /* JF: Ignore messages that aren't from the kernel */
-      if ( snl.nl_pid != 0 )
-        {
-          zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
-          continue;
-        }
-
       for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
            h = NLMSG_NEXT (h, status))
         {
@@ -1066,6 +1059,13 @@
 static int
 netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
 {
+  /* JF: Ignore messages that aren't from the kernel */
+  if ( snl->nl_pid != 0 )
+    {
+      zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
+      return 0;
+    }
+
   switch (h->nlmsg_type)
     {
     case RTM_NEWROUTE:
@@ -1935,45 +1935,26 @@
   return 0;
 }
 
-/* Filter out messages from self that occur on listener socket */
-static void netlink_install_filter (int sock)
+/* Filter out messages from self that occur on listener socket,
+   caused by our actions on the command socket
+ */
+static void netlink_install_filter (int sock, __u32 pid)
 {
-  /*
-   * Filter is equivalent to netlink_route_change
-   *
-   * if (h->nlmsg_type == RTM_DELROUTE || h->nlmsg_type == RTM_NEWROUTE) {
-   *    if (rtm->rtm_type != RTM_UNICAST)
-   *    	return 0;
-   *    if (rtm->rtm_flags & RTM_F_CLONED)
-   *    	return 0;
-   *    if (rtm->rtm_protocol == RTPROT_REDIRECT)
-   *    	return 0;
-   *    if (rtm->rtm_protocol == RTPROT_KERNEL)
-   *        return 0;
-   *    if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
-   * 	return 0;
-   * }
-   * return 0xffff;
-   */
   struct sock_filter filter[] = {
-    /* 0*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
-    /* 1*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 1, 0),
-    /* 2*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 11),
-    /* 3*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
-		    sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_type)),
-    /* 4*/ BPF_JUMP(BPF_JMP|BPF_B, RTN_UNICAST, 0, 8),
-    /* 5*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
-		    sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_flags)),
-    /* 6*/ BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, RTM_F_CLONED, 6, 0),
-    /* 7*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
-		    sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_protocol)),
-    /* 8*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_REDIRECT, 4, 0),
-    /* 9*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_KERNEL, 0, 1),
-    /*10*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_ZEBRA, 0, 3),
-    /*11*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
-    /*12*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 1),
-    /*13*/ BPF_STMT(BPF_RET|BPF_K, 0),		/* drop */
-    /*14*/ BPF_STMT(BPF_RET|BPF_K, 0xffff),	/* keep */
+    /* 0: ldh [4]	          */
+    BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
+    /* 1: jeq 0x18 jt 3 jf 6  */
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
+    /* 2: jeq 0x19 jt 3 jf 6  */
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
+    /* 3: ldw [12]		  */
+    BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
+    /* 4: jeq XX  jt 5 jf 6   */
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
+    /* 5: ret 0    (skip)     */
+    BPF_STMT(BPF_RET|BPF_K, 0),
+    /* 6: ret 0xffff (keep)   */
+    BPF_STMT(BPF_RET|BPF_K, 0xffff),
   };
 
   struct sock_fprog prog = {
@@ -2002,7 +1983,7 @@
   /* Register kernel socket. */
   if (netlink.sock > 0)
     {
-      netlink_install_filter (netlink.sock);
+      netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
       thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
     }
 }