diff options
-rw-r--r-- | lib/zebra.h | 2 | ||||
-rw-r--r-- | zebra/ChangeLog | 6 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 55 |
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); + } } |