Blame src/vma/proto/rule_table_mgr.cpp

Packit Service aa3af4
/*
Packit Service aa3af4
 * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
Packit Service aa3af4
 *
Packit Service aa3af4
 * This software is available to you under a choice of one of two
Packit Service aa3af4
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service aa3af4
 * General Public License (GPL) Version 2, available from the file
Packit Service aa3af4
 * COPYING in the main directory of this source tree, or the
Packit Service aa3af4
 * BSD license below:
Packit Service aa3af4
 *
Packit Service aa3af4
 *     Redistribution and use in source and binary forms, with or
Packit Service aa3af4
 *     without modification, are permitted provided that the following
Packit Service aa3af4
 *     conditions are met:
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions of source code must retain the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer.
Packit Service aa3af4
 *
Packit Service aa3af4
 *      - Redistributions in binary form must reproduce the above
Packit Service aa3af4
 *        copyright notice, this list of conditions and the following
Packit Service aa3af4
 *        disclaimer in the documentation and/or other materials
Packit Service aa3af4
 *        provided with the distribution.
Packit Service aa3af4
 *
Packit Service aa3af4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service aa3af4
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service aa3af4
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service aa3af4
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service aa3af4
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service aa3af4
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service aa3af4
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service aa3af4
 * SOFTWARE.
Packit Service aa3af4
 */
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
#include <stdio.h>
Packit Service aa3af4
#include <stdint.h>
Packit Service aa3af4
#include <string.h>
Packit Service aa3af4
#include <stdlib.h>
Packit Service aa3af4
#include <sys/ioctl.h>
Packit Service aa3af4
#include <sys/socket.h>
Packit Service aa3af4
#include <linux/rtnetlink.h>
Packit Service aa3af4
#include <linux/netlink.h>
Packit Service aa3af4
#include <linux/fib_rules.h>
Packit Service aa3af4
#include <netinet/in.h>
Packit Service aa3af4
#include <netinet/ether.h>
Packit Service aa3af4
#include <arpa/inet.h>
Packit Service aa3af4
Packit Service aa3af4
#include "utils/bullseye.h"
Packit Service aa3af4
#include "utils/lock_wrapper.h"
Packit Service aa3af4
#include "vlogger/vlogger.h"
Packit Service aa3af4
#include "vma/util/vtypes.h"
Packit Service aa3af4
#include "vma/util/utils.h"
Packit Service aa3af4
#include "vma/util/if.h"
Packit Service aa3af4
#include "rule_table_mgr.h"
Packit Service aa3af4
#include "vma/sock/socket_fd_api.h"
Packit Service aa3af4
#include "vma/sock/sock-redirect.h"
Packit Service aa3af4
#include "ip_address.h"
Packit Service aa3af4
Packit Service aa3af4
// debugging macros
Packit Service aa3af4
#define MODULE_NAME 		"rrm:"
Packit Service aa3af4
Packit Service aa3af4
#define rr_mgr_if_logpanic	__log_panic
Packit Service aa3af4
#define	rr_mgr_logerr		__log_err
Packit Service aa3af4
#define rr_mgr_logwarn		__log_warn
Packit Service aa3af4
#define rr_mgr_loginfo		__log_info
Packit Service aa3af4
#define rr_mgr_logdbg		__log_dbg
Packit Service aa3af4
#define rr_mgr_logfunc		__log_func
Packit Service aa3af4
#define rr_mgr_logfuncall	__log_funcall
Packit Service aa3af4
	
Packit Service aa3af4
rule_table_mgr* g_p_rule_table_mgr = NULL;
Packit Service aa3af4
Packit Service aa3af4
rule_table_mgr::rule_table_mgr() : netlink_socket_mgr<rule_val>(RULE_DATA_TYPE), cache_table_mgr<route_rule_table_key, std::deque<rule_val*>*>("rule_table_mgr")
Packit Service aa3af4
{
Packit Service aa3af4
Packit Service aa3af4
	rr_mgr_logdbg("");
Packit Service aa3af4
Packit Service aa3af4
	//Read Rule table from kernel and save it in local variable. 
Packit Service aa3af4
	update_tbl();
Packit Service aa3af4
	
Packit Service aa3af4
	//Print table
Packit Service aa3af4
	print_val_tbl();
Packit Service aa3af4
	
Packit Service aa3af4
	rr_mgr_logdbg("Done");
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
//This function uses Netlink to get routing rules saved in kernel then saved it locally.
Packit Service aa3af4
void rule_table_mgr::update_tbl()
Packit Service aa3af4
{
Packit Service aa3af4
	auto_unlocker lock(m_lock);
Packit Service aa3af4
Packit Service aa3af4
	netlink_socket_mgr<rule_val>::update_tbl();
Packit Service aa3af4
Packit Service aa3af4
	return;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Parse received rule entry into custom object (rule_val).
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		nl_header	: object that contain rule entry.
Packit Service aa3af4
//		p_val		: custom object that contain parsed rule data.
Packit Service aa3af4
// return true if its not related to local or default table, false otherwise.
Packit Service aa3af4
bool rule_table_mgr::parse_enrty(nlmsghdr *nl_header, rule_val *p_val)
Packit Service aa3af4
{
Packit Service aa3af4
	int len;
Packit Service aa3af4
	struct rtmsg *rt_msg;
Packit Service aa3af4
	struct rtattr *rt_attribute;
Packit Service aa3af4
Packit Service aa3af4
	// get rule entry header
Packit Service aa3af4
	rt_msg = (struct rtmsg *) NLMSG_DATA(nl_header);
Packit Service aa3af4
Packit Service aa3af4
	// we are not concerned about the local and default rule table
Packit Service aa3af4
	if (rt_msg->rtm_family != AF_INET || rt_msg->rtm_table == RT_TABLE_LOCAL)
Packit Service aa3af4
		return false;
Packit Service aa3af4
Packit Service aa3af4
	p_val->set_protocol(rt_msg->rtm_protocol);
Packit Service aa3af4
	p_val->set_scope(rt_msg->rtm_scope);
Packit Service aa3af4
	p_val->set_type(rt_msg->rtm_type);
Packit Service aa3af4
	p_val->set_tos(rt_msg->rtm_tos);
Packit Service aa3af4
	p_val->set_table_id(rt_msg->rtm_table);
Packit Service aa3af4
Packit Service aa3af4
	len = RTM_PAYLOAD(nl_header);
Packit Service aa3af4
	rt_attribute = (struct rtattr *) RTM_RTA(rt_msg);
Packit Service aa3af4
Packit Service aa3af4
	for (;RTA_OK(rt_attribute, len);rt_attribute=RTA_NEXT(rt_attribute,len)) {
Packit Service aa3af4
		parse_attr(rt_attribute, p_val);
Packit Service aa3af4
	}
Packit Service aa3af4
	p_val->set_state(true);
Packit Service aa3af4
	p_val->set_str();
Packit Service aa3af4
	return true;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Parse received rule attribute for given rule.
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		rt_attribute	: object that contain rule attribute.
Packit Service aa3af4
//		p_val			: custom object that contain parsed rule data.
Packit Service aa3af4
void rule_table_mgr::parse_attr(struct rtattr *rt_attribute, rule_val *p_val)
Packit Service aa3af4
{
Packit Service aa3af4
	switch (rt_attribute->rta_type) {
Packit Service aa3af4
		case FRA_PRIORITY:
Packit Service aa3af4
			p_val->set_priority(*(uint32_t *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
		case FRA_DST:
Packit Service aa3af4
			p_val->set_dst_addr(*(in_addr_t *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
		case FRA_SRC:
Packit Service aa3af4
			p_val->set_src_addr(*(in_addr_t *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
		case FRA_IFNAME:
Packit Service aa3af4
			p_val->set_iif_name((char *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
		case FRA_TABLE:
Packit Service aa3af4
			p_val->set_table_id(*(uint32_t *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
#if DEFINED_FRA_OIFNAME
Packit Service aa3af4
		case FRA_OIFNAME:
Packit Service aa3af4
			p_val->set_oif_name((char *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
#endif
Packit Service aa3af4
		default:
Packit Service aa3af4
			rr_mgr_logdbg("got undetected rta_type %d %x", rt_attribute->rta_type, *(uint32_t *)RTA_DATA(rt_attribute));
Packit Service aa3af4
			break;
Packit Service aa3af4
	}
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
Packit Service aa3af4
// Create rule entry object for given destination key and fill it with matching rule value from rule table.
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		key		: key object that contain information about destination.
Packit Service aa3af4
//		obs		: object that contain observer for specific rule entry.
Packit Service aa3af4
//	Returns created rule entry object.
Packit Service aa3af4
rule_entry* rule_table_mgr::create_new_entry(route_rule_table_key key, const observer *obs)
Packit Service aa3af4
{
Packit Service aa3af4
	rr_mgr_logdbg("");
Packit Service aa3af4
	NOT_IN_USE(obs);
Packit Service aa3af4
	rule_entry* p_ent = new rule_entry(key);
Packit Service aa3af4
	update_entry(p_ent);
Packit Service aa3af4
	rr_mgr_logdbg("new entry %p created successfully", p_ent);
Packit Service aa3af4
	return p_ent;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Update invalid rule entry with matching rule value from rule table.
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		p_ent		: rule entry that will be updated if it is invalid.
Packit Service aa3af4
void rule_table_mgr::update_entry(rule_entry* p_ent)
Packit Service aa3af4
{
Packit Service aa3af4
	rr_mgr_logdbg("entry [%p]", p_ent);
Packit Service aa3af4
	auto_unlocker lock(m_lock);
Packit Service aa3af4
	
Packit Service aa3af4
	if (p_ent && !p_ent->is_valid()) { //if entry is found in the collection and is not valid
Packit Service aa3af4
		
Packit Service aa3af4
		rr_mgr_logdbg("rule_entry is not valid-> update value");
Packit Service aa3af4
		std::deque<rule_val*>* p_rrv;
Packit Service aa3af4
		p_ent->get_val(p_rrv);
Packit Service aa3af4
		/* p_rrv->clear(); TODO for future rule live updates */
Packit Service aa3af4
		if (!find_rule_val(p_ent->get_key(), p_rrv)) {
Packit Service aa3af4
			rr_mgr_logdbg("ERROR: could not find rule val for rule_entry '%s'", p_ent->to_str().c_str());
Packit Service aa3af4
		}
Packit Service aa3af4
	} 
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Find rule form rule table that match given destination info. 
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		key		: key object that contain information about destination.
Packit Service aa3af4
//		p_val	: list of rule_val object that will contain information about all rule that match destination info    
Packit Service aa3af4
// Returns true if at least one rule match destination info, false otherwise.
Packit Service aa3af4
bool rule_table_mgr::find_rule_val(route_rule_table_key key, std::deque<rule_val*>* &p_val)
Packit Service aa3af4
{
Packit Service aa3af4
	rr_mgr_logfunc("destination info %s:", key.to_str().c_str());
Packit Service aa3af4
Packit Service aa3af4
	for (int index = 0; index < m_tab.entries_num; index++) {
Packit Service aa3af4
		rule_val* p_val_from_tbl = &m_tab.value[index];
Packit Service aa3af4
		if (p_val_from_tbl->is_valid() && is_matching_rule(key, p_val_from_tbl)) {
Packit Service aa3af4
			p_val->push_back(p_val_from_tbl);
Packit Service aa3af4
			rr_mgr_logdbg("found rule val[%p]: %s", p_val_from_tbl, p_val_from_tbl->to_str());
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	return !p_val->empty();
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Check matching between given destination info. and specific rule from rule table. 
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		key		: key object that contain information about destination.
Packit Service aa3af4
//		p_val	: rule_val object that contain information about specific rule from rule table   
Packit Service aa3af4
// Returns true if destination info match rule value, false otherwise.
Packit Service aa3af4
bool rule_table_mgr::is_matching_rule(route_rule_table_key key, rule_val* p_val)
Packit Service aa3af4
{
Packit Service aa3af4
Packit Service aa3af4
	in_addr_t	m_dst_ip	= key.get_dst_ip();
Packit Service aa3af4
	in_addr_t	m_src_ip	= key.get_src_ip();
Packit Service aa3af4
	uint8_t		m_tos		= key.get_tos();
Packit Service aa3af4
	
Packit Service aa3af4
	in_addr_t	rule_dst_ip	= p_val->get_dst_addr();
Packit Service aa3af4
	in_addr_t	rule_src_ip	= p_val->get_src_addr();
Packit Service aa3af4
	uint8_t		rule_tos	= p_val->get_tos();
Packit Service aa3af4
	char*		rule_iif_name	= (char *)p_val->get_iif_name();
Packit Service aa3af4
	char*		rule_oif_name	= (char *)p_val->get_oif_name();
Packit Service aa3af4
	
Packit Service aa3af4
	bool is_match = false;
Packit Service aa3af4
	
Packit Service aa3af4
	// Only destination IP, source IP and TOS are checked with rule, since IIF and OIF is not filled in dst_entry object.
Packit Service aa3af4
	if ((rule_dst_ip == 0) || (rule_dst_ip == m_dst_ip)) { // Check match in destination IP
Packit Service aa3af4
	
Packit Service aa3af4
		if ((rule_src_ip == 0) || (rule_src_ip == m_src_ip)) { // Check match in source IP
Packit Service aa3af4
		
Packit Service aa3af4
			if ((rule_tos == 0) || (rule_tos == m_tos)) { // Check match in TOS value
Packit Service aa3af4
			
Packit Service aa3af4
				if (strcmp(rule_iif_name, "") == 0) { // Check that rule doesn't contain IIF since we can't check match with
Packit Service aa3af4
				
Packit Service aa3af4
					if (strcmp(rule_oif_name, "") == 0) { // Check that rule doesn't contain OIF since we can't check match with
Packit Service aa3af4
						is_match = true;
Packit Service aa3af4
					}
Packit Service aa3af4
				}
Packit Service aa3af4
			}
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
Packit Service aa3af4
	return is_match;
Packit Service aa3af4
}
Packit Service aa3af4
Packit Service aa3af4
// Find table ID for given destination info.
Packit Service aa3af4
// Parameters: 
Packit Service aa3af4
//		key			: key object that contain information about destination.
Packit Service aa3af4
//		table_id_list	: list that will contain table ID for all rule that match destination info   
Packit Service aa3af4
// Returns true if at least one rule match destination info, false otherwise.
Packit Service aa3af4
bool rule_table_mgr::rule_resolve(route_rule_table_key key, std::deque<unsigned char> &table_id_list)
Packit Service aa3af4
{
Packit Service aa3af4
	rr_mgr_logdbg("dst info: '%s'", key.to_str().c_str());
Packit Service aa3af4
Packit Service aa3af4
	std::deque<rule_val*> values;
Packit Service aa3af4
	std::deque<rule_val*>* p_values = &values;
Packit Service aa3af4
	auto_unlocker lock(m_lock);
Packit Service aa3af4
	if (find_rule_val(key, p_values)) {
Packit Service aa3af4
		for (std::deque<rule_val*>::iterator val = values.begin(); val != values.end(); val++) {
Packit Service aa3af4
			table_id_list.push_back((*val)->get_table_id());
Packit Service aa3af4
			rr_mgr_logdbg("dst info: '%s' resolved to table ID '%u'", key.to_str().c_str(), (*val)->get_table_id());
Packit Service aa3af4
		}
Packit Service aa3af4
	}
Packit Service aa3af4
	
Packit Service aa3af4
	return !table_id_list.empty();
Packit Service aa3af4
}
Packit Service aa3af4