summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Jakma <paul.jakma@sun.com>2008-05-29 18:23:08 +0000
committerPaul Jakma <paul.jakma@sun.com>2008-05-29 18:23:08 +0000
commit768a27ea7ba25257c79689af83ab37945dc1cc3c (patch)
treed3d9b822a29090a8cfee41b4ae3f74248e5950fa
parent311064ddc5c52f6859cf1e6e8636c19a2e705147 (diff)
[zebra/linux] Use BPF to filter out responses, to try avoid netlink overruns
2008-05-29 Stephen Hemminger <stephen.hemminger@vyatta.com> * rt_netlink.c: (netlink_install_filter) BPF filter to catch and drop responses to zebra's own route messages. (kernel_init) add BPF filter on the netlink socket.
-rw-r--r--lib/zebra.h2
-rw-r--r--zebra/ChangeLog6
-rw-r--r--zebra/rt_netlink.c55
3 files changed, 62 insertions, 1 deletions
diff --git a/lib/zebra.h b/lib/zebra.h
index 150aa2c5..2716460f 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -162,6 +162,8 @@ typedef int socklen_t;
#ifdef HAVE_NETLINK
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/filter.h>
+#include <stddef.h>
#else
#define RT_TABLE_MAIN 0
#endif /* HAVE_NETLINK */
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index d9cae283..6f6dfa2c 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,9 @@
+2008-05-29 Stephen Hemminger <stephen.hemminger@vyatta.com>
+
+ * rt_netlink.c: (netlink_install_filter) BPF filter to catch and
+ drop responses to zebra's own route messages.
+ (kernel_init) add BPF filter on the netlink socket.
+
2008-02-26 Denis Ovsienko
* zebra_rib.[ch]: (rib_lookup_and_pushup) New function, which makes sure,
that if_set_prefix() has nothing in its way of assigning an address.
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 5b592f94..0bf2d9eb 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1938,6 +1938,56 @@ kernel_read (struct thread *thread)
return 0;
}
+/* Filter out messages from self that occur on listener socket */
+static void netlink_install_filter (int sock)
+{
+ /*
+ * 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 */
+ };
+
+ 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 +2004,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);
+ }
}