From 795b55d53b9e850e8f07d317c1dafa4f1b7e29ab Mon Sep 17 00:00:00 2001 From: Mohammad Heib Date: Mon, 6 Jan 2025 15:21:18 +0200 Subject: [PATCH] Add support for kernel 6.10. Resolves: RHEL-24810 Signed-off-by: Mohammad Heib --- ...-4223310-VMA-support-for-kernel-6.10.patch | 2131 +++++++++++++++++ libvma.spec | 7 +- 2 files changed, 2137 insertions(+), 1 deletion(-) create mode 100644 0001-Issue-4223310-VMA-support-for-kernel-6.10.patch 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..c51762d --- /dev/null +++ b/0001-Issue-4223310-VMA-support-for-kernel-6.10.patch @@ -0,0 +1,2131 @@ +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/libvma.spec b/libvma.spec index 9340b17..ae41f26 100644 --- a/libvma.spec +++ b/libvma.spec @@ -2,13 +2,14 @@ Name: libvma Version: 9.8.60 -Release: 1%{?dist} +Release: 2%{?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 # libvma currently supports only the following architectures ExclusiveArch: x86_64 ppc64le ppc64 aarch64 @@ -100,6 +101,10 @@ rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/init.d/vma %{_mandir}/man8/vma_stats.* %changelog +* Mon Jan 06 2025 Mohammad Heib - 9.8.60-2 +- Add support for kernel 6.10. + Resolves: RHEL-24810 + * Wed Nov 20 2024 Mohammad Heib - 9.8.60-1 - Update to upstream release 9.8.60. Resolves: RHEL-24810