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 + +#endif + +#include + +// 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, /**/ _table_id + }, + { + /* Packet may pass */ + BPF_RET | BPF_K, 0, 0, ~0 + }, + /* : */ + { + /* 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(&snl), sizeof(snl)) < 0) { + + if (bind(_fd, reinterpret_cast(&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 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 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& 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& 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& buffer); void netlink_socket_data(const vector& 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& 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& 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& 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& 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& 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& 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& buffer); void netlink_socket_data(const vector& 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::iterator iter = _fibconfig_entry_gets.begin(); + for (; iter != _fibconfig_entry_gets.end(); iter++) { + (*iter)->notify_table_id_change(tbl_id); + } + } + { + list::iterator iter = _fibconfig_entry_sets.begin(); + for (; iter != _fibconfig_entry_sets.end(); iter++) { + (*iter)->notify_table_id_change(tbl_id); + } + } + { + list::iterator iter = _fibconfig_entry_observers.begin(); + for (; iter != _fibconfig_entry_observers.end(); iter++) { + (*iter)->notify_table_id_change(tbl_id); + } + } + { + list::iterator iter = _fibconfig_table_gets.begin(); + for (; iter != _fibconfig_table_gets.end(); iter++) { + (*iter)->notify_table_id_change(tbl_id); + } + } + { + list::iterator iter = _fibconfig_table_sets.begin(); + for (; iter != _fibconfig_table_sets.end(); iter++) { + (*iter)->notify_table_id_change(tbl_id); + } + } + { + list::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& 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& 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& 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) { }