diff --git a/0001-Issue-4223310-VMA-support-for-kernel-6.10.patch b/0001-Issue-4223310-VMA-support-for-kernel-6.10.patch deleted file mode 100644 index c51762d..0000000 --- a/0001-Issue-4223310-VMA-support-for-kernel-6.10.patch +++ /dev/null @@ -1,2131 +0,0 @@ -From 0389fdac1dd022e93cb332b7b527a576fc8b064f Mon Sep 17 00:00:00 2001 -From: Tomer Cabouly -Date: Tue, 17 Dec 2024 14:57:33 +0200 -Subject: [PATCH] issue: 4223310 VMA support for kernel 6.10 - -Kernel 6.10 netlink has breaked VMA functionality. -Transitioned to libnl - an abstraction that wraps netlink. - -Signed-off-by: Tomer Cabouly ---- - src/vma/proto/netlink_socket_mgr.h | 326 ++++-------- - src/vma/proto/route_table_mgr.cpp | 823 +++++++++++++++-------------- - src/vma/proto/route_table_mgr.h | 66 ++- - src/vma/proto/rule_table_mgr.cpp | 341 ++++++------ - src/vma/proto/rule_table_mgr.h | 36 +- - src/vma/proto/rule_val.cpp | 106 ++-- - src/vma/proto/rule_val.h | 83 ++- - 7 files changed, 854 insertions(+), 927 deletions(-) - -diff --git a/src/vma/proto/netlink_socket_mgr.h b/src/vma/proto/netlink_socket_mgr.h -index 1e1c978c2..dbe1b545c 100644 ---- a/src/vma/proto/netlink_socket_mgr.h -+++ b/src/vma/proto/netlink_socket_mgr.h -@@ -30,10 +30,10 @@ - * SOFTWARE. - */ - -- - #ifndef NETLINK_SOCKET_MGR_H - #define NETLINK_SOCKET_MGR_H - -+#include - #include - #include - #include -@@ -48,6 +48,11 @@ - #include - #include - #include -+#include -+#include -+#include -+#include -+#include - - #include "utils/bullseye.h" - #include "utils/lock_wrapper.h" -@@ -60,261 +65,164 @@ - #include "vma/sock/socket_fd_api.h" - #include "vma/sock/sock-redirect.h" - -- - #ifndef MODULE_NAME --#define MODULE_NAME "netlink_socket_mgr:" -+#define MODULE_NAME "netlink_socket_mgr:" - #endif - --#define NLMSG_TAIL(nmsg) ((struct rtattr *) (((uint8_t *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) -+#define NLMSG_TAIL(nmsg) ((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - - #define MAX_TABLE_SIZE 4096 --#define MSG_BUFF_SIZE 81920 -+#define MSG_BUFF_SIZE 81920 - - // This enum specify the type of data to be retrieve using netlink socket. --enum nl_data_t --{ -- RULE_DATA_TYPE, -- ROUTE_DATA_TYPE --}; -+enum nl_data_t { RULE_DATA_TYPE, ROUTE_DATA_TYPE }; - - /* --* This class manage retrieving data (Rule, Route) from kernel using netlink socket. --*/ --template --class netlink_socket_mgr --{ -+ * This class manage retrieving data (Rule, Route) from kernel using netlink socket. -+ */ -+template class netlink_socket_mgr { - public: -- netlink_socket_mgr(nl_data_t data_type); -- virtual ~netlink_socket_mgr(); -- --protected: -- typedef struct -- { -- Type value[MAX_TABLE_SIZE]; -- uint16_t entries_num; -- } table_t; -- -- table_t m_tab; -- -- virtual bool parse_enrty(nlmsghdr *nl_header, Type *p_val) = 0; -- virtual void update_tbl(); -- virtual void print_val_tbl(); -- -- void build_request(struct nlmsghdr **nl_msg); -- bool query(struct nlmsghdr *&nl_msg, int &len); -- int recv_info(); -- void parse_tbl(int len, int *p_ent_num = NULL); -- -+ netlink_socket_mgr(nl_data_t data_type); -+ virtual ~netlink_socket_mgr(); -+ -+protected: -+ typedef struct { -+ Type value[MAX_TABLE_SIZE]; -+ uint16_t entries_num; -+ } table_t; -+ -+ table_t m_tab; -+ -+ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context) = 0; -+ virtual void update_tbl(); -+ virtual void print_val_tbl(); -+ -+ void build_request(struct nlmsghdr **nl_msg); -+ bool query(struct nlmsghdr *&nl_msg, int &len); -+ int recv_info(); -+ void parse_tbl_from_latest_cache(struct nl_cache *cache_state); -+ - private: -- nl_data_t m_data_type; -+ nl_data_t m_data_type; - -- int m_fd; // netlink socket to communicate with the kernel -- uint32_t m_pid; // process pid -- uint32_t m_seq_num; // seq num of the netlink messages -- char m_msg_buf[MSG_BUFF_SIZE]; // we use this buffer for sending/receiving netlink messages -- uint32_t m_buff_size; -+ nl_sock *m_sock; // netlink socket to communicate with the kernel -+ uint32_t m_pid; // process pid -+ uint32_t m_seq_num; // seq num of the netlink messages -+ char m_msg_buf[MSG_BUFF_SIZE]; // we use this buffer for sending/receiving netlink messages -+ uint32_t m_buff_size; - }; - - /*********************************Implementation ********************************/ - --template --netlink_socket_mgr ::netlink_socket_mgr(nl_data_t data_type) -+template netlink_socket_mgr::netlink_socket_mgr(nl_data_t data_type) - { -- __log_dbg(""); -- -- m_data_type = data_type; -- m_pid = getpid(); -- m_buff_size = MSG_BUFF_SIZE; -- m_seq_num = 0; -+ __log_dbg(""); - -- memset(m_msg_buf, 0, m_buff_size); -+ m_data_type = data_type; -+ m_pid = getpid(); -+ m_buff_size = MSG_BUFF_SIZE; -+ m_seq_num = 0; - -- // Create Socket -- BULLSEYE_EXCLUDE_BLOCK_START -- if ((m_fd = orig_os_api.socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { -- __log_err("NL socket Creation: "); -- return; -- } -+ memset(m_msg_buf, 0, m_buff_size); - -- if (orig_os_api.fcntl(m_fd, F_SETFD, FD_CLOEXEC) != 0) { -- __log_warn("Fail in fctl, error = %d", errno); -- } -- BULLSEYE_EXCLUDE_BLOCK_END -+ // Create Socket - -- __log_dbg("Done"); --} -+ BULLSEYE_EXCLUDE_BLOCK_START -+ m_sock = nl_socket_alloc(); -+ if (m_sock == nullptr) { -+ __log_err("NL socket Creation: "); -+ return; -+ } - --template --netlink_socket_mgr ::~netlink_socket_mgr() --{ -- __log_dbg(""); -- if (m_fd) { -- orig_os_api.close(m_fd); -- m_fd = -1; -- } -- -- __log_dbg("Done"); --} -+ if (nl_connect(m_sock, NETLINK_ROUTE) < 0) { -+ __log_err("NL socket Connection: "); -+ nl_socket_free(m_sock); -+ m_sock = nullptr; -+ return; -+ } - --// This function build Netlink request to retrieve data (Rule, Route) from kernel. --// Parameters : --// nl_msg : request to be returned --template --void netlink_socket_mgr ::build_request(struct nlmsghdr **nl_msg) --{ -- struct rtmsg *rt_msg; -- -- memset(m_msg_buf, 0, m_buff_size); -- -- // point the header and the msg structure pointers into the buffer -- *nl_msg = (struct nlmsghdr *)m_msg_buf; -- rt_msg = (struct rtmsg *)NLMSG_DATA(*nl_msg); -- -- //Fill in the nlmsg header -- (*nl_msg)->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); -- (*nl_msg)->nlmsg_seq = m_seq_num++; -- (*nl_msg)->nlmsg_pid = m_pid; -- rt_msg->rtm_family = AF_INET; -- -- if (m_data_type == RULE_DATA_TYPE) -- { -- (*nl_msg)->nlmsg_type = RTM_GETRULE; -- } -- else if (m_data_type == ROUTE_DATA_TYPE) -- { -- (*nl_msg)->nlmsg_type = RTM_GETROUTE; -- } -- -- (*nl_msg)->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; -+ BULLSEYE_EXCLUDE_BLOCK_END - -+ __log_dbg("Done"); - } - --// Query built request and receive requested data (Rule, Route) --// Parameters: --// nl_msg : request that is built previously. --// len : length of received data. --template --bool netlink_socket_mgr ::query(struct nlmsghdr *&nl_msg, int &len) -+template netlink_socket_mgr::~netlink_socket_mgr() - { -- if(m_fd < 0) -- return false; -- -- BULLSEYE_EXCLUDE_BLOCK_START -- if(orig_os_api.send(m_fd, nl_msg, nl_msg->nlmsg_len, 0) < 0){ -- __log_err("Write To Socket Failed...\n"); -- return false; -- } -- if((len = recv_info()) < 0) { -- __log_err("Read From Socket Failed...\n"); -- return false; -- } -- BULLSEYE_EXCLUDE_BLOCK_END -- -- return true; --} -+ __log_dbg(""); -+ if (m_sock != nullptr) { -+ nl_socket_free(m_sock); -+ m_sock = nullptr; -+ } - --// Receive requested data and save it locally. --// Return length of received data. --template --int netlink_socket_mgr ::recv_info() --{ -- struct nlmsghdr *nlHdr; -- int readLen = 0, msgLen = 0; -- -- char *buf_ptr = m_msg_buf; -- -- do{ -- //Receive response from the kernel -- BULLSEYE_EXCLUDE_BLOCK_START -- if((readLen = orig_os_api.recv(m_fd, buf_ptr, MSG_BUFF_SIZE - msgLen, 0)) < 0){ -- __log_err("SOCK READ: "); -- return -1; -- } -- -- nlHdr = (struct nlmsghdr *)buf_ptr; -- -- //Check if the header is valid -- if((NLMSG_OK(nlHdr, (u_int)readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)) -- { -- __log_err("Error in received packet, readLen = %d, msgLen = %d, type=%d, bufLen = %d", readLen, nlHdr->nlmsg_len, nlHdr->nlmsg_type, MSG_BUFF_SIZE); -- if (nlHdr->nlmsg_len == MSG_BUFF_SIZE) { -- __log_err("The buffer we pass to netlink is too small for reading the whole table"); -- } -- return -1; -- } -- BULLSEYE_EXCLUDE_BLOCK_END -- -- buf_ptr += readLen; -- msgLen += readLen; -- -- //Check if the its the last message -- if(nlHdr->nlmsg_type == NLMSG_DONE || -- (nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) { -- break; -- } -- -- } while((nlHdr->nlmsg_seq != m_seq_num) || (nlHdr->nlmsg_pid != m_pid)); -- return msgLen; -+ __log_dbg("Done"); - } - - // Update data in a table --template --void netlink_socket_mgr ::update_tbl() -+template void netlink_socket_mgr::update_tbl() - { -- struct nlmsghdr *nl_msg = NULL; -- int counter = 0; -- int len = 0; -+ m_tab.entries_num = 0; - -- m_tab.entries_num = 0; -+ struct nl_cache *cache_state = {0}; -+ int err = 0; - -- // Build Netlink request to get route entry -- build_request(&nl_msg); -+ // cache allocation fetches the latest existing rules/routes -+ if (m_data_type == RULE_DATA_TYPE) { -+ err = rtnl_rule_alloc_cache(m_sock, AF_INET, &cache_state); -+ } else if (m_data_type == ROUTE_DATA_TYPE) { -+ err = rtnl_route_alloc_cache(m_sock, AF_INET, 0, &cache_state); -+ } - -- // Query built request and receive requested data -- if (!query(nl_msg, len)) -- return; -+ if (err < 0) { -+ throw_vma_exception("Failed to allocate route cache"); -+ } - -- // Parse received data in custom object (route_val) -- parse_tbl(len, &counter); -- -- m_tab.entries_num = counter; -- -- if (counter >= MAX_TABLE_SIZE) { -- __log_warn("reached the maximum route table size"); -- } -+ // Parse received data in custom object (route_val) -+ parse_tbl_from_latest_cache(cache_state); - } - - // Parse received data in a table --// Parameters: -+// Parameters: - // len : length of received data. - // p_ent_num : number of rows in received data. - template --void netlink_socket_mgr ::parse_tbl(int len, int *p_ent_num) -+void netlink_socket_mgr::parse_tbl_from_latest_cache(struct nl_cache *cache_state) - { -- struct nlmsghdr *nl_header; -- int entry_cnt = 0; -- -- nl_header = (struct nlmsghdr *) m_msg_buf; -- for(;NLMSG_OK(nl_header, (u_int)len) && entry_cnt < MAX_TABLE_SIZE; nl_header = NLMSG_NEXT(nl_header, len)) -- { -- if (parse_enrty(nl_header, &m_tab.value[entry_cnt])) { -- entry_cnt++; -- } -- } -- if (p_ent_num) -- *p_ent_num = entry_cnt; -+ uint16_t entry_cnt = 0; -+ -+ struct nl_iterator_context { -+ Type *p_val_array; -+ uint16_t &entry_cnt; -+ netlink_socket_mgr *this_ptr; -+ } iterator_context = {m_tab.value, entry_cnt, this}; -+ -+ // a lambda can't be casted to a c-fptr with ref captures - so we provide context ourselves -+ nl_cache_foreach( -+ cache_state, -+ [](struct nl_object *nl_obj, void *context) { -+ nl_iterator_context *operation_context = -+ reinterpret_cast(context); -+ const bool is_valid_entry = operation_context->this_ptr->parse_entry( -+ nl_obj, operation_context->p_val_array + operation_context->entry_cnt); -+ if (is_valid_entry) { -+ ++operation_context->entry_cnt; -+ } -+ }, -+ &iterator_context); -+ -+ m_tab.entries_num = entry_cnt; -+ if (m_tab.entries_num >= MAX_TABLE_SIZE) { -+ __log_warn("reached the maximum route table size"); -+ } - } - - //print the table --template --void netlink_socket_mgr ::print_val_tbl() -+template void netlink_socket_mgr::print_val_tbl() - { -- Type *p_val; -- for (int i = 0; i < m_tab.entries_num; i++) -- { -- p_val = &m_tab.value[i]; -- p_val->print_val(); -- } -+ Type *p_val; -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ p_val = &m_tab.value[i]; -+ p_val->print_val(); -+ } - } - - #undef MODULE_NAME -diff --git a/src/vma/proto/route_table_mgr.cpp b/src/vma/proto/route_table_mgr.cpp -index 597d6343a..813772e74 100644 ---- a/src/vma/proto/route_table_mgr.cpp -+++ b/src/vma/proto/route_table_mgr.cpp -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #include - #include - #include -@@ -55,454 +54,470 @@ - #include "ip_address.h" - - // debugging macros --#define MODULE_NAME "rtm:" --#define rt_mgr_if_logpanic __log_panic --#define rt_mgr_logerr __log_err --#define rt_mgr_logwarn __log_warn --#define rt_mgr_loginfo __log_info --#define rt_mgr_logdbg __log_dbg --#define rt_mgr_logfunc __log_func --#define rt_mgr_logfuncall __log_funcall -- --route_table_mgr* g_p_route_table_mgr = NULL; -- --route_table_mgr::route_table_mgr() : netlink_socket_mgr(ROUTE_DATA_TYPE), cache_table_mgr("route_table_mgr") -+#define MODULE_NAME "rtm:" -+#define rt_mgr_if_logpanic __log_panic -+#define rt_mgr_logerr __log_err -+#define rt_mgr_logwarn __log_warn -+#define rt_mgr_loginfo __log_info -+#define rt_mgr_logdbg __log_dbg -+#define rt_mgr_logfunc __log_func -+#define rt_mgr_logfuncall __log_funcall -+ -+route_table_mgr *g_p_route_table_mgr = NULL; -+ -+route_table_mgr::route_table_mgr() -+ : netlink_socket_mgr(ROUTE_DATA_TYPE) -+ , cache_table_mgr("route_table_mgr") - { -- rt_mgr_logdbg(""); -- -- //Read Route table from kernel and save it in local variable. -- update_tbl(); -- -- // create route_entry for each net_dev- needed for receiving port up/down events for net_dev_entry -- route_val *p_val; -- for (int i = 0; i < m_tab.entries_num; i++) -- { -- p_val = &m_tab.value[i]; -- in_addr_t src_addr = p_val->get_src_addr(); -- in_addr_route_entry_map_t::iterator iter = m_rte_list_for_each_net_dev.find(src_addr); -- // if src_addr of interface exists in the map, no need to create another route_entry -- if (iter == m_rte_list_for_each_net_dev.end()) { -- in_addr_t dst_ip = src_addr; -- in_addr_t src_ip = 0; -- uint8_t tos = 0; -- m_rte_list_for_each_net_dev[src_addr] = create_new_entry(route_rule_table_key(dst_ip, src_ip, tos), NULL); -- } -- } -- -- //Print table -- print_val_tbl(); -- -- // register to netlink event -- g_p_netlink_handler->register_event(nlgrpROUTE, this); -- rt_mgr_logdbg("Registered to g_p_netlink_handler"); -- -- rt_mgr_logdbg("Done"); -+ rt_mgr_logdbg(""); -+ -+ //Read Route table from kernel and save it in local variable. -+ update_tbl(); -+ -+ // create route_entry for each net_dev- needed for receiving port up/down events for -+ // net_dev_entry -+ route_val *p_val; -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ p_val = &m_tab.value[i]; -+ in_addr_t src_addr = p_val->get_src_addr(); -+ in_addr_route_entry_map_t::iterator iter = m_rte_list_for_each_net_dev.find(src_addr); -+ // if src_addr of interface exists in the map, no need to create another route_entry -+ if (iter == m_rte_list_for_each_net_dev.end()) { -+ in_addr_t dst_ip = src_addr; -+ in_addr_t src_ip = 0; -+ uint8_t tos = 0; -+ m_rte_list_for_each_net_dev[src_addr] = -+ create_new_entry(route_rule_table_key(dst_ip, src_ip, tos), NULL); -+ } -+ } -+ -+ //Print table -+ print_val_tbl(); -+ -+ // register to netlink event -+ g_p_netlink_handler->register_event(nlgrpROUTE, this); -+ rt_mgr_logdbg("Registered to g_p_netlink_handler"); -+ -+ rt_mgr_logdbg("Done"); - } - - route_table_mgr::~route_table_mgr() - { -- rt_mgr_logdbg(""); -- -- // clear all route_entrys created in the constructor -- in_addr_route_entry_map_t::iterator iter; -- -- while ((iter = m_rte_list_for_each_net_dev.begin()) != m_rte_list_for_each_net_dev.end()) { -- delete(iter->second); -- m_rte_list_for_each_net_dev.erase(iter); -- } -- -- rt_tbl_cach_entry_map_t::iterator cache_itr; -- while ((cache_itr = m_cache_tbl.begin()) != m_cache_tbl.end()) { -- delete(cache_itr->second); -- m_cache_tbl.erase(cache_itr); -- } -- rt_mgr_logdbg("Done"); -+ rt_mgr_logdbg(""); -+ -+ // clear all route_entrys created in the constructor -+ in_addr_route_entry_map_t::iterator iter; -+ -+ while ((iter = m_rte_list_for_each_net_dev.begin()) != m_rte_list_for_each_net_dev.end()) { -+ delete (iter->second); -+ m_rte_list_for_each_net_dev.erase(iter); -+ } -+ -+ rt_tbl_cach_entry_map_t::iterator cache_itr; -+ while ((cache_itr = m_cache_tbl.begin()) != m_cache_tbl.end()) { -+ delete (cache_itr->second); -+ m_cache_tbl.erase(cache_itr); -+ } -+ rt_mgr_logdbg("Done"); - } - - void route_table_mgr::update_tbl() - { -- auto_unlocker lock(m_lock); -+ auto_unlocker lock(m_lock); - -- netlink_socket_mgr::update_tbl(); -+ netlink_socket_mgr::update_tbl(); - -- rt_mgr_update_source_ip(); -+ rt_mgr_update_source_ip(); - -- return; -+ return; - } - - void route_table_mgr::rt_mgr_update_source_ip() - { -- route_val *p_val; -- //for route entries which still have no src ip and no gw -- for (int i = 0; i < m_tab.entries_num; i++) { -- p_val = &m_tab.value[i]; -- if (p_val->get_src_addr() || p_val->get_gw_addr()) continue; -- if (g_p_net_device_table_mgr) { //try to get src ip from net_dev list of the interface -- in_addr_t longest_prefix = 0; -- in_addr_t correct_src = 0; -- local_ip_list_t::iterator lip_iter; -- local_ip_list_t lip_offloaded_list = g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index()); -- if (!lip_offloaded_list.empty()) { -- for (lip_iter = lip_offloaded_list.begin(); lip_offloaded_list.end() != lip_iter; lip_iter++) -- { -- ip_data_t ip = *lip_iter; -- if((p_val->get_dst_addr() & ip.netmask) == (ip.local_addr & ip.netmask)) { //found a match in routing table -- if((ip.netmask | longest_prefix) != longest_prefix){ -- longest_prefix = ip.netmask; // this is the longest prefix match -- correct_src = ip.local_addr; -- } -- } -- } -- if (correct_src) { -- p_val->set_src_addr(correct_src); -- continue; -- } -- } -- } -- // if still no src ip, get it from ioctl -- struct sockaddr_in src_addr; -- char *if_name = (char *)p_val->get_if_name(); -- if (!get_ipv4_from_ifname(if_name, &src_addr)) { -- p_val->set_src_addr(src_addr.sin_addr.s_addr); -- } -- else { -- // Failed mapping if_name to IPv4 address -- rt_mgr_logwarn("could not figure out source ip for rtv = %s", p_val->to_str()); -- } -- } -- -- //for route entries with gateway, do recursive search for src ip -- int num_unresolved_src = m_tab.entries_num; -- int prev_num_unresolved_src = 0; -- do { -- prev_num_unresolved_src = num_unresolved_src; -- num_unresolved_src = 0; -- for (int i = 0; i < m_tab.entries_num; i++) { -- p_val = &m_tab.value[i]; -- if (p_val->get_gw_addr() && !p_val->get_src_addr()) { -- route_val* p_val_dst; -- in_addr_t in_addr = p_val->get_gw_addr(); -- uint32_t table_id = p_val->get_table_id(); -- if (find_route_val(in_addr, table_id, p_val_dst)) { -- if (p_val_dst->get_src_addr()) { -- p_val->set_src_addr(p_val_dst->get_src_addr()); -- } else if (p_val == p_val_dst) { //gateway of the entry lead to same entry -- local_ip_list_t::iterator lip_iter; -- local_ip_list_t lip_offloaded_list = g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index()); -- for (lip_iter = lip_offloaded_list.begin(); lip_offloaded_list.end() != lip_iter; lip_iter++) -- { -- ip_data_t ip = *lip_iter; -- if(p_val->get_gw_addr() == ip.local_addr) { -- p_val->set_gw(0); -- p_val->set_src_addr(ip.local_addr); -- break; -- } -- } -- if (!p_val->get_src_addr()) -- num_unresolved_src++; -- } else { -- num_unresolved_src++; -- } -- // gateway and source are equal, no need of gw. -- if (p_val->get_src_addr() == p_val->get_gw_addr()) { -- p_val->set_gw(0); -- } -- } else { -- num_unresolved_src++; -- } -- } -- } -- } while (num_unresolved_src && prev_num_unresolved_src > num_unresolved_src); -- -- //for route entries which still have no src ip -- for (int i = 0; i < m_tab.entries_num; i++) { -- p_val = &m_tab.value[i]; -- if (p_val->get_src_addr()) continue; -- if (p_val->get_gw_addr()) { -- rt_mgr_logdbg("could not figure out source ip for gw address. rtv = %s", p_val->to_str()); -- } -- // if still no src ip, get it from ioctl -- struct sockaddr_in src_addr; -- char *if_name = (char *)p_val->get_if_name(); -- if (!get_ipv4_from_ifname(if_name, &src_addr)) { -- p_val->set_src_addr(src_addr.sin_addr.s_addr); -- } -- else { -- // Failed mapping if_name to IPv4 address -- rt_mgr_logdbg("could not figure out source ip for rtv = %s", p_val->to_str()); -- } -- } -+ route_val *p_val; -+ //for route entries which still have no src ip and no gw -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ p_val = &m_tab.value[i]; -+ if (p_val->get_src_addr() || p_val->get_gw_addr()) { -+ continue; -+ } -+ if (g_p_net_device_table_mgr) { //try to get src ip from net_dev list of the interface -+ in_addr_t longest_prefix = 0; -+ in_addr_t correct_src = 0; -+ local_ip_list_t::iterator lip_iter; -+ local_ip_list_t lip_offloaded_list = -+ g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index()); -+ if (!lip_offloaded_list.empty()) { -+ for (lip_iter = lip_offloaded_list.begin(); lip_offloaded_list.end() != lip_iter; -+ lip_iter++) { -+ ip_data_t ip = *lip_iter; -+ if ((p_val->get_dst_addr() & ip.netmask) == -+ (ip.local_addr & ip.netmask)) { //found a match in routing table -+ if ((ip.netmask | longest_prefix) != longest_prefix) { -+ longest_prefix = ip.netmask; // this is the longest prefix match -+ correct_src = ip.local_addr; -+ } -+ } -+ } -+ if (correct_src) { -+ p_val->set_src_addr(correct_src); -+ continue; -+ } -+ } -+ } -+ // if still no src ip, get it from ioctl -+ struct sockaddr_in src_addr; -+ char *if_name = (char *)p_val->get_if_name(); -+ if (!get_ipv4_from_ifname(if_name, &src_addr)) { -+ p_val->set_src_addr(src_addr.sin_addr.s_addr); -+ } else { -+ // Failed mapping if_name to IPv4 address -+ rt_mgr_logwarn("could not figure out source ip for rtv = %s", p_val->to_str()); -+ } -+ } -+ -+ //for route entries with gateway, do recursive search for src ip -+ int num_unresolved_src = m_tab.entries_num; -+ int prev_num_unresolved_src = 0; -+ do { -+ prev_num_unresolved_src = num_unresolved_src; -+ num_unresolved_src = 0; -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ p_val = &m_tab.value[i]; -+ if (p_val->get_gw_addr() && !p_val->get_src_addr()) { -+ route_val *p_val_dst; -+ in_addr_t in_addr = p_val->get_gw_addr(); -+ uint32_t table_id = p_val->get_table_id(); -+ if (find_route_val(in_addr, table_id, p_val_dst)) { -+ if (p_val_dst->get_src_addr()) { -+ p_val->set_src_addr(p_val_dst->get_src_addr()); -+ } else if (p_val == p_val_dst) { //gateway of the entry lead to same entry -+ local_ip_list_t::iterator lip_iter; -+ local_ip_list_t lip_offloaded_list = -+ g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index()); -+ for (lip_iter = lip_offloaded_list.begin(); -+ lip_offloaded_list.end() != lip_iter; lip_iter++) { -+ ip_data_t ip = *lip_iter; -+ if (p_val->get_gw_addr() == ip.local_addr) { -+ p_val->set_gw(0); -+ p_val->set_src_addr(ip.local_addr); -+ break; -+ } -+ } -+ if (!p_val->get_src_addr()) { -+ num_unresolved_src++; -+ } -+ } else { -+ num_unresolved_src++; -+ } -+ // gateway and source are equal, no need of gw. -+ if (p_val->get_src_addr() == p_val->get_gw_addr()) { -+ p_val->set_gw(0); -+ } -+ } else { -+ num_unresolved_src++; -+ } -+ } -+ } -+ } while (num_unresolved_src && prev_num_unresolved_src > num_unresolved_src); -+ -+ //for route entries which still have no src ip -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ p_val = &m_tab.value[i]; -+ if (p_val->get_src_addr()) { -+ continue; -+ } -+ if (p_val->get_gw_addr()) { -+ rt_mgr_logdbg("could not figure out source ip for gw address. rtv = %s", -+ p_val->to_str()); -+ } -+ // if still no src ip, get it from ioctl -+ struct sockaddr_in src_addr; -+ char *if_name = (char *)p_val->get_if_name(); -+ if (!get_ipv4_from_ifname(if_name, &src_addr)) { -+ p_val->set_src_addr(src_addr.sin_addr.s_addr); -+ } else { -+ // Failed mapping if_name to IPv4 address -+ rt_mgr_logdbg("could not figure out source ip for rtv = %s", p_val->to_str()); -+ } -+ } - } - --bool route_table_mgr::parse_enrty(nlmsghdr *nl_header, route_val *p_val) -+bool route_table_mgr::parse_entry(struct nl_object *nl_obj, void *p_val_context) - { -- int len; -- struct rtmsg *rt_msg; -- struct rtattr *rt_attribute; -- -- // get route entry header -- rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); -- -- // we are not concerned about the local and default route table -- if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL) -- return false; -- -- p_val->set_protocol(rt_msg->rtm_protocol); -- p_val->set_scope(rt_msg->rtm_scope); -- p_val->set_type(rt_msg->rtm_type); -- p_val->set_table_id(rt_msg->rtm_table); -- -- in_addr_t dst_mask = htonl(VMA_NETMASK(rt_msg->rtm_dst_len)); -- p_val->set_dst_mask(dst_mask); -- p_val->set_dst_pref_len(rt_msg->rtm_dst_len); -- -- len = RTM_PAYLOAD(nl_header); -- rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); -- -- for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { -- parse_attr(rt_attribute, p_val); -- } -- p_val->set_state(true); -- p_val->set_str(); -- return true; -+ route_val *p_val = static_cast(p_val_context); -+ // Cast the generic nl_object to a specific route or rule object -+ struct rtnl_route *route = reinterpret_cast(nl_obj); -+ -+ // we are not concerned about the local and default route table -+ if (rtnl_route_get_family(route) != AF_INET || rtnl_route_get_table(route) == RT_TABLE_LOCAL) { -+ return false; -+ } -+ -+ // Set protocol, scope, type, and table ID using libnl functions -+ p_val->set_protocol(rtnl_route_get_protocol(route)); -+ p_val->set_scope(rtnl_route_get_scope(route)); -+ p_val->set_type(rtnl_route_get_type(route)); -+ p_val->set_table_id(rtnl_route_get_table(route)); -+ -+ // Set destination mask and prefix length -+ struct nl_addr *dst = rtnl_route_get_dst(route); -+ if (dst != nullptr) { -+ in_addr_t dst_mask = htonl(VMA_NETMASK(nl_addr_get_prefixlen(dst))); -+ p_val->set_dst_mask(dst_mask); -+ p_val->set_dst_pref_len(nl_addr_get_prefixlen(dst)); -+ } -+ -+ parse_attr(route, p_val); -+ -+ p_val->set_state(true); -+ p_val->set_str(); -+ return true; - } - --void route_table_mgr::parse_attr(struct rtattr *rt_attribute, route_val *p_val) -+void route_table_mgr::parse_attr(struct rtnl_route *route, route_val *p_val) - { -- switch (rt_attribute->rta_type) { -- case RTA_DST: -- p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); -- break; -- // next hop IPv4 address -- case RTA_GATEWAY: -- p_val->set_gw(*(in_addr_t *)RTA_DATA(rt_attribute)); -- break; -- // unique ID associated with the network interface -- case RTA_OIF: -- p_val->set_if_index(*(int *)RTA_DATA(rt_attribute)); -- char if_name[IFNAMSIZ]; -- if_indextoname(p_val->get_if_index(),if_name); -- p_val->set_if_name(if_name); -- break; -- case RTA_SRC: -- case RTA_PREFSRC: -- p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); -- break; -- case RTA_TABLE: -- p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute)); -- break; -- case RTA_METRICS: -- { -- struct rtattr *rta = (struct rtattr *)RTA_DATA(rt_attribute); -- int len = RTA_PAYLOAD(rt_attribute); -- uint16_t type; -- while (RTA_OK(rta, len)) { -- type = rta->rta_type; -- switch (type) { -- case RTAX_MTU: -- p_val->set_mtu(*(uint32_t *)RTA_DATA(rta)); -- break; -- default: -- rt_mgr_logdbg("got unexpected METRICS %d %x", -- type, *(uint32_t *)RTA_DATA(rta)); -- break; -- } -- rta = RTA_NEXT(rta, len); -- } -- break; -- } -- default: -- rt_mgr_logdbg("got unexpected type %d %x", rt_attribute->rta_type, -- *(uint32_t *)RTA_DATA(rt_attribute)); -- break; -- } -+ struct nl_addr *addr; -+ -+ // Destination Address -+ addr = rtnl_route_get_dst(route); -+ if (addr) { -+ p_val->set_dst_addr(*(in_addr_t *)nl_addr_get_binary_addr(addr)); -+ } -+ -+ // Gateway Address (Next Hop) -+ struct rtnl_nexthop *nh = rtnl_route_nexthop_n(route, 0); // Assuming the first nexthop -+ if (nh) { -+ addr = rtnl_route_nh_get_gateway(nh); -+ if (addr) { -+ p_val->set_gw(*(in_addr_t *)nl_addr_get_binary_addr(addr)); -+ } -+ } -+ -+ // Output Interface Index and Name -+ const int if_index = rtnl_route_nh_get_ifindex(nh); -+ if (if_index > 0) { -+ p_val->set_if_index(if_index); -+ -+ char if_name[IFNAMSIZ] = {0}; -+ if_indextoname(if_index, if_name); -+ p_val->set_if_name(if_name); -+ } -+ -+ // Source Address -+ addr = rtnl_route_get_pref_src(route); -+ if (addr) { -+ p_val->set_src_addr(*(in_addr_t *)nl_addr_get_binary_addr(addr)); -+ } -+ -+ // Table ID -+ int table_id = rtnl_route_get_table(route); -+ p_val->set_table_id(table_id); -+ -+ // Metrics (e.g., MTU) -+ uint32_t mtu = 0; -+ int get_metric_result = rtnl_route_get_metric(route, RTAX_MTU, &mtu); -+ if (get_metric_result == 0) { -+ if (mtu > 0) { -+ p_val->set_mtu(mtu); -+ } -+ } - } - --bool route_table_mgr::find_route_val(in_addr_t &dst, uint32_t table_id, route_val* &p_val) -+bool route_table_mgr::find_route_val(in_addr_t &dst, uint32_t table_id, route_val *&p_val) - { -- ip_address dst_addr = dst; -- rt_mgr_logfunc("dst addr '%s'", dst_addr.to_str().c_str()); -- -- route_val *correct_route_val = NULL; -- int longest_prefix = -1; -- -- for (int i = 0; i < m_tab.entries_num; i++) { -- route_val* p_val_from_tbl = &m_tab.value[i]; -- if (!p_val_from_tbl->is_deleted() && p_val_from_tbl->is_if_up()) { // value was not deleted -- if(p_val_from_tbl->get_table_id() == table_id) { //found a match in routing table ID -- if(p_val_from_tbl->get_dst_addr() == (dst & p_val_from_tbl->get_dst_mask())) { //found a match in routing table -- if(p_val_from_tbl->get_dst_pref_len() > longest_prefix) { // this is the longest prefix match -- longest_prefix = p_val_from_tbl->get_dst_pref_len(); -- correct_route_val = p_val_from_tbl; -- } -- } -- } -- } -- } -- if (correct_route_val) { -- ip_address dst_gw = correct_route_val->get_dst_addr(); -- p_val = correct_route_val; -- rt_mgr_logdbg("found route val[%p]: %s", p_val, p_val->to_str()); -- return true; -- } -- -- rt_mgr_logdbg("destination gw wasn't found"); -- return false; -+ ip_address dst_addr = dst; -+ rt_mgr_logfunc("dst addr '%s'", dst_addr.to_str().c_str()); -+ -+ route_val *correct_route_val = NULL; -+ int longest_prefix = -1; -+ -+ for (int i = 0; i < m_tab.entries_num; i++) { -+ route_val *p_val_from_tbl = &m_tab.value[i]; -+ if (!p_val_from_tbl->is_deleted() && p_val_from_tbl->is_if_up()) { // value was not deleted -+ if (p_val_from_tbl->get_table_id() == table_id) { //found a match in routing table ID -+ if (p_val_from_tbl->get_dst_addr() == -+ (dst & p_val_from_tbl->get_dst_mask())) { //found a match in routing table -+ if (p_val_from_tbl->get_dst_pref_len() > -+ longest_prefix) { // this is the longest prefix match -+ longest_prefix = p_val_from_tbl->get_dst_pref_len(); -+ correct_route_val = p_val_from_tbl; -+ } -+ } -+ } -+ } -+ } -+ if (correct_route_val) { -+ ip_address dst_gw = correct_route_val->get_dst_addr(); -+ p_val = correct_route_val; -+ rt_mgr_logdbg("found route val[%p]: %s", p_val, p_val->to_str()); -+ return true; -+ } -+ -+ rt_mgr_logdbg("destination gw wasn't found"); -+ return false; - } - - bool route_table_mgr::route_resolve(IN route_rule_table_key key, OUT route_result &res) - { -- in_addr_t dst = key.get_dst_ip(); -- ip_address dst_addr = dst; -- rt_mgr_logdbg("dst addr '%s'", dst_addr.to_str().c_str()); -- -- route_val *p_val = NULL; -- std::deque table_id_list; -- -- g_p_rule_table_mgr->rule_resolve(key, table_id_list); -- -- auto_unlocker lock(m_lock); -- std::deque::iterator table_id_iter = table_id_list.begin(); -- for (; table_id_iter != table_id_list.end(); table_id_iter++) { -- if (find_route_val(dst, *table_id_iter, p_val)) { -- res.p_src = p_val->get_src_addr(); -- rt_mgr_logdbg("dst ip '%s' resolved to src addr " -- "'%d.%d.%d.%d'", dst_addr.to_str().c_str(), -- NIPQUAD(res.p_src)); -- res.p_gw = p_val->get_gw_addr(); -- rt_mgr_logdbg("dst ip '%s' resolved to gw addr '%d.%d.%d.%d'", -- dst_addr.to_str().c_str(), NIPQUAD(res.p_gw)); -- res.mtu = p_val->get_mtu(); -- rt_mgr_logdbg("found route mtu %d", res.mtu); -- return true; -- } -- } -- /* prevent usage on false return */ -- return false; -+ in_addr_t dst = key.get_dst_ip(); -+ ip_address dst_addr = dst; -+ rt_mgr_logdbg("dst addr '%s'", dst_addr.to_str().c_str()); -+ -+ route_val *p_val = NULL; -+ std::deque table_id_list; -+ -+ g_p_rule_table_mgr->rule_resolve(key, table_id_list); -+ -+ auto_unlocker lock(m_lock); -+ std::deque::iterator table_id_iter = table_id_list.begin(); -+ for (; table_id_iter != table_id_list.end(); table_id_iter++) { -+ if (find_route_val(dst, *table_id_iter, p_val)) { -+ res.p_src = p_val->get_src_addr(); -+ rt_mgr_logdbg("dst ip '%s' resolved to src addr " -+ "'%d.%d.%d.%d'", -+ dst_addr.to_str().c_str(), NIPQUAD(res.p_src)); -+ res.p_gw = p_val->get_gw_addr(); -+ rt_mgr_logdbg("dst ip '%s' resolved to gw addr '%d.%d.%d.%d'", -+ dst_addr.to_str().c_str(), NIPQUAD(res.p_gw)); -+ res.mtu = p_val->get_mtu(); -+ rt_mgr_logdbg("found route mtu %d", res.mtu); -+ return true; -+ } -+ } -+ /* prevent usage on false return */ -+ return false; - } - --void route_table_mgr::update_entry(INOUT route_entry* p_ent, bool b_register_to_net_dev /*= false*/) -+void route_table_mgr::update_entry(INOUT route_entry *p_ent, bool b_register_to_net_dev /*= false*/) - { -- rt_mgr_logdbg("entry [%p]", p_ent); -- auto_unlocker lock(m_lock); -- if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid -- rt_mgr_logdbg("route_entry is not valid-> update value"); -- rule_entry* p_rr_entry = p_ent->get_rule_entry(); -- std::deque* p_rr_val; -- if (p_rr_entry && p_rr_entry->get_val(p_rr_val)) { -- route_val* p_val = NULL; -- in_addr_t peer_ip = p_ent->get_key().get_dst_ip(); -- uint32_t table_id; -- for (std::deque::iterator p_rule_val = p_rr_val->begin(); p_rule_val != p_rr_val->end(); p_rule_val++) { -- table_id = (*p_rule_val)->get_table_id(); -- if (find_route_val(peer_ip, table_id, p_val)) { -- p_ent->set_val(p_val); -- if (b_register_to_net_dev) { -- //in_addr_t src_addr = p_val->get_src_addr(); -- //net_device_val* p_ndv = g_p_net_device_table_mgr->get_net_device_val(src_addr); -- -- // Check if broadcast IP which is NOT supported -- if (IS_BROADCAST_N(peer_ip)) { -- rt_mgr_logdbg("Disabling Offload for route_entry '%s' - this is BC address", p_ent->to_str().c_str()); -- // Need to route traffic to/from OS -- // Prevent registering of net_device to route entry -- } -- // Check if: Local loopback over Ethernet case which was not supported before OFED 2.1 -- /*else if (p_ndv && (p_ndv->get_transport_type() == VMA_TRANSPORT_ETH) && (peer_ip == src_addr)) { -- rt_mgr_logdbg("Disabling Offload for route_entry '%s' - this is an Ethernet unicast loopback route", p_ent->to_str().c_str()); -- // Need to route traffic to/from OS -- // Prevent registering of net_device to route entry -- }*/ -- else { -- // register to net device for bonding events -- p_ent->register_to_net_device(); -- } -- } -- // All good, validate the new route entry -- p_ent->set_entry_valid(); -- break; -- } else { -- rt_mgr_logdbg("could not find route val for route_entry '%s in table %u'", p_ent->to_str().c_str(), table_id); -- } -- } -- } -- else { -- rt_mgr_logdbg("rule entry is not valid"); -- } -- } -+ rt_mgr_logdbg("entry [%p]", p_ent); -+ auto_unlocker lock(m_lock); -+ if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid -+ rt_mgr_logdbg("route_entry is not valid-> update value"); -+ rule_entry *p_rr_entry = p_ent->get_rule_entry(); -+ std::deque *p_rr_val; -+ if (p_rr_entry && p_rr_entry->get_val(p_rr_val)) { -+ route_val *p_val = NULL; -+ in_addr_t peer_ip = p_ent->get_key().get_dst_ip(); -+ uint32_t table_id; -+ for (std::deque::iterator p_rule_val = p_rr_val->begin(); -+ p_rule_val != p_rr_val->end(); p_rule_val++) { -+ table_id = (*p_rule_val)->get_table_id(); -+ if (find_route_val(peer_ip, table_id, p_val)) { -+ p_ent->set_val(p_val); -+ if (b_register_to_net_dev) { -+ //in_addr_t src_addr = p_val->get_src_addr(); -+ //net_device_val* p_ndv = -+ //g_p_net_device_table_mgr->get_net_device_val(src_addr); -+ -+ // Check if broadcast IP which is NOT supported -+ if (IS_BROADCAST_N(peer_ip)) { -+ rt_mgr_logdbg( -+ "Disabling Offload for route_entry '%s' - this is BC address", -+ p_ent->to_str().c_str()); -+ // Need to route traffic to/from OS -+ // Prevent registering of net_device to route entry -+ } -+ // Check if: Local loopback over Ethernet case which was not supported -+ // before OFED 2.1 -+ /*else if (p_ndv && (p_ndv->get_transport_type() == VMA_TRANSPORT_ETH) && -+ (peer_ip == src_addr)) { rt_mgr_logdbg("Disabling Offload for route_entry -+ '%s' - this is an Ethernet unicast loopback route", -+ p_ent->to_str().c_str()); -+ // Need to route traffic to/from OS -+ // Prevent registering of net_device to route entry -+ }*/ -+ else { -+ // register to net device for bonding events -+ p_ent->register_to_net_device(); -+ } -+ } -+ // All good, validate the new route entry -+ p_ent->set_entry_valid(); -+ break; -+ } else { -+ rt_mgr_logdbg("could not find route val for route_entry '%s in table %u'", -+ p_ent->to_str().c_str(), table_id); -+ } -+ } -+ } else { -+ rt_mgr_logdbg("rule entry is not valid"); -+ } -+ } - } - --route_entry* route_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs) -+route_entry *route_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs) - { -- // no need for lock - lock is activated in cache_collection_mgr::register_observer -- -- rt_mgr_logdbg(""); -- NOT_IN_USE(obs); -- route_entry* p_ent = new route_entry(key); -- update_entry(p_ent, true); -- rt_mgr_logdbg("new entry %p created successfully", p_ent); -- return p_ent; -+ // no need for lock - lock is activated in cache_collection_mgr::register_observer -+ -+ rt_mgr_logdbg(""); -+ NOT_IN_USE(obs); -+ route_entry *p_ent = new route_entry(key); -+ update_entry(p_ent, true); -+ rt_mgr_logdbg("new entry %p created successfully", p_ent); -+ return p_ent; - } - --void route_table_mgr::new_route_event(route_val* netlink_route_val) -+void route_table_mgr::new_route_event(route_val *netlink_route_val) - { -- if (!netlink_route_val) { -- rt_mgr_logdbg("Invalid route entry"); -- return; -- } -- -- if (m_tab.entries_num >= MAX_TABLE_SIZE) { -- rt_mgr_logwarn("No available space for new route entry"); -- return; -- } -- -- auto_unlocker lock(m_lock); -- route_val* p_route_val = &m_tab.value[m_tab.entries_num]; -- p_route_val->set_dst_addr(netlink_route_val->get_dst_addr()); -- p_route_val->set_dst_mask(netlink_route_val->get_dst_mask()); -- p_route_val->set_dst_pref_len(netlink_route_val->get_dst_pref_len()); -- p_route_val->set_src_addr(netlink_route_val->get_src_addr()); -- p_route_val->set_gw(netlink_route_val->get_gw_addr()); -- p_route_val->set_protocol(netlink_route_val->get_protocol()); -- p_route_val->set_scope(netlink_route_val->get_scope()); -- p_route_val->set_type(netlink_route_val->get_type()); -- p_route_val->set_table_id(netlink_route_val->get_table_id()); -- p_route_val->set_if_index(netlink_route_val->get_if_index()); -- p_route_val->set_if_name(const_cast (netlink_route_val->get_if_name())); -- p_route_val->set_mtu((netlink_route_val->get_mtu())); -- p_route_val->set_state(true); -- p_route_val->set_str(); -- p_route_val->print_val(); -- ++m_tab.entries_num; -+ if (!netlink_route_val) { -+ rt_mgr_logdbg("Invalid route entry"); -+ return; -+ } -+ -+ if (m_tab.entries_num >= MAX_TABLE_SIZE) { -+ rt_mgr_logwarn("No available space for new route entry"); -+ return; -+ } -+ -+ auto_unlocker lock(m_lock); -+ route_val *p_route_val = &m_tab.value[m_tab.entries_num]; -+ p_route_val->set_dst_addr(netlink_route_val->get_dst_addr()); -+ p_route_val->set_dst_mask(netlink_route_val->get_dst_mask()); -+ p_route_val->set_dst_pref_len(netlink_route_val->get_dst_pref_len()); -+ p_route_val->set_src_addr(netlink_route_val->get_src_addr()); -+ p_route_val->set_gw(netlink_route_val->get_gw_addr()); -+ p_route_val->set_protocol(netlink_route_val->get_protocol()); -+ p_route_val->set_scope(netlink_route_val->get_scope()); -+ p_route_val->set_type(netlink_route_val->get_type()); -+ p_route_val->set_table_id(netlink_route_val->get_table_id()); -+ p_route_val->set_if_index(netlink_route_val->get_if_index()); -+ p_route_val->set_if_name(const_cast(netlink_route_val->get_if_name())); -+ p_route_val->set_mtu((netlink_route_val->get_mtu())); -+ p_route_val->set_state(true); -+ p_route_val->set_str(); -+ p_route_val->print_val(); -+ ++m_tab.entries_num; - } - - void route_table_mgr::notify_cb(event *ev) - { -- rt_mgr_logdbg("received route event from netlink"); -- -- route_nl_event *route_netlink_ev = dynamic_cast (ev); -- if (!route_netlink_ev) { -- rt_mgr_logwarn("Received non route event!!!"); -- return; -- } -- -- netlink_route_info* p_netlink_route_info = route_netlink_ev->get_route_info(); -- if (!p_netlink_route_info) { -- rt_mgr_logdbg("Received invalid route event!!!"); -- return; -- } -- -- switch(route_netlink_ev->nl_type) { -- case RTM_NEWROUTE: -- new_route_event(p_netlink_route_info->get_route_val()); -- break; -+ rt_mgr_logdbg("received route event from netlink"); -+ -+ route_nl_event *route_netlink_ev = dynamic_cast(ev); -+ if (!route_netlink_ev) { -+ rt_mgr_logwarn("Received non route event!!!"); -+ return; -+ } -+ -+ netlink_route_info *p_netlink_route_info = route_netlink_ev->get_route_info(); -+ if (!p_netlink_route_info) { -+ rt_mgr_logdbg("Received invalid route event!!!"); -+ return; -+ } -+ -+ switch (route_netlink_ev->nl_type) { -+ case RTM_NEWROUTE: -+ new_route_event(p_netlink_route_info->get_route_val()); -+ break; - #if 0 - case RTM_DELROUTE: - del_route_event(p_netlink_route_info->get_route_val()); - break; - #endif -- default: -- rt_mgr_logdbg("Route event (%u) is not handled", route_netlink_ev->nl_type); -- break; -- } -+ default: -+ rt_mgr_logdbg("Route event (%u) is not handled", route_netlink_ev->nl_type); -+ break; -+ } - } -diff --git a/src/vma/proto/route_table_mgr.h b/src/vma/proto/route_table_mgr.h -index fb0310f13..9a80945ae 100644 ---- a/src/vma/proto/route_table_mgr.h -+++ b/src/vma/proto/route_table_mgr.h -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #ifndef ROUTE_TABLE_MGR_H - #define ROUTE_TABLE_MGR_H - -@@ -45,47 +44,56 @@ - - #define ADDR_LEN 46 // needs 16-bytes for IPv4, and 46-bytes for IPv6 - --typedef std::unordered_map in_addr_route_entry_map_t; --typedef std::unordered_map *> rt_tbl_cach_entry_map_t; -+typedef std::unordered_map in_addr_route_entry_map_t; -+typedef std::unordered_map *> -+ rt_tbl_cach_entry_map_t; - - struct route_result { -- in_addr_t p_src; -- in_addr_t p_gw; -- uint32_t mtu; -- route_result(): p_src(0), p_gw(0) ,mtu(0) {} -+ in_addr_t p_src; -+ in_addr_t p_gw; -+ uint32_t mtu; -+ route_result() -+ : p_src(0) -+ , p_gw(0) -+ , mtu(0) -+ { -+ } - }; - --class route_table_mgr : public netlink_socket_mgr, public cache_table_mgr, public observer --{ -+class route_table_mgr : public netlink_socket_mgr, -+ public cache_table_mgr, -+ public observer { - public: -- route_table_mgr(); -- virtual ~route_table_mgr(); -+ route_table_mgr(); -+ virtual ~route_table_mgr(); - -- bool route_resolve(IN route_rule_table_key key, OUT route_result &res); -+ bool route_resolve(IN route_rule_table_key key, OUT route_result &res); - -- route_entry* create_new_entry(route_rule_table_key key, const observer *obs); -- void update_entry(INOUT route_entry* p_ent, bool b_register_to_net_dev = false); -+ route_entry *create_new_entry(route_rule_table_key key, const observer *obs); -+ void update_entry(INOUT route_entry *p_ent, bool b_register_to_net_dev = false); - -- virtual void notify_cb(event *ev); -+ virtual void notify_cb(event *ev); - - protected: -- virtual bool parse_enrty(nlmsghdr *nl_header, route_val *p_val); -+ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context); - - private: -- // in constructor creates route_entry for each net_dev, to receive events in case there are no other route_entrys -- in_addr_route_entry_map_t m_rte_list_for_each_net_dev; -- -- bool find_route_val(in_addr_t &dst_addr, uint32_t table_id, route_val* &p_val); -- -- // save current main rt table -- void update_tbl(); -- void parse_attr(struct rtattr *rt_attribute, route_val *p_val); -- -- void rt_mgr_update_source_ip(); -- -- void new_route_event(route_val* netlink_route_val); -+ // in constructor creates route_entry for each net_dev, to receive events in case there are no -+ // other route_entrys -+ in_addr_route_entry_map_t m_rte_list_for_each_net_dev; -+ -+ bool find_route_val(in_addr_t &dst_addr, uint32_t table_id, route_val *&p_val); -+ -+ // save current main rt table -+ void update_tbl(); -+ void parse_attr(struct rtnl_route *route, route_val *p_val); -+ -+ void rt_mgr_update_source_ip(); -+ -+ void new_route_event(route_val *netlink_route_val); - }; - --extern route_table_mgr* g_p_route_table_mgr; -+extern route_table_mgr *g_p_route_table_mgr; - - #endif /* ROUTE_TABLE_MGR_H */ -diff --git a/src/vma/proto/rule_table_mgr.cpp b/src/vma/proto/rule_table_mgr.cpp -index 32847014f..84ba80345 100644 ---- a/src/vma/proto/rule_table_mgr.cpp -+++ b/src/vma/proto/rule_table_mgr.cpp -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #include - #include - #include -@@ -53,228 +52,236 @@ - #include "rule_table_mgr.h" - #include "vma/sock/socket_fd_api.h" - #include "vma/sock/sock-redirect.h" --#include "ip_address.h" - - // debugging macros --#define MODULE_NAME "rrm:" -- --#define rr_mgr_if_logpanic __log_panic --#define rr_mgr_logerr __log_err --#define rr_mgr_logwarn __log_warn --#define rr_mgr_loginfo __log_info --#define rr_mgr_logdbg __log_dbg --#define rr_mgr_logfunc __log_func --#define rr_mgr_logfuncall __log_funcall -- --rule_table_mgr* g_p_rule_table_mgr = NULL; -- --rule_table_mgr::rule_table_mgr() : netlink_socket_mgr(RULE_DATA_TYPE), cache_table_mgr*>("rule_table_mgr") -+#define MODULE_NAME "rrm:" -+ -+#define rr_mgr_if_logpanic __log_panic -+#define rr_mgr_logerr __log_err -+#define rr_mgr_logwarn __log_warn -+#define rr_mgr_loginfo __log_info -+#define rr_mgr_logdbg __log_dbg -+#define rr_mgr_logfunc __log_func -+#define rr_mgr_logfuncall __log_funcall -+ -+rule_table_mgr *g_p_rule_table_mgr = NULL; -+ -+rule_table_mgr::rule_table_mgr() -+ : netlink_socket_mgr(RULE_DATA_TYPE) -+ , cache_table_mgr *>("rule_table_mgr") - { - -- rr_mgr_logdbg(""); -+ rr_mgr_logdbg(""); - -- //Read Rule table from kernel and save it in local variable. -- update_tbl(); -- -- //Print table -- print_val_tbl(); -- -- rr_mgr_logdbg("Done"); -+ //Read Rule table from kernel and save it in local variable. -+ update_tbl(); -+ -+ //Print table -+ print_val_tbl(); -+ -+ rr_mgr_logdbg("Done"); - } - - //This function uses Netlink to get routing rules saved in kernel then saved it locally. - void rule_table_mgr::update_tbl() - { -- auto_unlocker lock(m_lock); -+ auto_unlocker lock(m_lock); - -- netlink_socket_mgr::update_tbl(); -+ netlink_socket_mgr::update_tbl(); - -- return; -+ return; - } - - // Parse received rule entry into custom object (rule_val). --// Parameters: -+// Parameters: - // nl_header : object that contain rule entry. - // p_val : custom object that contain parsed rule data. - // return true if its not related to local or default table, false otherwise. --bool rule_table_mgr::parse_enrty(nlmsghdr *nl_header, rule_val *p_val) -+bool rule_table_mgr::parse_entry(struct nl_object *nl_obj, void *p_val_context) - { -- int len; -- struct rtmsg *rt_msg; -- struct rtattr *rt_attribute; -- -- // get rule entry header -- rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); -- -- // we are not concerned about the local and default rule table -- if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL) -- return false; -- -- p_val->set_protocol(rt_msg->rtm_protocol); -- p_val->set_scope(rt_msg->rtm_scope); -- p_val->set_type(rt_msg->rtm_type); -- p_val->set_tos(rt_msg->rtm_tos); -- p_val->set_table_id(rt_msg->rtm_table); -- -- len = RTM_PAYLOAD(nl_header); -- rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); -- -- for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { -- parse_attr(rt_attribute, p_val); -- } -- p_val->set_state(true); -- p_val->set_str(); -- return true; -+ rule_val *p_val = static_cast(p_val_context); -+ // Cast the generic nl_object to a specific route or rule object -+ struct rtnl_rule *rule = reinterpret_cast(nl_obj); -+ -+ uint32_t table_id = rtnl_rule_get_table(rule); -+ if (rtnl_rule_get_family(rule) != AF_INET || table_id == RT_TABLE_LOCAL) { -+ return false; -+ } -+ -+ p_val->set_tos(rtnl_rule_get_dsfield(rule)); -+ p_val->set_table_id(table_id); -+ -+ parse_attr(rule, p_val); -+ -+ p_val->set_state(true); -+ p_val->set_str(); -+ return true; - } - - // Parse received rule attribute for given rule. --// Parameters: -+// Parameters: - // rt_attribute : object that contain rule attribute. - // p_val : custom object that contain parsed rule data. --void rule_table_mgr::parse_attr(struct rtattr *rt_attribute, rule_val *p_val) -+void rule_table_mgr::parse_attr(struct rtnl_rule *rule, rule_val *p_val) - { -- switch (rt_attribute->rta_type) { -- case FRA_PRIORITY: -- p_val->set_priority(*(uint32_t *)RTA_DATA(rt_attribute)); -- break; -- case FRA_DST: -- p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); -- break; -- case FRA_SRC: -- p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); -- break; -- case FRA_IFNAME: -- p_val->set_iif_name((char *)RTA_DATA(rt_attribute)); -- break; -- case FRA_TABLE: -- p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute)); -- break; -+ // FRA_PRIORITY: Rule Priority -+ uint32_t priority = rtnl_rule_get_prio(rule); -+ if (priority) { -+ p_val->set_priority(priority); -+ } -+ -+ // FRA_DST: Destination Address -+ struct nl_addr *dst = rtnl_rule_get_dst(rule); -+ if (dst) { -+ p_val->set_dst_addr(*(in_addr_t *)nl_addr_get_binary_addr(dst)); -+ } -+ -+ // FRA_SRC: Source Address -+ struct nl_addr *src = rtnl_rule_get_src(rule); -+ if (src) { -+ p_val->set_src_addr(*(in_addr_t *)nl_addr_get_binary_addr(src)); -+ } -+ -+ // FRA_IFNAME: Input Interface Name -+ char *iif_name = rtnl_rule_get_iif(rule); -+ if (iif_name) { -+ p_val->set_iif_name(iif_name); -+ } -+ -+ // FRA_TABLE: Table ID -+ uint32_t table_id = rtnl_rule_get_table(rule); -+ if (table_id) { -+ p_val->set_table_id(table_id); -+ } -+ - #if DEFINED_FRA_OIFNAME -- case FRA_OIFNAME: -- p_val->set_oif_name((char *)RTA_DATA(rt_attribute)); -- break; -+ // FRA_OIFNAME: Output Interface Name (if available) -+ char *oif_name = rtnl_rule_get_oif(rule); -+ if (oif_name) { -+ p_val->set_oif_name(oif_name); -+ } - #endif -- default: -- rr_mgr_logdbg("got undetected rta_type %d %x", rt_attribute->rta_type, *(uint32_t *)RTA_DATA(rt_attribute)); -- break; -- } - } - -- --// Create rule entry object for given destination key and fill it with matching rule value from rule table. --// Parameters: -+// Create rule entry object for given destination key and fill it with matching rule value from rule -+// table. Parameters: - // key : key object that contain information about destination. - // obs : object that contain observer for specific rule entry. - // Returns created rule entry object. --rule_entry* rule_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs) -+rule_entry *rule_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs) - { -- rr_mgr_logdbg(""); -- NOT_IN_USE(obs); -- rule_entry* p_ent = new rule_entry(key); -- update_entry(p_ent); -- rr_mgr_logdbg("new entry %p created successfully", p_ent); -- return p_ent; -+ rr_mgr_logdbg(""); -+ NOT_IN_USE(obs); -+ rule_entry *p_ent = new rule_entry(key); -+ update_entry(p_ent); -+ rr_mgr_logdbg("new entry %p created successfully", p_ent); -+ return p_ent; - } - - // Update invalid rule entry with matching rule value from rule table. --// Parameters: -+// Parameters: - // p_ent : rule entry that will be updated if it is invalid. --void rule_table_mgr::update_entry(rule_entry* p_ent) -+void rule_table_mgr::update_entry(rule_entry *p_ent) - { -- rr_mgr_logdbg("entry [%p]", p_ent); -- auto_unlocker lock(m_lock); -- -- if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid -- -- rr_mgr_logdbg("rule_entry is not valid-> update value"); -- std::deque* p_rrv; -- p_ent->get_val(p_rrv); -- /* p_rrv->clear(); TODO for future rule live updates */ -- if (!find_rule_val(p_ent->get_key(), p_rrv)) { -- rr_mgr_logdbg("ERROR: could not find rule val for rule_entry '%s'", p_ent->to_str().c_str()); -- } -- } -+ rr_mgr_logdbg("entry [%p]", p_ent); -+ auto_unlocker lock(m_lock); -+ -+ if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid -+ -+ rr_mgr_logdbg("rule_entry is not valid-> update value"); -+ std::deque *p_rrv; -+ p_ent->get_val(p_rrv); -+ /* p_rrv->clear(); TODO for future rule live updates */ -+ if (!find_rule_val(p_ent->get_key(), p_rrv)) { -+ rr_mgr_logdbg("ERROR: could not find rule val for rule_entry '%s'", -+ p_ent->to_str().c_str()); -+ } -+ } - } - --// Find rule form rule table that match given destination info. --// Parameters: -+// Find rule form rule table that match given destination info. -+// Parameters: - // key : key object that contain information about destination. --// p_val : list of rule_val object that will contain information about all rule that match destination info -+// p_val : list of rule_val object that will contain information about all rule that match -+//destination info - // Returns true if at least one rule match destination info, false otherwise. --bool rule_table_mgr::find_rule_val(route_rule_table_key key, std::deque* &p_val) -+bool rule_table_mgr::find_rule_val(route_rule_table_key key, std::deque *&p_val) - { -- rr_mgr_logfunc("destination info %s:", key.to_str().c_str()); -+ rr_mgr_logfunc("destination info %s:", key.to_str().c_str()); - -- for (int index = 0; index < m_tab.entries_num; index++) { -- rule_val* p_val_from_tbl = &m_tab.value[index]; -- if (p_val_from_tbl->is_valid() && is_matching_rule(key, p_val_from_tbl)) { -- p_val->push_back(p_val_from_tbl); -- rr_mgr_logdbg("found rule val[%p]: %s", p_val_from_tbl, p_val_from_tbl->to_str()); -- } -- } -+ for (int index = 0; index < m_tab.entries_num; index++) { -+ rule_val *p_val_from_tbl = &m_tab.value[index]; -+ if (p_val_from_tbl->is_valid() && is_matching_rule(key, p_val_from_tbl)) { -+ p_val->push_back(p_val_from_tbl); -+ rr_mgr_logdbg("found rule val[%p]: %s", p_val_from_tbl, p_val_from_tbl->to_str()); -+ } -+ } - -- return !p_val->empty(); -+ return !p_val->empty(); - } - --// Check matching between given destination info. and specific rule from rule table. --// Parameters: -+// Check matching between given destination info. and specific rule from rule table. -+// Parameters: - // key : key object that contain information about destination. --// p_val : rule_val object that contain information about specific rule from rule table -+// p_val : rule_val object that contain information about specific rule from rule table - // Returns true if destination info match rule value, false otherwise. --bool rule_table_mgr::is_matching_rule(route_rule_table_key key, rule_val* p_val) -+bool rule_table_mgr::is_matching_rule(route_rule_table_key key, rule_val *p_val) - { - -- in_addr_t m_dst_ip = key.get_dst_ip(); -- in_addr_t m_src_ip = key.get_src_ip(); -- uint8_t m_tos = key.get_tos(); -- -- in_addr_t rule_dst_ip = p_val->get_dst_addr(); -- in_addr_t rule_src_ip = p_val->get_src_addr(); -- uint8_t rule_tos = p_val->get_tos(); -- char* rule_iif_name = (char *)p_val->get_iif_name(); -- char* rule_oif_name = (char *)p_val->get_oif_name(); -- -- bool is_match = false; -- -- // Only destination IP, source IP and TOS are checked with rule, since IIF and OIF is not filled in dst_entry object. -- if ((rule_dst_ip == 0) || (rule_dst_ip == m_dst_ip)) { // Check match in destination IP -- -- if ((rule_src_ip == 0) || (rule_src_ip == m_src_ip)) { // Check match in source IP -- -- if ((rule_tos == 0) || (rule_tos == m_tos)) { // Check match in TOS value -- -- if (strcmp(rule_iif_name, "") == 0) { // Check that rule doesn't contain IIF since we can't check match with -- -- if (strcmp(rule_oif_name, "") == 0) { // Check that rule doesn't contain OIF since we can't check match with -- is_match = true; -- } -- } -- } -- } -- } -- -- return is_match; -+ in_addr_t m_dst_ip = key.get_dst_ip(); -+ in_addr_t m_src_ip = key.get_src_ip(); -+ uint8_t m_tos = key.get_tos(); -+ -+ in_addr_t rule_dst_ip = p_val->get_dst_addr(); -+ in_addr_t rule_src_ip = p_val->get_src_addr(); -+ uint8_t rule_tos = p_val->get_tos(); -+ char *rule_iif_name = (char *)p_val->get_iif_name(); -+ char *rule_oif_name = (char *)p_val->get_oif_name(); -+ -+ bool is_match = false; -+ -+ // Only destination IP, source IP and TOS are checked with rule, since IIF and OIF is not filled -+ // in dst_entry object. -+ if ((rule_dst_ip == 0) || (rule_dst_ip == m_dst_ip)) { // Check match in destination IP -+ -+ if ((rule_src_ip == 0) || (rule_src_ip == m_src_ip)) { // Check match in source IP -+ -+ if ((rule_tos == 0) || (rule_tos == m_tos)) { // Check match in TOS value -+ -+ if (strcmp(rule_iif_name, "") == -+ 0) { // Check that rule doesn't contain IIF since we can't check match with -+ -+ if (strcmp(rule_oif_name, "") == -+ 0) { // Check that rule doesn't contain OIF since we can't check match with -+ is_match = true; -+ } -+ } -+ } -+ } -+ } -+ -+ return is_match; - } - - // Find table ID for given destination info. --// Parameters: -+// Parameters: - // key : key object that contain information about destination. --// table_id_list : list that will contain table ID for all rule that match destination info -+// table_id_list : list that will contain table ID for all rule that match destination info - // Returns true if at least one rule match destination info, false otherwise. - bool rule_table_mgr::rule_resolve(route_rule_table_key key, std::deque &table_id_list) - { -- rr_mgr_logdbg("dst info: '%s'", key.to_str().c_str()); -- -- std::deque values; -- std::deque* p_values = &values; -- auto_unlocker lock(m_lock); -- if (find_rule_val(key, p_values)) { -- for (std::deque::iterator val = values.begin(); val != values.end(); val++) { -- table_id_list.push_back((*val)->get_table_id()); -- rr_mgr_logdbg("dst info: '%s' resolved to table ID '%u'", key.to_str().c_str(), (*val)->get_table_id()); -- } -- } -- -- return !table_id_list.empty(); --} -+ rr_mgr_logdbg("dst info: '%s'", key.to_str().c_str()); -+ -+ std::deque values; -+ std::deque *p_values = &values; -+ auto_unlocker lock(m_lock); -+ if (find_rule_val(key, p_values)) { -+ for (std::deque::iterator val = values.begin(); val != values.end(); val++) { -+ table_id_list.push_back((*val)->get_table_id()); -+ rr_mgr_logdbg("dst info: '%s' resolved to table ID '%u'", key.to_str().c_str(), -+ (*val)->get_table_id()); -+ } -+ } - -+ return !table_id_list.empty(); -+} -diff --git a/src/vma/proto/rule_table_mgr.h b/src/vma/proto/rule_table_mgr.h -index f3f6fdcf7..4d2c68361 100644 ---- a/src/vma/proto/rule_table_mgr.h -+++ b/src/vma/proto/rule_table_mgr.h -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #ifndef RULE_TABLE_MGR_H - #define RULE_TABLE_MGR_H - -@@ -41,30 +40,29 @@ - #include "rule_entry.h" - - /* --* This class manages routing rule related operation such as getting rules from kernel, --* finding table ID for given destination info and cashing usage history for rule table. --*/ --class rule_table_mgr : public netlink_socket_mgr, public cache_table_mgr*> --{ -+ * This class manages routing rule related operation such as getting rules from kernel, -+ * finding table ID for given destination info and cashing usage history for rule table. -+ */ -+class rule_table_mgr : public netlink_socket_mgr, -+ public cache_table_mgr *> { - public: -- rule_table_mgr(); -- -- rule_entry* create_new_entry(route_rule_table_key key, const observer *obs); -- void update_entry(rule_entry* p_ent); -- bool rule_resolve(route_rule_table_key key, std::deque &table_id_list); -+ rule_table_mgr(); -+ -+ rule_entry *create_new_entry(route_rule_table_key key, const observer *obs); -+ void update_entry(rule_entry *p_ent); -+ bool rule_resolve(route_rule_table_key key, std::deque &table_id_list); - - protected: -- virtual bool parse_enrty(nlmsghdr *nl_header, rule_val *p_val); -- virtual void update_tbl(); -- -+ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context); -+ virtual void update_tbl(); -+ - private: -+ void parse_attr(struct rtnl_rule *rule, rule_val *p_val); - -- void parse_attr(struct rtattr *rt_attribute, rule_val *p_val); -- -- bool find_rule_val(route_rule_table_key key, std::deque* &p_val); -- bool is_matching_rule(route_rule_table_key rrk, rule_val* p_val); -+ bool find_rule_val(route_rule_table_key key, std::deque *&p_val); -+ bool is_matching_rule(route_rule_table_key rrk, rule_val *p_val); - }; - --extern rule_table_mgr* g_p_rule_table_mgr; -+extern rule_table_mgr *g_p_rule_table_mgr; - - #endif /* RULE_TABLE_MGR_H */ -diff --git a/src/vma/proto/rule_val.cpp b/src/vma/proto/rule_val.cpp -index 3c56f4561..937a419eb 100644 ---- a/src/vma/proto/rule_val.cpp -+++ b/src/vma/proto/rule_val.cpp -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #include - #include - #include -@@ -38,76 +37,77 @@ - #include "rule_val.h" - #include "rule_table_mgr.h" - --#define MODULE_NAME "rrv" -+#define MODULE_NAME "rrv" - --#define rr_val_loginfo __log_info_info --#define rr_val_logdbg __log_info_dbg --#define rr_val_logfunc __log_info_func -+#define rr_val_loginfo __log_info_info -+#define rr_val_logdbg __log_info_dbg -+#define rr_val_logfunc __log_info_func - --rule_val::rule_val(): cache_observer() -+rule_val::rule_val() -+ : cache_observer() - { -- m_protocol = 0; -- m_scope = 0; -- m_type = 0; -- m_dst_addr = 0; -- m_src_addr = 0; -- memset(m_oif_name, 0, IFNAMSIZ * sizeof(char)); -- memset(m_iif_name, 0, IFNAMSIZ * sizeof(char)); -- m_priority = 0; -- m_tos = 0; -- m_table_id = 0; -- m_is_valid = false; -- memset(m_str, 0, BUFF_SIZE * sizeof(char)); -- -+ m_dst_addr = 0; -+ m_src_addr = 0; -+ memset(m_oif_name, 0, IFNAMSIZ * sizeof(char)); -+ memset(m_iif_name, 0, IFNAMSIZ * sizeof(char)); -+ m_priority = 0; -+ m_tos = 0; -+ m_table_id = 0; -+ m_is_valid = false; -+ memset(m_str, 0, BUFF_SIZE * sizeof(char)); - } - - //This function build string that represent a row in the rule table. - void rule_val::set_str() - { -- char str_addr[INET_ADDRSTRLEN]; -- char str_x[100] = {0}; -+ char str_addr[INET_ADDRSTRLEN]; -+ char str_x[100] = {0}; - -- sprintf(m_str, "Priority :%-10u", m_priority); -+ sprintf(m_str, "Priority :%-10u", m_priority); - -- if (m_src_addr != 0) { -- inet_ntop(AF_INET, &m_src_addr_in_addr, str_addr, sizeof(str_addr)); -- sprintf(str_x, " from :%-10s", str_addr); -- } -- strcat(m_str, str_x); -+ if (m_src_addr != 0) { -+ inet_ntop(AF_INET, &m_src_addr_in_addr, str_addr, sizeof(str_addr)); -+ sprintf(str_x, " from :%-10s", str_addr); -+ } -+ strcat(m_str, str_x); - -- str_x[0] = '\0'; -- if (m_dst_addr != 0) { -- inet_ntop(AF_INET, &m_dst_addr_in_addr, str_addr, sizeof(str_addr)); -- sprintf(str_x, " to :%-12s", str_addr); -- } -- strcat(m_str, str_x); -+ str_x[0] = '\0'; -+ if (m_dst_addr != 0) { -+ inet_ntop(AF_INET, &m_dst_addr_in_addr, str_addr, sizeof(str_addr)); -+ sprintf(str_x, " to :%-12s", str_addr); -+ } -+ strcat(m_str, str_x); - -- str_x[0] = '\0'; -- if (m_tos != 0) -- sprintf(str_x, " tos :%-11u", m_tos); -- strcat(m_str, str_x); -+ str_x[0] = '\0'; -+ if (m_tos != 0) { -+ sprintf(str_x, " tos :%-11u", m_tos); -+ } -+ strcat(m_str, str_x); - -- str_x[0] = '\0'; -- if (strcmp(m_iif_name, "") != 0) -- sprintf(str_x, " iif :%-11s", m_iif_name); -- strcat(m_str, str_x); -+ str_x[0] = '\0'; -+ if (strcmp(m_iif_name, "") != 0) { -+ sprintf(str_x, " iif :%-11s", m_iif_name); -+ } -+ strcat(m_str, str_x); - -- str_x[0] = '\0'; -- if (strcmp(m_oif_name, "") != 0) -- sprintf(str_x, " oif :%-11s", m_oif_name); -- strcat(m_str, str_x); -+ str_x[0] = '\0'; -+ if (strcmp(m_oif_name, "") != 0) { -+ sprintf(str_x, " oif :%-11s", m_oif_name); -+ } -+ strcat(m_str, str_x); - -- str_x[0] = '\0'; -- if (m_table_id != RT_TABLE_MAIN) -- sprintf(str_x, " lookup table :%-10u", m_table_id); -- else -- sprintf(str_x, " lookup table :%-10s", "main"); -- strcat(m_str, str_x); -+ str_x[0] = '\0'; -+ if (m_table_id != RT_TABLE_MAIN) { -+ sprintf(str_x, " lookup table :%-10u", m_table_id); -+ } else { -+ sprintf(str_x, " lookup table :%-10s", "main"); -+ } -+ strcat(m_str, str_x); - } - - //This function prints a string that represent a row in the rule table as debug log. - void rule_val::print_val() - { -- set_str(); -- rr_val_logdbg("%s", to_str()); -+ set_str(); -+ rr_val_logdbg("%s", to_str()); - } -diff --git a/src/vma/proto/rule_val.h b/src/vma/proto/rule_val.h -index 9d6f8d200..80ec81f7c 100644 ---- a/src/vma/proto/rule_val.h -+++ b/src/vma/proto/rule_val.h -@@ -30,7 +30,6 @@ - * SOFTWARE. - */ - -- - #ifndef RULE_VAL_H - #define RULE_VAL_H - -@@ -44,61 +43,53 @@ - /* - This class will contain information for given routing rule entry. - */ --class rule_val : public cache_observer --{ -+class rule_val : public cache_observer { - public: -- rule_val(); -- virtual ~rule_val() {}; -+ rule_val(); -+ virtual ~rule_val() {}; - -- inline void set_dst_addr(in_addr_t const &dst_addr) { m_dst_addr = dst_addr; }; -- inline void set_src_addr(in_addr_t const &src_addr) { m_src_addr = src_addr; }; -- inline void set_protocol(unsigned char protocol) { m_protocol = protocol; }; -- inline void set_scope(unsigned char scope) { m_scope = scope; }; -- inline void set_type(unsigned char type) { m_type = type; }; -- inline void set_tos(unsigned char tos) { m_tos = tos; }; -- inline void set_table_id(uint32_t table_id) { m_table_id = table_id; }; -- inline void set_iif_name(char *iif_name) { memcpy(m_iif_name, iif_name, IFNAMSIZ); }; -- inline void set_oif_name(char *oif_name) { memcpy(m_oif_name, oif_name, IFNAMSIZ); }; -- inline void set_priority(uint32_t priority) { m_priority = priority; }; -+ inline void set_dst_addr(in_addr_t const &dst_addr) { m_dst_addr = dst_addr; }; -+ inline void set_src_addr(in_addr_t const &src_addr) { m_src_addr = src_addr; }; -+ inline void set_tos(unsigned char tos) { m_tos = tos; }; -+ inline void set_table_id(uint32_t table_id) { m_table_id = table_id; }; -+ inline void set_iif_name(char *iif_name) { memcpy(m_iif_name, iif_name, IFNAMSIZ); }; -+ inline void set_oif_name(char *oif_name) { memcpy(m_oif_name, oif_name, IFNAMSIZ); }; -+ inline void set_priority(uint32_t priority) { m_priority = priority; }; - -- void set_str(); -+ void set_str(); - -- inline in_addr_t get_dst_addr() const { return m_dst_addr; }; -- inline in_addr_t get_src_addr() const { return m_src_addr; }; -- inline unsigned char get_tos() const { return m_tos; }; -- inline uint32_t get_table_id() const { return m_table_id; }; -- inline const char* get_iif_name() const { return m_iif_name; }; -- inline const char* get_oif_name() const { return m_oif_name; }; -+ inline in_addr_t get_dst_addr() const { return m_dst_addr; }; -+ inline in_addr_t get_src_addr() const { return m_src_addr; }; -+ inline unsigned char get_tos() const { return m_tos; }; -+ inline uint32_t get_table_id() const { return m_table_id; }; -+ inline const char *get_iif_name() const { return m_iif_name; }; -+ inline const char *get_oif_name() const { return m_oif_name; }; - -- inline void set_state(bool state) { m_is_valid = state; }; -- inline bool is_valid() const { return m_is_valid; }; -+ inline void set_state(bool state) { m_is_valid = state; }; -+ inline bool is_valid() const { return m_is_valid; }; - -- void print_val(); -- char* to_str() { return m_str; }; -+ void print_val(); -+ char *to_str() { return m_str; }; - - private: -+ unsigned char m_tos; -+ -+ union { -+ in_addr_t m_dst_addr; -+ in_addr m_dst_addr_in_addr; -+ }; -+ union { -+ in_addr_t m_src_addr; -+ in_addr m_src_addr_in_addr; -+ }; -+ char m_iif_name[IFNAMSIZ]; -+ char m_oif_name[IFNAMSIZ]; -+ uint32_t m_priority; -+ uint32_t m_table_id; - -- unsigned char m_protocol; -- unsigned char m_scope; -- unsigned char m_type; -- unsigned char m_tos; -+ bool m_is_valid; - -- union { -- in_addr_t m_dst_addr; -- in_addr m_dst_addr_in_addr; -- }; -- union { -- in_addr_t m_src_addr; -- in_addr m_src_addr_in_addr; -- }; -- char m_iif_name[IFNAMSIZ]; -- char m_oif_name[IFNAMSIZ]; -- uint32_t m_priority; -- uint32_t m_table_id; -- -- bool m_is_valid; -- -- char m_str[BUFF_SIZE]; -+ char m_str[BUFF_SIZE]; - }; - - #endif /* RULE_VAL_H */ diff --git a/0001-issue-4223310-VMA-support-for-kernel-6.10.patch b/0001-issue-4223310-VMA-support-for-kernel-6.10.patch new file mode 100644 index 0000000..401a850 --- /dev/null +++ b/0001-issue-4223310-VMA-support-for-kernel-6.10.patch @@ -0,0 +1,688 @@ +From 1849e0ad10acf3430d21193a8fc9ca3f12e976a9 Mon Sep 17 00:00:00 2001 +From: Tomer Cabouly +Date: Mon, 13 Jan 2025 09:13:58 +0000 +Subject: issue: 4223310 VMA support for kernel 6.10 + +Kernel 6.10 netlink has breaked VMA functionality. +Transitioned to libnl - an abstraction that wraps netlink. + +Signed-off-by: Tomer Cabouly +--- + src/vma/proto/netlink_socket_mgr.h | 204 ++++++++++------------------- + src/vma/proto/route_table_mgr.cpp | 143 ++++++++++---------- + src/vma/proto/route_table_mgr.h | 4 +- + src/vma/proto/rule_table_mgr.cpp | 98 +++++++------- + src/vma/proto/rule_table_mgr.h | 4 +- + src/vma/proto/rule_val.cpp | 3 - + src/vma/proto/rule_val.h | 6 - + 7 files changed, 198 insertions(+), 264 deletions(-) + +diff --git a/src/vma/proto/netlink_socket_mgr.h b/src/vma/proto/netlink_socket_mgr.h +index ab14de05..c576721c 100644 +--- a/src/vma/proto/netlink_socket_mgr.h ++++ b/src/vma/proto/netlink_socket_mgr.h +@@ -35,6 +35,7 @@ + #ifndef NETLINK_SOCKET_MGR_H + #define NETLINK_SOCKET_MGR_H + ++#include + #include + #include + #include +@@ -49,6 +50,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + #include "utils/bullseye.h" + #include "utils/lock_wrapper.h" +@@ -97,19 +103,19 @@ protected: + + table_t m_tab; + +- virtual bool parse_enrty(nlmsghdr *nl_header, Type *p_val) = 0; ++ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context) = 0; + virtual void update_tbl(); + virtual void print_val_tbl(); + + void build_request(struct nlmsghdr **nl_msg); + bool query(struct nlmsghdr *&nl_msg, int &len); + int recv_info(); +- void parse_tbl(int len, int *p_ent_num = NULL); ++ void parse_tbl_from_latest_cache(struct nl_cache *cache_state); + + private: + nl_data_t m_data_type; + +- int m_fd; // netlink socket to communicate with the kernel ++ nl_sock *m_sock; // netlink socket to communicate with the kernel + uint32_t m_pid; // process pid + uint32_t m_seq_num; // seq num of the netlink messages + char m_msg_buf[MSG_BUFF_SIZE]; // we use this buffer for sending/receiving netlink messages +@@ -118,6 +124,7 @@ private: + + /*********************************Implementation ********************************/ + ++ + template + netlink_socket_mgr ::netlink_socket_mgr(nl_data_t data_type) + { +@@ -132,14 +139,19 @@ netlink_socket_mgr ::netlink_socket_mgr(nl_data_t data_type) + + // Create Socket + BULLSEYE_EXCLUDE_BLOCK_START +- if ((m_fd = orig_os_api.socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { ++ m_sock = nl_socket_alloc(); ++ if (m_sock == nullptr) { + __log_err("NL socket Creation: "); + return; + } + +- if (orig_os_api.fcntl(m_fd, F_SETFD, FD_CLOEXEC) != 0) { +- __log_warn("Fail in fctl, error = %d", errno); ++ if (nl_connect(m_sock, NETLINK_ROUTE) < 0) { ++ __log_err("NL socket Connection: "); ++ nl_socket_free(m_sock); ++ m_sock = nullptr; ++ return; + } ++ + BULLSEYE_EXCLUDE_BLOCK_END + + __log_dbg("Done"); +@@ -149,161 +161,79 @@ template + netlink_socket_mgr ::~netlink_socket_mgr() + { + __log_dbg(""); +- if (m_fd) { +- orig_os_api.close(m_fd); +- m_fd = -1; ++ if (m_sock != nullptr) { ++ nl_socket_free(m_sock); ++ m_sock = nullptr; + } +- +- __log_dbg("Done"); +-} +- +-// This function build Netlink request to retrieve data (Rule, Route) from kernel. +-// Parameters : +-// nl_msg : request to be returned +-template +-void netlink_socket_mgr ::build_request(struct nlmsghdr **nl_msg) +-{ +- struct rtmsg *rt_msg; +- +- memset(m_msg_buf, 0, m_buff_size); +- +- // point the header and the msg structure pointers into the buffer +- *nl_msg = (struct nlmsghdr *)m_msg_buf; +- rt_msg = (struct rtmsg *)NLMSG_DATA(*nl_msg); +- +- //Fill in the nlmsg header +- (*nl_msg)->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); +- (*nl_msg)->nlmsg_seq = m_seq_num++; +- (*nl_msg)->nlmsg_pid = m_pid; +- rt_msg->rtm_family = AF_INET; +- +- if (m_data_type == RULE_DATA_TYPE) +- { +- (*nl_msg)->nlmsg_type = RTM_GETRULE; +- } +- else if (m_data_type == ROUTE_DATA_TYPE) +- { +- (*nl_msg)->nlmsg_type = RTM_GETROUTE; +- } +- +- (*nl_msg)->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; +- +-} +- +-// Query built request and receive requested data (Rule, Route) +-// Parameters: +-// nl_msg : request that is built previously. +-// len : length of received data. +-template +-bool netlink_socket_mgr ::query(struct nlmsghdr *&nl_msg, int &len) +-{ +- if(m_fd < 0) +- return false; +- +- BULLSEYE_EXCLUDE_BLOCK_START +- if(orig_os_api.send(m_fd, nl_msg, nl_msg->nlmsg_len, 0) < 0){ +- __log_err("Write To Socket Failed...\n"); +- return false; +- } +- if((len = recv_info()) < 0) { +- __log_err("Read From Socket Failed...\n"); +- return false; +- } +- BULLSEYE_EXCLUDE_BLOCK_END + +- return true; +-} +- +-// Receive requested data and save it locally. +-// Return length of received data. +-template +-int netlink_socket_mgr ::recv_info() +-{ +- struct nlmsghdr *nlHdr; +- int readLen = 0, msgLen = 0; +- +- char *buf_ptr = m_msg_buf; +- +- do{ +- //Receive response from the kernel +- BULLSEYE_EXCLUDE_BLOCK_START +- if((readLen = orig_os_api.recv(m_fd, buf_ptr, MSG_BUFF_SIZE - msgLen, 0)) < 0){ +- __log_err("SOCK READ: "); +- return -1; +- } +- +- nlHdr = (struct nlmsghdr *)buf_ptr; +- +- //Check if the header is valid +- if((NLMSG_OK(nlHdr, (u_int)readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)) +- { +- __log_err("Error in received packet, readLen = %d, msgLen = %d, type=%d, bufLen = %d", readLen, nlHdr->nlmsg_len, nlHdr->nlmsg_type, MSG_BUFF_SIZE); +- if (nlHdr->nlmsg_len == MSG_BUFF_SIZE) { +- __log_err("The buffer we pass to netlink is too small for reading the whole table"); +- } +- return -1; +- } +- BULLSEYE_EXCLUDE_BLOCK_END +- +- buf_ptr += readLen; +- msgLen += readLen; +- +- //Check if the its the last message +- if(nlHdr->nlmsg_type == NLMSG_DONE || +- (nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) { +- break; +- } +- +- } while((nlHdr->nlmsg_seq != m_seq_num) || (nlHdr->nlmsg_pid != m_pid)); +- return msgLen; ++ __log_dbg("Done"); + } + + // Update data in a table + template + void netlink_socket_mgr ::update_tbl() + { +- struct nlmsghdr *nl_msg = NULL; +- int counter = 0; +- int len = 0; +- + m_tab.entries_num = 0; + +- // Build Netlink request to get route entry +- build_request(&nl_msg); ++ struct nl_cache *cache_state = nullptr; ++ int err = 0; + +- // Query built request and receive requested data +- if (!query(nl_msg, len)) +- return; ++ // cache allocation fetches the latest existing rules/routes ++ if (m_data_type == RULE_DATA_TYPE) { ++ err = rtnl_rule_alloc_cache(m_sock, AF_INET, &cache_state); ++ } else if (m_data_type == ROUTE_DATA_TYPE) { ++ err = rtnl_route_alloc_cache(m_sock, AF_INET, 0, &cache_state); ++ } + +- // Parse received data in custom object (route_val) +- parse_tbl(len, &counter); ++ if (err < 0) { ++ if (cache_state) { ++ nl_cache_free(cache_state); ++ } ++ ++ throw_vma_exception("Failed to allocate route cache"); ++ } + +- m_tab.entries_num = counter; ++ // Parse received data in custom object (route_val) ++ parse_tbl_from_latest_cache(cache_state); + +- if (counter >= MAX_TABLE_SIZE) { +- __log_warn("reached the maximum route table size"); ++ if (cache_state) { ++ nl_cache_free(cache_state); + } + } + + // Parse received data in a table +-// Parameters: ++// Parameters: + // len : length of received data. + // p_ent_num : number of rows in received data. + template +-void netlink_socket_mgr ::parse_tbl(int len, int *p_ent_num) ++void netlink_socket_mgr::parse_tbl_from_latest_cache(struct nl_cache *cache_state) + { +- struct nlmsghdr *nl_header; +- int entry_cnt = 0; ++ uint16_t entry_cnt = 0; ++ ++ struct nl_iterator_context { ++ Type *p_val_array; ++ uint16_t &entry_cnt; ++ netlink_socket_mgr *this_ptr; ++ } iterator_context = {m_tab.value, entry_cnt, this}; ++ ++ // a lambda can't be casted to a c-fptr with ref captures - so we provide context ourselves ++ nl_cache_foreach( ++ cache_state, ++ [](struct nl_object *nl_obj, void *context) { ++ nl_iterator_context *operation_context = ++ reinterpret_cast(context); ++ const bool is_valid_entry = operation_context->this_ptr->parse_entry( ++ nl_obj, operation_context->p_val_array + operation_context->entry_cnt); ++ if (is_valid_entry) { ++ ++operation_context->entry_cnt; ++ } ++ }, ++ &iterator_context); + +- nl_header = (struct nlmsghdr *) m_msg_buf; +- for(;NLMSG_OK(nl_header, (u_int)len) && entry_cnt < MAX_TABLE_SIZE; nl_header = NLMSG_NEXT(nl_header, len)) +- { +- if (parse_enrty(nl_header, &m_tab.value[entry_cnt])) { +- entry_cnt++; +- } ++ m_tab.entries_num = entry_cnt; ++ if (m_tab.entries_num >= MAX_TABLE_SIZE) { ++ __log_warn("reached the maximum route table size"); + } +- if (p_ent_num) +- *p_ent_num = entry_cnt; + } + + //print the table +diff --git a/src/vma/proto/route_table_mgr.cpp b/src/vma/proto/route_table_mgr.cpp +index bb97320f..45af9a8d 100644 +--- a/src/vma/proto/route_table_mgr.cpp ++++ b/src/vma/proto/route_table_mgr.cpp +@@ -235,87 +235,98 @@ void route_table_mgr::rt_mgr_update_source_ip() + } + } + +-bool route_table_mgr::parse_enrty(nlmsghdr *nl_header, route_val *p_val) ++bool route_table_mgr::parse_entry(struct nl_object *nl_obj, void *p_val_context) + { +- int len; +- struct rtmsg *rt_msg; +- struct rtattr *rt_attribute; +- +- // get route entry header +- rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); ++ route_val *p_val = static_cast(p_val_context); ++ // Cast the generic nl_object to a specific route or rule object ++ struct rtnl_route *route = reinterpret_cast(nl_obj); + + // we are not concerned about the local and default route table +- if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL) ++ if (rtnl_route_get_family(route) != AF_INET || rtnl_route_get_table(route) == RT_TABLE_LOCAL) { + return false; ++ } + +- p_val->set_protocol(rt_msg->rtm_protocol); +- p_val->set_scope(rt_msg->rtm_scope); +- p_val->set_type(rt_msg->rtm_type); +- p_val->set_table_id(rt_msg->rtm_table); +- +- in_addr_t dst_mask = htonl(VMA_NETMASK(rt_msg->rtm_dst_len)); +- p_val->set_dst_mask(dst_mask); +- p_val->set_dst_pref_len(rt_msg->rtm_dst_len); ++ // Set protocol, scope, type, and table ID using libnl functions ++ p_val->set_protocol(rtnl_route_get_protocol(route)); ++ p_val->set_scope(rtnl_route_get_scope(route)); ++ p_val->set_type(rtnl_route_get_type(route)); ++ p_val->set_table_id(rtnl_route_get_table(route)); ++ ++ // Set destination mask and prefix length ++ struct nl_addr *dst = rtnl_route_get_dst(route); ++ if (dst != nullptr) { ++ in_addr_t dst_mask = htonl(VMA_NETMASK(nl_addr_get_prefixlen(dst))); ++ p_val->set_dst_mask(dst_mask); ++ p_val->set_dst_pref_len(nl_addr_get_prefixlen(dst)); ++ } + +- len = RTM_PAYLOAD(nl_header); +- rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); ++ parse_attr(route, p_val); + +- for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { +- parse_attr(rt_attribute, p_val); +- } + p_val->set_state(true); + p_val->set_str(); + return true; + } + +-void route_table_mgr::parse_attr(struct rtattr *rt_attribute, route_val *p_val) ++static inline bool get_addr_from_nl_addr(struct nl_addr *addr, in_addr_t *p_addr) + { +- switch (rt_attribute->rta_type) { +- case RTA_DST: +- p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); +- break; +- // next hop IPv4 address +- case RTA_GATEWAY: +- p_val->set_gw(*(in_addr_t *)RTA_DATA(rt_attribute)); +- break; +- // unique ID associated with the network interface +- case RTA_OIF: +- p_val->set_if_index(*(int *)RTA_DATA(rt_attribute)); +- char if_name[IFNAMSIZ]; +- if_indextoname(p_val->get_if_index(),if_name); +- p_val->set_if_name(if_name); +- break; +- case RTA_SRC: +- case RTA_PREFSRC: +- p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); +- break; +- case RTA_TABLE: +- p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute)); +- break; +- case RTA_METRICS: +- { +- struct rtattr *rta = (struct rtattr *)RTA_DATA(rt_attribute); +- int len = RTA_PAYLOAD(rt_attribute); +- uint16_t type; +- while (RTA_OK(rta, len)) { +- type = rta->rta_type; +- switch (type) { +- case RTAX_MTU: +- p_val->set_mtu(*(uint32_t *)RTA_DATA(rta)); +- break; +- default: +- rt_mgr_logdbg("got unexpected METRICS %d %x", +- type, *(uint32_t *)RTA_DATA(rta)); +- break; +- } +- rta = RTA_NEXT(rta, len); ++ if (addr && nl_addr_get_family(addr) == AF_INET) { ++ void *binary_addr = nl_addr_get_binary_addr(addr); ++ unsigned int addr_len = nl_addr_get_len(addr); ++ ++ if (binary_addr && addr_len == sizeof(in_addr_t)) { ++ memcpy(p_addr, binary_addr, sizeof(in_addr_t)); ++ return true; + } +- break; + } +- default: +- rt_mgr_logdbg("got unexpected type %d %x", rt_attribute->rta_type, +- *(uint32_t *)RTA_DATA(rt_attribute)); +- break; ++ return false; ++} ++ ++void route_table_mgr::parse_attr(struct rtnl_route *route, route_val *p_val) ++{ ++ struct nl_addr *addr; ++ ++ // Destination Address ++ addr = rtnl_route_get_dst(route); ++ in_addr_t dst_addr = 0; ++ if (get_addr_from_nl_addr(addr, &dst_addr) && dst_addr) { ++ p_val->set_dst_addr(dst_addr); ++ } ++ ++ // Gateway Address (Next Hop) ++ struct rtnl_nexthop *nh = rtnl_route_nexthop_n(route, 0); // Assuming the first nexthop ++ in_addr_t gw_addr = 0; ++ if (nh && get_addr_from_nl_addr(rtnl_route_nh_get_gateway(nh), &gw_addr) && gw_addr) { ++ p_val->set_gw(gw_addr); ++ } ++ ++ // Output Interface Index and Name ++ const int if_index = rtnl_route_nh_get_ifindex(nh); ++ if (if_index > 0) { ++ p_val->set_if_index(if_index); ++ ++ char if_name[IFNAMSIZ] = {0}; ++ if_indextoname(if_index, if_name); ++ p_val->set_if_name(if_name); ++ } ++ ++ // Source Address ++ addr = rtnl_route_get_pref_src(route); ++ in_addr_t pref_src_addr = 0; ++ if (get_addr_from_nl_addr(addr, &pref_src_addr) && pref_src_addr) { ++ p_val->set_src_addr(pref_src_addr); ++ } ++ ++ // Table ID ++ int table_id = rtnl_route_get_table(route); ++ p_val->set_table_id(table_id); ++ ++ // Metrics (e.g., MTU) ++ uint32_t mtu = 0; ++ int get_metric_result = rtnl_route_get_metric(route, RTAX_MTU, &mtu); ++ if (get_metric_result == 0) { ++ if (mtu > 0) { ++ p_val->set_mtu(mtu); ++ } + } + } + +diff --git a/src/vma/proto/route_table_mgr.h b/src/vma/proto/route_table_mgr.h +index ea68bf76..2798498f 100644 +--- a/src/vma/proto/route_table_mgr.h ++++ b/src/vma/proto/route_table_mgr.h +@@ -70,7 +70,7 @@ public: + virtual void notify_cb(event *ev); + + protected: +- virtual bool parse_enrty(nlmsghdr *nl_header, route_val *p_val); ++ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context); + + private: + // in constructor creates route_entry for each net_dev, to receive events in case there are no other route_entrys +@@ -80,7 +80,7 @@ private: + + // save current main rt table + void update_tbl(); +- void parse_attr(struct rtattr *rt_attribute, route_val *p_val); ++ void parse_attr(struct rtnl_route *route, route_val *p_val); + + void rt_mgr_update_source_ip(); + +diff --git a/src/vma/proto/rule_table_mgr.cpp b/src/vma/proto/rule_table_mgr.cpp +index ea417654..6c341cc2 100644 +--- a/src/vma/proto/rule_table_mgr.cpp ++++ b/src/vma/proto/rule_table_mgr.cpp +@@ -94,74 +94,76 @@ void rule_table_mgr::update_tbl() + } + + // Parse received rule entry into custom object (rule_val). +-// Parameters: +-// nl_header : object that contain rule entry. ++// Parameters: ++// nl_obj : object that contain rule entry. + // p_val : custom object that contain parsed rule data. + // return true if its not related to local or default table, false otherwise. +-bool rule_table_mgr::parse_enrty(nlmsghdr *nl_header, rule_val *p_val) ++bool rule_table_mgr::parse_entry(struct nl_object *nl_obj, void *p_val_context) + { +- int len; +- struct rtmsg *rt_msg; +- struct rtattr *rt_attribute; +- +- // get rule entry header +- rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header); ++ rule_val *p_val = static_cast(p_val_context); ++ // Cast the generic nl_object to a specific route or rule object ++ struct rtnl_rule *rule = reinterpret_cast(nl_obj); + +- // we are not concerned about the local and default rule table +- if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL) ++ uint32_t table_id = rtnl_rule_get_table(rule); ++ if (rtnl_rule_get_family(rule) != AF_INET || table_id == RT_TABLE_LOCAL) { + return false; ++ } + +- p_val->set_protocol(rt_msg->rtm_protocol); +- p_val->set_scope(rt_msg->rtm_scope); +- p_val->set_type(rt_msg->rtm_type); +- p_val->set_tos(rt_msg->rtm_tos); +- p_val->set_table_id(rt_msg->rtm_table); ++ p_val->set_tos(rtnl_rule_get_dsfield(rule)); ++ p_val->set_table_id(table_id); + +- len = RTM_PAYLOAD(nl_header); +- rt_attribute = (struct rtattr *) RTM_RTA(rt_msg); ++ parse_attr(rule, p_val); + +- for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) { +- parse_attr(rt_attribute, p_val); +- } + p_val->set_state(true); + p_val->set_str(); + return true; + } + + // Parse received rule attribute for given rule. +-// Parameters: +-// rt_attribute : object that contain rule attribute. ++// Parameters: ++// rule : object that contain rule attribute. + // p_val : custom object that contain parsed rule data. +-void rule_table_mgr::parse_attr(struct rtattr *rt_attribute, rule_val *p_val) ++void rule_table_mgr::parse_attr(struct rtnl_rule *rule, rule_val *p_val) + { +- switch (rt_attribute->rta_type) { +- case FRA_PRIORITY: +- p_val->set_priority(*(uint32_t *)RTA_DATA(rt_attribute)); +- break; +- case FRA_DST: +- p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); +- break; +- case FRA_SRC: +- p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute)); +- break; +- case FRA_IFNAME: +- p_val->set_iif_name((char *)RTA_DATA(rt_attribute)); +- break; +- case FRA_TABLE: +- p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute)); +- break; ++ // FRA_PRIORITY: Rule Priority ++ uint32_t priority = rtnl_rule_get_prio(rule); ++ if (priority) { ++ p_val->set_priority(priority); ++ } ++ ++ // FRA_DST: Destination Address ++ struct nl_addr *dst = rtnl_rule_get_dst(rule); ++ if (dst) { ++ p_val->set_dst_addr(*(in_addr_t *)nl_addr_get_binary_addr(dst)); ++ } ++ ++ // FRA_SRC: Source Address ++ struct nl_addr *src = rtnl_rule_get_src(rule); ++ if (src) { ++ p_val->set_src_addr(*(in_addr_t *)nl_addr_get_binary_addr(src)); ++ } ++ ++ // FRA_IFNAME: Input Interface Name ++ char *iif_name = rtnl_rule_get_iif(rule); ++ if (iif_name) { ++ p_val->set_iif_name(iif_name); ++ } ++ ++ // FRA_TABLE: Table ID ++ uint32_t table_id = rtnl_rule_get_table(rule); ++ if (table_id) { ++ p_val->set_table_id(table_id); ++ } ++ + #if DEFINED_FRA_OIFNAME +- case FRA_OIFNAME: +- p_val->set_oif_name((char *)RTA_DATA(rt_attribute)); +- break; +-#endif +- default: +- rr_mgr_logdbg("got undetected rta_type %d %x", rt_attribute->rta_type, *(uint32_t *)RTA_DATA(rt_attribute)); +- break; ++ // FRA_OIFNAME: Output Interface Name (if available) ++ char *oif_name = rtnl_rule_get_oif(rule); ++ if (oif_name) { ++ p_val->set_oif_name(oif_name); + } ++#endif + } + +- + // Create rule entry object for given destination key and fill it with matching rule value from rule table. + // Parameters: + // key : key object that contain information about destination. +diff --git a/src/vma/proto/rule_table_mgr.h b/src/vma/proto/rule_table_mgr.h +index 74d6be40..273675a4 100644 +--- a/src/vma/proto/rule_table_mgr.h ++++ b/src/vma/proto/rule_table_mgr.h +@@ -55,12 +55,12 @@ public: + bool rule_resolve(route_rule_table_key key, std::deque &table_id_list); + + protected: +- virtual bool parse_enrty(nlmsghdr *nl_header, rule_val *p_val); ++ virtual bool parse_entry(struct nl_object *nl_obj, void *p_val_context); + virtual void update_tbl(); + + private: + +- void parse_attr(struct rtattr *rt_attribute, rule_val *p_val); ++ void parse_attr(struct rtnl_rule *rule, rule_val *p_val); + + bool find_rule_val(route_rule_table_key key, std::deque* &p_val); + bool is_matching_rule(route_rule_table_key rrk, rule_val* p_val); +diff --git a/src/vma/proto/rule_val.cpp b/src/vma/proto/rule_val.cpp +index 23309d22..1be700a0 100644 +--- a/src/vma/proto/rule_val.cpp ++++ b/src/vma/proto/rule_val.cpp +@@ -47,9 +47,6 @@ + + rule_val::rule_val(): cache_observer() + { +- m_protocol = 0; +- m_scope = 0; +- m_type = 0; + m_dst_addr = 0; + m_src_addr = 0; + memset(m_oif_name, 0, IFNAMSIZ * sizeof(char)); +diff --git a/src/vma/proto/rule_val.h b/src/vma/proto/rule_val.h +index 7340c765..58bdd71a 100644 +--- a/src/vma/proto/rule_val.h ++++ b/src/vma/proto/rule_val.h +@@ -53,9 +53,6 @@ public: + + inline void set_dst_addr(in_addr_t const &dst_addr) { m_dst_addr = dst_addr; }; + inline void set_src_addr(in_addr_t const &src_addr) { m_src_addr = src_addr; }; +- inline void set_protocol(unsigned char protocol) { m_protocol = protocol; }; +- inline void set_scope(unsigned char scope) { m_scope = scope; }; +- inline void set_type(unsigned char type) { m_type = type; }; + inline void set_tos(unsigned char tos) { m_tos = tos; }; + inline void set_table_id(uint32_t table_id) { m_table_id = table_id; }; + inline void set_iif_name(char *iif_name) { memcpy(m_iif_name, iif_name, IFNAMSIZ); }; +@@ -79,9 +76,6 @@ public: + + private: + +- unsigned char m_protocol; +- unsigned char m_scope; +- unsigned char m_type; + unsigned char m_tos; + + union { +-- +2.47.1 + diff --git a/libvma.spec b/libvma.spec index ae41f26..63682bc 100644 --- a/libvma.spec +++ b/libvma.spec @@ -2,14 +2,14 @@ Name: libvma Version: 9.8.60 -Release: 2%{?dist} +Release: 3%{?dist} Summary: A library for boosting TCP and UDP traffic (over RDMA hardware) License: GPLv2 or BSD Url: https://github.com/Mellanox/libvma Source0: https://github.com/Mellanox/libvma/archive/%{version}/%{name}-%{version}.tar.gz Patch0: 0001-Fix-build-failure.patch -Patch1: 0001-Issue-4223310-VMA-support-for-kernel-6.10.patch +Patch1: 0001-issue-4223310-VMA-support-for-kernel-6.10.patch # libvma currently supports only the following architectures ExclusiveArch: x86_64 ppc64le ppc64 aarch64 @@ -101,6 +101,10 @@ rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/init.d/vma %{_mandir}/man8/vma_stats.* %changelog +* Tue Jan 14 2025 Mohammad Heib - 9.8.60-3 +- Fix a small memory leak and adjusted the code style. + Resolves: RHEL-24810 + * Mon Jan 06 2025 Mohammad Heib - 9.8.60-2 - Add support for kernel 6.10. Resolves: RHEL-24810