Files
m241Neelima/components/ip_net2-6.9/ipcom/src/ipcom_route.c
T
2026-07-30 11:19:44 +05:30

1037 lines
34 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_route.c,v $ $Revision: 1.49.10.2 $
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_route.c,v $
* $Author: hchu0 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* Route table functions, based on Patricia tree */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipcom_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include "ipcom_route.h"
#include "ipcom_clib.h"
#include "ipcom_err.h"
#include "ipcom_set.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
*===========================================================================
* IPCOM_IS_BIT_SET
*===========================================================================
* Description: Tests if a specifed bit in a buffer is set.
* Parameters: [in] data - const void * pointer.
* [in] bit - The bit to test, counted from left.
* Returns: 0 if the bit is not set, !=0 if the bit the is set.
*
*/
#define IPCOM_IS_BIT_SET(data, bit) \
(((Ip_u8 *) (data))[(bit) >> 3] & (0x80 >> ((bit) & 0x7)))
/* Status of internal nodes during tree traversal */
#define IPCOM_ROUTE_STATUS_INIT 0
#define IPCOM_ROUTE_STATUS_OFF_SUBTREE 1
#define IPCOM_ROUTE_STATUS_ON_SUBTREE 2
#define IPCOM_ROUTE_STATUS_DONE 3
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
*===========================================================================
* Ipcom_route_walk_subtree_cb
*===========================================================================
* Description: Will be called for all leaf nodes when walking the tree.
* Parameters: leaf - A leaf node (leaf->on == leaf->off == IP_NULL).
* user - User defined data.
* Returns:
*
*/
typedef void (*Ipcom_route_walk_subtree_cb)(Ipcom_route_entry *leaf,
void *user);
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC void
ipcom_route_init_subtree_mask2(Ipcom_route_entry *rt, Ip_bool consecutive_mask);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_patricia_search
*===========================================================================
* Description: Search a patricia tree for the the entry that best matches the
* search criteria.
* Parameters: top - The top of the patricia (sub)tree.
* key - The key to search for,
* mask - The mask to apply to the key before doing any test.
* Returns: The best match entry.
*
*/
IP_STATIC Ipcom_route_entry*
ipcom_patricia_search(Ipcom_route_entry *top, const void *key, const void *mask)
{
Ipcom_route_entry *current = top;
while (current->off != IP_NULL)
{
if ((mask == IP_NULL
|| IPCOM_IS_BIT_SET(mask, current->bit))
&& IPCOM_IS_BIT_SET(key, current->bit))
current = current->on;
else
current = current->off;
}
ip_assert(current->on == IP_NULL);
return current;
}
/*
*===========================================================================
* ipcom_patricia_insert
*===========================================================================
* Description: Insert route entry into the patricia route tree.
* Parameters: domain - The address domain.
* new_leaf - The new node to insert. The following fields must
* have valid values:
* flags must contain any user defined flags.
* key must point to the search key
* mask must point to the mask or be IP_NULL if the mask is all 1:s.
* all other fields are initialized by this function.
* Returns: 0 = success, <0 = error code
*
*/
IP_STATIC Ip_err
ipcom_patricia_insert(Ipcom_route *rtab, Ipcom_route_entry *new_leaf)
{
Ipcom_route_entry *new_internal_node;
Ipcom_route_entry *current;
#ifdef IP_ASSERT
Ip_u16 max_bit;
#endif
Ip_u16 partition_bit;
void *matched_key;
current = ipcom_patricia_search(rtab->top, new_leaf->key, new_leaf->mask);
if (ipcom_route_key_cmp(rtab->bit_count, current->key, new_leaf->key, new_leaf->mask)
== IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH)
{
/* Perfect match, replace this entry */
new_leaf->parent = current->parent;
if (new_leaf->parent->on == current)
new_leaf->parent->on = new_leaf;
else
{
ip_assert(new_leaf->parent->off == current);
new_leaf->parent->off = new_leaf;
}
if (IP_BIT_ISSET(current->flags, IPCOM_ROUTE_FLAG_END))
IP_BIT_SET(new_leaf->flags, IPCOM_ROUTE_FLAG_END);
if (current->mask != IP_NULL)
{
/* current->mask pointer will become invalid, remove it */
Ipcom_route_entry *internal;
for (internal = current->parent; internal != IP_NULL; internal = internal->parent)
if (current->mask == internal->mask)
internal->mask = IP_NULL;
}
ipcom_route_init_subtree_mask2(rtab->top, rtab->consecutive_mask);
ipcom_route_init_subtree_mask2(new_leaf, rtab->consecutive_mask);
current->parent = IP_NULL;
ip_assert(rtab->notify_func != IP_NULL);
if (IP_BIT_ISFALSE(current->flags, IPCOM_ROUTE_FLAG_INIT))
{
rtab->notify_func(rtab, current, IPCOM_ROUTE_CODE_DUPLICATE);
}
return IPCOM_SUCCESS;
}
/* Find out where the entry should be inserted */
IP_ASSERTLINE(max_bit = (Ip_u16) (rtab->bit_count - 1));
matched_key = current->key;
for (;;)
{
if (ipcom_route_key_cmp(current->parent->bit, new_leaf->key, matched_key, IP_NULL)
!= IPCOM_ROUTE_KEY_CMP_NO_MATCH)
break;
/* Need to compare fewer bits to make the addresses match */
current = current->parent;
IP_ASSERTLINE(max_bit = (Ip_u16) (current->bit - 1));
}
partition_bit = (Ip_u16) (current->parent->bit + 1);
/* current->key and new_leaf->key differs in a bit between 'partition_bit'
and 'max_bit' */
while (IPCOM_IS_BIT_SET(new_leaf->key, partition_bit)
== IPCOM_IS_BIT_SET(matched_key, partition_bit))
{
partition_bit++;
}
/* The key differ in bit 'partition_bit' */
ip_assert(max_bit >= partition_bit);
/* Allocate memory for a new patricia tree internal node */
new_internal_node = ipcom_malloc(sizeof(Ipcom_route_entry));
if (new_internal_node == IP_NULL)
return IPCOM_ERR_NO_MEMORY;
ipcom_memset(new_internal_node, 0, sizeof(Ipcom_route_entry));
new_internal_node->bit = partition_bit;
new_internal_node->flags = IPCOM_ROUTE_FLAG_INTERNAL;
new_internal_node->key = IP_NULL;
new_internal_node->mask = IP_NULL;
/* Insert the new internal and leaf nodes */
new_internal_node->parent = current->parent;
/* Add the new internal node as child of the 'current' parent */
if (current->parent->off == current)
current->parent->off = new_internal_node;
else
current->parent->on = new_internal_node;
current->parent = new_internal_node;
new_leaf->parent = new_internal_node;
/* Add the new leaf and the 'current' node as child to the new internal node */
if (IPCOM_IS_BIT_SET(new_leaf->key, partition_bit))
{
new_internal_node->off = current;
new_internal_node->on = new_leaf;
}
else
{
new_internal_node->on = current;
new_internal_node->off = new_leaf;
}
ipcom_route_init_subtree_mask2(new_internal_node, rtab->consecutive_mask);
return 0;
}
/*
*===========================================================================
* ipcom_route_walk_subtree
*===========================================================================
* Description: Visits all nodes rooted at 'subtree'.
* Parameters: subtree - The root of the subtree to travers.
* only_off_subtree - Visit only the nodes with the partition
* bits cleared.
* include_init_nodes - IP_TRUE if the user function should be
* called even for initial nodes.
* cb - The user function that will be called for leaf nodes.
* user - User defined data passed to 'cb'.
* Returns:
*
*/
IP_STATIC void
ipcom_route_walk_subtree(Ipcom_route_entry *subtree,
Ip_bool only_off_subtree,
Ip_bool include_init_nodes,
Ipcom_route_walk_subtree_cb cb,
void *user)
{
Ipcom_route_entry *rt = subtree;
Ip_bool done = IP_FALSE;
rt->status = IPCOM_ROUTE_STATUS_INIT;
do {
if (rt->off != IP_NULL
&& rt->status == IPCOM_ROUTE_STATUS_INIT)
{
/* Go down the sub-tree with partition bit cleared */
ip_assert(rt->on != IP_NULL);
rt->status = IPCOM_ROUTE_STATUS_OFF_SUBTREE;
rt = rt->off;
rt->status = IPCOM_ROUTE_STATUS_INIT;
}
else if (!only_off_subtree
&& rt->on != IP_NULL
&& rt->status == IPCOM_ROUTE_STATUS_OFF_SUBTREE)
{
/* Go down the sub-tree with partition bit set */
ip_assert(rt->off != IP_NULL);
rt->status = IPCOM_ROUTE_STATUS_ON_SUBTREE;
rt = rt->on;
rt->status = IPCOM_ROUTE_STATUS_INIT;
}
else
{
Ipcom_route_entry *leaf = rt;
/* Must set status to DONE before calling the callback,
since the callback might free the leaf node */
rt->status = IPCOM_ROUTE_STATUS_DONE;
if (rt == subtree)
/* Done with the whole subtree */
done = IP_TRUE;
else
rt = rt->parent;
if (leaf->off == IP_NULL
&& (IP_BIT_ISFALSE(leaf->flags, IPCOM_ROUTE_FLAG_INIT)
|| include_init_nodes))
{
ip_assert(leaf->on == IP_NULL);
cb(leaf, user);
}
}
} while (!done);
}
/*
*===========================================================================
* ipcom_route_init_subtree_mask_cb
*===========================================================================
* Description: Initialize the internal node mask references on a subtree.
* Parameters: subtree - The head of the subtree.
* consecutive_mask - Must be IP_FALSE if the masks can be
* non-consecutive, this operation is much
* expensive in this case.
* Returns:
*
*/
IP_STATIC void
ipcom_route_init_subtree_mask_cb(Ipcom_route_entry *rt, void *unused)
{
/* Process the leaf node */
Ipcom_route_entry *current;
(void) unused;
ip_assert(rt->on == IP_NULL);
if (rt->mask != IP_NULL)
for (current = rt->parent; current != IP_NULL; current = current->parent)
if (!IPCOM_IS_BIT_SET(rt->mask, current->bit))
current->mask = rt->mask;
}
/*
*===========================================================================
* ipcom_route_init_subtree_mask2
*===========================================================================
* Description: Initialize the internal node mask references on a subtree.
* Parameters: subtree - The head of the subtree.
* consecutive_mask - Must be IP_FALSE if the masks can be
* non-consecutive, this operation is much
* expensive in this case.
* Returns:
*
*/
IP_STATIC void
ipcom_route_init_subtree_mask2(Ipcom_route_entry *subtree, Ip_bool consecutive_mask)
{
ipcom_route_walk_subtree(subtree,
consecutive_mask,
IP_TRUE,
ipcom_route_init_subtree_mask_cb,
IP_NULL);
}
/*
*===========================================================================
* ipcom_route_free_subtree_cb
*===========================================================================
* Description: Frees the specified entry.
* Parameters: rt - The entry to free.
* Returns:
*
*/
IP_STATIC void
ipcom_route_free_subtree_cb(Ipcom_route_entry *rt, Ipcom_route *rtab)
{
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INTERNAL))
ipcom_free(rt);
else
rtab->notify_func(rtab, rt, IPCOM_ROUTE_CODE_REMOVE);
}
/*
*===========================================================================
* ipcom_route_prev_entry
*===========================================================================
* Description: Returns the previous leaf element in the route table.
* Parameters: rt - The current route entry
* Returns: The previous route entry or IP_NULL if the passed entry was
* the first.
*
*/
IP_INLINE Ipcom_route_entry *
ipcom_route_prev_entry(Ipcom_route_entry *rt)
{
while (rt->parent->off == rt)
{
rt = rt->parent;
if (rt->parent == IP_NULL)
return IP_NULL;
}
rt = rt->parent->off;
while (rt->on != IP_NULL)
rt = rt->on;
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT))
return IP_NULL;
return rt;
}
/*
*===========================================================================
* ipcom_route_last_entry
*===========================================================================
* Description: Returns the last entry in the route table.
* Parameters: rtab - The route table for which the last entry should be returned.
* Returns: The last route entry or IP_NULL if the route table is empty.
*
*/
IP_INLINE Ipcom_route_entry *
ipcom_route_last_entry(Ipcom_route *rtab)
{
Ipcom_route_entry *rt;
rt = rtab->top;
while (rt->on != IP_NULL)
rt = rt->on;
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT))
rt = ipcom_route_prev_entry(rt);
return rt;
}
/*
****************************************************************************
* 9 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_route_next_entry
*===========================================================================
* Description: Returns the next leaf element in the route table.
* Parameters: rt - The current route entry
* Returns: The next route entry or IP_NULL if the passed entry was the last.
*
*/
IP_GLOBAL Ipcom_route_entry *
ipcom_route_next_entry(Ipcom_route_entry *rt)
{
while (rt->parent->on == rt)
{
rt = rt->parent;
if (rt->parent == IP_NULL)
return IP_NULL;
}
rt = rt->parent->on;
while (rt->off != IP_NULL)
rt = rt->off;
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT))
return IP_NULL;
return rt;
}
/*
*===========================================================================
* ipcom_route_first_entry
*===========================================================================
* Description: Returns the first entry in the route table.
* Parameters: rtab - The route table for which the first entry should be returned.
* Returns: The first route entry or IP_NULL if the route table is empty.
*
*/
IP_GLOBAL Ipcom_route_entry *
ipcom_route_first_entry(Ipcom_route *rtab)
{
Ipcom_route_entry *rt;
rt = rtab->top;
while (rt->off != IP_NULL)
rt = rt->off;
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT))
rt = ipcom_route_next_entry(rt);
return rt;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipcom_route_lookup
*===========================================================================
* Description: Returns the matching entry in the route table.
* Parameters: rtab - The route table to search in.
* key - The key to use when searching. Must be at least
* as long as specified in rtab->bit_size.
* perfect_match - Will be set to IP_TRUE if the match was
* perfect. Can be IP_NULL if this it not interesting.
* Returns: The matching route entry (or IP_NULL if nothing matches).
*
*/
IP_PUBLIC Ipcom_route_entry *
ipcom_route_lookup(Ipcom_route *rtab, const void *key, Ip_bool *prefect_match)
{
Ipcom_route_entry *current;
Ipcom_route_entry *found;
Ipcom_set *start_nodes = IP_NULL;
found = ipcom_patricia_search(rtab->top, key, IP_NULL);
if (ipcom_route_key_cmp(rtab->bit_count, key, found->key, IP_NULL)
== IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH)
{
if (IP_BIT_ISSET(found->flags, IPCOM_ROUTE_FLAG_INIT))
/* This entry is one of the two entries added when the tree was created */
return IP_NULL;
if (prefect_match != IP_NULL)
*prefect_match = IP_TRUE;
return found;
}
/* Start backtracking */
current = found;
while (ipcom_route_key_cmp(rtab->bit_count, key, found->key, found->mask)
== IPCOM_ROUTE_KEY_CMP_NO_MATCH)
{
if (rtab->consecutive_mask == IP_FALSE)
{
if (start_nodes == IP_NULL)
{
start_nodes = ipcom_set_new(sizeof(Ipcom_route_entry*));
if (start_nodes == IP_NULL)
return IP_NULL;
}
if (current->mask != found->mask)
{
found = ipcom_patricia_search(current, key, found->mask);
if (ipcom_route_key_cmp(rtab->bit_count, key, found->key, found->mask)
!= IPCOM_ROUTE_KEY_CMP_NO_MATCH)
break;
}
current = found;
}
do
{
/* Go up to the next node with a netmask. */
current = current->parent;
if (current == IP_NULL)
{
ipcom_set_delete(start_nodes);
return IP_NULL;
}
} while (current->mask == IP_NULL
|| (start_nodes != IP_NULL
&& ipcom_set_contains(start_nodes, current)));
/* Remember all internal nodes that we have used as a sub-root */
if (start_nodes != IP_NULL
&& ipcom_set_add(start_nodes, current) != IPCOM_SUCCESS)
{
ipcom_set_delete(start_nodes);
return IP_NULL;
}
found = ipcom_patricia_search(current, key, current->mask);
}
ipcom_set_delete(start_nodes);
if (IP_BIT_ISSET(found->flags, IPCOM_ROUTE_FLAG_INIT))
/* This entry is one of the two entries added when the tree was created */
return IP_NULL;
if (prefect_match != IP_NULL)
*prefect_match = IP_FALSE;
return found;
}
/*
*===========================================================================
* ipcom_route_new_table
*===========================================================================
* Description: Create a empty routing table with 3 nodes. 1 internal node
* and 2 leafs (all bits zero + all bits one).
* Parameters: addr_bit_size - The bitsize of the addresses in the address
* domain in which this routing table will be used.
* Returns: Head of the route table.
*
*/
IP_PUBLIC Ipcom_route *
ipcom_route_new_table(Ip_u16 bit_count,
Ipcom_route_notify_func notify_func)
{
Ip_u16 entry_size;
Ip_u16 key_octet_count;
Ipcom_route *rtab;
Ipcom_route_entry *top;
Ipcom_route_entry *off;
Ipcom_route_entry *on;
ip_assert(notify_func != IP_NULL);
/* Round the bitsize up to the nearest size that can be divided by 4 */
key_octet_count = (Ip_u16) (((bit_count + 31) & ~31) / 8);
/* Allocate memory for all 3 nodes */
entry_size = (Ip_u16) (sizeof(Ipcom_route_entry) + key_octet_count);
rtab = ipcom_malloc((Ip_size_t)sizeof(Ipcom_route) + (Ip_size_t)sizeof(Ipcom_route_entry) + (Ip_size_t)entry_size * 2);
if (rtab == IP_NULL)
/* Not enough memory */
return IP_NULL;
top = (Ipcom_route_entry *) (rtab + 1);
off = top + 1;
on = (Ipcom_route_entry *) ((Ip_u8 *) off + entry_size);
/* Init the route table */
rtab->bit_count = bit_count;
rtab->octet_count = key_octet_count;
rtab->notify_func = notify_func;
rtab->top = top;
rtab->org_off = off;
rtab->org_on = on;
/* Init the internal node (head of table) */
top->parent = IP_NULL;
top->off = off;
top->on = on;
top->bit = 0;
top->flags = IPCOM_ROUTE_FLAG_INIT | IPCOM_ROUTE_FLAG_INTERNAL;
top->key = IP_NULL;
top->mask = IP_NULL;
/* All zero end mark (default route) */
off->parent = top;
off->on = IP_NULL;
off->off = IP_NULL;
off->bit = 0xffff;
off->flags = IPCOM_ROUTE_FLAG_END | IPCOM_ROUTE_FLAG_INIT;
off->key = (off + 1);
ipcom_memset(off->key, 0, key_octet_count);
off->mask = IP_NULL;
/* All one end mark */
on->parent = top;
on->on = IP_NULL;
on->off = IP_NULL;
on->bit = 0xffff;
on->flags = IPCOM_ROUTE_FLAG_END | IPCOM_ROUTE_FLAG_INIT;
on->key = (on + 1);
ipcom_memset(on->key, -1, key_octet_count);
on->mask = IP_NULL;
rtab->consecutive_mask = IP_TRUE;
return rtab;
}
/*
*===========================================================================
* ipcom_route_free_table
*===========================================================================
* Description: Frees all entries in the route table including the route
* table head pointed to by 'rtab'.
* Parameters: rtab - The route table to free.
* Returns:
*
*/
IP_PUBLIC void
ipcom_route_free_table(Ipcom_route *rtab)
{
ip_assert(rtab != IP_NULL);
ipcom_route_walk_subtree(rtab->top,
IP_FALSE,
IP_FALSE,
(Ipcom_route_walk_subtree_cb) ipcom_route_free_subtree_cb,
rtab);
ipcom_free(rtab);
}
/*
*===========================================================================
* iplite_add_route
*===========================================================================
* Description: Adds a route entry to the specified routing tabel.
* Parameters: rtab - The route tabel in which the element will be inserted.
* elem_to_add - The new node to insert. The following fields must
* have valid values:
* flags must contain any user defined flags.
* key must point to the search key
* mask must point to the mask or be IP_NULL if the mask is all 1:s.
* all other fields are initialized by this function.
* Returns: IPCOM_SUCCESS or ipcom error code.
*
*/
IP_PUBLIC Ip_err
ipcom_route_add(Ipcom_route *rtab, Ipcom_route_entry *elem_to_add)
{
Ip_err err;
ip_assert(elem_to_add->key != IP_NULL);
elem_to_add->off = IP_NULL;
elem_to_add->on = IP_NULL;
elem_to_add->flags &= IPCOM_ROUTE_FLAG_MASK;
ip_assert(rtab->notify_func != IP_NULL);
err = ipcom_patricia_insert(rtab, elem_to_add);
if (err == IPCOM_SUCCESS)
rtab->notify_func(rtab, elem_to_add, IPCOM_ROUTE_CODE_ADD);
return err;
}
/*
*===========================================================================
* ipcom_route_remove
*===========================================================================
* Description: Removes the specified entry from the route tabel.
* NOTE: The entry is only removed, not freed.
* Parameters: top - The top node in the route table.
* elem_to_remove - The element to remove.
* Returns: ipcom error code.
*
*/
IP_PUBLIC Ip_err
ipcom_route_remove(Ipcom_route *rtab, Ipcom_route_entry *elem_to_remove)
{
Ipcom_route_entry *del_internal;
Ipcom_route_entry *internal;
Ipcom_route_entry **pleaf = IP_NULL;
Ip_bool fix_subtree_mask = IP_FALSE;
/* The element to remove must be a leaf */
ip_assert(elem_to_remove->off == IP_NULL);
ip_assert(elem_to_remove->on == IP_NULL);
if (elem_to_remove->mask != IP_NULL)
{
/* There might be internal node that has a reference to this mask */
for (internal = elem_to_remove->parent;
internal != IP_NULL;
internal = internal->parent)
{
if (internal->mask == elem_to_remove->mask)
{
internal->mask = IP_NULL;
fix_subtree_mask = IP_TRUE;
}
}
}
if (IP_BIT_ISSET(elem_to_remove->flags, IPCOM_ROUTE_FLAG_END))
{
/* Put back the orginal end node */
internal = elem_to_remove->parent;
if (elem_to_remove->parent->on == elem_to_remove)
{
elem_to_remove->parent->on = rtab->org_on;
rtab->org_on->parent = internal;
}
else
{
elem_to_remove->parent->off = rtab->org_off;
rtab->org_off->parent = internal;
}
}
else
{
/* Remove the parent (internal node) of the remove entry also */
del_internal = elem_to_remove->parent;
ip_assert(del_internal != IP_NULL);
internal = del_internal->parent;
ip_assert(internal != IP_NULL);
if (internal->off == del_internal)
pleaf = &internal->off;
else
pleaf = &internal->on;
/* Link the other subtree/leaf to the parent of the removed internal node */
if (del_internal->on == elem_to_remove)
*pleaf = del_internal->off;
else
*pleaf = del_internal->on;
(*pleaf)->parent = internal;
ipcom_free(del_internal);
}
if (fix_subtree_mask)
/* The 'internal' variable now points to the nearest parent of deleted entry */
ipcom_route_init_subtree_mask2(internal, rtab->consecutive_mask);
/* pass the node info to notify_func to update all next & narrow's parent pointer */
if(pleaf != IP_NULL)
{
ip_assert(*pleaf);
if((*pleaf)->on == IP_NULL &&
IP_BIT_ISFALSE((*pleaf)->flags, IPCOM_ROUTE_FLAG_INIT))
{
elem_to_remove->parent = *pleaf;
}
else
{
elem_to_remove->parent = IP_NULL;
}
}
else
{
elem_to_remove->parent = IP_NULL;
}
if (IP_BIT_ISFALSE(elem_to_remove->flags, IPCOM_ROUTE_FLAG_INIT))
rtab->notify_func(rtab, elem_to_remove, IPCOM_ROUTE_CODE_REMOVE);
rtab->restart_walk = IP_TRUE;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipcom_route_walk_tree
*===========================================================================
* Description: Calls a callback function for each element in the route tree.
* Parameters: rtab - The route tree to use
* cb - Callback function to that will be called for each route entry.
* data - User data that will be passed each time the callback
* function is called.
* Returns:
*
*/
IP_PUBLIC void
ipcom_route_walk_tree(Ipcom_route *rtab,
Ipcom_route_walk_cb cb,
void *data)
{
Ipcom_route_entry *current;
Ipcom_route_entry *next;
current = ipcom_route_first_entry(rtab);
rtab->restart_walk = IP_FALSE;
while (current != IP_NULL)
{
next = ipcom_route_next_entry(current);
if (cb(current, data))
{
/* The callback told us to remove this entry */
(void) ipcom_route_remove(rtab, current);
rtab->restart_walk = IP_FALSE;
}
if (rtab->restart_walk)
{
rtab->restart_walk = IP_FALSE;
next = ipcom_route_first_entry(rtab);
}
current = next;
}
rtab->restart_walk = IP_TRUE;
}
/*
*===========================================================================
* ipcom_route_walk_tree_backwards
*===========================================================================
* Description: Calls a callback function for each element in the route tree
* in backwards order.
* Parameters: rtab - The route tree to use
* cb - Callback function to that will be called for each route entry.
* data - User data that will be passed each time the callback
* function is called.
* Returns:
*
*/
IP_PUBLIC void
ipcom_route_walk_tree_backwards(Ipcom_route *rtab,
Ipcom_route_walk_cb cb,
void *data)
{
Ipcom_route_entry *current;
Ipcom_route_entry *prev;
current = ipcom_route_last_entry(rtab);
rtab->restart_walk = IP_FALSE;
while (current != IP_NULL)
{
prev = ipcom_route_prev_entry(current);
if (cb(current, data))
{
/* The callback told us to remove this entry */
(void) ipcom_route_remove(rtab, current);
rtab->restart_walk = IP_FALSE;
}
if (rtab->restart_walk)
{
rtab->restart_walk = IP_FALSE;
prev = ipcom_route_last_entry(rtab);
}
current = prev;
}
rtab->restart_walk = IP_TRUE;
}
/*
*===========================================================================
* ipcom_route_key_cmp
*===========================================================================
* Description: Compares 2 keys with or without a mask and returns
* the result.
* Parameters: key_bit_size - The size of the keys in bits.
* key1 - A key.
* key2 - Another key.
* mask - The mask to use when comparing the keys, a 0 bit means
* that this bit is alwasy a match. A value of IP_NULL is
* interpreted as a mask of all 1.
* Returns: IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH,
* IPCOM_ROUTE_KEY_CMP_MASK_MATCH,
* IPCOM_ROUTE_KEY_CMP_NO_MATCH
*/
/*lint -efunc(413,ipcom_route_key_cmp) Likely use of null pointer */
IP_PUBLIC int
ipcom_route_key_cmp(Ip_u32 key_bit_size, const void *key1, const void *key2, const void *mask)
{
int i = 0;
/* Check if the key bit size is dividable with 16 */
if ((key_bit_size & 0xf) == 0)
{
int key_byte_size;
int key_short_size = (int)(key_bit_size >> 4);
/* Check for perfect match first */
for (; i < key_short_size; i++)
{
if (((Ip_u16 *) key1)[i] != ((Ip_u16 *) key2)[i])
break;
}
if (i == key_short_size)
return IPCOM_ROUTE_KEY_CMP_PREFECT_MATCH;
/* No perfect match, check for mask match */
key_byte_size = key_short_size << 1;
for (i <<= 1; i < key_byte_size; i++)
{
if (mask && ((Ip_u8 *) mask)[i] != 0xff)
break;
if (((Ip_u8 *) key1)[i] != ((Ip_u8 *) key2)[i])
return IPCOM_ROUTE_KEY_CMP_NO_MATCH;
}
ip_assert(mask != IP_NULL);
while (i < key_byte_size && ((Ip_u8 *) mask)[i] == 0)
i++;
}
for (i <<= 3; i < (int)key_bit_size; i++)
if (mask == IP_NULL || IPCOM_IS_BIT_SET(mask, i))
if (IPCOM_IS_BIT_SET(key1, i) != IPCOM_IS_BIT_SET(key2, i))
return IPCOM_ROUTE_KEY_CMP_NO_MATCH;
return IPCOM_ROUTE_KEY_CMP_MASK_MATCH;
}
/*
*===========================================================================
* ipcom_route_init_subtree_mask
*===========================================================================
* Description: Initialize the internal node mask references on a subtree.
* Parameters: rt - The head of the subtree.
* Returns:
*
*/
IP_PUBLIC void
ipcom_route_init_subtree_mask(Ipcom_route_entry *rt)
{
ipcom_route_init_subtree_mask2(rt, IP_FALSE);
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/