Home | History | Annotate | Line # | Download | only in netinet
      1 /*	$NetBSD: ipf_rb.h,v 1.5 2013/01/09 13:23:20 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2012 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  *
      8  */
      9 
     10 /*
     11  * If the OS has a red-black tree implementation, use it.
     12  */
     13 #ifdef HAVE_RBTREE
     14 
     15 #include <sys/rbtree.h>
     16 
     17 # define	RBI_LINK(_n, _t)
     18 # define	RBI_FIELD(_n)			rb_node_t
     19 # define	RBI_HEAD(_n, _t)		rb_tree_t
     20 
     21 /* Define adapter code between the ipf-specific and the system rb impls. */
     22 # define	RBI_CODE(_n, _t, _f, _cmp)				\
     23 signed int _n##_compare_nodes(void *ctx, const void *n1, const void *n2);\
     24 signed int _n##_compare_key(void *ctx, const void *n1, const void *key);\
     25 typedef	void	(*_n##_rb_walker_t)(_t *, void *);			\
     26 void	_n##_rb_walktree(rb_tree_t *, _n##_rb_walker_t, void *);	\
     27 									\
     28 static const rb_tree_ops_t _n##_tree_ops = {				\
     29         .rbto_compare_nodes = _n##_compare_nodes,			\
     30         .rbto_compare_key = _n##_compare_key,				\
     31         .rbto_node_offset = offsetof(_t, _f),				\
     32         .rbto_context = NULL						\
     33 };									\
     34 									\
     35 int									\
     36 _n##_compare_nodes(void *ctx, const void *n1, const void *n2) {		\
     37 	return _cmp(n1, n2);						\
     38 }									\
     39 									\
     40 int									\
     41 _n##_compare_key(void *ctx, const void *n1, const void *key) {		\
     42 	return _cmp(n1, key);						\
     43 }									\
     44 									\
     45 void									\
     46 _n##_rb_walktree(rb_tree_t *head, _n##_rb_walker_t func, void *arg)	\
     47 {									\
     48 	_t *rb;								\
     49 	/* Take advantage of the fact that the ipf code only uses this  \
     50 	   method to clear the tree, in order to do it more safely. */	\
     51 	while ((rb = rb_tree_iterate(head, NULL, RB_DIR_RIGHT)) != NULL) {\
     52 		rb_tree_remove_node(head, rb);				\
     53 		func(rb, arg);						\
     54 	}								\
     55 }
     56 
     57 # define	RBI_DELETE(_n, _h, _v)		rb_tree_remove_node(_h, _v)
     58 # define	RBI_INIT(_n, _h)		rb_tree_init(_h, &_n##_tree_ops)
     59 # define	RBI_INSERT(_n, _h, _v)		rb_tree_insert_node(_h, _v)
     60 # define	RBI_ISEMPTY(_h)			(rb_tree_iterate(_h, NULL, RB_DIR_RIGHT) == NULL)
     61 # define	RBI_SEARCH(_n, _h, _k)		rb_tree_find_node(_h, _k)
     62 # define	RBI_WALK(_n, _h, _w, _a)	_n##_rb_walktree(_h, _w, _a)
     63 
     64 #else
     65 
     66 typedef enum rbcolour_e {
     67 	C_BLACK = 0,
     68 	C_RED = 1
     69 } rbcolour_t;
     70 
     71 #define	RBI_LINK(_n, _t)						\
     72 	struct _n##_rb_link {						\
     73 		struct _t	*left;					\
     74 		struct _t	*right;					\
     75 		struct _t	*parent;				\
     76 		rbcolour_t	colour;					\
     77 	}
     78 
     79 #define	RBI_HEAD(_n, _t)						\
     80 struct _n##_rb_head {							\
     81 	struct _t	top;						\
     82 	int		count;						\
     83 	int		(* compare)(struct _t *, struct _t *);		\
     84 }
     85 
     86 #define	RBI_FIELD(_n)			struct _n##_rb_link
     87 
     88 #define	RBI_CODE(_n, _t, _f, _cmp)					\
     89 									\
     90 _t RBI_ZERO(_n);							\
     91 									\
     92 typedef	void	(*_n##_rb_walker_t)(_t *, void *);			\
     93 									\
     94 _t *	_n##_rb_delete(struct _n##_rb_head *, _t *);			\
     95 void	_n##_rb_init(struct _n##_rb_head *);				\
     96 void	_n##_rb_insert(struct _n##_rb_head *, _t *);			\
     97 _t *	_n##_rb_search(struct _n##_rb_head *, void *);			\
     98 void	_n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
     99 									\
    100 static void								\
    101 rotate_left(struct _n##_rb_head *head, _t *node)			\
    102 {									\
    103 	_t *parent, *tmp1, *tmp2;					\
    104 									\
    105 	parent = node->_f.parent;					\
    106 	tmp1 = node->_f.right;						\
    107 	tmp2 = tmp1->_f.left;						\
    108 	node->_f.right = tmp2;						\
    109 	if (tmp2 != & _n##_rb_zero)					\
    110 		tmp2->_f.parent = node;					\
    111 	if (parent == & _n##_rb_zero)					\
    112 		head->top._f.right = tmp1;				\
    113 	else if (parent->_f.right == node)				\
    114 		parent->_f.right = tmp1;				\
    115 	else								\
    116 		parent->_f.left = tmp1;					\
    117 	tmp1->_f.left = node;						\
    118 	tmp1->_f.parent = parent;					\
    119 	node->_f.parent = tmp1;						\
    120 }									\
    121 									\
    122 static void								\
    123 rotate_right(struct _n##_rb_head *head, _t *node)			\
    124 {									\
    125 	_t *parent, *tmp1, *tmp2;					\
    126 									\
    127 	parent = node->_f.parent;					\
    128 	tmp1 = node->_f.left;						\
    129 	tmp2 = tmp1->_f.right;						\
    130 	node->_f.left = tmp2;						\
    131 	if (tmp2 != &_n##_rb_zero)					\
    132 		tmp2->_f.parent = node;					\
    133 	if (parent == &_n##_rb_zero)					\
    134 		head->top._f.right = tmp1;				\
    135 	else if (parent->_f.right == node)				\
    136 		parent->_f.right = tmp1;				\
    137 	else								\
    138 		parent->_f.left = tmp1;					\
    139 	tmp1->_f.right = node;						\
    140 	tmp1->_f.parent = parent;					\
    141 	node->_f.parent = tmp1;						\
    142 }									\
    143 									\
    144 void									\
    145 _n##_rb_insert(struct _n##_rb_head *head, _t *node)			\
    146 {									\
    147 	_t *n, *parent, **p, *tmp1, *gparent;				\
    148 									\
    149 	parent = &head->top;						\
    150 	node->_f.left = &_n##_rb_zero;					\
    151 	node->_f.right = &_n##_rb_zero;					\
    152 	p = &head->top._f.right;					\
    153 	while ((n = *p) != &_n##_rb_zero) {				\
    154 		if (_cmp(node, n) < 0)					\
    155 			p = &n->_f.left;				\
    156 		else							\
    157 			p = &n->_f.right;				\
    158 		parent = n;						\
    159 	}								\
    160 	*p = node;							\
    161 	node->_f.colour = C_RED;					\
    162 	node->_f.parent = parent;					\
    163 									\
    164 	while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
    165 		gparent = parent->_f.parent;				\
    166 		if (parent == gparent->_f.left) {			\
    167 			tmp1 = gparent->_f.right;			\
    168 			if (tmp1->_f.colour == C_RED) {			\
    169 				parent->_f.colour = C_BLACK;		\
    170 				tmp1->_f.colour = C_BLACK;		\
    171 				gparent->_f.colour = C_RED;		\
    172 				node = gparent;				\
    173 			} else {					\
    174 				if (node == parent->_f.right) {		\
    175 					node = parent;			\
    176 					rotate_left(head, node);	\
    177 					parent = node->_f.parent;	\
    178 				}					\
    179 				parent->_f.colour = C_BLACK;		\
    180 				gparent->_f.colour = C_RED;		\
    181 				rotate_right(head, gparent);		\
    182 			}						\
    183 		} else {						\
    184 			tmp1 = gparent->_f.left;			\
    185 			if (tmp1->_f.colour == C_RED) {			\
    186 				parent->_f.colour = C_BLACK;		\
    187 				tmp1->_f.colour = C_BLACK;		\
    188 				gparent->_f.colour = C_RED;		\
    189 				node = gparent;				\
    190 			} else {					\
    191 				if (node == parent->_f.left) {		\
    192 					node = parent;			\
    193 					rotate_right(head, node);	\
    194 					parent = node->_f.parent;	\
    195 				}					\
    196 				parent->_f.colour = C_BLACK;		\
    197 				gparent->_f.colour = C_RED;		\
    198 				rotate_left(head, parent->_f.parent);	\
    199 			}						\
    200 		}							\
    201 		parent = node->_f.parent;				\
    202 	}								\
    203 	head->top._f.right->_f.colour = C_BLACK;			\
    204 	head->count++;						\
    205 }									\
    206 									\
    207 static void								\
    208 deleteblack(struct _n##_rb_head *head, _t *parent, _t *node)		\
    209 {									\
    210 	_t *tmp;							\
    211 									\
    212 	while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) &&	\
    213 	       node != &head->top) {					\
    214 		if (parent->_f.left == node) {				\
    215 			tmp = parent->_f.right;				\
    216 			if (tmp->_f.colour == C_RED) {			\
    217 				tmp->_f.colour = C_BLACK;		\
    218 				parent->_f.colour = C_RED;		\
    219 				rotate_left(head, parent);		\
    220 				tmp = parent->_f.right;			\
    221 			}						\
    222 			if ((tmp->_f.left == &_n##_rb_zero ||		\
    223 			     tmp->_f.left->_f.colour == C_BLACK) &&	\
    224 			    (tmp->_f.right == &_n##_rb_zero ||		\
    225 			     tmp->_f.right->_f.colour == C_BLACK)) {	\
    226 				tmp->_f.colour = C_RED;			\
    227 				node = parent;				\
    228 				parent = node->_f.parent;		\
    229 			} else {					\
    230 				if (tmp->_f.right == &_n##_rb_zero ||	\
    231 				    tmp->_f.right->_f.colour == C_BLACK) {\
    232 					_t *tmp2 = tmp->_f.left;	\
    233 									\
    234 					if (tmp2 != &_n##_rb_zero)	\
    235 						tmp2->_f.colour = C_BLACK;\
    236 					tmp->_f.colour = C_RED;		\
    237 					rotate_right(head, tmp);	\
    238 					tmp = parent->_f.right;		\
    239 				}					\
    240 				tmp->_f.colour = parent->_f.colour;	\
    241 				parent->_f.colour = C_BLACK;		\
    242 				if (tmp->_f.right != &_n##_rb_zero)	\
    243 					tmp->_f.right->_f.colour = C_BLACK;\
    244 				rotate_left(head, parent);		\
    245 				node = head->top._f.right;		\
    246 			}						\
    247 		} else {						\
    248 			tmp = parent->_f.left;				\
    249 			if (tmp->_f.colour == C_RED) {			\
    250 				tmp->_f.colour = C_BLACK;		\
    251 				parent->_f.colour = C_RED;		\
    252 				rotate_right(head, parent);		\
    253 				tmp = parent->_f.left;			\
    254 			}						\
    255 			if ((tmp->_f.left == &_n##_rb_zero ||		\
    256 			     tmp->_f.left->_f.colour == C_BLACK) &&	\
    257 			    (tmp->_f.right == &_n##_rb_zero ||		\
    258 			     tmp->_f.right->_f.colour == C_BLACK)) {	\
    259 				tmp->_f.colour = C_RED;			\
    260 				node = parent;				\
    261 				parent = node->_f.parent;		\
    262 			} else {					\
    263 				if (tmp->_f.left == &_n##_rb_zero ||	\
    264 				    tmp->_f.left->_f.colour == C_BLACK) {\
    265 					_t *tmp2 = tmp->_f.right;	\
    266 									\
    267 					if (tmp2 != &_n##_rb_zero)	\
    268 						tmp2->_f.colour = C_BLACK;\
    269 					tmp->_f.colour = C_RED;		\
    270 					rotate_left(head, tmp);		\
    271 					tmp = parent->_f.left;		\
    272 				}					\
    273 				tmp->_f.colour = parent->_f.colour;	\
    274 				parent->_f.colour = C_BLACK;		\
    275 				if (tmp->_f.left != &_n##_rb_zero)	\
    276 					tmp->_f.left->_f.colour = C_BLACK;\
    277 				rotate_right(head, parent);		\
    278 				node = head->top._f.right;		\
    279 				break;					\
    280 			}						\
    281 		}							\
    282 	}								\
    283 	if (node != &_n##_rb_zero)					\
    284 		node->_f.colour = C_BLACK;				\
    285 }									\
    286 									\
    287 _t *									\
    288 _n##_rb_delete(struct _n##_rb_head *head, _t *node)			\
    289 {									\
    290 	_t *child, *parent, *old = node, *left;				\
    291 	rbcolour_t color;						\
    292 									\
    293 	if (node->_f.left == &_n##_rb_zero) {				\
    294 		child = node->_f.right;					\
    295 	} else if (node->_f.right == &_n##_rb_zero) {			\
    296 		child = node->_f.left;					\
    297 	} else {							\
    298 		node = node->_f.right;					\
    299 		while ((left = node->_f.left) != &_n##_rb_zero)		\
    300 			node = left;					\
    301 		child = node->_f.right;					\
    302 		parent = node->_f.parent;				\
    303 		color = node->_f.colour;				\
    304 		if (child != &_n##_rb_zero)				\
    305 			child->_f.parent = parent;			\
    306 		if (parent != &_n##_rb_zero) {				\
    307 			if (parent->_f.left == node)			\
    308 				parent->_f.left = child;		\
    309 			else						\
    310 				parent->_f.right = child;		\
    311 		} else {						\
    312 			head->top._f.right = child;			\
    313 		}							\
    314 		if (node->_f.parent == old)				\
    315 			parent = node;					\
    316 		*node = *old;						\
    317 		if (old->_f.parent != &_n##_rb_zero) {			\
    318 			if (old->_f.parent->_f.left == old)		\
    319 				old->_f.parent->_f.left = node;		\
    320 			else						\
    321 				old->_f.parent->_f.right = node;	\
    322 		} else {						\
    323 			head->top._f.right = child;			\
    324 		}							\
    325 		old->_f.left->_f.parent = node;				\
    326 		if (old->_f.right != &_n##_rb_zero)			\
    327 			old->_f.right->_f.parent = node;		\
    328 		if (parent != &_n##_rb_zero) {				\
    329 			left = parent;					\
    330 		}							\
    331 		goto colour;						\
    332 	}								\
    333 	parent = node->_f.parent;					\
    334 	color= node->_f.colour;						\
    335 	if (child != &_n##_rb_zero)					\
    336 		child->_f.parent = parent;				\
    337 	if (parent != &_n##_rb_zero) {					\
    338 		if (parent->_f.left == node)				\
    339 			parent->_f.left = child;			\
    340 		else							\
    341 			parent->_f.right = child;			\
    342 	} else {							\
    343 		head->top._f.right = child;				\
    344 	}								\
    345 colour:									\
    346 	if (color == C_BLACK)						\
    347 		deleteblack(head, parent, node);			\
    348 	head->count--;							\
    349 	return old;							\
    350 }									\
    351 									\
    352 void									\
    353 _n##_rb_init(struct _n##_rb_head *head)					\
    354 {									\
    355 	memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero));			\
    356 	head->top._f.left = &_n##_rb_zero;				\
    357 	head->top._f.right = &_n##_rb_zero;				\
    358 	head->top._f.parent = &head->top;				\
    359 	_n##_rb_zero._f.left = &_n##_rb_zero;				\
    360 	_n##_rb_zero._f.right = &_n##_rb_zero;				\
    361 	_n##_rb_zero._f.parent = &_n##_rb_zero;				\
    362 }									\
    363 									\
    364 void									\
    365 _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
    366 {									\
    367 	_t *prev;							\
    368 	_t *next;							\
    369 	_t *node = head->top._f.right;					\
    370 	_t *base;							\
    371 									\
    372 	while (node != &_n##_rb_zero)					\
    373 		node = node->_f.left;					\
    374 									\
    375 	for (;;) {							\
    376 		base = node;						\
    377 		prev = node;						\
    378 		while ((node->_f.parent->_f.right == node) &&		\
    379 		       (node != &_n##_rb_zero))	{			\
    380 			prev = node;					\
    381 			node = node->_f.parent;				\
    382 		}							\
    383 									\
    384 		node = prev;						\
    385 		for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
    386 		     node = node->_f.left)				\
    387 			prev = node;					\
    388 		next = prev;						\
    389 									\
    390 		if (node != &_n##_rb_zero)				\
    391 			func(node, arg);				\
    392 									\
    393 		node = next;						\
    394 		if (node == &_n##_rb_zero)				\
    395 			break;						\
    396 	}								\
    397 }									\
    398 									\
    399 _t *									\
    400 _n##_rb_search(struct _n##_rb_head *head, void *key)			\
    401 {									\
    402 	int	match = 0;						\
    403 	_t	*node;							\
    404 	node = head->top._f.right;					\
    405 	while (node != &_n##_rb_zero) {					\
    406 		match = _cmp(key, node);				\
    407 		if (match == 0)						\
    408 			break;						\
    409 		if (match< 0)						\
    410 			node = node->_f.left;				\
    411 		else							\
    412 			node = node->_f.right;				\
    413 	}								\
    414 	if (node == &_n##_rb_zero || match != 0)			\
    415 		return (NULL);						\
    416 	return (node);							\
    417 }
    418 
    419 #define	RBI_DELETE(_n, _h, _v)		_n##_rb_delete(_h, _v)
    420 #define	RBI_INIT(_n, _h)		_n##_rb_init(_h)
    421 #define	RBI_INSERT(_n, _h, _v)		_n##_rb_insert(_h, _v)
    422 #define	RBI_ISEMPTY(_h)			((_h)->count == 0)
    423 #define	RBI_SEARCH(_n, _h, _k)		_n##_rb_search(_h, _k)
    424 #define	RBI_WALK(_n, _h, _w, _a)	_n##_rb_walktree(_h, _w, _a)
    425 #define	RBI_ZERO(_n)			_n##_rb_zero
    426 
    427 #endif
    428