Skip to content

Commit

Permalink
Added improved Patricia tree with payload implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-odintsov committed Mar 2, 2025
1 parent 74aee5e commit 5b960f7
Showing 1 changed file with 175 additions and 0 deletions.
175 changes: 175 additions & 0 deletions src/ip_lookup_tree_with_payload.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#pragma once

#include "fastnetmon_networks.hpp"
#include "libpatricia/patricia.hpp"
#include <iostream>

// This is safe wrapper for Patricia with support for storing data directly in tree leafs without doing memory
// allocations We can store only types which does not exceed void* by length
template <typename T> class lookup_tree_128bit_with_payload_t {
public:
lookup_tree_128bit_with_payload_t() {
patricia_tree = New_Patricia(128);
}

// Loads all the elements from passed tree to our tree
// using inline storage method
void load_inline(const lookup_tree_128bit_with_payload_t<T>& another_tree) {

patricia_process(another_tree.patricia_tree, [this](prefix_t* prefix, void* data) {
subnet_ipv6_cidr_mask_t subnet;

memcpy(&subnet.subnet_address, &prefix->add.sin6, sizeof(subnet.subnet_address));
subnet.cidr_prefix_length = prefix->bitlen;

// Add it to tree
this->add_subnet_with_payload_inline(subnet, (T)data);
});
}

bool add_subnet_with_payload_inline(const subnet_ipv6_cidr_mask_t& ipv6_subnet, T object_to_store) {
std::string subnet_as_string = convert_ipv6_subnet_to_string(ipv6_subnet);

make_and_lookup_ipv6_with_data(patricia_tree, (char*)subnet_as_string.c_str(), (void*)object_to_store);
return true;
}

// Try to find payload for certain subnet. But we return value directly
bool lookup_value_inline_for_subnet(const subnet_ipv6_cidr_mask_t& ipv6_subnet, T& target_object_ptr) {
prefix_t prefix_for_check_address;

prefix_for_check_address.add.sin6 = ipv6_subnet.subnet_address;
prefix_for_check_address.family = AF_INET6;
prefix_for_check_address.bitlen = ipv6_subnet.cidr_prefix_length;

patricia_node_t* found_patrica_node = patricia_search_best2(patricia_tree, &prefix_for_check_address, 1);

// Could not find anything
if (found_patrica_node == NULL) {
return false;
}

// Return value itself
target_object_ptr = (T)found_patrica_node->data;
return true;
}

// Try to find payload for certain subnet. But we return value directly
// It will return data only if we have exactly this subnet with exactly this prefix
bool lookup_value_inline_for_subnet_exact_match(const subnet_ipv6_cidr_mask_t& ipv6_subnet, T& target_object_ptr) {
prefix_t prefix_for_check_address;

prefix_for_check_address.add.sin6 = ipv6_subnet.subnet_address;
prefix_for_check_address.family = AF_INET6;
prefix_for_check_address.bitlen = ipv6_subnet.cidr_prefix_length;

patricia_node_t* found_patrica_node = patricia_search_exact(patricia_tree, &prefix_for_check_address);

// Could not find anything
if (found_patrica_node == NULL) {
return false;
}

// Return value itself
target_object_ptr = (T)found_patrica_node->data;
return true;
}

~lookup_tree_128bit_with_payload_t() {
if (patricia_tree) {
Destroy_Patricia(patricia_tree);
}
}

patricia_tree_t* patricia_tree = nullptr;
};

// This is safe wrapper for Patricia with support for storing data directly in tree leafs without doing memory
// allocations We can store only types which does not exceed void* by length
template <typename T> class lookup_tree_32bit_with_payload_t {
public:
lookup_tree_32bit_with_payload_t() {
patricia_tree = New_Patricia(32);
}

// Loads all the elements from passed tree to our tree
// using inline storage method
void load_inline(const lookup_tree_32bit_with_payload_t<T>& another_tree) {
patricia_process(another_tree.patricia_tree, [this](prefix_t* prefix, void* data) {
// Construct our network from low level structure in Patricia
subnet_cidr_mask_t subnet;
subnet.subnet_address = prefix->add.sin.s_addr;
subnet.cidr_prefix_length = prefix->bitlen;

// Add it to tree
add_subnet_with_payload_inline(subnet, (T)data);
});
}

bool add_subnet_with_payload_inline(const subnet_cidr_mask_t& subnet, T object_to_store) {
std::string subnet_as_string = convert_ipv4_subnet_to_string(subnet);

make_and_lookup_with_data(patricia_tree, (char*)subnet_as_string.c_str(), (void*)object_to_store);
return true;
}

// Try to find payload for certain subnet. But we return value directly
bool lookup_value_inline_for_subnet(const subnet_cidr_mask_t& subnet, T& target_object_ptr) {
prefix_t prefix_for_check_address;

prefix_for_check_address.add.sin.s_addr = subnet.subnet_address;
prefix_for_check_address.family = AF_INET;
prefix_for_check_address.bitlen = subnet.cidr_prefix_length;

patricia_node_t* found_patrica_node = patricia_search_best2(patricia_tree, &prefix_for_check_address, 1);

// Could not find anything
if (found_patrica_node == NULL) {
return false;
}

// Return value itself
target_object_ptr = (T)found_patrica_node->data;
return true;
}


// Try to find payload for certain subnet. But we return value directly
// It will return data only if we have exactly this subnet with exactly t
bool lookup_value_inline_for_subnet_exact_match(const subnet_cidr_mask_t& subnet, T& target_object_ptr) {
prefix_t prefix_for_check_address;

prefix_for_check_address.add.sin.s_addr = subnet.subnet_address;
prefix_for_check_address.family = AF_INET;
prefix_for_check_address.bitlen = subnet.cidr_prefix_length;

patricia_node_t* found_patrica_node = patricia_search_exact(patricia_tree, &prefix_for_check_address);

// Could not find anything
if (found_patrica_node == NULL) {
return false;
}

// Return value itself
target_object_ptr = (T)found_patrica_node->data;
return true;
}


// Try to find payload for certain IP. But we return pointer to value instead of value
bool lookup_value_inline_for_ip(uint32_t ip, T& target_object_ptr) {
subnet_cidr_mask_t subnet(ip, 32);

return lookup_value_inline_for_subnet(subnet, target_object_ptr);
}

~lookup_tree_32bit_with_payload_t() {
if (patricia_tree) {
Destroy_Patricia(patricia_tree);

patricia_tree = nullptr;
}
}

patricia_tree_t* patricia_tree = nullptr;
};

0 comments on commit 5b960f7

Please sign in to comment.