summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-03-31 12:23:25 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-03-31 12:32:16 -0700
commit2bc693173112ea436884aca19352624504e2246a (patch)
tree0c0aa9e020d71dbaa13881b2e74361e447e65d25
parent9357f49cd9387b9111c3ae7d03f149dfbd1e73f8 (diff)
downloadquagga-2bc693173112ea436884aca19352624504e2246a.tar.bz2
quagga-2bc693173112ea436884aca19352624504e2246a.tar.xz
Filter unwanted netlink messages
Use socket filter to drop unwanted messages on the netlink listen socket. This prevents problems where the listener socket buffer gets overrruns with echos of the new route update that occurs when link changes.
-rw-r--r--lib/zebra.h1
-rw-r--r--zebra/rt_netlink.c33
2 files changed, 33 insertions, 1 deletions
diff --git a/lib/zebra.h b/lib/zebra.h
index 150aa2c5..d4f68cf0 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -162,6 +162,7 @@ typedef int socklen_t;
#ifdef HAVE_NETLINK
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/filter.h>
#else
#define RT_TABLE_MAIN 0
#endif /* HAVE_NETLINK */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index f071eb24..07e473bc 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -41,6 +41,7 @@
#include "zebra/redistribute.h"
#include "zebra/interface.h"
#include "zebra/debug.h"
+#include <stddef.h>
/* Socket interface to kernel */
struct nlsock
@@ -1938,6 +1939,33 @@ kernel_read (struct thread *thread)
return 0;
}
+/* Filter out messages from self that occur on listener socket */
+static void netlink_install_filter (int sock)
+{
+ /* BPF code to exclude all RTM_NEWROUTE messages from ZEBRA */
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
+ /* 0: ldh [4] */
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 3),
+ /* 1: jeq 0x18 jt 2 jf 5 */
+ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
+ sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_protocol)),
+ /* 2: ldb [23] */
+ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_ZEBRA, 2, 0),
+ /* 3: jeq 0xb jt 4 jf 5 */
+ BPF_STMT(BPF_RET|BPF_K, 0), /* 4: ret 0 */
+ BPF_STMT(BPF_RET|BPF_K, 0xffff), /* 5: ret 0xffff */
+ };
+
+ struct sock_fprog prog = {
+ .len = sizeof(filter) / sizeof(filter[0]),
+ .filter = filter,
+ };
+
+ if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
+ zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
+}
+
/* Exported interface function. This function simply calls
netlink_socket (). */
void
@@ -1954,5 +1982,8 @@ kernel_init (void)
/* Register kernel socket. */
if (netlink.sock > 0)
- thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
+ {
+ netlink_install_filter (netlink.sock);
+ thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
+ }
}