|
Packit |
6d2c1b |
/*
|
|
Packit |
6d2c1b |
* Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* This software is available to you under a choice of one of two
|
|
Packit |
6d2c1b |
* licenses. You may choose to be licensed under the terms of the GNU
|
|
Packit |
6d2c1b |
* General Public License (GPL) Version 2, available from the file
|
|
Packit |
6d2c1b |
* COPYING in the main directory of this source tree, or the
|
|
Packit |
6d2c1b |
* BSD license below:
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* Redistribution and use in source and binary forms, with or
|
|
Packit |
6d2c1b |
* without modification, are permitted provided that the following
|
|
Packit |
6d2c1b |
* conditions are met:
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* - Redistributions of source code must retain the above
|
|
Packit |
6d2c1b |
* copyright notice, this list of conditions and the following
|
|
Packit |
6d2c1b |
* disclaimer.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* - Redistributions in binary form must reproduce the above
|
|
Packit |
6d2c1b |
* copyright notice, this list of conditions and the following
|
|
Packit |
6d2c1b |
* disclaimer in the documentation and/or other materials
|
|
Packit |
6d2c1b |
* provided with the distribution.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
6d2c1b |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
6d2c1b |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
6d2c1b |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
Packit |
6d2c1b |
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
Packit |
6d2c1b |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
6d2c1b |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
6d2c1b |
* SOFTWARE.
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#include <stdio.h>
|
|
Packit |
6d2c1b |
#include <stdint.h>
|
|
Packit |
6d2c1b |
#include <string.h>
|
|
Packit |
6d2c1b |
#include <stdlib.h>
|
|
Packit |
6d2c1b |
#include <sys/ioctl.h>
|
|
Packit |
6d2c1b |
#include <sys/socket.h>
|
|
Packit |
6d2c1b |
#include <linux/rtnetlink.h>
|
|
Packit |
6d2c1b |
#include <linux/netlink.h>
|
|
Packit |
6d2c1b |
#include <netinet/in.h>
|
|
Packit |
6d2c1b |
#include <netinet/ether.h>
|
|
Packit |
6d2c1b |
#include <arpa/inet.h>
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#include "utils/bullseye.h"
|
|
Packit |
6d2c1b |
#include "utils/lock_wrapper.h"
|
|
Packit |
6d2c1b |
#include "vlogger/vlogger.h"
|
|
Packit |
6d2c1b |
#include "vma/util/vtypes.h"
|
|
Packit |
6d2c1b |
#include "vma/util/utils.h"
|
|
Packit |
6d2c1b |
#include "route_table_mgr.h"
|
|
Packit |
6d2c1b |
#include "vma/sock/socket_fd_api.h"
|
|
Packit |
6d2c1b |
#include "vma/sock/sock-redirect.h"
|
|
Packit |
6d2c1b |
#include "vma/dev/net_device_table_mgr.h"
|
|
Packit |
6d2c1b |
#include "ip_address.h"
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// debugging macros
|
|
Packit |
6d2c1b |
#define MODULE_NAME "rtm:"
|
|
Packit |
6d2c1b |
#define rt_mgr_if_logpanic __log_panic
|
|
Packit |
6d2c1b |
#define rt_mgr_logerr __log_err
|
|
Packit |
6d2c1b |
#define rt_mgr_logwarn __log_warn
|
|
Packit |
6d2c1b |
#define rt_mgr_loginfo __log_info
|
|
Packit |
6d2c1b |
#define rt_mgr_logdbg __log_dbg
|
|
Packit |
6d2c1b |
#define rt_mgr_logfunc __log_func
|
|
Packit |
6d2c1b |
#define rt_mgr_logfuncall __log_funcall
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_table_mgr* g_p_route_table_mgr = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_table_mgr::route_table_mgr() : netlink_socket_mgr<route_val>(ROUTE_DATA_TYPE), cache_table_mgr<route_rule_table_key, route_val*>("route_table_mgr")
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("");
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
//Read Route table from kernel and save it in local variable.
|
|
Packit |
6d2c1b |
update_tbl();
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// create route_entry for each net_dev- needed for receiving port up/down events for net_dev_entry
|
|
Packit |
6d2c1b |
route_val *p_val;
|
|
Packit |
6d2c1b |
for (int i = 0; i < m_tab.entries_num; i++)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
p_val = &m_tab.value[i];
|
|
Packit |
6d2c1b |
in_addr_t src_addr = p_val->get_src_addr();
|
|
Packit |
6d2c1b |
in_addr_route_entry_map_t::iterator iter = m_rte_list_for_each_net_dev.find(src_addr);
|
|
Packit |
6d2c1b |
// if src_addr of interface exists in the map, no need to create another route_entry
|
|
Packit |
6d2c1b |
if (iter == m_rte_list_for_each_net_dev.end()) {
|
|
Packit |
6d2c1b |
in_addr_t dst_ip = src_addr;
|
|
Packit |
6d2c1b |
in_addr_t src_ip = 0;
|
|
Packit |
6d2c1b |
uint8_t tos = 0;
|
|
Packit |
6d2c1b |
m_rte_list_for_each_net_dev.insert(pair<in_addr_t, route_entry*> (src_addr, create_new_entry(route_rule_table_key(dst_ip, src_ip, tos), NULL)));
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
//Print table
|
|
Packit |
6d2c1b |
print_val_tbl();
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// register to netlink event
|
|
Packit |
6d2c1b |
g_p_netlink_handler->register_event(nlgrpROUTE, this);
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Registered to g_p_netlink_handler");
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Done");
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_table_mgr::~route_table_mgr()
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("");
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// clear all route_entrys created in the constructor
|
|
Packit |
6d2c1b |
in_addr_route_entry_map_t::iterator iter;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
while ((iter = m_rte_list_for_each_net_dev.begin()) != m_rte_list_for_each_net_dev.end()) {
|
|
Packit |
6d2c1b |
delete(iter->second);
|
|
Packit |
6d2c1b |
m_rte_list_for_each_net_dev.erase(iter);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
rt_tbl_cach_entry_map_t::iterator cache_itr;
|
|
Packit |
6d2c1b |
while ((cache_itr = m_cache_tbl.begin()) != m_cache_tbl.end()) {
|
|
Packit |
6d2c1b |
delete(cache_itr->second);
|
|
Packit |
6d2c1b |
m_cache_tbl.erase(cache_itr);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Done");
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::update_tbl()
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
auto_unlocker lock(m_lock);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
netlink_socket_mgr<route_val>::update_tbl();
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
rt_mgr_update_source_ip();
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::rt_mgr_update_source_ip()
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
route_val *p_val;
|
|
Packit |
6d2c1b |
//for route entries which still have no src ip and no gw
|
|
Packit |
6d2c1b |
for (int i = 0; i < m_tab.entries_num; i++) {
|
|
Packit |
6d2c1b |
p_val = &m_tab.value[i];
|
|
Packit |
6d2c1b |
if (p_val->get_src_addr() || p_val->get_gw_addr()) continue;
|
|
Packit |
6d2c1b |
if (g_p_net_device_table_mgr) { //try to get src ip from net_dev list of the interface
|
|
Packit |
6d2c1b |
in_addr_t longest_prefix = 0;
|
|
Packit |
6d2c1b |
in_addr_t correct_src = 0;
|
|
Packit |
6d2c1b |
local_ip_list_t::iterator lip_iter;
|
|
Packit |
6d2c1b |
local_ip_list_t lip_offloaded_list = g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index());
|
|
Packit |
6d2c1b |
if (!lip_offloaded_list.empty()) {
|
|
Packit |
6d2c1b |
for (lip_iter = lip_offloaded_list.begin(); lip_offloaded_list.end() != lip_iter; lip_iter++)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
ip_data_t ip = *lip_iter;
|
|
Packit |
6d2c1b |
if((p_val->get_dst_addr() & ip.netmask) == (ip.local_addr & ip.netmask)) { //found a match in routing table
|
|
Packit |
6d2c1b |
if((ip.netmask | longest_prefix) != longest_prefix){
|
|
Packit |
6d2c1b |
longest_prefix = ip.netmask; // this is the longest prefix match
|
|
Packit |
6d2c1b |
correct_src = ip.local_addr;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (correct_src) {
|
|
Packit |
6d2c1b |
p_val->set_src_addr(correct_src);
|
|
Packit |
6d2c1b |
continue;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
// if still no src ip, get it from ioctl
|
|
Packit |
6d2c1b |
struct sockaddr_in src_addr;
|
|
Packit |
6d2c1b |
char *if_name = (char *)p_val->get_if_name();
|
|
Packit |
6d2c1b |
if (!get_ipv4_from_ifname(if_name, &src_addr)) {
|
|
Packit |
6d2c1b |
p_val->set_src_addr(src_addr.sin_addr.s_addr);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
else {
|
|
Packit |
6d2c1b |
// Failed mapping if_name to IPv4 address
|
|
Packit |
6d2c1b |
rt_mgr_logwarn("could not figure out source ip for rtv = %s", p_val->to_str());
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
//for route entries with gateway, do recursive search for src ip
|
|
Packit |
6d2c1b |
int num_unresolved_src = m_tab.entries_num;
|
|
Packit |
6d2c1b |
int prev_num_unresolved_src = 0;
|
|
Packit |
6d2c1b |
do {
|
|
Packit |
6d2c1b |
prev_num_unresolved_src = num_unresolved_src;
|
|
Packit |
6d2c1b |
num_unresolved_src = 0;
|
|
Packit |
6d2c1b |
for (int i = 0; i < m_tab.entries_num; i++) {
|
|
Packit |
6d2c1b |
p_val = &m_tab.value[i];
|
|
Packit |
6d2c1b |
if (p_val->get_gw_addr() && !p_val->get_src_addr()) {
|
|
Packit |
6d2c1b |
route_val* p_val_dst;
|
|
Packit |
6d2c1b |
in_addr_t in_addr = p_val->get_gw_addr();
|
|
Packit |
6d2c1b |
unsigned char table_id = p_val->get_table_id();
|
|
Packit |
6d2c1b |
if (find_route_val(in_addr, table_id, p_val_dst)) {
|
|
Packit |
6d2c1b |
if (p_val_dst->get_src_addr()) {
|
|
Packit |
6d2c1b |
p_val->set_src_addr(p_val_dst->get_src_addr());
|
|
Packit |
6d2c1b |
} else if (p_val == p_val_dst) { //gateway of the entry lead to same entry
|
|
Packit |
6d2c1b |
local_ip_list_t::iterator lip_iter;
|
|
Packit |
6d2c1b |
local_ip_list_t lip_offloaded_list = g_p_net_device_table_mgr->get_ip_list(p_val->get_if_index());
|
|
Packit |
6d2c1b |
for (lip_iter = lip_offloaded_list.begin(); lip_offloaded_list.end() != lip_iter; lip_iter++)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
ip_data_t ip = *lip_iter;
|
|
Packit |
6d2c1b |
if(p_val->get_gw_addr() == ip.local_addr) {
|
|
Packit |
6d2c1b |
p_val->set_gw(0);
|
|
Packit |
6d2c1b |
p_val->set_src_addr(ip.local_addr);
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (!p_val->get_src_addr())
|
|
Packit |
6d2c1b |
num_unresolved_src++;
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
num_unresolved_src++;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
// gateway and source are equal, no need of gw.
|
|
Packit |
6d2c1b |
if (p_val->get_src_addr() == p_val->get_gw_addr()) {
|
|
Packit |
6d2c1b |
p_val->set_gw(0);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
num_unresolved_src++;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
} while (num_unresolved_src && prev_num_unresolved_src > num_unresolved_src);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
//for route entries which still have no src ip
|
|
Packit |
6d2c1b |
for (int i = 0; i < m_tab.entries_num; i++) {
|
|
Packit |
6d2c1b |
p_val = &m_tab.value[i];
|
|
Packit |
6d2c1b |
if (p_val->get_src_addr()) continue;
|
|
Packit |
6d2c1b |
if (p_val->get_gw_addr()) {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("could not figure out source ip for gw address. rtv = %s", p_val->to_str());
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
// if still no src ip, get it from ioctl
|
|
Packit |
6d2c1b |
struct sockaddr_in src_addr;
|
|
Packit |
6d2c1b |
char *if_name = (char *)p_val->get_if_name();
|
|
Packit |
6d2c1b |
if (!get_ipv4_from_ifname(if_name, &src_addr)) {
|
|
Packit |
6d2c1b |
p_val->set_src_addr(src_addr.sin_addr.s_addr);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
else {
|
|
Packit |
6d2c1b |
// Failed mapping if_name to IPv4 address
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("could not figure out source ip for rtv = %s", p_val->to_str());
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
bool route_table_mgr::parse_enrty(nlmsghdr *nl_header, route_val *p_val)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
int len;
|
|
Packit |
6d2c1b |
struct rtmsg *rt_msg;
|
|
Packit |
6d2c1b |
struct rtattr *rt_attribute;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// get route entry header
|
|
Packit |
6d2c1b |
rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// we are not concerned about the local and default route table
|
|
Packit |
6d2c1b |
if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL)
|
|
Packit |
6d2c1b |
return false;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
p_val->set_protocol(rt_msg->rtm_protocol);
|
|
Packit |
6d2c1b |
p_val->set_scope(rt_msg->rtm_scope);
|
|
Packit |
6d2c1b |
p_val->set_type(rt_msg->rtm_type);
|
|
Packit |
6d2c1b |
p_val->set_table_id(rt_msg->rtm_table);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
in_addr_t dst_mask = htonl(VMA_NETMASK(rt_msg->rtm_dst_len));
|
|
Packit |
6d2c1b |
p_val->set_dst_mask(dst_mask);
|
|
Packit |
6d2c1b |
p_val->set_dst_pref_len(rt_msg->rtm_dst_len);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
len = RTM_PAYLOAD(nl_header);
|
|
Packit |
6d2c1b |
rt_attribute = (struct rtattr *) RTM_RTA(rt_msg);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) {
|
|
Packit |
6d2c1b |
parse_attr(rt_attribute, p_val);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
p_val->set_state(true);
|
|
Packit |
6d2c1b |
p_val->set_str();
|
|
Packit |
6d2c1b |
return true;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::parse_attr(struct rtattr *rt_attribute, route_val *p_val)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
switch (rt_attribute->rta_type) {
|
|
Packit |
6d2c1b |
case RTA_DST:
|
|
Packit |
6d2c1b |
p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
// next hop IPv4 address
|
|
Packit |
6d2c1b |
case RTA_GATEWAY:
|
|
Packit |
6d2c1b |
p_val->set_gw(*(in_addr_t *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
// unique ID associated with the network interface
|
|
Packit |
6d2c1b |
case RTA_OIF:
|
|
Packit |
6d2c1b |
p_val->set_if_index(*(int *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
char if_name[IFNAMSIZ];
|
|
Packit |
6d2c1b |
if_indextoname(p_val->get_if_index(),if_name);
|
|
Packit |
6d2c1b |
p_val->set_if_name(if_name);
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
case RTA_SRC:
|
|
Packit |
6d2c1b |
case RTA_PREFSRC:
|
|
Packit |
6d2c1b |
p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
case RTA_TABLE:
|
|
Packit |
6d2c1b |
p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
case RTA_METRICS:
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
struct rtattr *rta = (struct rtattr *)RTA_DATA(rt_attribute);
|
|
Packit |
6d2c1b |
int len = RTA_PAYLOAD(rt_attribute);
|
|
Packit |
6d2c1b |
uint16_t type;
|
|
Packit |
6d2c1b |
while (RTA_OK(rta, len)) {
|
|
Packit |
6d2c1b |
type = rta->rta_type;
|
|
Packit |
6d2c1b |
switch (type) {
|
|
Packit |
6d2c1b |
case RTAX_MTU:
|
|
Packit |
6d2c1b |
p_val->set_mtu(*(uint32_t *)RTA_DATA(rta));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
default:
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("got unexpected METRICS %d %x",
|
|
Packit |
6d2c1b |
type, *(uint32_t *)RTA_DATA(rta));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
rta = RTA_NEXT(rta, len);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
default:
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("got unexpected type %d %x", rt_attribute->rta_type,
|
|
Packit |
6d2c1b |
*(uint32_t *)RTA_DATA(rt_attribute));
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
bool route_table_mgr::find_route_val(in_addr_t &dst, unsigned char table_id, route_val* &p_val)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
ip_address dst_addr = dst;
|
|
Packit |
6d2c1b |
rt_mgr_logfunc("dst addr '%s'", dst_addr.to_str().c_str());
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_val *correct_route_val = NULL;
|
|
Packit |
6d2c1b |
int longest_prefix = -1;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
for (int i = 0; i < m_tab.entries_num; i++) {
|
|
Packit |
6d2c1b |
route_val* p_val_from_tbl = &m_tab.value[i];
|
|
Packit |
6d2c1b |
if (!p_val_from_tbl->is_deleted() && p_val_from_tbl->is_if_up()) { // value was not deleted
|
|
Packit |
6d2c1b |
if(p_val_from_tbl->get_table_id() == table_id) { //found a match in routing table ID
|
|
Packit |
6d2c1b |
if(p_val_from_tbl->get_dst_addr() == (dst & p_val_from_tbl->get_dst_mask())) { //found a match in routing table
|
|
Packit |
6d2c1b |
if(p_val_from_tbl->get_dst_pref_len() > longest_prefix) { // this is the longest prefix match
|
|
Packit |
6d2c1b |
longest_prefix = p_val_from_tbl->get_dst_pref_len();
|
|
Packit |
6d2c1b |
correct_route_val = p_val_from_tbl;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (correct_route_val) {
|
|
Packit |
6d2c1b |
ip_address dst_gw = correct_route_val->get_dst_addr();
|
|
Packit |
6d2c1b |
p_val = correct_route_val;
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("found route val[%p]: %s", p_val, p_val->to_str());
|
|
Packit |
6d2c1b |
return true;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("destination gw wasn't found");
|
|
Packit |
6d2c1b |
return false;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
bool route_table_mgr::route_resolve(IN route_rule_table_key key, OUT route_result &res)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
in_addr_t dst = key.get_dst_ip();
|
|
Packit |
6d2c1b |
ip_address dst_addr = dst;
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("dst addr '%s'", dst_addr.to_str().c_str());
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_val *p_val = NULL;
|
|
Packit |
6d2c1b |
std::deque<unsigned char> table_id_list;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
g_p_rule_table_mgr->rule_resolve(key, table_id_list);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
auto_unlocker lock(m_lock);
|
|
Packit |
6d2c1b |
std::deque<unsigned char>::iterator table_id_iter = table_id_list.begin();
|
|
Packit |
6d2c1b |
for (; table_id_iter != table_id_list.end(); table_id_iter++) {
|
|
Packit |
6d2c1b |
if (find_route_val(dst, *table_id_iter, p_val)) {
|
|
Packit |
6d2c1b |
res.p_src = p_val->get_src_addr();
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("dst ip '%s' resolved to src addr "
|
|
Packit |
6d2c1b |
"'%d.%d.%d.%d'", dst_addr.to_str().c_str(),
|
|
Packit |
6d2c1b |
NIPQUAD(res.p_src));
|
|
Packit |
6d2c1b |
res.p_gw = p_val->get_gw_addr();
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("dst ip '%s' resolved to gw addr '%d.%d.%d.%d'",
|
|
Packit |
6d2c1b |
dst_addr.to_str().c_str(), NIPQUAD(res.p_gw));
|
|
Packit |
6d2c1b |
res.mtu = p_val->get_mtu();
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("found route mtu %d", res.mtu);
|
|
Packit |
6d2c1b |
return true;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
/* prevent usage on false return */
|
|
Packit |
6d2c1b |
return false;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::update_entry(INOUT route_entry* p_ent, bool b_register_to_net_dev /*= false*/)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("entry [%p]", p_ent);
|
|
Packit |
6d2c1b |
auto_unlocker lock(m_lock);
|
|
Packit |
6d2c1b |
if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("route_entry is not valid-> update value");
|
|
Packit |
6d2c1b |
rule_entry* p_rr_entry = p_ent->get_rule_entry();
|
|
Packit |
6d2c1b |
std::deque<rule_val*>* p_rr_val;
|
|
Packit |
6d2c1b |
if (p_rr_entry && p_rr_entry->get_val(p_rr_val)) {
|
|
Packit |
6d2c1b |
route_val* p_val = NULL;
|
|
Packit |
6d2c1b |
in_addr_t peer_ip = p_ent->get_key().get_dst_ip();
|
|
Packit |
6d2c1b |
unsigned char table_id;
|
|
Packit |
6d2c1b |
for (std::deque<rule_val*>::iterator p_rule_val = p_rr_val->begin(); p_rule_val != p_rr_val->end(); p_rule_val++) {
|
|
Packit |
6d2c1b |
table_id = (*p_rule_val)->get_table_id();
|
|
Packit |
6d2c1b |
if (find_route_val(peer_ip, table_id, p_val)) {
|
|
Packit |
6d2c1b |
p_ent->set_val(p_val);
|
|
Packit |
6d2c1b |
if (b_register_to_net_dev) {
|
|
Packit |
6d2c1b |
//in_addr_t src_addr = p_val->get_src_addr();
|
|
Packit |
6d2c1b |
//net_device_val* p_ndv = g_p_net_device_table_mgr->get_net_device_val(src_addr);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
// Check if broadcast IP which is NOT supported
|
|
Packit |
6d2c1b |
if (IS_BROADCAST_N(peer_ip)) {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Disabling Offload for route_entry '%s' - this is BC address", p_ent->to_str().c_str());
|
|
Packit |
6d2c1b |
// Need to route traffic to/from OS
|
|
Packit |
6d2c1b |
// Prevent registering of net_device to route entry
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
// Check if: Local loopback over Ethernet case which was not supported before OFED 2.1
|
|
Packit |
6d2c1b |
/*else if (p_ndv && (p_ndv->get_transport_type() == VMA_TRANSPORT_ETH) && (peer_ip == src_addr)) {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Disabling Offload for route_entry '%s' - this is an Ethernet unicast loopback route", p_ent->to_str().c_str());
|
|
Packit |
6d2c1b |
// Need to route traffic to/from OS
|
|
Packit |
6d2c1b |
// Prevent registering of net_device to route entry
|
|
Packit |
6d2c1b |
}*/
|
|
Packit |
6d2c1b |
else {
|
|
Packit |
6d2c1b |
// register to net device for bonding events
|
|
Packit |
6d2c1b |
p_ent->register_to_net_device();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
// All good, validate the new route entry
|
|
Packit |
6d2c1b |
p_ent->set_entry_valid();
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("could not find route val for route_entry '%s in table %u'", p_ent->to_str().c_str(), table_id);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
else {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("rule entry is not valid");
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_entry* route_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
// no need for lock - lock is activated in cache_collection_mgr::register_observer
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("");
|
|
Packit |
6d2c1b |
NOT_IN_USE(obs);
|
|
Packit |
6d2c1b |
route_entry* p_ent = new route_entry(key);
|
|
Packit |
6d2c1b |
update_entry(p_ent, true);
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("new entry %p created successfully", p_ent);
|
|
Packit |
6d2c1b |
return p_ent;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::new_route_event(route_val* netlink_route_val)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (!netlink_route_val) {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Invalid route entry");
|
|
Packit |
6d2c1b |
return;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
if (m_tab.entries_num >= MAX_TABLE_SIZE) {
|
|
Packit |
6d2c1b |
rt_mgr_logwarn("No available space for new route entry");
|
|
Packit |
6d2c1b |
return;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
auto_unlocker lock(m_lock);
|
|
Packit |
6d2c1b |
route_val* p_route_val = &m_tab.value[m_tab.entries_num];
|
|
Packit |
6d2c1b |
p_route_val->set_dst_addr(netlink_route_val->get_dst_addr());
|
|
Packit |
6d2c1b |
p_route_val->set_dst_mask(netlink_route_val->get_dst_mask());
|
|
Packit |
6d2c1b |
p_route_val->set_dst_pref_len(netlink_route_val->get_dst_pref_len());
|
|
Packit |
6d2c1b |
p_route_val->set_src_addr(netlink_route_val->get_src_addr());
|
|
Packit |
6d2c1b |
p_route_val->set_gw(netlink_route_val->get_gw_addr());
|
|
Packit |
6d2c1b |
p_route_val->set_protocol(netlink_route_val->get_protocol());
|
|
Packit |
6d2c1b |
p_route_val->set_scope(netlink_route_val->get_scope());
|
|
Packit |
6d2c1b |
p_route_val->set_type(netlink_route_val->get_type());
|
|
Packit |
6d2c1b |
p_route_val->set_table_id(netlink_route_val->get_table_id());
|
|
Packit |
6d2c1b |
p_route_val->set_if_index(netlink_route_val->get_if_index());
|
|
Packit |
6d2c1b |
p_route_val->set_if_name(const_cast<char*> (netlink_route_val->get_if_name()));
|
|
Packit |
6d2c1b |
p_route_val->set_mtu((netlink_route_val->get_mtu()));
|
|
Packit |
6d2c1b |
p_route_val->set_state(true);
|
|
Packit |
6d2c1b |
p_route_val->set_str();
|
|
Packit |
6d2c1b |
p_route_val->print_val();
|
|
Packit |
6d2c1b |
++m_tab.entries_num;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void route_table_mgr::notify_cb(event *ev)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("received route event from netlink");
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
route_nl_event *route_netlink_ev = dynamic_cast <route_nl_event*>(ev);
|
|
Packit |
6d2c1b |
if (!route_netlink_ev) {
|
|
Packit |
6d2c1b |
rt_mgr_logwarn("Received non route event!!!");
|
|
Packit |
6d2c1b |
return;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
netlink_route_info* p_netlink_route_info = route_netlink_ev->get_route_info();
|
|
Packit |
6d2c1b |
if (!p_netlink_route_info) {
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Received invalid route event!!!");
|
|
Packit |
6d2c1b |
return;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
switch(route_netlink_ev->nl_type) {
|
|
Packit |
6d2c1b |
case RTM_NEWROUTE:
|
|
Packit |
6d2c1b |
new_route_event(p_netlink_route_info->get_route_val());
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
#if 0
|
|
Packit |
6d2c1b |
case RTM_DELROUTE:
|
|
Packit |
6d2c1b |
del_route_event(p_netlink_route_info->get_route_val());
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
#endif
|
|
Packit |
6d2c1b |
default:
|
|
Packit |
6d2c1b |
rt_mgr_logdbg("Route event (%u) is not handled", route_netlink_ev->nl_type);
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|