Implement packet filter on netlink interfaces so that FEA only
gets route updates for the table(s) it cares about.  When running
100 routers with around 300 routes each, this takes system load from
300+ down to max of around 20 (on a dual quad-core system).
This should greatly help scalability as virtual routers increase, since
number of netlink messages will be Routers * Routes, instead of Routers^2
* Routes.
This patch also makes netlink socket reading non-blocking, which is required
to keep fea from hanging when packets are filtered.

Thanks,
Ben

--
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com

diff --git a/fea/data_plane/control_socket/netlink_socket.cc 
b/fea/data_plane/control_socket/netlink_socket.cc
index 4308830..3822bf8 100644
--- a/fea/data_plane/control_socket/netlink_socket.cc
+++ b/fea/data_plane/control_socket/netlink_socket.cc
@@ -50,6 +50,18 @@
 #endif
 #ifdef HAVE_LINUX_RTNETLINK_H
 #include <linux/rtnetlink.h>
+
+#endif
+
+#include <pcap-bpf.h>
+
+// standard headers might not be up to date with the latest kernels.
+#ifndef SKF_AD_OFF
+#define SKF_AD_OFF (-0x1000)
+#endif
+
+#ifndef SKF_AD_NLATTR
+#define SKF_AD_NLATTR 12
 #endif
 
 #include "libcomm/comm_api.h"
@@ -57,19 +69,19 @@
 #include "netlink_socket.hh"
 #include "netlink_socket_utilities.hh"
 
-
 uint16_t NetlinkSocket::_instance_cnt = 0;
 
 //
 // Netlink Sockets (see netlink(7)) communication with the kernel
 //
 
-NetlinkSocket::NetlinkSocket(EventLoop& eventloop)
+NetlinkSocket::NetlinkSocket(EventLoop& eventloop, uint32_t table_id)
     : _eventloop(eventloop),
       _fd(-1),
       _seqno(0),
       _instance_no(_instance_cnt++),
       _nl_groups(0),           // XXX: no netlink multicast groups
+      _table_id(table_id),
       _is_multipart_message_read(false),
       _nlm_count(0)
 {
@@ -87,6 +99,11 @@ NetlinkSocket::~NetlinkSocket()
     XLOG_ASSERT(_ol.empty());
 }
 
+int
+NetlinkSocket::force_recvmsg(bool only_kernel_messages, string& err_msg) {
+    return force_recvmsg_flgs(MSG_DONTWAIT, only_kernel_messages, err_msg);
+}
+
 #ifndef HAVE_NETLINK_SOCKETS
 
 int
@@ -113,7 +130,7 @@ NetlinkSocket::stop(string& error_msg)
 
 
 int
-NetlinkSocket::force_recvmsg(int flags, bool only_kernel_messages,
+NetlinkSocket::force_recvmsg_flgs(int flags, bool only_kernel_messages,
                             string& error_msg)
 {
     UNUSED(flags);
@@ -128,11 +145,93 @@ NetlinkSocket::force_recvmsg(int flags, bool 
only_kernel_messages,
 
 #else // HAVE_NETLINK_SOCKETS
 
+int NetlinkSocket::bind_table_id() {
+    if (_table_id) {
+       // Use socket filter.  Shouldn't require kernel hackings if it's a 
recent-ish kernel (2.6.30+ I think).
+       struct bpf_program bpf;
+       bpf.bf_insns = NULL;
+       static struct bpf_insn instructions[] = {
+           {
+               /* A = offset of first attribute */
+               BPF_LD | BPF_IMM, 0, 0, sizeof(struct nlmsghdr) + 
NLMSG_ALIGN(sizeof(struct rtmsg))
+           },
+           {
+               /* X = RTA_TABLE */
+               BPF_LDX | BPF_IMM, 0, 0, RTA_TABLE
+           },
+           {
+               /* A = netlink attribute (X) offset */
+               BPF_LD | BPF_W | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_NLATTR
+           },
+           {
+               /* If table offset was not found, then pass it through. */
+               BPF_JMP | BPF_JEQ | BPF_K, 3, 0, 0
+           },
+           {
+               /* X = A (netlink attribute offset) */
+               BPF_MISC | BPF_TAX, 0, 0, 0
+           },
+           {
+               /* A = skb->data[X + k] */
+               BPF_LD | BPF_W | BPF_IND, 0, 0, sizeof(struct nlattr)
+           },
+           {
+               /* Exit if wrong routing table */
+               BPF_JMP | BPF_JEQ | BPF_K, 0, 1, /*<error>*/ _table_id
+           },
+           {
+               /* Packet may pass */
+               BPF_RET | BPF_K, 0, 0, ~0
+           },
+           /* <error>: */
+           {
+               /* Packet may not pass */
+               BPF_RET | BPF_K, 0, 0, 0
+           }
+       }; /* bpf instructions */
+       bpf.bf_insns = instructions;
+       bpf.bf_len = 9;
+       
+       if (setsockopt(_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 
0) {
+           XLOG_WARNING("Failed to set filter on netlink socket, error: %s\n"
+                        "The program will run fine, but may be slightly less 
efficient if\n"
+                        "multiple Xorps are run on the same system using 
different routing tables.\n",
+                        strerror(errno));
+       }
+       else {
+           static bool do_once = true;
+           if (do_once) {
+               XLOG_WARNING("Successfully attached Netlink socket filter for 
table id: %u on fd: %i",
+                            _table_id, _fd);
+               do_once = false;
+           }
+       }
+    }
+    else {
+       if (setsockopt(_fd, SOL_SOCKET, SO_DETACH_FILTER, 0, 0) < 0) {
+           // Not a real problem..fails if we don't have one already attached, 
for instance.
+           //XLOG_WARNING("Failed to detach filter on netlink socket, error: 
%s", strerror(errno));
+       }
+    }
+    return XORP_OK;
+}
+
+/** Routing table ID that we are interested in might have changed.
+ */
+int NetlinkSocket::notify_table_id_change(uint32_t new_tbl) {
+    if (new_tbl != _table_id) {
+       _table_id = new_tbl;
+       return bind_table_id();
+    }
+    return XORP_OK;
+}
+       
+
 int
 NetlinkSocket::start(string& error_msg)
 {
-    struct sockaddr_nl snl;
-    socklen_t          snl_len;
+    struct sockaddr_nl snl;
+    socklen_t snl_len = sizeof(snl);
 
     if (_fd >= 0)
        return (XORP_OK);
@@ -160,11 +259,12 @@ NetlinkSocket::start(string& error_msg)
     //
     // Bind the socket
     //
-    memset(&snl, 0, sizeof(snl));
+    memset(&snl, 0, snl_len);
     snl.nl_family = AF_NETLINK;
     snl.nl_pid    = 0;         // Let the kernel assign the pid to the socket
     snl.nl_groups = _nl_groups;
-    if (bind(_fd, reinterpret_cast<struct sockaddr*>(&snl), sizeof(snl)) < 0) {
+
+    if (bind(_fd, reinterpret_cast<struct sockaddr*>(&snl), snl_len) < 0) {
        error_msg = c_format("bind(AF_NETLINK) failed: %s", strerror(errno));
        close(_fd);
        _fd = -1;
@@ -200,6 +300,9 @@ NetlinkSocket::start(string& error_msg)
        return (XORP_ERROR);
     }
 
+    // Bind to table-id
+    bind_table_id();
+
     //
     // Store the pid of the socket for checking the unicast destination of
     // the netlink(7) messages.
@@ -252,7 +355,7 @@ NetlinkSocket::sendto(const void* data, size_t nbytes, int 
flags,
 
 
 int
-NetlinkSocket::force_recvmsg(int flags, bool only_kernel_messages,
+NetlinkSocket::force_recvmsg_flgs(int flags, bool only_kernel_messages,
                             string& error_msg)
 {
     vector<uint8_t> message;
@@ -297,6 +400,10 @@ NetlinkSocket::force_recvmsg(int flags, bool 
only_kernel_messages,
        
        got = recvmsg(_fd, &msg, flags);
        if (got < 0) {
+           // Nothing to read after all, msg was probably filtered.
+           if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+               return XORP_ERROR;
+
            if (errno == EINTR)
                continue;
            error_msg = c_format("Netlink socket recvmsg error: %s",
@@ -379,9 +486,12 @@ NetlinkSocket::io_event(XorpFd fd, IoEventType type)
 
     XLOG_ASSERT(fd == _fd);
     XLOG_ASSERT(type == IOT_READ);
-    if (force_recvmsg(0, true, error_msg) != XORP_OK) {
-       XLOG_ERROR("Error force_recvmsg() from netlink socket: %s",
-                  error_msg.c_str());
+    errno = 0;
+    if (force_recvmsg(true, error_msg) != XORP_OK) {
+       if (!(errno == EWOULDBLOCK || errno == EAGAIN)) {
+           XLOG_ERROR("Error force_recvmsg() from netlink socket: %s",
+                      error_msg.c_str());
+       }
     }
 }
 
@@ -461,9 +571,14 @@ NetlinkSocketReader::receive_data(NetlinkSocket& ns, 
uint32_t seqno,
 {
     _cache_seqno = seqno;
     _cache_valid = false;
+    errno = 0;
     while (_cache_valid == false) {
-       if (ns.force_recvmsg(0, true, error_msg) != XORP_OK)
+       if (ns.force_recvmsg(true, error_msg) != XORP_OK) {
+           if (errno == EWOULDBLOCK || errno == EAGAIN) {
+               return XORP_OK;
+           }
            return (XORP_ERROR);
+       }
     }
 
     return (XORP_OK);
diff --git a/fea/data_plane/control_socket/netlink_socket.hh 
b/fea/data_plane/control_socket/netlink_socket.hh
index 0e490ed..8423149 100644
--- a/fea/data_plane/control_socket/netlink_socket.hh
+++ b/fea/data_plane/control_socket/netlink_socket.hh
@@ -30,6 +30,7 @@
 class NetlinkSocketObserver;
 struct NetlinkSocketPlumber;
 
+
 /**
  * NetlinkSocket class opens a netlink socket and forwards data arriving
  * on the socket to NetlinkSocketObservers.  The NetlinkSocket hooks itself
@@ -37,8 +38,8 @@ struct NetlinkSocketPlumber;
  */
 class NetlinkSocket {
 public:
-    NetlinkSocket(EventLoop& eventloop);
-    ~NetlinkSocket();
+    NetlinkSocket(EventLoop& eventloop, uint32_t table_id);
+    virtual ~NetlinkSocket();
 
     /**
      * Start the netlink socket operation.
@@ -105,7 +106,6 @@ public:
      */
     uint32_t nl_pid() const { return _nl_pid; }
 
-
     /**
      * Force socket to recvmsg data.
      * 
@@ -120,7 +120,12 @@ public:
      * @param error_msg the error message (if error).
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
-    int force_recvmsg(int flags, bool only_kernel_messages, string& error_msg);
+    int force_recvmsg_flgs(int flags, bool only_kernel_messages, string& 
error_msg);
+
+    /** Same as above, but always passes MSG_DONTWAIT as flags so that we 
don't block
+     * if packet is filtered, for example.
+     */
+    int force_recvmsg(bool only_kernel_messages, string& err_msg);
 
     /**
      * Set the netlink multicast groups to listen for on the netlink socket.
@@ -149,6 +154,10 @@ public:
      */
     void       set_multipart_message_read(bool v) { _is_multipart_message_read 
= v; }
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl);
+
 private:
     typedef list<NetlinkSocketObserver*> ObserverList;
 
@@ -162,6 +171,8 @@ private:
     NetlinkSocket& operator=(const NetlinkSocket&);    // Not implemented
     NetlinkSocket(const NetlinkSocket&);               // Not implemented
 
+    int bind_table_id();
+
     static const size_t NETLINK_SOCKET_BYTES = 8*1024; // Initial guess at msg 
size
 
     EventLoop&  _eventloop;
@@ -175,6 +186,7 @@ private:
     uint32_t   _nl_pid;
 
     uint32_t   _nl_groups;     // The netlink multicast groups to listen for
+    uint32_t _table_id; // routing table.. or 0 if any/all (default behaviour) 
     bool       _is_multipart_message_read; // If true, expect to read a 
multipart message
 
     uint32_t   _nlm_count; // keep track of how many msgs received.
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_get_click.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_get_click.hh
index e886fe6..52c49de 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_get_click.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_get_click.hh
@@ -94,6 +94,10 @@ public:
      */
     virtual int lookup_route_by_network6(const IPv6Net& dst, Fte6& fte);
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
+
 private:
     ClickSocketReader  _cs_reader;
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_get_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_get_dummy.hh
index 3bb4992..6a986eb 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_get_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_get_dummy.hh
@@ -92,6 +92,10 @@ public:
      */
     virtual int lookup_route_by_network6(const IPv6Net& dst, Fte6& fte);
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
+
 private:
 };
 
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.cc
index 615f5f2..2e5cf17 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.cc
@@ -49,7 +49,8 @@
 
 
FibConfigEntryGetNetlinkSocket::FibConfigEntryGetNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : FibConfigEntryGet(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       _ns_reader(*(NetlinkSocket *)this)
 {
 }
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.hh
index a472eb2..26516e5 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_get_netlink_socket.hh
@@ -113,6 +113,12 @@ public:
                                           const vector<uint8_t>& buffer,
                                           bool is_nlm_get_only, const 
FibConfig& fibconfig);
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) {
+       return NetlinkSocket::notify_table_id_change(new_tbl);
+    }
+
 private:
     /**
      * Lookup a route by destination address.
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_observer_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_observer_dummy.hh
index 3c79727..e316923 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_observer_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_observer_dummy.hh
@@ -62,6 +62,10 @@ public:
      * @param buffer the buffer with the received data.
      */
     virtual void receive_data(const vector<uint8_t>& buffer);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git 
a/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.cc
index a31e3ff..a54e257 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.cc
@@ -51,7 +51,8 @@
 
 
FibConfigEntryObserverNetlinkSocket::FibConfigEntryObserverNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : FibConfigEntryObserver(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       NetlinkSocketObserver(*(NetlinkSocket *)this)
 {
 }
diff --git 
a/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.hh
index 7799e77..9cf0300 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_observer_netlink_socket.hh
@@ -67,6 +67,12 @@ public:
     virtual void receive_data(const vector<uint8_t>& buffer);
     
     void netlink_socket_data(const vector<uint8_t>& buffer);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) {
+       return NetlinkSocket::notify_table_id_change(new_tbl);
+    }
     
 private:
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_set_click.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_set_click.hh
index 31c3f32..c962c18 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_set_click.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_set_click.hh
@@ -121,6 +121,10 @@ public:
      */
     const map<IPv6Net, Fte6>& fte_table6() const { return _fte_table6; }
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
+
 private:
     virtual void nexthop_port_mapper_event(bool is_mapping_changed);
 
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_set_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_set_dummy.hh
index 3936d19..15537ef 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_set_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_set_dummy.hh
@@ -95,6 +95,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int delete_entry6(const Fte6& fte);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc
index 65db621..f8e0399 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.cc
@@ -51,7 +51,8 @@
 
 
FibConfigEntrySetNetlinkSocket::FibConfigEntrySetNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : FibConfigEntrySet(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       _ns_reader(*(NetlinkSocket *)this)
 {
 }
@@ -68,6 +69,12 @@ 
FibConfigEntrySetNetlinkSocket::~FibConfigEntrySetNetlinkSocket()
     }
 }
 
+/** Routing table ID that we are interested in might have changed.
+ */
+int FibConfigEntrySetNetlinkSocket::notify_table_id_change(uint32_t new_tbl) {
+    return NetlinkSocket::notify_table_id_change(new_tbl);
+}
+
 int
 FibConfigEntrySetNetlinkSocket::start(string& error_msg)
 {
diff --git a/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.hh
index af28985..043b954 100644
--- a/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_entry_set_netlink_socket.hh
@@ -98,6 +98,10 @@ public:
      */
     virtual int delete_entry6(const Fte6& fte);
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl);
+
 private:
     int add_entry(const FteX& fte);
     int delete_entry(const FteX& fte);
diff --git a/fea/data_plane/fibconfig/fibconfig_table_get_click.hh 
b/fea/data_plane/fibconfig/fibconfig_table_get_click.hh
index 753c52a..f64eb9e 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_get_click.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_get_click.hh
@@ -75,6 +75,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int get_table6(list<Fte6>& fte_list);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
     ClickSocketReader  _cs_reader;
diff --git a/fea/data_plane/fibconfig/fibconfig_table_get_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_table_get_dummy.hh
index 8ff4e12..bdbeeda 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_get_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_get_dummy.hh
@@ -73,6 +73,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int get_table6(list<Fte6>& fte_list);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.cc
index bde6e1e..185d3ad 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.cc
@@ -47,7 +47,8 @@
 
 
FibConfigTableGetNetlinkSocket::FibConfigTableGetNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : FibConfigTableGet(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       _ns_reader(*(NetlinkSocket *)this)
 {
 }
diff --git a/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.hh
index e5d9f8c..74d163a 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_get_netlink_socket.hh
@@ -98,6 +98,12 @@ public:
                                           const vector<uint8_t>& buffer,
                                           bool is_nlm_get_only, const 
FibConfig& fibconfig);
 
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) {
+       return NetlinkSocket::notify_table_id_change(new_tbl);
+    }
+
 private:
     int get_table(int family, list<FteX>& fte_list);
 
diff --git a/fea/data_plane/fibconfig/fibconfig_table_observer_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_table_observer_dummy.hh
index 9403c42..6711e30 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_observer_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_observer_dummy.hh
@@ -62,6 +62,10 @@ public:
      * @param buffer the buffer with the received data.
      */
     virtual void receive_data(const vector<uint8_t>& buffer);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git 
a/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.cc
index 4401bcc..a563e11 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.cc
@@ -52,7 +52,8 @@
 
 
FibConfigTableObserverNetlinkSocket::FibConfigTableObserverNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : FibConfigTableObserver(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       NetlinkSocketObserver(*(NetlinkSocket *)this)
 {
 }
diff --git 
a/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.hh
index 6ed0d61..fb50899 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_observer_netlink_socket.hh
@@ -67,6 +67,12 @@ public:
     virtual void receive_data(const vector<uint8_t>& buffer);
     
     void netlink_socket_data(const vector<uint8_t>& buffer);
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) {
+       return NetlinkSocket::notify_table_id_change(new_tbl);
+    }
     
 private:
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_table_set_click.hh 
b/fea/data_plane/fibconfig/fibconfig_table_set_click.hh
index 34236cc..4783b66 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_set_click.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_set_click.hh
@@ -93,6 +93,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int delete_all_entries6();
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
     ClickSocketReader  _cs_reader;
diff --git a/fea/data_plane/fibconfig/fibconfig_table_set_dummy.hh 
b/fea/data_plane/fibconfig/fibconfig_table_set_dummy.hh
index 9aaa973..a647d4f 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_set_dummy.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_set_dummy.hh
@@ -91,6 +91,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int delete_all_entries6();
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git a/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.cc 
b/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.cc
index 1dd6e5f..6590065 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.cc
+++ b/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.cc
@@ -55,6 +55,7 @@ 
FibConfigTableSetNetlinkSocket::~FibConfigTableSetNetlinkSocket()
     }
 }
 
+
 int
 FibConfigTableSetNetlinkSocket::start(string& error_msg)
 {
diff --git a/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.hh 
b/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.hh
index 2987081..82e349b 100644
--- a/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.hh
+++ b/fea/data_plane/fibconfig/fibconfig_table_set_netlink_socket.hh
@@ -92,6 +92,10 @@ public:
      * @return XORP_OK on success, otherwise XORP_ERROR.
      */
     virtual int delete_all_entries6();
+
+    /** Routing table ID that we are interested in might have changed.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) { UNUSED(new_tbl); 
return XORP_OK; }
     
 private:
 };
diff --git a/fea/data_plane/ifconfig/ifconfig_get_netlink_socket.cc 
b/fea/data_plane/ifconfig/ifconfig_get_netlink_socket.cc
index d76b57a..4bc392d 100644
--- a/fea/data_plane/ifconfig/ifconfig_get_netlink_socket.cc
+++ b/fea/data_plane/ifconfig/ifconfig_get_netlink_socket.cc
@@ -38,7 +38,7 @@
 #endif
 
 #include "fea/ifconfig.hh"
-
+#include "fea/fibconfig.hh"
 #include "ifconfig_get_netlink_socket.hh"
 
 
@@ -52,7 +52,8 @@
 
 IfConfigGetNetlinkSocket::IfConfigGetNetlinkSocket(FeaDataPlaneManager& 
fea_data_plane_manager)
     : IfConfigGet(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       _ns_reader(*(NetlinkSocket *)this)
 {
 }
diff --git a/fea/data_plane/ifconfig/ifconfig_observer_netlink_socket.cc 
b/fea/data_plane/ifconfig/ifconfig_observer_netlink_socket.cc
index 907b88c..d794b26 100644
--- a/fea/data_plane/ifconfig/ifconfig_observer_netlink_socket.cc
+++ b/fea/data_plane/ifconfig/ifconfig_observer_netlink_socket.cc
@@ -33,6 +33,7 @@
 #endif
 
 #include "fea/ifconfig.hh"
+#include "fea/fibconfig.hh"
 
 #include "ifconfig_get_netlink_socket.hh"
 #include "ifconfig_observer_netlink_socket.hh"
@@ -49,7 +50,8 @@
 
 
IfConfigObserverNetlinkSocket::IfConfigObserverNetlinkSocket(FeaDataPlaneManager&
 fea_data_plane_manager)
     : IfConfigObserver(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       NetlinkSocketObserver(*(NetlinkSocket *)this)
 {
 }
diff --git a/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc 
b/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
index 14074ed..59ab6f9 100644
--- a/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
+++ b/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
@@ -45,6 +45,7 @@
 #endif
 
 #include "fea/ifconfig.hh"
+#include "fea/fibconfig.hh"
 #include "fea/data_plane/control_socket/netlink_socket_utilities.hh"
 
 #include "ifconfig_set_netlink_socket.hh"
@@ -61,7 +62,8 @@
 
 IfConfigSetNetlinkSocket::IfConfigSetNetlinkSocket(FeaDataPlaneManager& 
fea_data_plane_manager)
     : IfConfigSet(fea_data_plane_manager),
-      NetlinkSocket(fea_data_plane_manager.eventloop()),
+      NetlinkSocket(fea_data_plane_manager.eventloop(),
+                   
fea_data_plane_manager.fibconfig().get_netlink_filter_table_id()),
       _ns_reader(*(NetlinkSocket *)this)
 {
 }
@@ -650,7 +652,7 @@ IfConfigSetNetlinkSocket::wait_interface_status(const 
IfTreeInterface* ifp,
        return;
 
     while (ifp->enabled() != is_enabled) {
-       if (ns->force_recvmsg(0, true, error_msg) != XORP_OK)
+       if (ns->force_recvmsg(true, error_msg) != XORP_OK)
            XLOG_ERROR("Netlink force_recvmsg(): %s", error_msg.c_str());
     }
 }
diff --git a/fea/fibconfig.cc b/fea/fibconfig.cc
index d49d6dc..df07f72 100644
--- a/fea/fibconfig.cc
+++ b/fea/fibconfig.cc
@@ -86,6 +86,72 @@ FibConfig::status(string& reason) const
     return (PROC_READY);
 }
 
+uint32_t FibConfig::get_netlink_filter_table_id() const {
+    uint32_t tbl_id = 0;
+    if (unicast_forwarding_table_id4_is_configured() ||
+       unicast_forwarding_table_id6_is_configured()) {
+       if (unicast_forwarding_table_id4_is_configured()) {
+           tbl_id = unicast_forwarding_table_id4();
+           if (unicast_forwarding_table_id6_is_configured()) {
+               if (unicast_forwarding_table_id6() != tbl_id) {
+                   XLOG_WARNING("WARNING:  IPv4 and v6 tables are configured 
and are different.  Cannot filter on netlink table-id, will use default 
behaviour and listen to all tables.\n");
+                   tbl_id = 0;
+               }
+           }
+       }
+       else {
+           tbl_id = unicast_forwarding_table_id6();
+       }
+    }
+    //XLOG_WARNING("IPv4 configured: %i %u  IPv6: %i %u  filter-table: %u",
+    //  unicast_forwarding_table_id4_is_configured(),
+    //  unicast_forwarding_table_id4(),
+    //  unicast_forwarding_table_id6_is_configured(),
+    //  unicast_forwarding_table_id6(), tbl_id);
+    return tbl_id;
+}
+
+void FibConfig::propagate_table_id_change() {
+    uint32_t tbl_id = get_netlink_filter_table_id();
+    // Tell the various plugins our configured table changed in case they can 
filter.
+    {
+       list<FibConfigEntryGet*>::iterator iter = _fibconfig_entry_gets.begin();
+       for (; iter != _fibconfig_entry_gets.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+    {
+       list<FibConfigEntrySet*>::iterator iter = _fibconfig_entry_sets.begin();
+       for (; iter != _fibconfig_entry_sets.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+    {
+       list<FibConfigEntryObserver*>::iterator iter = 
_fibconfig_entry_observers.begin();
+       for (; iter != _fibconfig_entry_observers.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+    {
+       list<FibConfigTableGet*>::iterator iter = _fibconfig_table_gets.begin();
+       for (; iter != _fibconfig_table_gets.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+    {
+       list<FibConfigTableSet*>::iterator iter = _fibconfig_table_sets.begin();
+       for (; iter != _fibconfig_table_sets.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+    {
+       list<FibConfigTableObserver*>::iterator iter = 
_fibconfig_table_observers.begin();
+       for (; iter != _fibconfig_table_observers.end(); iter++) {
+           (*iter)->notify_table_id_change(tbl_id);
+       }
+    }
+}
+
 int
 FibConfig::start_transaction(uint32_t& tid, string& error_msg)
 {
@@ -909,8 +975,12 @@ FibConfig::set_unicast_forwarding_table_id4(bool 
is_configured,
                                            uint32_t table_id,
                                            string& error_msg)
 {
-    _unicast_forwarding_table_id4_is_configured = is_configured;
-    _unicast_forwarding_table_id4 = table_id;
+    if ((_unicast_forwarding_table_id4_is_configured != is_configured) ||
+       (_unicast_forwarding_table_id4 != table_id)) {
+       _unicast_forwarding_table_id4_is_configured = is_configured;
+       _unicast_forwarding_table_id4 = table_id;
+       propagate_table_id_change();
+    }
 
     error_msg = "";            // XXX: reset
     return (XORP_OK);
@@ -921,8 +991,12 @@ FibConfig::set_unicast_forwarding_table_id6(bool 
is_configured,
                                            uint32_t table_id,
                                            string& error_msg)
 {
-    _unicast_forwarding_table_id6_is_configured = is_configured;
-    _unicast_forwarding_table_id6 = table_id;
+    if ((_unicast_forwarding_table_id6_is_configured != is_configured) ||
+       (_unicast_forwarding_table_id6 != table_id)) {
+       _unicast_forwarding_table_id6_is_configured = is_configured;
+       _unicast_forwarding_table_id6 = table_id;
+       propagate_table_id_change();
+    }
 
     error_msg = "";            // XXX: reset
     return (XORP_OK);
diff --git a/fea/fibconfig.hh b/fea/fibconfig.hh
index 2364030..d5af349 100644
--- a/fea/fibconfig.hh
+++ b/fea/fibconfig.hh
@@ -465,6 +465,14 @@ public:
        return (_unicast_forwarding_table_id6);
     }
 
+    /** If IPv4 and IPv6 table ids are configured, and configured to the same 
thing,
+     * we can attempt to filter the netlink route messages on that table id.
+     * Otherwise, return 0 (no filtering)
+     */
+    uint32_t get_netlink_filter_table_id() const;
+
+    void propagate_table_id_change();
+
     /**
      * Set the IPv4 unicast forwarding table ID to be used.
      *
diff --git a/fea/fibconfig_entry_get.hh b/fea/fibconfig_entry_get.hh
index d7dbd7e..6567cb0 100644
--- a/fea/fibconfig_entry_get.hh
+++ b/fea/fibconfig_entry_get.hh
@@ -121,6 +121,11 @@ public:
      */
     virtual int lookup_route_by_network6(const IPv6Net& dst, Fte6& fte) = 0;
 
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
+
 protected:
     // Misc other state
     bool       _is_running;
diff --git a/fea/fibconfig_entry_observer.hh b/fea/fibconfig_entry_observer.hh
index 7635545..07af45a 100644
--- a/fea/fibconfig_entry_observer.hh
+++ b/fea/fibconfig_entry_observer.hh
@@ -93,6 +93,11 @@ public:
      * @param buffer the buffer with the received data.
      */
     virtual void receive_data(const vector<uint8_t>& buffer) = 0;
+
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
     
 protected:
     // Misc other state
diff --git a/fea/fibconfig_entry_set.hh b/fea/fibconfig_entry_set.hh
index cdf8dc4..94bbfcb 100644
--- a/fea/fibconfig_entry_set.hh
+++ b/fea/fibconfig_entry_set.hh
@@ -158,6 +158,11 @@ public:
      */
     virtual int delete_entry6(const Fte6& fte) = 0;
 
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
+
 protected:
     /**
      * Mark start of a configuration.
diff --git a/fea/fibconfig_table_get.hh b/fea/fibconfig_table_get.hh
index e48236f..5bed452 100644
--- a/fea/fibconfig_table_get.hh
+++ b/fea/fibconfig_table_get.hh
@@ -105,6 +105,11 @@ public:
      */
     virtual int get_table6(list<Fte6>& fte_list) = 0;
 
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
+
 protected:
     // Misc other state
     bool       _is_running;
diff --git a/fea/fibconfig_table_observer.hh b/fea/fibconfig_table_observer.hh
index 0964284..13ac23e 100644
--- a/fea/fibconfig_table_observer.hh
+++ b/fea/fibconfig_table_observer.hh
@@ -94,6 +94,11 @@ public:
      */
     virtual void receive_data(const vector<uint8_t>& buffer) = 0;
 
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
+
 protected:
     // Misc other state
     bool       _is_running;
diff --git a/fea/fibconfig_table_set.hh b/fea/fibconfig_table_set.hh
index 72c9f28..effda8c 100644
--- a/fea/fibconfig_table_set.hh
+++ b/fea/fibconfig_table_set.hh
@@ -156,6 +156,11 @@ public:
      */
     virtual int delete_all_entries6() = 0;
 
+    /** Routing table ID that we are interested in might have changed.  Maybe 
something
+     * can filter on this for increased efficiency.
+     */
+    virtual int notify_table_id_change(uint32_t new_tbl) = 0;
+
 protected:
     /**
      * Mark start of a configuration.
diff --git a/rtrmgr/template_tree.cc b/rtrmgr/template_tree.cc
index 8edcc79..a5c9143 100644
--- a/rtrmgr/template_tree.cc
+++ b/rtrmgr/template_tree.cc
@@ -50,8 +50,10 @@ extern void parse_template() throw (ParseError);
 
 TemplateTree::TemplateTree(const string& xorp_root_dir,
                           bool verbose) throw (InitError)
-    : _xorp_root_dir(xorp_root_dir),
-      _verbose(verbose)
+       : _root_node(NULL),
+         _current_node(NULL),
+         _xorp_root_dir(xorp_root_dir),
+         _verbose(verbose)
 {
 }
 
_______________________________________________
Xorp-hackers mailing list
[email protected]
http://mailman.ICSI.Berkeley.EDU/mailman/listinfo/xorp-hackers

Reply via email to