/* $OpenBSD: art.h,v 1.28 2025/07/10 05:28:13 dlg Exp $ */ /* * Copyright (c) 2015 Martin Pieuchot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET_ART_H_ #define _NET_ART_H_ /* * Allotment Routing Table (ART) * * Yoichi Hariguchi paper can be found at: * http://www.hariguchi.org/art/art.pdf * * Locking: * * Modification (ie, art_insert or art_delete) and iteration * (art_iter_next, etc) over the ART must be serialised by the caller. * Lookups (ie, art_match and art_lookup) run within an SMR critical * section. * * Iteration requires serialisation as it manipulates the reference * counts on tables as it traverses the tree. The iterator maintains * these references until it runs out of entries. This allows code * iterating over the ART to release locks in between calls to * art_iter_open and art_iter_next. The references may be dropped * early with art_iter_close. * * Note, the iterator does not hold a reference to the art_node * structure or the data hanging off the an_value pointer, they must * be accounted for separately or their use must be serialised with * art_delete. */ typedef uintptr_t art_heap_entry; /* * Root of the ART, equivalent to the radix head. */ struct art { art_heap_entry *art_root; const unsigned int *art_levels; unsigned int art_nlevels; unsigned int art_alen; }; /* * Allotment Table. */ struct art_table { art_heap_entry *at_heap; struct art_table *at_parent; /* Parent table */ unsigned int at_index; /* Index in the parent table */ unsigned int at_minfringe; /* Index that fringe begins */ unsigned int at_level; /* Level of the table */ unsigned int at_bits; /* Stride length of the table */ unsigned int at_offset; /* Sum of parents' stride len */ unsigned int at_refcnt; }; #define ART_HEAP_IDX_TABLE 0 #define ART_HEAP_IDX_DEFAULT 1 #define AT_HEAPSIZE(bits) ((1 << ((bits) + 1)) * sizeof(art_heap_entry)) /* * A node is the internal representation of a route entry. */ struct art_node { void *an_value; union { struct art_node *an__gc; uint8_t an__addr[16]; } an__u; #define an_gc an__u.an__gc #define an_addr an__u.an__addr unsigned int an_plen; }; static inline struct art_table * art_heap_to_table(art_heap_entry *heap) { return ((struct art_table *)heap[ART_HEAP_IDX_TABLE]); } static inline int art_heap_entry_is_node(art_heap_entry ahe) { return ((ahe & 1UL) == 0); } static inline struct art_node * art_heap_entry_to_node(art_heap_entry ahe) { return ((struct art_node *)ahe); } static inline art_heap_entry * art_heap_entry_to_heap(art_heap_entry ahe) { return ((art_heap_entry *)(ahe & ~1UL)); } static inline art_heap_entry art_node_to_heap_entry(struct art_node *an) { return ((art_heap_entry)an); } static inline art_heap_entry art_heap_to_heap_entry(art_heap_entry *heap) { return ((art_heap_entry)heap | 1UL); } #ifdef _KERNEL void art_boot(void); struct art *art_alloc(unsigned int); void art_init(struct art *, unsigned int); struct art_node *art_insert(struct art *, struct art_node *); struct art_node *art_delete(struct art *, const void *, unsigned int); struct art_node *art_match(struct art *, const void *); struct art_node *art_lookup(struct art *, const void *, unsigned int); int art_is_empty(struct art *); struct art_node *art_get(const uint8_t *, unsigned int); void art_node_init(struct art_node *, const uint8_t *, unsigned int); void art_put(struct art_node *); struct art_iter { struct art *ai_art; struct art_table *ai_table; unsigned int ai_j; unsigned int ai_i; }; struct art_node *art_iter_open(struct art *, struct art_iter *); struct art_node *art_iter_next(struct art_iter *); void art_iter_close(struct art_iter *); #define ART_FOREACH(_an, _art, _ai) \ for ((_an) = art_iter_open((_art), (_ai)); \ (_an) != NULL; \ (_an) = art_iter_next((_ai))) int art_walk(struct art *, int (*)(struct art_node *, void *), void *); #endif /* _KERNEL */ #endif /* _NET_ART_H_ */