Bug Summary

File:src/usr.sbin/bgpd/rde_rib.c
Warning:line 258, column 29
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name rde_rib.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/bgpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/bgpd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/bgpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/bgpd/rde_rib.c
1/* $OpenBSD: rde_rib.c,v 1.261 2023/10/16 10:25:46 claudio Exp $ */
2
3/*
4 * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/queue.h>
21
22#include <limits.h>
23#include <stdlib.h>
24#include <string.h>
25#include <time.h>
26
27#include "bgpd.h"
28#include "rde.h"
29#include "log.h"
30
31/*
32 * BGP RIB -- Routing Information Base
33 *
34 * The RIB is build with one aspect in mind. Speed -- actually update speed.
35 * Therefore one thing needs to be absolutely avoided, long table walks.
36 * This is achieved by heavily linking the different parts together.
37 */
38uint16_t rib_size;
39struct rib **ribs;
40struct rib flowrib = { .id = 1, .tree = RB_INITIALIZER(&flowrib.tree){ ((void *)0) } };
41
42struct rib_entry *rib_add(struct rib *, struct pt_entry *);
43static inline int rib_compare(const struct rib_entry *,
44 const struct rib_entry *);
45void rib_remove(struct rib_entry *);
46int rib_empty(struct rib_entry *);
47static void rib_dump_abort(uint16_t);
48
49RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare)void rib_tree_RB_INSERT_COLOR(struct rib_tree *, struct rib_entry
*); void rib_tree_RB_REMOVE_COLOR(struct rib_tree *, struct rib_entry
*, struct rib_entry *); struct rib_entry *rib_tree_RB_REMOVE
(struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_INSERT
(struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_FIND
(struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_NFIND
(struct rib_tree *, struct rib_entry *); struct rib_entry *rib_tree_RB_NEXT
(struct rib_entry *); struct rib_entry *rib_tree_RB_PREV(struct
rib_entry *); struct rib_entry *rib_tree_RB_MINMAX(struct rib_tree
*, int);
;
50RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare)void rib_tree_RB_INSERT_COLOR(struct rib_tree *head, struct rib_entry
*elm) { struct rib_entry *parent, *gparent, *tmp; while ((parent
= (elm)->rib_e.rbe_parent) && (parent)->rib_e.
rbe_color == 1) { gparent = (parent)->rib_e.rbe_parent; if
(parent == (gparent)->rib_e.rbe_left) { tmp = (gparent)->
rib_e.rbe_right; if (tmp && (tmp)->rib_e.rbe_color
== 1) { (tmp)->rib_e.rbe_color = 0; do { (parent)->rib_e
.rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0
); elm = gparent; continue; } if ((parent)->rib_e.rbe_right
== elm) { do { (tmp) = (parent)->rib_e.rbe_right; if (((parent
)->rib_e.rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)->
rib_e.rbe_left)->rib_e.rbe_parent = (parent); } do {} while
(0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent
)) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e
.rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left
= (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e
.rbe_left = (parent); (parent)->rib_e.rbe_parent = (tmp); do
{} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while (
0); } while (0); tmp = parent; parent = elm; elm = tmp; } do {
(parent)->rib_e.rbe_color = 0; (gparent)->rib_e.rbe_color
= 1; } while (0); do { (tmp) = (gparent)->rib_e.rbe_left;
if (((gparent)->rib_e.rbe_left = (tmp)->rib_e.rbe_right
)) { ((tmp)->rib_e.rbe_right)->rib_e.rbe_parent = (gparent
); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (gparent
)->rib_e.rbe_parent)) { if ((gparent) == ((gparent)->rib_e
.rbe_parent)->rib_e.rbe_left) ((gparent)->rib_e.rbe_parent
)->rib_e.rbe_left = (tmp); else ((gparent)->rib_e.rbe_parent
)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->rib_e.rbe_right = (gparent); (gparent)->rib_e
.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent
)) do {} while (0); } while (0); } else { tmp = (gparent)->
rib_e.rbe_left; if (tmp && (tmp)->rib_e.rbe_color ==
1) { (tmp)->rib_e.rbe_color = 0; do { (parent)->rib_e.
rbe_color = 0; (gparent)->rib_e.rbe_color = 1; } while (0)
; elm = gparent; continue; } if ((parent)->rib_e.rbe_left ==
elm) { do { (tmp) = (parent)->rib_e.rbe_left; if (((parent
)->rib_e.rbe_left = (tmp)->rib_e.rbe_right)) { ((tmp)->
rib_e.rbe_right)->rib_e.rbe_parent = (parent); } do {} while
(0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent
)) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e
.rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left
= (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e
.rbe_right = (parent); (parent)->rib_e.rbe_parent = (tmp);
do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while
(0); } while (0); tmp = parent; parent = elm; elm = tmp; } do
{ (parent)->rib_e.rbe_color = 0; (gparent)->rib_e.rbe_color
= 1; } while (0); do { (tmp) = (gparent)->rib_e.rbe_right
; if (((gparent)->rib_e.rbe_right = (tmp)->rib_e.rbe_left
)) { ((tmp)->rib_e.rbe_left)->rib_e.rbe_parent = (gparent
); } do {} while (0); if (((tmp)->rib_e.rbe_parent = (gparent
)->rib_e.rbe_parent)) { if ((gparent) == ((gparent)->rib_e
.rbe_parent)->rib_e.rbe_left) ((gparent)->rib_e.rbe_parent
)->rib_e.rbe_left = (tmp); else ((gparent)->rib_e.rbe_parent
)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->rib_e.rbe_left = (gparent); (gparent)->rib_e
.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent
)) do {} while (0); } while (0); } } (head->rbh_root)->
rib_e.rbe_color = 0; } void rib_tree_RB_REMOVE_COLOR(struct rib_tree
*head, struct rib_entry *parent, struct rib_entry *elm) { struct
rib_entry *tmp; while ((elm == ((void *)0) || (elm)->rib_e
.rbe_color == 0) && elm != (head)->rbh_root) { if (
(parent)->rib_e.rbe_left == elm) { tmp = (parent)->rib_e
.rbe_right; if ((tmp)->rib_e.rbe_color == 1) { do { (tmp)->
rib_e.rbe_color = 0; (parent)->rib_e.rbe_color = 1; } while
(0); do { (tmp) = (parent)->rib_e.rbe_right; if (((parent
)->rib_e.rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)->
rib_e.rbe_left)->rib_e.rbe_parent = (parent); } do {} while
(0); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent
)) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e
.rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left
= (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e
.rbe_left = (parent); (parent)->rib_e.rbe_parent = (tmp); do
{} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while (
0); } while (0); tmp = (parent)->rib_e.rbe_right; } if (((
tmp)->rib_e.rbe_left == ((void *)0) || ((tmp)->rib_e.rbe_left
)->rib_e.rbe_color == 0) && ((tmp)->rib_e.rbe_right
== ((void *)0) || ((tmp)->rib_e.rbe_right)->rib_e.rbe_color
== 0)) { (tmp)->rib_e.rbe_color = 1; elm = parent; parent
= (elm)->rib_e.rbe_parent; } else { if ((tmp)->rib_e.rbe_right
== ((void *)0) || ((tmp)->rib_e.rbe_right)->rib_e.rbe_color
== 0) { struct rib_entry *oleft; if ((oleft = (tmp)->rib_e
.rbe_left)) (oleft)->rib_e.rbe_color = 0; (tmp)->rib_e.
rbe_color = 1; do { (oleft) = (tmp)->rib_e.rbe_left; if ((
(tmp)->rib_e.rbe_left = (oleft)->rib_e.rbe_right)) { ((
oleft)->rib_e.rbe_right)->rib_e.rbe_parent = (tmp); } do
{} while (0); if (((oleft)->rib_e.rbe_parent = (tmp)->
rib_e.rbe_parent)) { if ((tmp) == ((tmp)->rib_e.rbe_parent
)->rib_e.rbe_left) ((tmp)->rib_e.rbe_parent)->rib_e.
rbe_left = (oleft); else ((tmp)->rib_e.rbe_parent)->rib_e
.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (
oleft)->rib_e.rbe_right = (tmp); (tmp)->rib_e.rbe_parent
= (oleft); do {} while (0); if (((oleft)->rib_e.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->rib_e.rbe_right
; } (tmp)->rib_e.rbe_color = (parent)->rib_e.rbe_color;
(parent)->rib_e.rbe_color = 0; if ((tmp)->rib_e.rbe_right
) ((tmp)->rib_e.rbe_right)->rib_e.rbe_color = 0; do { (
tmp) = (parent)->rib_e.rbe_right; if (((parent)->rib_e.
rbe_right = (tmp)->rib_e.rbe_left)) { ((tmp)->rib_e.rbe_left
)->rib_e.rbe_parent = (parent); } do {} while (0); if (((tmp
)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent)) { if
((parent) == ((parent)->rib_e.rbe_parent)->rib_e.rbe_left
) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left = (tmp);
else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right = (
tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e.rbe_left
= (parent); (parent)->rib_e.rbe_parent = (tmp); do {} while
(0); if (((tmp)->rib_e.rbe_parent)) do {} while (0); } while
(0); elm = (head)->rbh_root; break; } } else { tmp = (parent
)->rib_e.rbe_left; if ((tmp)->rib_e.rbe_color == 1) { do
{ (tmp)->rib_e.rbe_color = 0; (parent)->rib_e.rbe_color
= 1; } while (0); do { (tmp) = (parent)->rib_e.rbe_left; if
(((parent)->rib_e.rbe_left = (tmp)->rib_e.rbe_right)) {
((tmp)->rib_e.rbe_right)->rib_e.rbe_parent = (parent);
} do {} while (0); if (((tmp)->rib_e.rbe_parent = (parent
)->rib_e.rbe_parent)) { if ((parent) == ((parent)->rib_e
.rbe_parent)->rib_e.rbe_left) ((parent)->rib_e.rbe_parent
)->rib_e.rbe_left = (tmp); else ((parent)->rib_e.rbe_parent
)->rib_e.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->rib_e.rbe_right = (parent); (parent)->rib_e
.rbe_parent = (tmp); do {} while (0); if (((tmp)->rib_e.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->rib_e.rbe_left
; } if (((tmp)->rib_e.rbe_left == ((void *)0) || ((tmp)->
rib_e.rbe_left)->rib_e.rbe_color == 0) && ((tmp)->
rib_e.rbe_right == ((void *)0) || ((tmp)->rib_e.rbe_right)
->rib_e.rbe_color == 0)) { (tmp)->rib_e.rbe_color = 1; elm
= parent; parent = (elm)->rib_e.rbe_parent; } else { if (
(tmp)->rib_e.rbe_left == ((void *)0) || ((tmp)->rib_e.rbe_left
)->rib_e.rbe_color == 0) { struct rib_entry *oright; if ((
oright = (tmp)->rib_e.rbe_right)) (oright)->rib_e.rbe_color
= 0; (tmp)->rib_e.rbe_color = 1; do { (oright) = (tmp)->
rib_e.rbe_right; if (((tmp)->rib_e.rbe_right = (oright)->
rib_e.rbe_left)) { ((oright)->rib_e.rbe_left)->rib_e.rbe_parent
= (tmp); } do {} while (0); if (((oright)->rib_e.rbe_parent
= (tmp)->rib_e.rbe_parent)) { if ((tmp) == ((tmp)->rib_e
.rbe_parent)->rib_e.rbe_left) ((tmp)->rib_e.rbe_parent)
->rib_e.rbe_left = (oright); else ((tmp)->rib_e.rbe_parent
)->rib_e.rbe_right = (oright); } else (head)->rbh_root =
(oright); (oright)->rib_e.rbe_left = (tmp); (tmp)->rib_e
.rbe_parent = (oright); do {} while (0); if (((oright)->rib_e
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
rib_e.rbe_left; } (tmp)->rib_e.rbe_color = (parent)->rib_e
.rbe_color; (parent)->rib_e.rbe_color = 0; if ((tmp)->rib_e
.rbe_left) ((tmp)->rib_e.rbe_left)->rib_e.rbe_color = 0
; do { (tmp) = (parent)->rib_e.rbe_left; if (((parent)->
rib_e.rbe_left = (tmp)->rib_e.rbe_right)) { ((tmp)->rib_e
.rbe_right)->rib_e.rbe_parent = (parent); } do {} while (0
); if (((tmp)->rib_e.rbe_parent = (parent)->rib_e.rbe_parent
)) { if ((parent) == ((parent)->rib_e.rbe_parent)->rib_e
.rbe_left) ((parent)->rib_e.rbe_parent)->rib_e.rbe_left
= (tmp); else ((parent)->rib_e.rbe_parent)->rib_e.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->rib_e
.rbe_right = (parent); (parent)->rib_e.rbe_parent = (tmp);
do {} while (0); if (((tmp)->rib_e.rbe_parent)) do {} while
(0); } while (0); elm = (head)->rbh_root; break; } } } if
(elm) (elm)->rib_e.rbe_color = 0; } struct rib_entry * rib_tree_RB_REMOVE
(struct rib_tree *head, struct rib_entry *elm) { struct rib_entry
*child, *parent, *old = elm; int color; if ((elm)->rib_e.
rbe_left == ((void *)0)) child = (elm)->rib_e.rbe_right; else
if ((elm)->rib_e.rbe_right == ((void *)0)) child = (elm)->
rib_e.rbe_left; else { struct rib_entry *left; elm = (elm)->
rib_e.rbe_right; while ((left = (elm)->rib_e.rbe_left)) elm
= left; child = (elm)->rib_e.rbe_right; parent = (elm)->
rib_e.rbe_parent; color = (elm)->rib_e.rbe_color; if (child
) (child)->rib_e.rbe_parent = parent; if (parent) { if ((parent
)->rib_e.rbe_left == elm) (parent)->rib_e.rbe_left = child
; else (parent)->rib_e.rbe_right = child; do {} while (0);
} else (head)->rbh_root = child; if ((elm)->rib_e.rbe_parent
== old) parent = elm; (elm)->rib_e = (old)->rib_e; if (
(old)->rib_e.rbe_parent) { if (((old)->rib_e.rbe_parent
)->rib_e.rbe_left == old) ((old)->rib_e.rbe_parent)->
rib_e.rbe_left = elm; else ((old)->rib_e.rbe_parent)->rib_e
.rbe_right = elm; do {} while (0); } else (head)->rbh_root
= elm; ((old)->rib_e.rbe_left)->rib_e.rbe_parent = elm
; if ((old)->rib_e.rbe_right) ((old)->rib_e.rbe_right)->
rib_e.rbe_parent = elm; if (parent) { left = parent; do { do {
} while (0); } while ((left = (left)->rib_e.rbe_parent)); }
goto color; } parent = (elm)->rib_e.rbe_parent; color = (
elm)->rib_e.rbe_color; if (child) (child)->rib_e.rbe_parent
= parent; if (parent) { if ((parent)->rib_e.rbe_left == elm
) (parent)->rib_e.rbe_left = child; else (parent)->rib_e
.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; color: if (color == 0) rib_tree_RB_REMOVE_COLOR(head
, parent, child); return (old); } struct rib_entry * rib_tree_RB_INSERT
(struct rib_tree *head, struct rib_entry *elm) { struct rib_entry
*tmp; struct rib_entry *parent = ((void *)0); int comp = 0; tmp
= (head)->rbh_root; while (tmp) { parent = tmp; comp = (rib_compare
)(elm, parent); if (comp < 0) tmp = (tmp)->rib_e.rbe_left
; else if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else
return (tmp); } do { (elm)->rib_e.rbe_parent = parent; (elm
)->rib_e.rbe_left = (elm)->rib_e.rbe_right = ((void *)0
); (elm)->rib_e.rbe_color = 1; } while (0); if (parent != (
(void *)0)) { if (comp < 0) (parent)->rib_e.rbe_left = elm
; else (parent)->rib_e.rbe_right = elm; do {} while (0); }
else (head)->rbh_root = elm; rib_tree_RB_INSERT_COLOR(head
, elm); return (((void *)0)); } struct rib_entry * rib_tree_RB_FIND
(struct rib_tree *head, struct rib_entry *elm) { struct rib_entry
*tmp = (head)->rbh_root; int comp; while (tmp) { comp = rib_compare
(elm, tmp); if (comp < 0) tmp = (tmp)->rib_e.rbe_left; else
if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else return
(tmp); } return (((void *)0)); } struct rib_entry * rib_tree_RB_NFIND
(struct rib_tree *head, struct rib_entry *elm) { struct rib_entry
*tmp = (head)->rbh_root; struct rib_entry *res = ((void *
)0); int comp; while (tmp) { comp = rib_compare(elm, tmp); if
(comp < 0) { res = tmp; tmp = (tmp)->rib_e.rbe_left; }
else if (comp > 0) tmp = (tmp)->rib_e.rbe_right; else return
(tmp); } return (res); } struct rib_entry * rib_tree_RB_NEXT
(struct rib_entry *elm) { if ((elm)->rib_e.rbe_right) { elm
= (elm)->rib_e.rbe_right; while ((elm)->rib_e.rbe_left
) elm = (elm)->rib_e.rbe_left; } else { if ((elm)->rib_e
.rbe_parent && (elm == ((elm)->rib_e.rbe_parent)->
rib_e.rbe_left)) elm = (elm)->rib_e.rbe_parent; else { while
((elm)->rib_e.rbe_parent && (elm == ((elm)->rib_e
.rbe_parent)->rib_e.rbe_right)) elm = (elm)->rib_e.rbe_parent
; elm = (elm)->rib_e.rbe_parent; } } return (elm); } struct
rib_entry * rib_tree_RB_PREV(struct rib_entry *elm) { if ((elm
)->rib_e.rbe_left) { elm = (elm)->rib_e.rbe_left; while
((elm)->rib_e.rbe_right) elm = (elm)->rib_e.rbe_right;
} else { if ((elm)->rib_e.rbe_parent && (elm == (
(elm)->rib_e.rbe_parent)->rib_e.rbe_right)) elm = (elm)
->rib_e.rbe_parent; else { while ((elm)->rib_e.rbe_parent
&& (elm == ((elm)->rib_e.rbe_parent)->rib_e.rbe_left
)) elm = (elm)->rib_e.rbe_parent; elm = (elm)->rib_e.rbe_parent
; } } return (elm); } struct rib_entry * rib_tree_RB_MINMAX(struct
rib_tree *head, int val) { struct rib_entry *tmp = (head)->
rbh_root; struct rib_entry *parent = ((void *)0); while (tmp)
{ parent = tmp; if (val < 0) tmp = (tmp)->rib_e.rbe_left
; else tmp = (tmp)->rib_e.rbe_right; } return (parent); }
;
51
52struct rib_context {
53 LIST_ENTRY(rib_context)struct { struct rib_context *le_next; struct rib_context **le_prev
; }
entry;
54 struct rib_entry *ctx_re;
55 struct prefix *ctx_p;
56 uint32_t ctx_id;
57 void (*ctx_rib_call)(struct rib_entry *, void *);
58 void (*ctx_prefix_call)(struct prefix *, void *);
59 void (*ctx_done)(void *, uint8_t);
60 int (*ctx_throttle)(void *);
61 void *ctx_arg;
62 struct bgpd_addr ctx_subtree;
63 unsigned int ctx_count;
64 uint8_t ctx_aid;
65 uint8_t ctx_subtreelen;
66};
67LIST_HEAD(, rib_context)struct { struct rib_context *lh_first; } rib_dumps = LIST_HEAD_INITIALIZER(rib_dumps){ ((void *)0) };
68
69static void prefix_dump_r(struct rib_context *);
70
71static inline struct rib_entry *
72re_lock(struct rib_entry *re)
73{
74 if (re->lock != 0)
75 log_warnx("%s: entry already locked", __func__);
76 re->lock = 1;
77 return re;
78}
79
80static inline struct rib_entry *
81re_unlock(struct rib_entry *re)
82{
83 if (re->lock == 0)
84 log_warnx("%s: entry already unlocked", __func__);
85 re->lock = 0;
86 return re;
87}
88
89static inline int
90re_is_locked(struct rib_entry *re)
91{
92 return (re->lock != 0);
93}
94
95static inline struct prefix *
96prefix_lock(struct prefix *p)
97{
98 if (p->flags & PREFIX_FLAG_LOCKED0x80)
99 fatalx("%s: locking locked prefix", __func__);
100 p->flags |= PREFIX_FLAG_LOCKED0x80;
101 return p;
102}
103
104static inline struct prefix *
105prefix_unlock(struct prefix *p)
106{
107 if ((p->flags & PREFIX_FLAG_LOCKED0x80) == 0)
108 fatalx("%s: unlocking unlocked prefix", __func__);
109 p->flags &= ~PREFIX_FLAG_LOCKED0x80;
110 return p;
111}
112
113static inline int
114prefix_is_locked(struct prefix *p)
115{
116 return (p->flags & PREFIX_FLAG_LOCKED0x80) != 0;
117}
118
119static inline int
120prefix_is_dead(struct prefix *p)
121{
122 return (p->flags & PREFIX_FLAG_DEAD0x04) != 0;
123}
124
125static inline struct rib_tree *
126rib_tree(struct rib *rib)
127{
128 return (&rib->tree);
129}
130
131static inline int
132rib_compare(const struct rib_entry *a, const struct rib_entry *b)
133{
134 return (pt_prefix_cmp(a->prefix, b->prefix));
135}
136
137/* RIB specific functions */
138struct rib *
139rib_new(char *name, u_int rtableid, uint16_t flags)
140{
141 struct rib *new;
142 uint16_t id;
143
144 for (id = 0; id < rib_size; id++) {
145 if (ribs[id] == NULL((void *)0))
146 break;
147 }
148
149 if (id >= rib_size) {
150 if ((ribs = recallocarray(ribs, id, id + 8,
151 sizeof(struct rib *))) == NULL((void *)0))
152 fatal(NULL((void *)0));
153 rib_size = id + 8;
154 }
155
156 if ((new = calloc(1, sizeof(*new))) == NULL((void *)0))
157 fatal(NULL((void *)0));
158
159 strlcpy(new->name, name, sizeof(new->name));
160 RB_INIT(rib_tree(new))do { (rib_tree(new))->rbh_root = ((void *)0); } while (0);
161 new->state = RECONF_REINIT;
162 new->id = id;
163 new->flags = flags;
164 new->rtableid = rtableid;
165
166 new->in_rules = calloc(1, sizeof(struct filter_head));
167 if (new->in_rules == NULL((void *)0))
168 fatal(NULL((void *)0));
169 TAILQ_INIT(new->in_rules)do { (new->in_rules)->tqh_first = ((void *)0); (new->
in_rules)->tqh_last = &(new->in_rules)->tqh_first
; } while (0)
;
170
171 ribs[id] = new;
172
173 log_debug("%s: %s -> %u", __func__, name, id);
174 return (new);
175}
176
177/*
178 * This function is only called when the FIB information of a RIB changed.
179 * It will flush the FIB if there was one previously and change the fibstate
180 * from RECONF_NONE (nothing to do) to either RECONF_RELOAD (reload the FIB)
181 * or RECONF_REINIT (rerun the route decision process for every element)
182 * depending on the new flags.
183 */
184int
185rib_update(struct rib *rib)
186{
187 /* flush fib first if there was one */
188 if ((rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0)
189 rde_send_kroute_flush(rib);
190
191 /* if no evaluate changes then a full reinit is needed */
192 if ((rib->flags & F_RIB_NOEVALUATE0x0002) !=
193 (rib->flags_tmp & F_RIB_NOEVALUATE0x0002))
194 rib->fibstate = RECONF_REINIT;
195
196 rib->flags = rib->flags_tmp;
197 rib->rtableid = rib->rtableid_tmp;
198
199 /* reload fib if there is no reinit pending and there will be a fib */
200 if (rib->fibstate != RECONF_REINIT &&
201 (rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0)
202 rib->fibstate = RECONF_RELOAD;
203
204 return (rib->fibstate == RECONF_REINIT);
205}
206
207struct rib *
208rib_byid(uint16_t id)
209{
210 if (id == RIB_NOTFOUND0xffff || id >= rib_size || ribs[id] == NULL((void *)0))
211 return NULL((void *)0);
212 return ribs[id];
213}
214
215uint16_t
216rib_find(char *name)
217{
218 uint16_t id;
219
220 /* no name returns the first Loc-RIB */
221 if (name == NULL((void *)0) || *name == '\0')
222 return RIB_LOC_START1;
223
224 for (id = 0; id < rib_size; id++) {
225 if (ribs[id] != NULL((void *)0) && !strcmp(ribs[id]->name, name))
226 return id;
227 }
228
229 return RIB_NOTFOUND0xffff;
230}
231
232void
233rib_free(struct rib *rib)
234{
235 struct rib_entry *re, *xre;
236 struct prefix *p;
237
238 rib_dump_abort(rib->id);
239
240 /*
241 * flush the rib, disable route evaluation and fib sync to speed up
242 * the prefix removal. Nothing depends on this data anymore.
243 */
244 if ((rib->flags & (F_RIB_NOFIB0x0004 | F_RIB_NOEVALUATE0x0002)) == 0)
7
Assuming the condition is false
8
Taking false branch
245 rde_send_kroute_flush(rib);
246 rib->flags |= F_RIB_NOEVALUATE0x0002 | F_RIB_NOFIB0x0004;
247
248 for (re = RB_MIN(rib_tree, rib_tree(rib))rib_tree_RB_MINMAX(rib_tree(rib), -1); re != NULL((void *)0); re = xre) {
9
Assuming 're' is not equal to NULL
10
Loop condition is true. Entering loop body
249 xre = RB_NEXT(rib_tree, rib_tree(rib), re)rib_tree_RB_NEXT(re);
250
251 /*
252 * Removing the prefixes is tricky because the last one
253 * will remove the rib_entry as well and because we do
254 * an empty check in prefix_destroy() it is not possible to
255 * use the default for loop.
256 */
257 while ((p = TAILQ_FIRST(&re->prefix_h)((&re->prefix_h)->tqh_first))) {
11
Loop condition is true. Entering loop body
18
Loop condition is true. Entering loop body
258 struct rde_aspath *asp = prefix_aspath(p);
19
Use of memory after it is freed
259 if (asp && asp->pftableid)
12
Assuming 'asp' is null
260 rde_pftable_del(asp->pftableid, p);
261 prefix_destroy(p);
13
Calling 'prefix_destroy'
17
Returning; memory was released via 1st parameter
262 }
263 }
264 if (rib->id <= RIB_LOC_START1)
265 return; /* never remove the default ribs */
266 filterlist_free(rib->in_rules_tmp);
267 filterlist_free(rib->in_rules);
268 ribs[rib->id] = NULL((void *)0);
269 free(rib);
270}
271
272void
273rib_shutdown(void)
274{
275 struct rib *rib;
276 uint16_t id;
277
278 for (id = 0; id < rib_size; id++) {
1
Assuming 'id' is < 'rib_size'
2
Loop condition is true. Entering loop body
279 rib = rib_byid(id);
280 if (rib
2.1
'rib' is not equal to NULL
== NULL((void *)0))
3
Taking false branch
281 continue;
282 if (!RB_EMPTY(rib_tree(ribs[id]))((rib_tree(ribs[id]))->rbh_root == ((void *)0))) {
4
Assuming field 'rbh_root' is not equal to null
5
Taking true branch
283 log_warnx("%s: rib %s is not empty", __func__,
284 ribs[id]->name);
285 }
286 rib_free(ribs[id]);
6
Calling 'rib_free'
287 }
288 for (id = 0; id <= RIB_LOC_START1; id++) {
289 rib = rib_byid(id);
290 if (rib == NULL((void *)0))
291 continue;
292 filterlist_free(rib->in_rules_tmp);
293 filterlist_free(rib->in_rules);
294 ribs[id] = NULL((void *)0);
295 free(rib);
296 }
297 free(ribs);
298}
299
300struct rib_entry *
301rib_get(struct rib *rib, struct pt_entry *pte)
302{
303 struct rib_entry xre, *re;
304
305 memset(&xre, 0, sizeof(xre));
306 xre.prefix = pte;
307
308 re = RB_FIND(rib_tree, rib_tree(rib), &xre)rib_tree_RB_FIND(rib_tree(rib), &xre);
309 if (re && re->rib_id != rib->id)
310 fatalx("%s: Unexpected RIB %u != %u.", __func__,
311 re->rib_id, rib->id);
312 return re;
313}
314
315struct rib_entry *
316rib_get_addr(struct rib *rib, struct bgpd_addr *prefix, int prefixlen)
317{
318 return rib_get(rib, pt_fill(prefix, prefixlen));
319}
320
321struct rib_entry *
322rib_match(struct rib *rib, struct bgpd_addr *addr)
323{
324 struct rib_entry *re;
325 int i;
326
327 switch (addr->aid) {
328 case AID_INET1:
329 case AID_VPN_IPv43:
330 for (i = 32; i >= 0; i--) {
331 re = rib_get_addr(rib, addr, i);
332 if (re != NULL((void *)0))
333 return (re);
334 }
335 break;
336 case AID_INET62:
337 case AID_VPN_IPv64:
338 for (i = 128; i >= 0; i--) {
339 re = rib_get_addr(rib, addr, i);
340 if (re != NULL((void *)0))
341 return (re);
342 }
343 break;
344 default:
345 fatalx("%s: unknown af", __func__);
346 }
347 return (NULL((void *)0));
348}
349
350
351struct rib_entry *
352rib_add(struct rib *rib, struct pt_entry *pte)
353{
354 struct rib_entry *re;
355
356 if ((re = calloc(1, sizeof(*re))) == NULL((void *)0))
357 fatal("rib_add");
358
359 TAILQ_INIT(&re->prefix_h)do { (&re->prefix_h)->tqh_first = ((void *)0); (&
re->prefix_h)->tqh_last = &(&re->prefix_h)->
tqh_first; } while (0)
;
360 re->prefix = pt_ref(pte);
361 re->rib_id = rib->id;
362
363 if (RB_INSERT(rib_tree, rib_tree(rib), re)rib_tree_RB_INSERT(rib_tree(rib), re) != NULL((void *)0)) {
364 log_warnx("rib_add: insert failed");
365 free(re);
366 return (NULL((void *)0));
367 }
368
369
370 rdemem.rib_cnt++;
371
372 return (re);
373}
374
375void
376rib_remove(struct rib_entry *re)
377{
378 if (!rib_empty(re))
379 fatalx("rib_remove: entry not empty");
380
381 if (re_is_locked(re))
382 /* entry is locked, don't free it. */
383 return;
384
385 pt_unref(re->prefix);
386
387 if (RB_REMOVE(rib_tree, rib_tree(re_rib(re)), re)rib_tree_RB_REMOVE(rib_tree(re_rib(re)), re) == NULL((void *)0))
388 log_warnx("rib_remove: remove failed.");
389
390 free(re);
391 rdemem.rib_cnt--;
392}
393
394int
395rib_empty(struct rib_entry *re)
396{
397 return TAILQ_EMPTY(&re->prefix_h)(((&re->prefix_h)->tqh_first) == ((void *)0));
398}
399
400static struct rib_entry *
401rib_restart(struct rib_context *ctx)
402{
403 struct rib_entry *re = NULL((void *)0);
404
405 if (ctx->ctx_re)
406 re = re_unlock(ctx->ctx_re);
407
408 /* find first non empty element */
409 while (re && rib_empty(re))
410 re = RB_NEXT(rib_tree, unused, re)rib_tree_RB_NEXT(re);
411
412 /* free the previously locked rib element if empty */
413 if (ctx->ctx_re && rib_empty(ctx->ctx_re))
414 rib_remove(ctx->ctx_re);
415 ctx->ctx_re = NULL((void *)0);
416 return (re);
417}
418
419static void
420rib_dump_r(struct rib_context *ctx)
421{
422 struct rib_entry *re, *next;
423 struct rib *rib;
424 unsigned int i;
425
426 rib = rib_byid(ctx->ctx_id);
427 if (rib == NULL((void *)0))
428 fatalx("%s: rib id %u gone", __func__, ctx->ctx_id);
429
430 if (ctx->ctx_re == NULL((void *)0) && ctx->ctx_subtree.aid == AID_UNSPEC0)
431 re = RB_MIN(rib_tree, rib_tree(rib))rib_tree_RB_MINMAX(rib_tree(rib), -1);
432 else
433 re = rib_restart(ctx);
434
435 for (i = 0; re != NULL((void *)0); re = next) {
436 next = RB_NEXT(rib_tree, unused, re)rib_tree_RB_NEXT(re);
437 if (re->rib_id != ctx->ctx_id)
438 fatalx("%s: Unexpected RIB %u != %u.", __func__,
439 re->rib_id, ctx->ctx_id);
440 if (ctx->ctx_aid != AID_UNSPEC0 &&
441 ctx->ctx_aid != re->prefix->aid)
442 continue;
443 if (ctx->ctx_subtree.aid != AID_UNSPEC0) {
444 struct bgpd_addr addr;
445 pt_getaddr(re->prefix, &addr);
446 if (prefix_compare(&ctx->ctx_subtree, &addr,
447 ctx->ctx_subtreelen) != 0)
448 /* left subtree, walk is done */
449 break;
450 }
451 if (ctx->ctx_count && i++ >= ctx->ctx_count &&
452 !re_is_locked(re)) {
453 /* store and lock last element */
454 ctx->ctx_re = re_lock(re);
455 return;
456 }
457 ctx->ctx_rib_call(re, ctx->ctx_arg);
458 }
459
460 if (ctx->ctx_done)
461 ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid);
462 LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void *)0)) (ctx)->entry
.le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)->
entry.le_prev = (ctx)->entry.le_next; ; ; } while (0)
;
463 free(ctx);
464}
465
466int
467rib_dump_pending(void)
468{
469 struct rib_context *ctx;
470
471 /* return true if at least one context is not throttled */
472 LIST_FOREACH(ctx, &rib_dumps, entry)for((ctx) = ((&rib_dumps)->lh_first); (ctx)!= ((void *
)0); (ctx) = ((ctx)->entry.le_next))
{
473 if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg))
474 continue;
475 return 1;
476 }
477 return 0;
478}
479
480void
481rib_dump_runner(void)
482{
483 struct rib_context *ctx, *next;
484
485 LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) &&
((next) = ((ctx)->entry.le_next), 1); (ctx) = (next))
{
486 if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg))
487 continue;
488 if (ctx->ctx_rib_call != NULL((void *)0))
489 rib_dump_r(ctx);
490 else
491 prefix_dump_r(ctx);
492 }
493}
494
495static void
496rib_dump_abort(uint16_t id)
497{
498 struct rib_context *ctx, *next;
499
500 LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) &&
((next) = ((ctx)->entry.le_next), 1); (ctx) = (next))
{
501 if (id != ctx->ctx_id)
502 continue;
503 if (ctx->ctx_done)
504 ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid);
505 if (ctx->ctx_re && rib_empty(re_unlock(ctx->ctx_re)))
506 rib_remove(ctx->ctx_re);
507 if (ctx->ctx_p && prefix_is_dead(prefix_unlock(ctx->ctx_p)))
508 prefix_adjout_destroy(ctx->ctx_p);
509 LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void *)0)) (ctx)->entry
.le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)->
entry.le_prev = (ctx)->entry.le_next; ; ; } while (0)
;
510 free(ctx);
511 }
512}
513
514void
515rib_dump_terminate(void *arg)
516{
517 struct rib_context *ctx, *next;
518
519 LIST_FOREACH_SAFE(ctx, &rib_dumps, entry, next)for ((ctx) = ((&rib_dumps)->lh_first); (ctx) &&
((next) = ((ctx)->entry.le_next), 1); (ctx) = (next))
{
520 if (ctx->ctx_arg != arg)
521 continue;
522 if (ctx->ctx_done)
523 ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid);
524 if (ctx->ctx_re && rib_empty(re_unlock(ctx->ctx_re)))
525 rib_remove(ctx->ctx_re);
526 if (ctx->ctx_p && prefix_is_dead(prefix_unlock(ctx->ctx_p)))
527 prefix_adjout_destroy(ctx->ctx_p);
528 LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void *)0)) (ctx)->entry
.le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)->
entry.le_prev = (ctx)->entry.le_next; ; ; } while (0)
;
529 free(ctx);
530 }
531}
532
533int
534rib_dump_new(uint16_t id, uint8_t aid, unsigned int count, void *arg,
535 void (*upcall)(struct rib_entry *, void *), void (*done)(void *, uint8_t),
536 int (*throttle)(void *))
537{
538 struct rib_context *ctx;
539
540 if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void *)0))
541 return -1;
542 ctx->ctx_id = id;
543 ctx->ctx_aid = aid;
544 ctx->ctx_count = count;
545 ctx->ctx_arg = arg;
546 ctx->ctx_rib_call = upcall;
547 ctx->ctx_done = done;
548 ctx->ctx_throttle = throttle;
549
550 LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first
) != ((void *)0)) (&rib_dumps)->lh_first->entry.le_prev
= &(ctx)->entry.le_next; (&rib_dumps)->lh_first
= (ctx); (ctx)->entry.le_prev = &(&rib_dumps)->
lh_first; } while (0)
;
551
552 /* requested a sync traversal */
553 if (count == 0)
554 rib_dump_r(ctx);
555
556 return 0;
557}
558
559int
560rib_dump_subtree(uint16_t id, struct bgpd_addr *subtree, uint8_t subtreelen,
561 unsigned int count, void *arg, void (*upcall)(struct rib_entry *, void *),
562 void (*done)(void *, uint8_t), int (*throttle)(void *))
563{
564 struct rib_context *ctx;
565 struct rib_entry xre;
566
567 if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void *)0))
568 return -1;
569 ctx->ctx_id = id;
570 ctx->ctx_aid = subtree->aid;
571 ctx->ctx_count = count;
572 ctx->ctx_arg = arg;
573 ctx->ctx_rib_call = upcall;
574 ctx->ctx_done = done;
575 ctx->ctx_throttle = throttle;
576 ctx->ctx_subtree = *subtree;
577 ctx->ctx_subtreelen = subtreelen;
578
579 LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first
) != ((void *)0)) (&rib_dumps)->lh_first->entry.le_prev
= &(ctx)->entry.le_next; (&rib_dumps)->lh_first
= (ctx); (ctx)->entry.le_prev = &(&rib_dumps)->
lh_first; } while (0)
;
580
581 /* lookup start of subtree */
582 memset(&xre, 0, sizeof(xre));
583 xre.prefix = pt_fill(subtree, subtreelen);
584 ctx->ctx_re = RB_NFIND(rib_tree, rib_tree(rib_byid(id)), &xre)rib_tree_RB_NFIND(rib_tree(rib_byid(id)), &xre);
585 if (ctx->ctx_re)
586 re_lock(ctx->ctx_re);
587
588 /* requested a sync traversal */
589 if (count == 0)
590 rib_dump_r(ctx);
591
592 return 0;
593}
594
595/* path specific functions */
596
597static struct rde_aspath *path_lookup(struct rde_aspath *);
598static void path_link(struct rde_aspath *);
599static void path_unlink(struct rde_aspath *);
600
601static inline int
602path_compare(struct rde_aspath *a, struct rde_aspath *b)
603{
604 int r;
605
606 if (a == NULL((void *)0) && b == NULL((void *)0))
607 return (0);
608 else if (b == NULL((void *)0))
609 return (1);
610 else if (a == NULL((void *)0))
611 return (-1);
612 if ((a->flags & ~F_ATTR_LINKED0x20000) > (b->flags & ~F_ATTR_LINKED0x20000))
613 return (1);
614 if ((a->flags & ~F_ATTR_LINKED0x20000) < (b->flags & ~F_ATTR_LINKED0x20000))
615 return (-1);
616 if (a->origin > b->origin)
617 return (1);
618 if (a->origin < b->origin)
619 return (-1);
620 if (a->med > b->med)
621 return (1);
622 if (a->med < b->med)
623 return (-1);
624 if (a->lpref > b->lpref)
625 return (1);
626 if (a->lpref < b->lpref)
627 return (-1);
628 if (a->weight > b->weight)
629 return (1);
630 if (a->weight < b->weight)
631 return (-1);
632 if (a->rtlabelid > b->rtlabelid)
633 return (1);
634 if (a->rtlabelid < b->rtlabelid)
635 return (-1);
636 if (a->pftableid > b->pftableid)
637 return (1);
638 if (a->pftableid < b->pftableid)
639 return (-1);
640
641 /* no need to check aspa_state or aspa_generation */
642
643 r = aspath_compare(a->aspath, b->aspath);
644 if (r > 0)
645 return (1);
646 if (r < 0)
647 return (-1);
648
649 return (attr_compare(a, b));
650}
651
652RB_HEAD(path_tree, rde_aspath)struct path_tree { struct rde_aspath *rbh_root; } pathtable = RB_INITIALIZER(&pathtable){ ((void *)0) };
653RB_GENERATE_STATIC(path_tree, rde_aspath, entry, path_compare)__attribute__((__unused__)) static void path_tree_RB_INSERT_COLOR
(struct path_tree *head, struct rde_aspath *elm) { struct rde_aspath
*parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent
) && (parent)->entry.rbe_color == 1) { gparent = (
parent)->entry.rbe_parent; if (parent == (gparent)->entry
.rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp &&
(tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color =
0; do { (parent)->entry.rbe_color = 0; (gparent)->entry
.rbe_color = 1; } while (0); elm = gparent; continue; } if ((
parent)->entry.rbe_right == elm) { do { (tmp) = (parent)->
entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (parent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (parent)->entry.rbe_parent)) { if ((parent) == ((parent
)->entry.rbe_parent)->entry.rbe_left) ((parent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry
.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)->
entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } else { tmp
= (gparent)->entry.rbe_left; if (tmp && (tmp)->
entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (
parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color
= 1; } while (0); elm = gparent; continue; } if ((parent)->
entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left
; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right
)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } } (head->
rbh_root)->entry.rbe_color = 0; } __attribute__((__unused__
)) static void path_tree_RB_REMOVE_COLOR(struct path_tree *head
, struct rde_aspath *parent, struct rde_aspath *elm) { struct
rde_aspath *tmp; while ((elm == ((void *)0) || (elm)->entry
.rbe_color == 0) && elm != (head)->rbh_root) { if (
(parent)->entry.rbe_left == elm) { tmp = (parent)->entry
.rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->
entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while
(0); do { (tmp) = (parent)->entry.rbe_right; if (((parent
)->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->
entry.rbe_left)->entry.rbe_parent = (parent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do
{} while (0); if (((tmp)->entry.rbe_parent)) do {} while (
0); } while (0); tmp = (parent)->entry.rbe_right; } if (((
tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left
)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent
= (elm)->entry.rbe_parent; } else { if ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0) { struct rde_aspath *oleft; if ((oleft = (tmp)->entry
.rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry.
rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if ((
(tmp)->entry.rbe_left = (oleft)->entry.rbe_right)) { ((
oleft)->entry.rbe_right)->entry.rbe_parent = (tmp); } do
{} while (0); if (((oleft)->entry.rbe_parent = (tmp)->
entry.rbe_parent)) { if ((tmp) == ((tmp)->entry.rbe_parent
)->entry.rbe_left) ((tmp)->entry.rbe_parent)->entry.
rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry
.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (
oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent
= (oleft); do {} while (0); if (((oleft)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right
; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color;
(parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right
) ((tmp)->entry.rbe_right)->entry.rbe_color = 0; do { (
tmp) = (parent)->entry.rbe_right; if (((parent)->entry.
rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left
)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp
)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if
((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left
) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp);
else ((parent)->entry.rbe_parent)->entry.rbe_right = (
tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left
= (parent); (parent)->entry.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while
(0); elm = (head)->rbh_root; break; } } else { tmp = (parent
)->entry.rbe_left; if ((tmp)->entry.rbe_color == 1) { do
{ (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color
= 1; } while (0); do { (tmp) = (parent)->entry.rbe_left; if
(((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) {
((tmp)->entry.rbe_right)->entry.rbe_parent = (parent);
} do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left
; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->
entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->
entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)
->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm
= parent; parent = (elm)->entry.rbe_parent; } else { if (
(tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left
)->entry.rbe_color == 0) { struct rde_aspath *oright; if (
(oright = (tmp)->entry.rbe_right)) (oright)->entry.rbe_color
= 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)->
entry.rbe_right; if (((tmp)->entry.rbe_right = (oright)->
entry.rbe_left)) { ((oright)->entry.rbe_left)->entry.rbe_parent
= (tmp); } do {} while (0); if (((oright)->entry.rbe_parent
= (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry
.rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent)
->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent
)->entry.rbe_right = (oright); } else (head)->rbh_root =
(oright); (oright)->entry.rbe_left = (tmp); (tmp)->entry
.rbe_parent = (oright); do {} while (0); if (((oright)->entry
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.rbe_left; } (tmp)->entry.rbe_color = (parent)->entry
.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry
.rbe_left) ((tmp)->entry.rbe_left)->entry.rbe_color = 0
; do { (tmp) = (parent)->entry.rbe_left; if (((parent)->
entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry
.rbe_right)->entry.rbe_parent = (parent); } do {} while (0
); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_right = (parent); (parent)->entry.rbe_parent = (tmp);
do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); elm = (head)->rbh_root; break; } } } if
(elm) (elm)->entry.rbe_color = 0; } __attribute__((__unused__
)) static struct rde_aspath * path_tree_RB_REMOVE(struct path_tree
*head, struct rde_aspath *elm) { struct rde_aspath *child, *
parent, *old = elm; int color; if ((elm)->entry.rbe_left ==
((void *)0)) child = (elm)->entry.rbe_right; else if ((elm
)->entry.rbe_right == ((void *)0)) child = (elm)->entry
.rbe_left; else { struct rde_aspath *left; elm = (elm)->entry
.rbe_right; while ((left = (elm)->entry.rbe_left)) elm = left
; child = (elm)->entry.rbe_right; parent = (elm)->entry
.rbe_parent; color = (elm)->entry.rbe_color; if (child) (child
)->entry.rbe_parent = parent; if (parent) { if ((parent)->
entry.rbe_left == elm) (parent)->entry.rbe_left = child; else
(parent)->entry.rbe_right = child; do {} while (0); } else
(head)->rbh_root = child; if ((elm)->entry.rbe_parent ==
old) parent = elm; (elm)->entry = (old)->entry; if ((old
)->entry.rbe_parent) { if (((old)->entry.rbe_parent)->
entry.rbe_left == old) ((old)->entry.rbe_parent)->entry
.rbe_left = elm; else ((old)->entry.rbe_parent)->entry.
rbe_right = elm; do {} while (0); } else (head)->rbh_root =
elm; ((old)->entry.rbe_left)->entry.rbe_parent = elm; if
((old)->entry.rbe_right) ((old)->entry.rbe_right)->
entry.rbe_parent = elm; if (parent) { left = parent; do { do {
} while (0); } while ((left = (left)->entry.rbe_parent)); }
goto color; } parent = (elm)->entry.rbe_parent; color = (
elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent
= parent; if (parent) { if ((parent)->entry.rbe_left == elm
) (parent)->entry.rbe_left = child; else (parent)->entry
.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; color: if (color == 0) path_tree_RB_REMOVE_COLOR(head
, parent, child); return (old); } __attribute__((__unused__))
static struct rde_aspath * path_tree_RB_INSERT(struct path_tree
*head, struct rde_aspath *elm) { struct rde_aspath *tmp; struct
rde_aspath *parent = ((void *)0); int comp = 0; tmp = (head)
->rbh_root; while (tmp) { parent = tmp; comp = (path_compare
)(elm, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left
; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else
return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm
)->entry.rbe_left = (elm)->entry.rbe_right = ((void *)0
); (elm)->entry.rbe_color = 1; } while (0); if (parent != (
(void *)0)) { if (comp < 0) (parent)->entry.rbe_left = elm
; else (parent)->entry.rbe_right = elm; do {} while (0); }
else (head)->rbh_root = elm; path_tree_RB_INSERT_COLOR(head
, elm); return (((void *)0)); } __attribute__((__unused__)) static
struct rde_aspath * path_tree_RB_FIND(struct path_tree *head
, struct rde_aspath *elm) { struct rde_aspath *tmp = (head)->
rbh_root; int comp; while (tmp) { comp = path_compare(elm, tmp
); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (
comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp
); } return (((void *)0)); } __attribute__((__unused__)) static
struct rde_aspath * path_tree_RB_NFIND(struct path_tree *head
, struct rde_aspath *elm) { struct rde_aspath *tmp = (head)->
rbh_root; struct rde_aspath *res = ((void *)0); int comp; while
(tmp) { comp = path_compare(elm, tmp); if (comp < 0) { res
= tmp; tmp = (tmp)->entry.rbe_left; } else if (comp > 0
) tmp = (tmp)->entry.rbe_right; else return (tmp); } return
(res); } __attribute__((__unused__)) static struct rde_aspath
* path_tree_RB_NEXT(struct rde_aspath *elm) { if ((elm)->
entry.rbe_right) { elm = (elm)->entry.rbe_right; while ((elm
)->entry.rbe_left) elm = (elm)->entry.rbe_left; } else {
if ((elm)->entry.rbe_parent && (elm == ((elm)->
entry.rbe_parent)->entry.rbe_left)) elm = (elm)->entry.
rbe_parent; else { while ((elm)->entry.rbe_parent &&
(elm == ((elm)->entry.rbe_parent)->entry.rbe_right)) elm
= (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent
; } } return (elm); } __attribute__((__unused__)) static struct
rde_aspath * path_tree_RB_PREV(struct rde_aspath *elm) { if (
(elm)->entry.rbe_left) { elm = (elm)->entry.rbe_left; while
((elm)->entry.rbe_right) elm = (elm)->entry.rbe_right;
} else { if ((elm)->entry.rbe_parent && (elm == (
(elm)->entry.rbe_parent)->entry.rbe_right)) elm = (elm)
->entry.rbe_parent; else { while ((elm)->entry.rbe_parent
&& (elm == ((elm)->entry.rbe_parent)->entry.rbe_left
)) elm = (elm)->entry.rbe_parent; elm = (elm)->entry.rbe_parent
; } } return (elm); } __attribute__((__unused__)) static struct
rde_aspath * path_tree_RB_MINMAX(struct path_tree *head, int
val) { struct rde_aspath *tmp = (head)->rbh_root; struct rde_aspath
*parent = ((void *)0); while (tmp) { parent = tmp; if (val <
0) tmp = (tmp)->entry.rbe_left; else tmp = (tmp)->entry
.rbe_right; } return (parent); }
;
654
655static inline struct rde_aspath *
656path_ref(struct rde_aspath *asp)
657{
658 if ((asp->flags & F_ATTR_LINKED0x20000) == 0)
659 fatalx("%s: unlinked object", __func__);
660 asp->refcnt++;
661 rdemem.path_refs++;
662
663 return asp;
664}
665
666static inline void
667path_unref(struct rde_aspath *asp)
668{
669 if (asp == NULL((void *)0))
670 return;
671 if ((asp->flags & F_ATTR_LINKED0x20000) == 0)
672 fatalx("%s: unlinked object", __func__);
673 asp->refcnt--;
674 rdemem.path_refs--;
675 if (asp->refcnt <= 0)
676 path_unlink(asp);
677}
678
679void
680path_shutdown(void)
681{
682 if (!RB_EMPTY(&pathtable)((&pathtable)->rbh_root == ((void *)0)))
683 log_warnx("path_free: free non-free table");
684}
685
686static struct rde_aspath *
687path_lookup(struct rde_aspath *aspath)
688{
689 return (RB_FIND(path_tree, &pathtable, aspath)path_tree_RB_FIND(&pathtable, aspath));
690}
691
692/*
693 * Link this aspath into the global table.
694 * The asp had to be alloced with path_get.
695 */
696static void
697path_link(struct rde_aspath *asp)
698{
699 if (RB_INSERT(path_tree, &pathtable, asp)path_tree_RB_INSERT(&pathtable, asp) != NULL((void *)0))
700 fatalx("%s: already linked object", __func__);
701 asp->flags |= F_ATTR_LINKED0x20000;
702}
703
704/*
705 * This function can only be called when all prefix have been removed first.
706 * Normally this happens directly out of the prefix removal functions.
707 */
708static void
709path_unlink(struct rde_aspath *asp)
710{
711 if (asp == NULL((void *)0))
712 return;
713
714 /* make sure no reference is hold for this rde_aspath */
715 if (asp->refcnt != 0)
716 fatalx("%s: still holds references", __func__);
717
718 RB_REMOVE(path_tree, &pathtable, asp)path_tree_RB_REMOVE(&pathtable, asp);
719 asp->flags &= ~F_ATTR_LINKED0x20000;
720
721 path_put(asp);
722}
723
724/*
725 * Copy asp to a new UNLINKED aspath.
726 * On dst either path_get() or path_prep() had to be called before.
727 */
728struct rde_aspath *
729path_copy(struct rde_aspath *dst, const struct rde_aspath *src)
730{
731 dst->aspath = aspath_copy(src->aspath);
732 dst->refcnt = 0;
733 dst->flags = src->flags & ~F_ATTR_LINKED0x20000;
734
735 dst->med = src->med;
736 dst->lpref = src->lpref;
737 dst->weight = src->weight;
738 dst->rtlabelid = rtlabel_ref(src->rtlabelid);
739 dst->pftableid = pftable_ref(src->pftableid);
740 dst->origin = src->origin;
741
742 attr_copy(dst, src);
743
744 return (dst);
745}
746
747/* initialize or prepare an aspath for use */
748struct rde_aspath *
749path_prep(struct rde_aspath *asp)
750{
751 memset(asp, 0, sizeof(*asp));
752 asp->origin = ORIGIN_INCOMPLETE2;
753 asp->lpref = DEFAULT_LPREF100;
754
755 return (asp);
756}
757
758/* alloc and initialize new entry. May not fail. */
759struct rde_aspath *
760path_get(void)
761{
762 struct rde_aspath *asp;
763
764 asp = malloc(sizeof(*asp));
765 if (asp == NULL((void *)0))
766 fatal("path_get");
767 rdemem.path_cnt++;
768
769 return (path_prep(asp));
770}
771
772/* clean up an asp after use (frees all references to sub-objects) */
773void
774path_clean(struct rde_aspath *asp)
775{
776 if (asp->flags & F_ATTR_LINKED0x20000)
777 fatalx("%s: linked object", __func__);
778
779 rtlabel_unref(asp->rtlabelid);
780 pftable_unref(asp->pftableid);
781 aspath_put(asp->aspath);
782 asp->aspath = NULL((void *)0);
783 attr_freeall(asp);
784}
785
786/* free an unlinked element */
787void
788path_put(struct rde_aspath *asp)
789{
790 if (asp == NULL((void *)0))
791 return;
792
793 path_clean(asp);
794
795 rdemem.path_cnt--;
796 free(asp);
797}
798
799/* prefix specific functions */
800
801static int prefix_add(struct bgpd_addr *, int, struct rib *,
802 struct rde_peer *, uint32_t, uint32_t, struct rde_aspath *,
803 struct rde_community *, struct nexthop *,
804 uint8_t, uint8_t);
805static int prefix_move(struct prefix *, struct rde_peer *,
806 struct rde_aspath *, struct rde_community *,
807 struct nexthop *, uint8_t, uint8_t);
808
809static void prefix_link(struct prefix *, struct rib_entry *,
810 struct pt_entry *, struct rde_peer *, uint32_t, uint32_t,
811 struct rde_aspath *, struct rde_community *,
812 struct nexthop *, uint8_t, uint8_t);
813static void prefix_unlink(struct prefix *);
814
815static struct prefix *prefix_alloc(void);
816static void prefix_free(struct prefix *);
817
818/* RB tree comparison function */
819static inline int
820prefix_index_cmp(struct prefix *a, struct prefix *b)
821{
822 int r;
823 r = pt_prefix_cmp(a->pt, b->pt);
824 if (r != 0)
825 return r;
826
827 if (a->path_id_tx > b->path_id_tx)
828 return 1;
829 if (a->path_id_tx < b->path_id_tx)
830 return -1;
831 return 0;
832}
833
834static inline int
835prefix_cmp(struct prefix *a, struct prefix *b)
836{
837 if ((a->flags & PREFIX_FLAG_EOR0x20) != (b->flags & PREFIX_FLAG_EOR0x20))
838 return (a->flags & PREFIX_FLAG_EOR0x20) ? 1 : -1;
839 /* if EOR marker no need to check the rest */
840 if (a->flags & PREFIX_FLAG_EOR0x20)
841 return 0;
842
843 if (a->aspath != b->aspath)
844 return (a->aspath > b->aspath ? 1 : -1);
845 if (a->communities != b->communities)
846 return (a->communities > b->communities ? 1 : -1);
847 if (a->nexthop != b->nexthop)
848 return (a->nexthop > b->nexthop ? 1 : -1);
849 if (a->nhflags != b->nhflags)
850 return (a->nhflags > b->nhflags ? 1 : -1);
851 return prefix_index_cmp(a, b);
852}
853
854RB_GENERATE(prefix_tree, prefix, entry.tree.update, prefix_cmp)void prefix_tree_RB_INSERT_COLOR(struct prefix_tree *head, struct
prefix *elm) { struct prefix *parent, *gparent, *tmp; while (
(parent = (elm)->entry.tree.update.rbe_parent) && (
parent)->entry.tree.update.rbe_color == 1) { gparent = (parent
)->entry.tree.update.rbe_parent; if (parent == (gparent)->
entry.tree.update.rbe_left) { tmp = (gparent)->entry.tree.
update.rbe_right; if (tmp && (tmp)->entry.tree.update
.rbe_color == 1) { (tmp)->entry.tree.update.rbe_color = 0;
do { (parent)->entry.tree.update.rbe_color = 0; (gparent)
->entry.tree.update.rbe_color = 1; } while (0); elm = gparent
; continue; } if ((parent)->entry.tree.update.rbe_right ==
elm) { do { (tmp) = (parent)->entry.tree.update.rbe_right
; if (((parent)->entry.tree.update.rbe_right = (tmp)->entry
.tree.update.rbe_left)) { ((tmp)->entry.tree.update.rbe_left
)->entry.tree.update.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.update.rbe_parent = (parent)->
entry.tree.update.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.update.rbe_parent)->entry.tree.update.rbe_left)
((parent)->entry.tree.update.rbe_parent)->entry.tree.update
.rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent
)->entry.tree.update.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (parent
); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); tmp = parent; parent = elm; elm = tmp; } do
{ (parent)->entry.tree.update.rbe_color = 0; (gparent)->
entry.tree.update.rbe_color = 1; } while (0); do { (tmp) = (gparent
)->entry.tree.update.rbe_left; if (((gparent)->entry.tree
.update.rbe_left = (tmp)->entry.tree.update.rbe_right)) { (
(tmp)->entry.tree.update.rbe_right)->entry.tree.update.
rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry
.tree.update.rbe_parent = (gparent)->entry.tree.update.rbe_parent
)) { if ((gparent) == ((gparent)->entry.tree.update.rbe_parent
)->entry.tree.update.rbe_left) ((gparent)->entry.tree.update
.rbe_parent)->entry.tree.update.rbe_left = (tmp); else ((gparent
)->entry.tree.update.rbe_parent)->entry.tree.update.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.tree.update.rbe_right = (gparent); (gparent)->entry.tree.
update.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry
.tree.update.rbe_parent)) do {} while (0); } while (0); } else
{ tmp = (gparent)->entry.tree.update.rbe_left; if (tmp &&
(tmp)->entry.tree.update.rbe_color == 1) { (tmp)->entry
.tree.update.rbe_color = 0; do { (parent)->entry.tree.update
.rbe_color = 0; (gparent)->entry.tree.update.rbe_color = 1
; } while (0); elm = gparent; continue; } if ((parent)->entry
.tree.update.rbe_left == elm) { do { (tmp) = (parent)->entry
.tree.update.rbe_left; if (((parent)->entry.tree.update.rbe_left
= (tmp)->entry.tree.update.rbe_right)) { ((tmp)->entry
.tree.update.rbe_right)->entry.tree.update.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.tree.update.rbe_parent
= (parent)->entry.tree.update.rbe_parent)) { if ((parent)
== ((parent)->entry.tree.update.rbe_parent)->entry.tree
.update.rbe_left) ((parent)->entry.tree.update.rbe_parent)
->entry.tree.update.rbe_left = (tmp); else ((parent)->entry
.tree.update.rbe_parent)->entry.tree.update.rbe_right = (tmp
); } else (head)->rbh_root = (tmp); (tmp)->entry.tree.update
.rbe_right = (parent); (parent)->entry.tree.update.rbe_parent
= (tmp); do {} while (0); if (((tmp)->entry.tree.update.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.tree.update.rbe_color = 0; (
gparent)->entry.tree.update.rbe_color = 1; } while (0); do
{ (tmp) = (gparent)->entry.tree.update.rbe_right; if (((gparent
)->entry.tree.update.rbe_right = (tmp)->entry.tree.update
.rbe_left)) { ((tmp)->entry.tree.update.rbe_left)->entry
.tree.update.rbe_parent = (gparent); } do {} while (0); if ((
(tmp)->entry.tree.update.rbe_parent = (gparent)->entry.
tree.update.rbe_parent)) { if ((gparent) == ((gparent)->entry
.tree.update.rbe_parent)->entry.tree.update.rbe_left) ((gparent
)->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left
= (tmp); else ((gparent)->entry.tree.update.rbe_parent)->
entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.update.rbe_left = (gparent); (
gparent)->entry.tree.update.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); } } (head->rbh_root)->entry.tree.update
.rbe_color = 0; } void prefix_tree_RB_REMOVE_COLOR(struct prefix_tree
*head, struct prefix *parent, struct prefix *elm) { struct prefix
*tmp; while ((elm == ((void *)0) || (elm)->entry.tree.update
.rbe_color == 0) && elm != (head)->rbh_root) { if (
(parent)->entry.tree.update.rbe_left == elm) { tmp = (parent
)->entry.tree.update.rbe_right; if ((tmp)->entry.tree.update
.rbe_color == 1) { do { (tmp)->entry.tree.update.rbe_color
= 0; (parent)->entry.tree.update.rbe_color = 1; } while (
0); do { (tmp) = (parent)->entry.tree.update.rbe_right; if
(((parent)->entry.tree.update.rbe_right = (tmp)->entry
.tree.update.rbe_left)) { ((tmp)->entry.tree.update.rbe_left
)->entry.tree.update.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.update.rbe_parent = (parent)->
entry.tree.update.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.update.rbe_parent)->entry.tree.update.rbe_left)
((parent)->entry.tree.update.rbe_parent)->entry.tree.update
.rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent
)->entry.tree.update.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.tree.update.rbe_left = (parent
); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.tree.update.rbe_right
; } if (((tmp)->entry.tree.update.rbe_left == ((void *)0) ||
((tmp)->entry.tree.update.rbe_left)->entry.tree.update
.rbe_color == 0) && ((tmp)->entry.tree.update.rbe_right
== ((void *)0) || ((tmp)->entry.tree.update.rbe_right)->
entry.tree.update.rbe_color == 0)) { (tmp)->entry.tree.update
.rbe_color = 1; elm = parent; parent = (elm)->entry.tree.update
.rbe_parent; } else { if ((tmp)->entry.tree.update.rbe_right
== ((void *)0) || ((tmp)->entry.tree.update.rbe_right)->
entry.tree.update.rbe_color == 0) { struct prefix *oleft; if (
(oleft = (tmp)->entry.tree.update.rbe_left)) (oleft)->entry
.tree.update.rbe_color = 0; (tmp)->entry.tree.update.rbe_color
= 1; do { (oleft) = (tmp)->entry.tree.update.rbe_left; if
(((tmp)->entry.tree.update.rbe_left = (oleft)->entry.tree
.update.rbe_right)) { ((oleft)->entry.tree.update.rbe_right
)->entry.tree.update.rbe_parent = (tmp); } do {} while (0)
; if (((oleft)->entry.tree.update.rbe_parent = (tmp)->entry
.tree.update.rbe_parent)) { if ((tmp) == ((tmp)->entry.tree
.update.rbe_parent)->entry.tree.update.rbe_left) ((tmp)->
entry.tree.update.rbe_parent)->entry.tree.update.rbe_left =
(oleft); else ((tmp)->entry.tree.update.rbe_parent)->entry
.tree.update.rbe_right = (oleft); } else (head)->rbh_root =
(oleft); (oleft)->entry.tree.update.rbe_right = (tmp); (tmp
)->entry.tree.update.rbe_parent = (oleft); do {} while (0)
; if (((oleft)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.tree.update.rbe_right
; } (tmp)->entry.tree.update.rbe_color = (parent)->entry
.tree.update.rbe_color; (parent)->entry.tree.update.rbe_color
= 0; if ((tmp)->entry.tree.update.rbe_right) ((tmp)->entry
.tree.update.rbe_right)->entry.tree.update.rbe_color = 0; do
{ (tmp) = (parent)->entry.tree.update.rbe_right; if (((parent
)->entry.tree.update.rbe_right = (tmp)->entry.tree.update
.rbe_left)) { ((tmp)->entry.tree.update.rbe_left)->entry
.tree.update.rbe_parent = (parent); } do {} while (0); if (((
tmp)->entry.tree.update.rbe_parent = (parent)->entry.tree
.update.rbe_parent)) { if ((parent) == ((parent)->entry.tree
.update.rbe_parent)->entry.tree.update.rbe_left) ((parent)
->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left
= (tmp); else ((parent)->entry.tree.update.rbe_parent)->
entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.update.rbe_left = (parent); (parent
)->entry.tree.update.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.update.rbe_parent)) do {} while (0); }
while (0); elm = (head)->rbh_root; break; } } else { tmp =
(parent)->entry.tree.update.rbe_left; if ((tmp)->entry
.tree.update.rbe_color == 1) { do { (tmp)->entry.tree.update
.rbe_color = 0; (parent)->entry.tree.update.rbe_color = 1;
} while (0); do { (tmp) = (parent)->entry.tree.update.rbe_left
; if (((parent)->entry.tree.update.rbe_left = (tmp)->entry
.tree.update.rbe_right)) { ((tmp)->entry.tree.update.rbe_right
)->entry.tree.update.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.update.rbe_parent = (parent)->
entry.tree.update.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.update.rbe_parent)->entry.tree.update.rbe_left)
((parent)->entry.tree.update.rbe_parent)->entry.tree.update
.rbe_left = (tmp); else ((parent)->entry.tree.update.rbe_parent
)->entry.tree.update.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.tree.update.rbe_right = (parent
); (parent)->entry.tree.update.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.tree.update.rbe_left
; } if (((tmp)->entry.tree.update.rbe_left == ((void *)0) ||
((tmp)->entry.tree.update.rbe_left)->entry.tree.update
.rbe_color == 0) && ((tmp)->entry.tree.update.rbe_right
== ((void *)0) || ((tmp)->entry.tree.update.rbe_right)->
entry.tree.update.rbe_color == 0)) { (tmp)->entry.tree.update
.rbe_color = 1; elm = parent; parent = (elm)->entry.tree.update
.rbe_parent; } else { if ((tmp)->entry.tree.update.rbe_left
== ((void *)0) || ((tmp)->entry.tree.update.rbe_left)->
entry.tree.update.rbe_color == 0) { struct prefix *oright; if
((oright = (tmp)->entry.tree.update.rbe_right)) (oright)->
entry.tree.update.rbe_color = 0; (tmp)->entry.tree.update.
rbe_color = 1; do { (oright) = (tmp)->entry.tree.update.rbe_right
; if (((tmp)->entry.tree.update.rbe_right = (oright)->entry
.tree.update.rbe_left)) { ((oright)->entry.tree.update.rbe_left
)->entry.tree.update.rbe_parent = (tmp); } do {} while (0)
; if (((oright)->entry.tree.update.rbe_parent = (tmp)->
entry.tree.update.rbe_parent)) { if ((tmp) == ((tmp)->entry
.tree.update.rbe_parent)->entry.tree.update.rbe_left) ((tmp
)->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left
= (oright); else ((tmp)->entry.tree.update.rbe_parent)->
entry.tree.update.rbe_right = (oright); } else (head)->rbh_root
= (oright); (oright)->entry.tree.update.rbe_left = (tmp);
(tmp)->entry.tree.update.rbe_parent = (oright); do {} while
(0); if (((oright)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.tree.update.rbe_left
; } (tmp)->entry.tree.update.rbe_color = (parent)->entry
.tree.update.rbe_color; (parent)->entry.tree.update.rbe_color
= 0; if ((tmp)->entry.tree.update.rbe_left) ((tmp)->entry
.tree.update.rbe_left)->entry.tree.update.rbe_color = 0; do
{ (tmp) = (parent)->entry.tree.update.rbe_left; if (((parent
)->entry.tree.update.rbe_left = (tmp)->entry.tree.update
.rbe_right)) { ((tmp)->entry.tree.update.rbe_right)->entry
.tree.update.rbe_parent = (parent); } do {} while (0); if (((
tmp)->entry.tree.update.rbe_parent = (parent)->entry.tree
.update.rbe_parent)) { if ((parent) == ((parent)->entry.tree
.update.rbe_parent)->entry.tree.update.rbe_left) ((parent)
->entry.tree.update.rbe_parent)->entry.tree.update.rbe_left
= (tmp); else ((parent)->entry.tree.update.rbe_parent)->
entry.tree.update.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.update.rbe_right = (parent); (
parent)->entry.tree.update.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.tree.update.rbe_parent)) do {} while
(0); } while (0); elm = (head)->rbh_root; break; } } } if
(elm) (elm)->entry.tree.update.rbe_color = 0; } struct prefix
* prefix_tree_RB_REMOVE(struct prefix_tree *head, struct prefix
*elm) { struct prefix *child, *parent, *old = elm; int color
; if ((elm)->entry.tree.update.rbe_left == ((void *)0)) child
= (elm)->entry.tree.update.rbe_right; else if ((elm)->
entry.tree.update.rbe_right == ((void *)0)) child = (elm)->
entry.tree.update.rbe_left; else { struct prefix *left; elm =
(elm)->entry.tree.update.rbe_right; while ((left = (elm)->
entry.tree.update.rbe_left)) elm = left; child = (elm)->entry
.tree.update.rbe_right; parent = (elm)->entry.tree.update.
rbe_parent; color = (elm)->entry.tree.update.rbe_color; if
(child) (child)->entry.tree.update.rbe_parent = parent; if
(parent) { if ((parent)->entry.tree.update.rbe_left == elm
) (parent)->entry.tree.update.rbe_left = child; else (parent
)->entry.tree.update.rbe_right = child; do {} while (0); }
else (head)->rbh_root = child; if ((elm)->entry.tree.update
.rbe_parent == old) parent = elm; (elm)->entry.tree.update
= (old)->entry.tree.update; if ((old)->entry.tree.update
.rbe_parent) { if (((old)->entry.tree.update.rbe_parent)->
entry.tree.update.rbe_left == old) ((old)->entry.tree.update
.rbe_parent)->entry.tree.update.rbe_left = elm; else ((old
)->entry.tree.update.rbe_parent)->entry.tree.update.rbe_right
= elm; do {} while (0); } else (head)->rbh_root = elm; ((
old)->entry.tree.update.rbe_left)->entry.tree.update.rbe_parent
= elm; if ((old)->entry.tree.update.rbe_right) ((old)->
entry.tree.update.rbe_right)->entry.tree.update.rbe_parent
= elm; if (parent) { left = parent; do { do {} while (0); } while
((left = (left)->entry.tree.update.rbe_parent)); } goto color
; } parent = (elm)->entry.tree.update.rbe_parent; color = (
elm)->entry.tree.update.rbe_color; if (child) (child)->
entry.tree.update.rbe_parent = parent; if (parent) { if ((parent
)->entry.tree.update.rbe_left == elm) (parent)->entry.tree
.update.rbe_left = child; else (parent)->entry.tree.update
.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; color: if (color == 0) prefix_tree_RB_REMOVE_COLOR(
head, parent, child); return (old); } struct prefix * prefix_tree_RB_INSERT
(struct prefix_tree *head, struct prefix *elm) { struct prefix
*tmp; struct prefix *parent = ((void *)0); int comp = 0; tmp
= (head)->rbh_root; while (tmp) { parent = tmp; comp = (prefix_cmp
)(elm, parent); if (comp < 0) tmp = (tmp)->entry.tree.update
.rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.update
.rbe_right; else return (tmp); } do { (elm)->entry.tree.update
.rbe_parent = parent; (elm)->entry.tree.update.rbe_left = (
elm)->entry.tree.update.rbe_right = ((void *)0); (elm)->
entry.tree.update.rbe_color = 1; } while (0); if (parent != (
(void *)0)) { if (comp < 0) (parent)->entry.tree.update
.rbe_left = elm; else (parent)->entry.tree.update.rbe_right
= elm; do {} while (0); } else (head)->rbh_root = elm; prefix_tree_RB_INSERT_COLOR
(head, elm); return (((void *)0)); } struct prefix * prefix_tree_RB_FIND
(struct prefix_tree *head, struct prefix *elm) { struct prefix
*tmp = (head)->rbh_root; int comp; while (tmp) { comp = prefix_cmp
(elm, tmp); if (comp < 0) tmp = (tmp)->entry.tree.update
.rbe_left; else if (comp > 0) tmp = (tmp)->entry.tree.update
.rbe_right; else return (tmp); } return (((void *)0)); } struct
prefix * prefix_tree_RB_NFIND(struct prefix_tree *head, struct
prefix *elm) { struct prefix *tmp = (head)->rbh_root; struct
prefix *res = ((void *)0); int comp; while (tmp) { comp = prefix_cmp
(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry
.tree.update.rbe_left; } else if (comp > 0) tmp = (tmp)->
entry.tree.update.rbe_right; else return (tmp); } return (res
); } struct prefix * prefix_tree_RB_NEXT(struct prefix *elm) {
if ((elm)->entry.tree.update.rbe_right) { elm = (elm)->
entry.tree.update.rbe_right; while ((elm)->entry.tree.update
.rbe_left) elm = (elm)->entry.tree.update.rbe_left; } else
{ if ((elm)->entry.tree.update.rbe_parent && (elm
== ((elm)->entry.tree.update.rbe_parent)->entry.tree.update
.rbe_left)) elm = (elm)->entry.tree.update.rbe_parent; else
{ while ((elm)->entry.tree.update.rbe_parent && (
elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree
.update.rbe_right)) elm = (elm)->entry.tree.update.rbe_parent
; elm = (elm)->entry.tree.update.rbe_parent; } } return (elm
); } struct prefix * prefix_tree_RB_PREV(struct prefix *elm) {
if ((elm)->entry.tree.update.rbe_left) { elm = (elm)->
entry.tree.update.rbe_left; while ((elm)->entry.tree.update
.rbe_right) elm = (elm)->entry.tree.update.rbe_right; } else
{ if ((elm)->entry.tree.update.rbe_parent && (elm
== ((elm)->entry.tree.update.rbe_parent)->entry.tree.update
.rbe_right)) elm = (elm)->entry.tree.update.rbe_parent; else
{ while ((elm)->entry.tree.update.rbe_parent && (
elm == ((elm)->entry.tree.update.rbe_parent)->entry.tree
.update.rbe_left)) elm = (elm)->entry.tree.update.rbe_parent
; elm = (elm)->entry.tree.update.rbe_parent; } } return (elm
); } struct prefix * prefix_tree_RB_MINMAX(struct prefix_tree
*head, int val) { struct prefix *tmp = (head)->rbh_root; struct
prefix *parent = ((void *)0); while (tmp) { parent = tmp; if
(val < 0) tmp = (tmp)->entry.tree.update.rbe_left; else
tmp = (tmp)->entry.tree.update.rbe_right; } return (parent
); }
855RB_GENERATE_STATIC(prefix_index, prefix, entry.tree.index, prefix_index_cmp)__attribute__((__unused__)) static void prefix_index_RB_INSERT_COLOR
(struct prefix_index *head, struct prefix *elm) { struct prefix
*parent, *gparent, *tmp; while ((parent = (elm)->entry.tree
.index.rbe_parent) && (parent)->entry.tree.index.rbe_color
== 1) { gparent = (parent)->entry.tree.index.rbe_parent; if
(parent == (gparent)->entry.tree.index.rbe_left) { tmp = (
gparent)->entry.tree.index.rbe_right; if (tmp && (
tmp)->entry.tree.index.rbe_color == 1) { (tmp)->entry.tree
.index.rbe_color = 0; do { (parent)->entry.tree.index.rbe_color
= 0; (gparent)->entry.tree.index.rbe_color = 1; } while (
0); elm = gparent; continue; } if ((parent)->entry.tree.index
.rbe_right == elm) { do { (tmp) = (parent)->entry.tree.index
.rbe_right; if (((parent)->entry.tree.index.rbe_right = (tmp
)->entry.tree.index.rbe_left)) { ((tmp)->entry.tree.index
.rbe_left)->entry.tree.index.rbe_parent = (parent); } do {
} while (0); if (((tmp)->entry.tree.index.rbe_parent = (parent
)->entry.tree.index.rbe_parent)) { if ((parent) == ((parent
)->entry.tree.index.rbe_parent)->entry.tree.index.rbe_left
) ((parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent
)->entry.tree.index.rbe_color = 0; (gparent)->entry.tree
.index.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.tree.index.rbe_left; if (((gparent)->entry.tree.index
.rbe_left = (tmp)->entry.tree.index.rbe_right)) { ((tmp)->
entry.tree.index.rbe_right)->entry.tree.index.rbe_parent =
(gparent); } do {} while (0); if (((tmp)->entry.tree.index
.rbe_parent = (gparent)->entry.tree.index.rbe_parent)) { if
((gparent) == ((gparent)->entry.tree.index.rbe_parent)->
entry.tree.index.rbe_left) ((gparent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_left = (tmp); else ((gparent)->
entry.tree.index.rbe_parent)->entry.tree.index.rbe_right =
(tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.tree
.index.rbe_right = (gparent); (gparent)->entry.tree.index.
rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.tree
.index.rbe_parent)) do {} while (0); } while (0); } else { tmp
= (gparent)->entry.tree.index.rbe_left; if (tmp &&
(tmp)->entry.tree.index.rbe_color == 1) { (tmp)->entry
.tree.index.rbe_color = 0; do { (parent)->entry.tree.index
.rbe_color = 0; (gparent)->entry.tree.index.rbe_color = 1;
} while (0); elm = gparent; continue; } if ((parent)->entry
.tree.index.rbe_left == elm) { do { (tmp) = (parent)->entry
.tree.index.rbe_left; if (((parent)->entry.tree.index.rbe_left
= (tmp)->entry.tree.index.rbe_right)) { ((tmp)->entry.
tree.index.rbe_right)->entry.tree.index.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.tree.index.rbe_parent
= (parent)->entry.tree.index.rbe_parent)) { if ((parent) ==
((parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left) ((parent)->entry.tree.index.rbe_parent)->entry
.tree.index.rbe_left = (tmp); else ((parent)->entry.tree.index
.rbe_parent)->entry.tree.index.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.tree.index.rbe_right
= (parent); (parent)->entry.tree.index.rbe_parent = (tmp)
; do {} while (0); if (((tmp)->entry.tree.index.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.tree.index.rbe_color = 0; (
gparent)->entry.tree.index.rbe_color = 1; } while (0); do {
(tmp) = (gparent)->entry.tree.index.rbe_right; if (((gparent
)->entry.tree.index.rbe_right = (tmp)->entry.tree.index
.rbe_left)) { ((tmp)->entry.tree.index.rbe_left)->entry
.tree.index.rbe_parent = (gparent); } do {} while (0); if (((
tmp)->entry.tree.index.rbe_parent = (gparent)->entry.tree
.index.rbe_parent)) { if ((gparent) == ((gparent)->entry.tree
.index.rbe_parent)->entry.tree.index.rbe_left) ((gparent)->
entry.tree.index.rbe_parent)->entry.tree.index.rbe_left = (
tmp); else ((gparent)->entry.tree.index.rbe_parent)->entry
.tree.index.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.tree.index.rbe_left = (gparent); (gparent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); } } (head->rbh_root)->entry.tree.index.rbe_color
= 0; } __attribute__((__unused__)) static void prefix_index_RB_REMOVE_COLOR
(struct prefix_index *head, struct prefix *parent, struct prefix
*elm) { struct prefix *tmp; while ((elm == ((void *)0) || (elm
)->entry.tree.index.rbe_color == 0) && elm != (head
)->rbh_root) { if ((parent)->entry.tree.index.rbe_left ==
elm) { tmp = (parent)->entry.tree.index.rbe_right; if ((tmp
)->entry.tree.index.rbe_color == 1) { do { (tmp)->entry
.tree.index.rbe_color = 0; (parent)->entry.tree.index.rbe_color
= 1; } while (0); do { (tmp) = (parent)->entry.tree.index
.rbe_right; if (((parent)->entry.tree.index.rbe_right = (tmp
)->entry.tree.index.rbe_left)) { ((tmp)->entry.tree.index
.rbe_left)->entry.tree.index.rbe_parent = (parent); } do {
} while (0); if (((tmp)->entry.tree.index.rbe_parent = (parent
)->entry.tree.index.rbe_parent)) { if ((parent) == ((parent
)->entry.tree.index.rbe_parent)->entry.tree.index.rbe_left
) ((parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); tmp = (parent)->entry.tree.index.rbe_right; } if
(((tmp)->entry.tree.index.rbe_left == ((void *)0) || ((tmp
)->entry.tree.index.rbe_left)->entry.tree.index.rbe_color
== 0) && ((tmp)->entry.tree.index.rbe_right == ((
void *)0) || ((tmp)->entry.tree.index.rbe_right)->entry
.tree.index.rbe_color == 0)) { (tmp)->entry.tree.index.rbe_color
= 1; elm = parent; parent = (elm)->entry.tree.index.rbe_parent
; } else { if ((tmp)->entry.tree.index.rbe_right == ((void
*)0) || ((tmp)->entry.tree.index.rbe_right)->entry.tree
.index.rbe_color == 0) { struct prefix *oleft; if ((oleft = (
tmp)->entry.tree.index.rbe_left)) (oleft)->entry.tree.index
.rbe_color = 0; (tmp)->entry.tree.index.rbe_color = 1; do {
(oleft) = (tmp)->entry.tree.index.rbe_left; if (((tmp)->
entry.tree.index.rbe_left = (oleft)->entry.tree.index.rbe_right
)) { ((oleft)->entry.tree.index.rbe_right)->entry.tree.
index.rbe_parent = (tmp); } do {} while (0); if (((oleft)->
entry.tree.index.rbe_parent = (tmp)->entry.tree.index.rbe_parent
)) { if ((tmp) == ((tmp)->entry.tree.index.rbe_parent)->
entry.tree.index.rbe_left) ((tmp)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_left = (oleft); else ((tmp)->entry
.tree.index.rbe_parent)->entry.tree.index.rbe_right = (oleft
); } else (head)->rbh_root = (oleft); (oleft)->entry.tree
.index.rbe_right = (tmp); (tmp)->entry.tree.index.rbe_parent
= (oleft); do {} while (0); if (((oleft)->entry.tree.index
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.tree.index.rbe_right; } (tmp)->entry.tree.index.rbe_color
= (parent)->entry.tree.index.rbe_color; (parent)->entry
.tree.index.rbe_color = 0; if ((tmp)->entry.tree.index.rbe_right
) ((tmp)->entry.tree.index.rbe_right)->entry.tree.index
.rbe_color = 0; do { (tmp) = (parent)->entry.tree.index.rbe_right
; if (((parent)->entry.tree.index.rbe_right = (tmp)->entry
.tree.index.rbe_left)) { ((tmp)->entry.tree.index.rbe_left
)->entry.tree.index.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.index.rbe_parent = (parent)->
entry.tree.index.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) (
(parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.index.rbe_left = (parent); (parent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); elm = (head)->rbh_root; break; } } else { tmp =
(parent)->entry.tree.index.rbe_left; if ((tmp)->entry.
tree.index.rbe_color == 1) { do { (tmp)->entry.tree.index.
rbe_color = 0; (parent)->entry.tree.index.rbe_color = 1; }
while (0); do { (tmp) = (parent)->entry.tree.index.rbe_left
; if (((parent)->entry.tree.index.rbe_left = (tmp)->entry
.tree.index.rbe_right)) { ((tmp)->entry.tree.index.rbe_right
)->entry.tree.index.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.index.rbe_parent = (parent)->
entry.tree.index.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) (
(parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.index.rbe_right = (parent); (parent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); tmp = (parent)->entry.tree.index.rbe_left; } if
(((tmp)->entry.tree.index.rbe_left == ((void *)0) || ((tmp
)->entry.tree.index.rbe_left)->entry.tree.index.rbe_color
== 0) && ((tmp)->entry.tree.index.rbe_right == ((
void *)0) || ((tmp)->entry.tree.index.rbe_right)->entry
.tree.index.rbe_color == 0)) { (tmp)->entry.tree.index.rbe_color
= 1; elm = parent; parent = (elm)->entry.tree.index.rbe_parent
; } else { if ((tmp)->entry.tree.index.rbe_left == ((void *
)0) || ((tmp)->entry.tree.index.rbe_left)->entry.tree.index
.rbe_color == 0) { struct prefix *oright; if ((oright = (tmp)
->entry.tree.index.rbe_right)) (oright)->entry.tree.index
.rbe_color = 0; (tmp)->entry.tree.index.rbe_color = 1; do {
(oright) = (tmp)->entry.tree.index.rbe_right; if (((tmp)->
entry.tree.index.rbe_right = (oright)->entry.tree.index.rbe_left
)) { ((oright)->entry.tree.index.rbe_left)->entry.tree.
index.rbe_parent = (tmp); } do {} while (0); if (((oright)->
entry.tree.index.rbe_parent = (tmp)->entry.tree.index.rbe_parent
)) { if ((tmp) == ((tmp)->entry.tree.index.rbe_parent)->
entry.tree.index.rbe_left) ((tmp)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_left = (oright); else ((tmp)->entry
.tree.index.rbe_parent)->entry.tree.index.rbe_right = (oright
); } else (head)->rbh_root = (oright); (oright)->entry.
tree.index.rbe_left = (tmp); (tmp)->entry.tree.index.rbe_parent
= (oright); do {} while (0); if (((oright)->entry.tree.index
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.tree.index.rbe_left; } (tmp)->entry.tree.index.rbe_color
= (parent)->entry.tree.index.rbe_color; (parent)->entry
.tree.index.rbe_color = 0; if ((tmp)->entry.tree.index.rbe_left
) ((tmp)->entry.tree.index.rbe_left)->entry.tree.index.
rbe_color = 0; do { (tmp) = (parent)->entry.tree.index.rbe_left
; if (((parent)->entry.tree.index.rbe_left = (tmp)->entry
.tree.index.rbe_right)) { ((tmp)->entry.tree.index.rbe_right
)->entry.tree.index.rbe_parent = (parent); } do {} while (
0); if (((tmp)->entry.tree.index.rbe_parent = (parent)->
entry.tree.index.rbe_parent)) { if ((parent) == ((parent)->
entry.tree.index.rbe_parent)->entry.tree.index.rbe_left) (
(parent)->entry.tree.index.rbe_parent)->entry.tree.index
.rbe_left = (tmp); else ((parent)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.tree.index.rbe_right = (parent); (parent
)->entry.tree.index.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.tree.index.rbe_parent)) do {} while (0); }
while (0); elm = (head)->rbh_root; break; } } } if (elm) (
elm)->entry.tree.index.rbe_color = 0; } __attribute__((__unused__
)) static struct prefix * prefix_index_RB_REMOVE(struct prefix_index
*head, struct prefix *elm) { struct prefix *child, *parent, *
old = elm; int color; if ((elm)->entry.tree.index.rbe_left
== ((void *)0)) child = (elm)->entry.tree.index.rbe_right
; else if ((elm)->entry.tree.index.rbe_right == ((void *)0
)) child = (elm)->entry.tree.index.rbe_left; else { struct
prefix *left; elm = (elm)->entry.tree.index.rbe_right; while
((left = (elm)->entry.tree.index.rbe_left)) elm = left; child
= (elm)->entry.tree.index.rbe_right; parent = (elm)->entry
.tree.index.rbe_parent; color = (elm)->entry.tree.index.rbe_color
; if (child) (child)->entry.tree.index.rbe_parent = parent
; if (parent) { if ((parent)->entry.tree.index.rbe_left ==
elm) (parent)->entry.tree.index.rbe_left = child; else (parent
)->entry.tree.index.rbe_right = child; do {} while (0); } else
(head)->rbh_root = child; if ((elm)->entry.tree.index.
rbe_parent == old) parent = elm; (elm)->entry.tree.index =
(old)->entry.tree.index; if ((old)->entry.tree.index.rbe_parent
) { if (((old)->entry.tree.index.rbe_parent)->entry.tree
.index.rbe_left == old) ((old)->entry.tree.index.rbe_parent
)->entry.tree.index.rbe_left = elm; else ((old)->entry.
tree.index.rbe_parent)->entry.tree.index.rbe_right = elm; do
{} while (0); } else (head)->rbh_root = elm; ((old)->entry
.tree.index.rbe_left)->entry.tree.index.rbe_parent = elm; if
((old)->entry.tree.index.rbe_right) ((old)->entry.tree
.index.rbe_right)->entry.tree.index.rbe_parent = elm; if (
parent) { left = parent; do { do {} while (0); } while ((left
= (left)->entry.tree.index.rbe_parent)); } goto color; } parent
= (elm)->entry.tree.index.rbe_parent; color = (elm)->entry
.tree.index.rbe_color; if (child) (child)->entry.tree.index
.rbe_parent = parent; if (parent) { if ((parent)->entry.tree
.index.rbe_left == elm) (parent)->entry.tree.index.rbe_left
= child; else (parent)->entry.tree.index.rbe_right = child
; do {} while (0); } else (head)->rbh_root = child; color:
if (color == 0) prefix_index_RB_REMOVE_COLOR(head, parent, child
); return (old); } __attribute__((__unused__)) static struct prefix
* prefix_index_RB_INSERT(struct prefix_index *head, struct prefix
*elm) { struct prefix *tmp; struct prefix *parent = ((void *
)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent
= tmp; comp = (prefix_index_cmp)(elm, parent); if (comp <
0) tmp = (tmp)->entry.tree.index.rbe_left; else if (comp >
0) tmp = (tmp)->entry.tree.index.rbe_right; else return (
tmp); } do { (elm)->entry.tree.index.rbe_parent = parent; (
elm)->entry.tree.index.rbe_left = (elm)->entry.tree.index
.rbe_right = ((void *)0); (elm)->entry.tree.index.rbe_color
= 1; } while (0); if (parent != ((void *)0)) { if (comp <
0) (parent)->entry.tree.index.rbe_left = elm; else (parent
)->entry.tree.index.rbe_right = elm; do {} while (0); } else
(head)->rbh_root = elm; prefix_index_RB_INSERT_COLOR(head
, elm); return (((void *)0)); } __attribute__((__unused__)) static
struct prefix * prefix_index_RB_FIND(struct prefix_index *head
, struct prefix *elm) { struct prefix *tmp = (head)->rbh_root
; int comp; while (tmp) { comp = prefix_index_cmp(elm, tmp); if
(comp < 0) tmp = (tmp)->entry.tree.index.rbe_left; else
if (comp > 0) tmp = (tmp)->entry.tree.index.rbe_right;
else return (tmp); } return (((void *)0)); } __attribute__((
__unused__)) static struct prefix * prefix_index_RB_NFIND(struct
prefix_index *head, struct prefix *elm) { struct prefix *tmp
= (head)->rbh_root; struct prefix *res = ((void *)0); int
comp; while (tmp) { comp = prefix_index_cmp(elm, tmp); if (comp
< 0) { res = tmp; tmp = (tmp)->entry.tree.index.rbe_left
; } else if (comp > 0) tmp = (tmp)->entry.tree.index.rbe_right
; else return (tmp); } return (res); } __attribute__((__unused__
)) static struct prefix * prefix_index_RB_NEXT(struct prefix *
elm) { if ((elm)->entry.tree.index.rbe_right) { elm = (elm
)->entry.tree.index.rbe_right; while ((elm)->entry.tree
.index.rbe_left) elm = (elm)->entry.tree.index.rbe_left; }
else { if ((elm)->entry.tree.index.rbe_parent && (
elm == ((elm)->entry.tree.index.rbe_parent)->entry.tree
.index.rbe_left)) elm = (elm)->entry.tree.index.rbe_parent
; else { while ((elm)->entry.tree.index.rbe_parent &&
(elm == ((elm)->entry.tree.index.rbe_parent)->entry.tree
.index.rbe_right)) elm = (elm)->entry.tree.index.rbe_parent
; elm = (elm)->entry.tree.index.rbe_parent; } } return (elm
); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_PREV
(struct prefix *elm) { if ((elm)->entry.tree.index.rbe_left
) { elm = (elm)->entry.tree.index.rbe_left; while ((elm)->
entry.tree.index.rbe_right) elm = (elm)->entry.tree.index.
rbe_right; } else { if ((elm)->entry.tree.index.rbe_parent
&& (elm == ((elm)->entry.tree.index.rbe_parent)->
entry.tree.index.rbe_right)) elm = (elm)->entry.tree.index
.rbe_parent; else { while ((elm)->entry.tree.index.rbe_parent
&& (elm == ((elm)->entry.tree.index.rbe_parent)->
entry.tree.index.rbe_left)) elm = (elm)->entry.tree.index.
rbe_parent; elm = (elm)->entry.tree.index.rbe_parent; } } return
(elm); } __attribute__((__unused__)) static struct prefix * prefix_index_RB_MINMAX
(struct prefix_index *head, int val) { struct prefix *tmp = (
head)->rbh_root; struct prefix *parent = ((void *)0); while
(tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry.
tree.index.rbe_left; else tmp = (tmp)->entry.tree.index.rbe_right
; } return (parent); }
856
857/*
858 * Search for specified prefix of a peer. Returns NULL if not found.
859 */
860struct prefix *
861prefix_get(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
862 struct bgpd_addr *prefix, int prefixlen)
863{
864 struct rib_entry *re;
865
866 re = rib_get_addr(rib, prefix, prefixlen);
867 if (re == NULL((void *)0))
868 return (NULL((void *)0));
869 return (prefix_bypeer(re, peer, path_id));
870}
871
872/*
873 * Search for specified prefix in the peer prefix_index.
874 * Returns NULL if not found.
875 */
876struct prefix *
877prefix_adjout_get(struct rde_peer *peer, uint32_t path_id_tx,
878 struct pt_entry *pte)
879{
880 struct prefix xp;
881
882 memset(&xp, 0, sizeof(xp));
883 xp.pt = pte;
884 xp.path_id_tx = path_id_tx;
885
886 return RB_FIND(prefix_index, &peer->adj_rib_out, &xp)prefix_index_RB_FIND(&peer->adj_rib_out, &xp);
887}
888
889/*
890 * Lookup a prefix without considering path_id in the peer prefix_index.
891 * Returns NULL if not found.
892 */
893struct prefix *
894prefix_adjout_first(struct rde_peer *peer, struct pt_entry *pte)
895{
896 struct prefix xp, *np;
897
898 memset(&xp, 0, sizeof(xp));
899 xp.pt = pte;
900
901 np = RB_NFIND(prefix_index, &peer->adj_rib_out, &xp)prefix_index_RB_NFIND(&peer->adj_rib_out, &xp);
902 if (np == NULL((void *)0) || pt_prefix_cmp(np->pt, xp.pt) != 0)
903 return NULL((void *)0);
904 return np;
905}
906
907/*
908 * Return next prefix after a lookup that is actually an update.
909 */
910struct prefix *
911prefix_adjout_next(struct rde_peer *peer, struct prefix *p)
912{
913 struct prefix *np;
914
915 np = RB_NEXT(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_NEXT(p);
916 if (np == NULL((void *)0) || np->pt != p->pt)
917 return NULL((void *)0);
918 return np;
919}
920
921/*
922 * Lookup addr/prefixlen in the peer prefix_index. Returns first match.
923 * Returns NULL if not found.
924 */
925struct prefix *
926prefix_adjout_lookup(struct rde_peer *peer, struct bgpd_addr *addr, int plen)
927{
928 return prefix_adjout_first(peer, pt_fill(addr, plen));
929}
930
931/*
932 * Lookup addr in the peer prefix_index. Returns first match.
933 * Returns NULL if not found.
934 */
935struct prefix *
936prefix_adjout_match(struct rde_peer *peer, struct bgpd_addr *addr)
937{
938 struct prefix *p;
939 int i;
940
941 switch (addr->aid) {
942 case AID_INET1:
943 case AID_VPN_IPv43:
944 for (i = 32; i >= 0; i--) {
945 p = prefix_adjout_lookup(peer, addr, i);
946 if (p != NULL((void *)0))
947 return p;
948 }
949 break;
950 case AID_INET62:
951 case AID_VPN_IPv64:
952 for (i = 128; i >= 0; i--) {
953 p = prefix_adjout_lookup(peer, addr, i);
954 if (p != NULL((void *)0))
955 return p;
956 }
957 break;
958 default:
959 fatalx("%s: unknown af", __func__);
960 }
961 return NULL((void *)0);
962}
963
964/*
965 * Update a prefix.
966 * Return 1 if prefix was newly added, 0 if it was just changed.
967 */
968int
969prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
970 uint32_t path_id_tx, struct filterstate *state, struct bgpd_addr *prefix,
971 int prefixlen)
972{
973 struct rde_aspath *asp, *nasp = &state->aspath;
974 struct rde_community *comm, *ncomm = &state->communities;
975 struct prefix *p;
976
977 /*
978 * First try to find a prefix in the specified RIB.
979 */
980 if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL((void *)0)) {
981 if (path_id_tx != p->path_id_tx)
982 fatalx("path_id mismatch");
983 if (prefix_nexthop(p) == state->nexthop &&
984 prefix_nhflags(p) == state->nhflags &&
985 communities_equal(ncomm, prefix_communities(p)) &&
986 path_compare(nasp, prefix_aspath(p)) == 0) {
987 /* no change, update last change */
988 p->lastchange = getmonotime();
989 p->validation_state = state->vstate;
990 return (0);
991 }
992 }
993
994 /*
995 * Either the prefix does not exist or the path changed.
996 * In both cases lookup the new aspath to make sure it is not
997 * already in the RIB.
998 */
999 if ((asp = path_lookup(nasp)) == NULL((void *)0)) {
1000 /* Path not available, create and link a new one. */
1001 asp = path_copy(path_get(), nasp);
1002 path_link(asp);
1003 }
1004
1005 if ((comm = communities_lookup(ncomm)) == NULL((void *)0)) {
1006 /* Communities not available, create and link a new one. */
1007 comm = communities_link(ncomm);
1008 }
1009
1010 /* If the prefix was found move it else add it to the RIB. */
1011 if (p != NULL((void *)0))
1012 return (prefix_move(p, peer, asp, comm, state->nexthop,
1013 state->nhflags, state->vstate));
1014 else
1015 return (prefix_add(prefix, prefixlen, rib, peer, path_id,
1016 path_id_tx, asp, comm, state->nexthop, state->nhflags,
1017 state->vstate));
1018}
1019
1020/*
1021 * Adds or updates a prefix.
1022 */
1023static int
1024prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
1025 struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
1026 struct rde_aspath *asp, struct rde_community *comm,
1027 struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
1028{
1029 struct pt_entry *pte;
1030 struct prefix *p;
1031 struct rib_entry *re;
1032
1033 pte = pt_get(prefix, prefixlen);
1034 if (pte == NULL((void *)0))
1035 pte = pt_add(prefix, prefixlen);
1036 re = rib_get(rib, pte);
1037 if (re == NULL((void *)0))
1038 re = rib_add(rib, pte);
1039
1040 p = prefix_alloc();
1041 prefix_link(p, re, re->prefix, peer, path_id, path_id_tx, asp, comm,
1042 nexthop, nhflags, vstate);
1043
1044 /* add possible pftable reference form aspath */
1045 if (asp && asp->pftableid)
1046 rde_pftable_add(asp->pftableid, p);
1047 /* make route decision */
1048 prefix_evaluate(re, p, NULL((void *)0));
1049 return (1);
1050}
1051
1052/*
1053 * Move the prefix to the specified as path, removes the old asp if needed.
1054 */
1055static int
1056prefix_move(struct prefix *p, struct rde_peer *peer,
1057 struct rde_aspath *asp, struct rde_community *comm,
1058 struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
1059{
1060 struct prefix *np;
1061
1062 if (p->flags & PREFIX_FLAG_ADJOUT0x10)
1063 fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__);
1064
1065 if (peer != prefix_peer(p))
1066 fatalx("prefix_move: cross peer move");
1067
1068 /* add new prefix node */
1069 np = prefix_alloc();
1070 prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, p->path_id_tx,
1071 asp, comm, nexthop, nhflags, vstate);
1072
1073 /* add possible pftable reference from new aspath */
1074 if (asp && asp->pftableid)
1075 rde_pftable_add(asp->pftableid, np);
1076
1077 /*
1078 * no need to update the peer prefix count because we are only moving
1079 * the prefix without changing the peer.
1080 */
1081 prefix_evaluate(prefix_re(np), np, p);
1082
1083 /* remove possible pftable reference from old path */
1084 if (p->aspath && p->aspath->pftableid)
1085 rde_pftable_del(p->aspath->pftableid, p);
1086
1087 /* remove old prefix node */
1088 prefix_unlink(p);
1089 prefix_free(p);
1090
1091 return (0);
1092}
1093
1094/*
1095 * Removes a prefix from the specified RIB. If the parent objects -- rib_entry
1096 * or pt_entry -- become empty remove them too.
1097 */
1098int
1099prefix_withdraw(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
1100 struct bgpd_addr *prefix, int prefixlen)
1101{
1102 struct prefix *p;
1103 struct rde_aspath *asp;
1104
1105 p = prefix_get(rib, peer, path_id, prefix, prefixlen);
1106 if (p == NULL((void *)0)) /* Got a dummy withdrawn request. */
1107 return (0);
1108
1109 if (p->flags & PREFIX_FLAG_ADJOUT0x10)
1110 fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__);
1111 asp = prefix_aspath(p);
1112 if (asp && asp->pftableid)
1113 /* only prefixes in the local RIB were pushed into pf */
1114 rde_pftable_del(asp->pftableid, p);
1115
1116 prefix_destroy(p);
1117
1118 return (1);
1119}
1120
1121/*
1122 * Special functions for flowspec until full integration is available.
1123 * This just directly feeds the prefixes into the Adj-RIB-Out bypassing
1124 * Adj-RIB-In and Loc-RIB for now.
1125 */
1126int
1127prefix_flowspec_update(struct rde_peer *peer, struct filterstate *state,
1128 struct pt_entry *pte, uint32_t path_id_tx)
1129{
1130 struct rde_aspath *asp, *nasp;
1131 struct rde_community *comm, *ncomm;
1132 struct rib_entry *re;
1133 struct prefix *new, *old;
1134
1135 re = rib_get(&flowrib, pte);
1136 if (re == NULL((void *)0))
1137 re = rib_add(&flowrib, pte);
1138
1139 old = prefix_bypeer(re, peer, 0);
1140 new = prefix_alloc();
1141
1142 nasp = &state->aspath;
1143 ncomm = &state->communities;
1144 if ((asp = path_lookup(nasp)) == NULL((void *)0)) {
1145 /* Path not available, create and link a new one. */
1146 asp = path_copy(path_get(), nasp);
1147 path_link(asp);
1148 }
1149 if ((comm = communities_lookup(ncomm)) == NULL((void *)0)) {
1150 /* Communities not available, create and link a new one. */
1151 comm = communities_link(ncomm);
1152 }
1153
1154 prefix_link(new, re, re->prefix, peer, 0, path_id_tx, asp, comm,
1155 NULL((void *)0), 0, 0);
1156 TAILQ_INSERT_HEAD(&re->prefix_h, new, entry.list.rib)do { if (((new)->entry.list.rib.tqe_next = (&re->prefix_h
)->tqh_first) != ((void *)0)) (&re->prefix_h)->tqh_first
->entry.list.rib.tqe_prev = &(new)->entry.list.rib.
tqe_next; else (&re->prefix_h)->tqh_last = &(new
)->entry.list.rib.tqe_next; (&re->prefix_h)->tqh_first
= (new); (new)->entry.list.rib.tqe_prev = &(&re->
prefix_h)->tqh_first; } while (0)
;
1157
1158 rde_generate_updates(re, new, old, EVAL_DEFAULT);
1159
1160 if (old != NULL((void *)0)) {
1161 TAILQ_REMOVE(&re->prefix_h, old, entry.list.rib)do { if (((old)->entry.list.rib.tqe_next) != ((void *)0)) (
old)->entry.list.rib.tqe_next->entry.list.rib.tqe_prev =
(old)->entry.list.rib.tqe_prev; else (&re->prefix_h
)->tqh_last = (old)->entry.list.rib.tqe_prev; *(old)->
entry.list.rib.tqe_prev = (old)->entry.list.rib.tqe_next; ;
; } while (0)
;
1162 prefix_unlink(old);
1163 prefix_free(old);
1164 return 0;
1165 }
1166 return 1;
1167}
1168
1169/*
1170 * Remove a possible flowspec prefix from all Adj-RIB-Outs.
1171 */
1172int
1173prefix_flowspec_withdraw(struct rde_peer *peer, struct pt_entry *pte)
1174{
1175 struct rib_entry *re;
1176 struct prefix *p;
1177
1178 re = rib_get(&flowrib, pte);
1179 if (re == NULL((void *)0))
1180 return 0;
1181 p = prefix_bypeer(re, peer, 0);
1182 if (p == NULL((void *)0))
1183 return 0;
1184 rde_generate_updates(re, NULL((void *)0), p, EVAL_DEFAULT);
1185 TAILQ_REMOVE(&re->prefix_h, p, entry.list.rib)do { if (((p)->entry.list.rib.tqe_next) != ((void *)0)) (p
)->entry.list.rib.tqe_next->entry.list.rib.tqe_prev = (
p)->entry.list.rib.tqe_prev; else (&re->prefix_h)->
tqh_last = (p)->entry.list.rib.tqe_prev; *(p)->entry.list
.rib.tqe_prev = (p)->entry.list.rib.tqe_next; ; ; } while (
0)
;
1186 prefix_unlink(p);
1187 prefix_free(p);
1188 return 1;
1189}
1190
1191/*
1192 * Push all flowspec rules into a newly available Adj-RIB-Out.
1193 */
1194void
1195prefix_flowspec_dump(uint8_t aid, void *arg,
1196 void (*call)(struct rib_entry *, void *), void (*done)(void *, uint8_t))
1197{
1198 struct rib_entry *re, *next;
1199
1200 RB_FOREACH_SAFE(re, rib_tree, rib_tree(&flowrib), next)for ((re) = rib_tree_RB_MINMAX(rib_tree(&flowrib), -1); (
(re) != ((void *)0)) && ((next) = rib_tree_RB_NEXT(re
), 1); (re) = (next))
{
1201 if (aid != AID_UNSPEC0 && aid != re->prefix->aid)
1202 continue;
1203 call(re, arg);
1204 }
1205 if (done != NULL((void *)0))
1206 done(arg, aid);
1207}
1208
1209/*
1210 * Insert an End-of-RIB marker into the update queue.
1211 */
1212void
1213prefix_add_eor(struct rde_peer *peer, uint8_t aid)
1214{
1215 struct prefix *p;
1216
1217 p = prefix_alloc();
1218 p->flags = PREFIX_FLAG_ADJOUT0x10 | PREFIX_FLAG_UPDATE0x02 | PREFIX_FLAG_EOR0x20;
1219 if (RB_INSERT(prefix_tree, &peer->updates[aid], p)prefix_tree_RB_INSERT(&peer->updates[aid], p) != NULL((void *)0))
1220 /* no need to add if EoR marker already present */
1221 prefix_free(p);
1222 /* EOR marker is not inserted into the adj_rib_out index */
1223}
1224
1225/*
1226 * Put a prefix from the Adj-RIB-Out onto the update queue.
1227 */
1228void
1229prefix_adjout_update(struct prefix *p, struct rde_peer *peer,
1230 struct filterstate *state, struct pt_entry *pte, uint32_t path_id_tx)
1231{
1232 struct rde_aspath *asp;
1233 struct rde_community *comm;
1234
1235 if (p == NULL((void *)0)) {
1236 p = prefix_alloc();
1237 /* initially mark DEAD so code below is skipped */
1238 p->flags |= PREFIX_FLAG_ADJOUT0x10 | PREFIX_FLAG_DEAD0x04;
1239
1240 p->pt = pt_ref(pte);
1241 p->peer = peer;
1242 p->path_id_tx = path_id_tx;
1243
1244 if (RB_INSERT(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_INSERT(&peer->adj_rib_out, p) != NULL((void *)0))
1245 fatalx("%s: RB index invariant violated", __func__);
1246 }
1247
1248 if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0)
1249 fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
1250 if ((p->flags & (PREFIX_FLAG_WITHDRAW0x01 | PREFIX_FLAG_DEAD0x04)) == 0) {
1251 /*
1252 * XXX for now treat a different path_id_tx like different
1253 * attributes and force out an update. It is unclear how
1254 * common it is to have equivalent updates from alternative
1255 * paths.
1256 */
1257 if (p->path_id_tx == path_id_tx &&
1258 prefix_nhflags(p) == state->nhflags &&
1259 prefix_nexthop(p) == state->nexthop &&
1260 communities_equal(&state->communities,
1261 prefix_communities(p)) &&
1262 path_compare(&state->aspath, prefix_aspath(p)) == 0) {
1263 /* nothing changed */
1264 p->validation_state = state->vstate;
1265 p->lastchange = getmonotime();
1266 p->flags &= ~PREFIX_FLAG_STALE0x08;
1267 return;
1268 }
1269
1270 /* if pending update unhook it before it is unlinked */
1271 if (p->flags & PREFIX_FLAG_UPDATE0x02) {
1272 RB_REMOVE(prefix_tree, &peer->updates[pte->aid], p)prefix_tree_RB_REMOVE(&peer->updates[pte->aid], p);
1273 peer->stats.pending_update--;
1274 }
1275
1276 /* unlink prefix so it can be relinked below */
1277 prefix_unlink(p);
1278 peer->stats.prefix_out_cnt--;
1279 }
1280 if (p->flags & PREFIX_FLAG_WITHDRAW0x01) {
1281 RB_REMOVE(prefix_tree, &peer->withdraws[pte->aid], p)prefix_tree_RB_REMOVE(&peer->withdraws[pte->aid], p
)
;
1282 peer->stats.pending_withdraw--;
1283 }
1284
1285 /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
1286 p->flags &= ~PREFIX_FLAG_MASK0x0f;
1287
1288 /* update path_id_tx now that the prefix is unlinked */
1289 if (p->path_id_tx != path_id_tx) {
1290 /* path_id_tx is part of the index so remove and re-insert p */
1291 RB_REMOVE(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_REMOVE(&peer->adj_rib_out, p);
1292 p->path_id_tx = path_id_tx;
1293 if (RB_INSERT(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_INSERT(&peer->adj_rib_out, p) != NULL((void *)0))
1294 fatalx("%s: RB index invariant violated", __func__);
1295 }
1296
1297 if ((asp = path_lookup(&state->aspath)) == NULL((void *)0)) {
1298 /* Path not available, create and link a new one. */
1299 asp = path_copy(path_get(), &state->aspath);
1300 path_link(asp);
1301 }
1302
1303 if ((comm = communities_lookup(&state->communities)) == NULL((void *)0)) {
1304 /* Communities not available, create and link a new one. */
1305 comm = communities_link(&state->communities);
1306 }
1307
1308 prefix_link(p, NULL((void *)0), p->pt, peer, 0, p->path_id_tx, asp, comm,
1309 state->nexthop, state->nhflags, state->vstate);
1310 peer->stats.prefix_out_cnt++;
1311
1312 if (p->flags & PREFIX_FLAG_MASK0x0f)
1313 fatalx("%s: bad flags %x", __func__, p->flags);
1314 p->flags |= PREFIX_FLAG_UPDATE0x02;
1315 if (RB_INSERT(prefix_tree, &peer->updates[pte->aid], p)prefix_tree_RB_INSERT(&peer->updates[pte->aid], p) != NULL((void *)0))
1316 fatalx("%s: RB tree invariant violated", __func__);
1317 peer->stats.pending_update++;
1318}
1319
1320/*
1321 * Withdraw a prefix from the Adj-RIB-Out, this unlinks the aspath but leaves
1322 * the prefix in the RIB linked to the peer withdraw list.
1323 */
1324void
1325prefix_adjout_withdraw(struct prefix *p)
1326{
1327 struct rde_peer *peer = prefix_peer(p);
1328
1329 if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0)
1330 fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
1331
1332 /* already a withdraw, shortcut */
1333 if (p->flags & PREFIX_FLAG_WITHDRAW0x01) {
1334 p->lastchange = getmonotime();
1335 p->flags &= ~PREFIX_FLAG_STALE0x08;
1336 return;
1337 }
1338 /* pending update just got withdrawn */
1339 if (p->flags & PREFIX_FLAG_UPDATE0x02) {
1340 RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->updates[p->pt->aid]
, p)
;
1341 peer->stats.pending_update--;
1342 }
1343 /* unlink prefix if it was linked (not a withdraw or dead) */
1344 if ((p->flags & (PREFIX_FLAG_WITHDRAW0x01 | PREFIX_FLAG_DEAD0x04)) == 0) {
1345 prefix_unlink(p);
1346 peer->stats.prefix_out_cnt--;
1347 }
1348
1349 /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
1350 p->flags &= ~PREFIX_FLAG_MASK0x0f;
1351 p->lastchange = getmonotime();
1352
1353 p->flags |= PREFIX_FLAG_WITHDRAW0x01;
1354 if (RB_INSERT(prefix_tree, &peer->withdraws[p->pt->aid], p)prefix_tree_RB_INSERT(&peer->withdraws[p->pt->aid
], p)
!= NULL((void *)0))
1355 fatalx("%s: RB tree invariant violated", __func__);
1356 peer->stats.pending_withdraw++;
1357}
1358
1359void
1360prefix_adjout_destroy(struct prefix *p)
1361{
1362 struct rde_peer *peer = prefix_peer(p);
1363
1364 if ((p->flags & PREFIX_FLAG_ADJOUT0x10) == 0)
1365 fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
1366
1367 if (p->flags & PREFIX_FLAG_EOR0x20) {
1368 /* EOR marker is not linked in the index */
1369 prefix_free(p);
1370 return;
1371 }
1372
1373 if (p->flags & PREFIX_FLAG_WITHDRAW0x01) {
1374 RB_REMOVE(prefix_tree, &peer->withdraws[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->withdraws[p->pt->aid
], p)
;
1375 peer->stats.pending_withdraw--;
1376 }
1377 if (p->flags & PREFIX_FLAG_UPDATE0x02) {
1378 RB_REMOVE(prefix_tree, &peer->updates[p->pt->aid], p)prefix_tree_RB_REMOVE(&peer->updates[p->pt->aid]
, p)
;
1379 peer->stats.pending_update--;
1380 }
1381 /* unlink prefix if it was linked (not a withdraw or dead) */
1382 if ((p->flags & (PREFIX_FLAG_WITHDRAW0x01 | PREFIX_FLAG_DEAD0x04)) == 0) {
1383 prefix_unlink(p);
1384 peer->stats.prefix_out_cnt--;
1385 }
1386
1387 /* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
1388 p->flags &= ~PREFIX_FLAG_MASK0x0f;
1389
1390 if (prefix_is_locked(p)) {
1391 /* mark prefix dead but leave it for prefix_restart */
1392 p->flags |= PREFIX_FLAG_DEAD0x04;
1393 } else {
1394 RB_REMOVE(prefix_index, &peer->adj_rib_out, p)prefix_index_RB_REMOVE(&peer->adj_rib_out, p);
1395 /* remove the last prefix reference before free */
1396 pt_unref(p->pt);
1397 prefix_free(p);
1398 }
1399}
1400
1401static struct prefix *
1402prefix_restart(struct rib_context *ctx)
1403{
1404 struct prefix *p = NULL((void *)0);
1405
1406 if (ctx->ctx_p)
1407 p = prefix_unlock(ctx->ctx_p);
1408
1409 if (p && prefix_is_dead(p)) {
1410 struct prefix *next;
1411
1412 next = RB_NEXT(prefix_index, unused, p)prefix_index_RB_NEXT(p);
1413 prefix_adjout_destroy(p);
1414 p = next;
1415 }
1416 ctx->ctx_p = NULL((void *)0);
1417 return p;
1418}
1419
1420static void
1421prefix_dump_r(struct rib_context *ctx)
1422{
1423 struct prefix *p, *next;
1424 struct rde_peer *peer;
1425 unsigned int i;
1426
1427 if ((peer = peer_get(ctx->ctx_id)) == NULL((void *)0))
1428 goto done;
1429
1430 if (ctx->ctx_p == NULL((void *)0) && ctx->ctx_subtree.aid == AID_UNSPEC0)
1431 p = RB_MIN(prefix_index, &peer->adj_rib_out)prefix_index_RB_MINMAX(&peer->adj_rib_out, -1);
1432 else
1433 p = prefix_restart(ctx);
1434
1435 for (i = 0; p != NULL((void *)0); p = next) {
1436 next = RB_NEXT(prefix_index, unused, p)prefix_index_RB_NEXT(p);
1437 if (prefix_is_dead(p))
1438 continue;
1439 if (ctx->ctx_aid != AID_UNSPEC0 &&
1440 ctx->ctx_aid != p->pt->aid)
1441 continue;
1442 if (ctx->ctx_subtree.aid != AID_UNSPEC0) {
1443 struct bgpd_addr addr;
1444 pt_getaddr(p->pt, &addr);
1445 if (prefix_compare(&ctx->ctx_subtree, &addr,
1446 ctx->ctx_subtreelen) != 0)
1447 /* left subtree, walk is done */
1448 break;
1449 }
1450 if (ctx->ctx_count && i++ >= ctx->ctx_count &&
1451 !prefix_is_locked(p)) {
1452 /* store and lock last element */
1453 ctx->ctx_p = prefix_lock(p);
1454 return;
1455 }
1456 ctx->ctx_prefix_call(p, ctx->ctx_arg);
1457 }
1458
1459done:
1460 if (ctx->ctx_done)
1461 ctx->ctx_done(ctx->ctx_arg, ctx->ctx_aid);
1462 LIST_REMOVE(ctx, entry)do { if ((ctx)->entry.le_next != ((void *)0)) (ctx)->entry
.le_next->entry.le_prev = (ctx)->entry.le_prev; *(ctx)->
entry.le_prev = (ctx)->entry.le_next; ; ; } while (0)
;
1463 free(ctx);
1464}
1465
1466int
1467prefix_dump_new(struct rde_peer *peer, uint8_t aid, unsigned int count,
1468 void *arg, void (*upcall)(struct prefix *, void *),
1469 void (*done)(void *, uint8_t), int (*throttle)(void *))
1470{
1471 struct rib_context *ctx;
1472
1473 if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void *)0))
1474 return -1;
1475 ctx->ctx_id = peer->conf.id;
1476 ctx->ctx_aid = aid;
1477 ctx->ctx_count = count;
1478 ctx->ctx_arg = arg;
1479 ctx->ctx_prefix_call = upcall;
1480 ctx->ctx_done = done;
1481 ctx->ctx_throttle = throttle;
1482
1483 LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first
) != ((void *)0)) (&rib_dumps)->lh_first->entry.le_prev
= &(ctx)->entry.le_next; (&rib_dumps)->lh_first
= (ctx); (ctx)->entry.le_prev = &(&rib_dumps)->
lh_first; } while (0)
;
1484
1485 /* requested a sync traversal */
1486 if (count == 0)
1487 prefix_dump_r(ctx);
1488
1489 return 0;
1490}
1491
1492int
1493prefix_dump_subtree(struct rde_peer *peer, struct bgpd_addr *subtree,
1494 uint8_t subtreelen, unsigned int count, void *arg,
1495 void (*upcall)(struct prefix *, void *), void (*done)(void *, uint8_t),
1496 int (*throttle)(void *))
1497{
1498 struct rib_context *ctx;
1499 struct prefix xp;
1500
1501 if ((ctx = calloc(1, sizeof(*ctx))) == NULL((void *)0))
1502 return -1;
1503 ctx->ctx_id = peer->conf.id;
1504 ctx->ctx_aid = subtree->aid;
1505 ctx->ctx_count = count;
1506 ctx->ctx_arg = arg;
1507 ctx->ctx_prefix_call = upcall;
1508 ctx->ctx_done = done;
1509 ctx->ctx_throttle = throttle;
1510 ctx->ctx_subtree = *subtree;
1511 ctx->ctx_subtreelen = subtreelen;
1512
1513 LIST_INSERT_HEAD(&rib_dumps, ctx, entry)do { if (((ctx)->entry.le_next = (&rib_dumps)->lh_first
) != ((void *)0)) (&rib_dumps)->lh_first->entry.le_prev
= &(ctx)->entry.le_next; (&rib_dumps)->lh_first
= (ctx); (ctx)->entry.le_prev = &(&rib_dumps)->
lh_first; } while (0)
;
1514
1515 /* lookup start of subtree */
1516 memset(&xp, 0, sizeof(xp));
1517 xp.pt = pt_fill(subtree, subtreelen);
1518 ctx->ctx_p = RB_NFIND(prefix_index, &peer->adj_rib_out, &xp)prefix_index_RB_NFIND(&peer->adj_rib_out, &xp);
1519 if (ctx->ctx_p)
1520 prefix_lock(ctx->ctx_p);
1521
1522 /* requested a sync traversal */
1523 if (count == 0)
1524 prefix_dump_r(ctx);
1525
1526 return 0;
1527}
1528
1529/*
1530 * Searches in the prefix list of specified rib_entry for a prefix entry
1531 * belonging to the peer peer. Returns NULL if no match found.
1532 */
1533struct prefix *
1534prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, uint32_t path_id)
1535{
1536 struct prefix *p;
1537
1538 TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib)for((p) = ((&re->prefix_h)->tqh_first); (p) != ((void
*)0); (p) = ((p)->entry.list.rib.tqe_next))
1539 if (prefix_peer(p) == peer && p->path_id == path_id)
1540 return (p);
1541 return (NULL((void *)0));
1542}
1543
1544/* kill a prefix. */
1545void
1546prefix_destroy(struct prefix *p)
1547{
1548 /* make route decision */
1549 prefix_evaluate(prefix_re(p), NULL((void *)0), p);
1550
1551 prefix_unlink(p);
1552 prefix_free(p);
14
Calling 'prefix_free'
16
Returning; memory was released via 1st parameter
1553}
1554
1555/*
1556 * Link a prefix into the different parent objects.
1557 */
1558static void
1559prefix_link(struct prefix *p, struct rib_entry *re, struct pt_entry *pt,
1560 struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
1561 struct rde_aspath *asp, struct rde_community *comm,
1562 struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
1563{
1564 if (re)
1565 p->entry.list.re = re;
1566 p->aspath = path_ref(asp);
1567 p->communities = communities_ref(comm);
1568 p->peer = peer;
1569 p->pt = pt_ref(pt);
1570 p->path_id = path_id;
1571 p->path_id_tx = path_id_tx;
1572 p->validation_state = vstate;
1573 p->nhflags = nhflags;
1574 p->nexthop = nexthop_ref(nexthop);
1575 nexthop_link(p);
1576 p->lastchange = getmonotime();
1577}
1578
1579/*
1580 * Unlink a prefix from the different parent objects.
1581 */
1582static void
1583prefix_unlink(struct prefix *p)
1584{
1585 struct rib_entry *re = prefix_re(p);
1586
1587 /* destroy all references to other objects */
1588 /* remove nexthop ref ... */
1589 nexthop_unlink(p);
1590 nexthop_unref(p->nexthop);
1591 p->nexthop = NULL((void *)0);
1592 p->nhflags = 0;
1593 /* ... communities ... */
1594 communities_unref(p->communities);
1595 p->communities = NULL((void *)0);
1596 /* and unlink from aspath */
1597 path_unref(p->aspath);
1598 p->aspath = NULL((void *)0);
1599
1600 if (re && rib_empty(re))
1601 rib_remove(re);
1602
1603 pt_unref(p->pt);
1604}
1605
1606/* alloc and zero new entry. May not fail. */
1607static struct prefix *
1608prefix_alloc(void)
1609{
1610 struct prefix *p;
1611
1612 p = calloc(1, sizeof(*p));
1613 if (p == NULL((void *)0))
1614 fatal("prefix_alloc");
1615 rdemem.prefix_cnt++;
1616 return p;
1617}
1618
1619/* free a unlinked entry */
1620static void
1621prefix_free(struct prefix *p)
1622{
1623 rdemem.prefix_cnt--;
1624 free(p);
15
Memory is released
1625}
1626
1627/*
1628 * nexthop functions
1629 */
1630struct nexthop *nexthop_lookup(struct bgpd_addr *);
1631
1632/*
1633 * In BGP there exist two nexthops: the exit nexthop which was announced via
1634 * BGP and the true nexthop which is used in the FIB -- forward information
1635 * base a.k.a kernel routing table. When sending updates it is even more
1636 * confusing. In IBGP we pass the unmodified exit nexthop to the neighbors
1637 * while in EBGP normally the address of the router is sent. The exit nexthop
1638 * may be passed to the external neighbor if the neighbor and the exit nexthop
1639 * reside in the same subnet -- directly connected.
1640 */
1641
1642TAILQ_HEAD(nexthop_queue, nexthop)struct nexthop_queue { struct nexthop *tqh_first; struct nexthop
**tqh_last; }
nexthop_runners =
1643 TAILQ_HEAD_INITIALIZER(nexthop_runners){ ((void *)0), &(nexthop_runners).tqh_first };
1644
1645RB_HEAD(nexthop_tree, nexthop)struct nexthop_tree { struct nexthop *rbh_root; } nexthoptable =
1646 RB_INITIALIZER(&nexthoptree){ ((void *)0) };
1647RB_GENERATE_STATIC(nexthop_tree, nexthop, entry, nexthop_compare)__attribute__((__unused__)) static void nexthop_tree_RB_INSERT_COLOR
(struct nexthop_tree *head, struct nexthop *elm) { struct nexthop
*parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent
) && (parent)->entry.rbe_color == 1) { gparent = (
parent)->entry.rbe_parent; if (parent == (gparent)->entry
.rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp &&
(tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color =
0; do { (parent)->entry.rbe_color = 0; (gparent)->entry
.rbe_color = 1; } while (0); elm = gparent; continue; } if ((
parent)->entry.rbe_right == elm) { do { (tmp) = (parent)->
entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (parent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (parent)->entry.rbe_parent)) { if ((parent) == ((parent
)->entry.rbe_parent)->entry.rbe_left) ((parent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry
.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)->
entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } else { tmp
= (gparent)->entry.rbe_left; if (tmp && (tmp)->
entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (
parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color
= 1; } while (0); elm = gparent; continue; } if ((parent)->
entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left
; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right
)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } } (head->
rbh_root)->entry.rbe_color = 0; } __attribute__((__unused__
)) static void nexthop_tree_RB_REMOVE_COLOR(struct nexthop_tree
*head, struct nexthop *parent, struct nexthop *elm) { struct
nexthop *tmp; while ((elm == ((void *)0) || (elm)->entry.
rbe_color == 0) && elm != (head)->rbh_root) { if (
(parent)->entry.rbe_left == elm) { tmp = (parent)->entry
.rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->
entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while
(0); do { (tmp) = (parent)->entry.rbe_right; if (((parent
)->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->
entry.rbe_left)->entry.rbe_parent = (parent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do
{} while (0); if (((tmp)->entry.rbe_parent)) do {} while (
0); } while (0); tmp = (parent)->entry.rbe_right; } if (((
tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left
)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent
= (elm)->entry.rbe_parent; } else { if ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0) { struct nexthop *oleft; if ((oleft = (tmp)->entry.
rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry.rbe_color
= 1; do { (oleft) = (tmp)->entry.rbe_left; if (((tmp)->
entry.rbe_left = (oleft)->entry.rbe_right)) { ((oleft)->
entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while (
0); if (((oleft)->entry.rbe_parent = (tmp)->entry.rbe_parent
)) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left
) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oleft); else
((tmp)->entry.rbe_parent)->entry.rbe_right = (oleft); }
else (head)->rbh_root = (oleft); (oleft)->entry.rbe_right
= (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while (
0); if (((oleft)->entry.rbe_parent)) do {} while (0); } while
(0); tmp = (parent)->entry.rbe_right; } (tmp)->entry.rbe_color
= (parent)->entry.rbe_color; (parent)->entry.rbe_color
= 0; if ((tmp)->entry.rbe_right) ((tmp)->entry.rbe_right
)->entry.rbe_color = 0; do { (tmp) = (parent)->entry.rbe_right
; if (((parent)->entry.rbe_right = (tmp)->entry.rbe_left
)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); elm = (head)->rbh_root; break
; } } else { tmp = (parent)->entry.rbe_left; if ((tmp)->
entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (
parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent
)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp
)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry
.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry
.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) ==
((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
tmp = (parent)->entry.rbe_left; } if (((tmp)->entry.rbe_left
== ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color
== 0) && ((tmp)->entry.rbe_right == ((void *)0) ||
((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp
)->entry.rbe_color = 1; elm = parent; parent = (elm)->entry
.rbe_parent; } else { if ((tmp)->entry.rbe_left == ((void *
)0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) {
struct nexthop *oright; if ((oright = (tmp)->entry.rbe_right
)) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color
= 1; do { (oright) = (tmp)->entry.rbe_right; if (((tmp)->
entry.rbe_right = (oright)->entry.rbe_left)) { ((oright)->
entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while (
0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent
)) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left
) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oright);
else ((tmp)->entry.rbe_parent)->entry.rbe_right = (oright
); } else (head)->rbh_root = (oright); (oright)->entry.
rbe_left = (tmp); (tmp)->entry.rbe_parent = (oright); do {
} while (0); if (((oright)->entry.rbe_parent)) do {} while
(0); } while (0); tmp = (parent)->entry.rbe_left; } (tmp)
->entry.rbe_color = (parent)->entry.rbe_color; (parent)
->entry.rbe_color = 0; if ((tmp)->entry.rbe_left) ((tmp
)->entry.rbe_left)->entry.rbe_color = 0; do { (tmp) = (
parent)->entry.rbe_left; if (((parent)->entry.rbe_left =
(tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)->
entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->
entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent
) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent
)->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent
)->entry.rbe_parent)->entry.rbe_right = (tmp); } else (
head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent
); (parent)->entry.rbe_parent = (tmp); do {} while (0); if
(((tmp)->entry.rbe_parent)) do {} while (0); } while (0);
elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry
.rbe_color = 0; } __attribute__((__unused__)) static struct nexthop
* nexthop_tree_RB_REMOVE(struct nexthop_tree *head, struct nexthop
*elm) { struct nexthop *child, *parent, *old = elm; int color
; if ((elm)->entry.rbe_left == ((void *)0)) child = (elm)->
entry.rbe_right; else if ((elm)->entry.rbe_right == ((void
*)0)) child = (elm)->entry.rbe_left; else { struct nexthop
*left; elm = (elm)->entry.rbe_right; while ((left = (elm)
->entry.rbe_left)) elm = left; child = (elm)->entry.rbe_right
; parent = (elm)->entry.rbe_parent; color = (elm)->entry
.rbe_color; if (child) (child)->entry.rbe_parent = parent;
if (parent) { if ((parent)->entry.rbe_left == elm) (parent
)->entry.rbe_left = child; else (parent)->entry.rbe_right
= child; do {} while (0); } else (head)->rbh_root = child
; if ((elm)->entry.rbe_parent == old) parent = elm; (elm)->
entry = (old)->entry; if ((old)->entry.rbe_parent) { if
(((old)->entry.rbe_parent)->entry.rbe_left == old) ((old
)->entry.rbe_parent)->entry.rbe_left = elm; else ((old)
->entry.rbe_parent)->entry.rbe_right = elm; do {} while
(0); } else (head)->rbh_root = elm; ((old)->entry.rbe_left
)->entry.rbe_parent = elm; if ((old)->entry.rbe_right) (
(old)->entry.rbe_right)->entry.rbe_parent = elm; if (parent
) { left = parent; do { do {} while (0); } while ((left = (left
)->entry.rbe_parent)); } goto color; } parent = (elm)->
entry.rbe_parent; color = (elm)->entry.rbe_color; if (child
) (child)->entry.rbe_parent = parent; if (parent) { if ((parent
)->entry.rbe_left == elm) (parent)->entry.rbe_left = child
; else (parent)->entry.rbe_right = child; do {} while (0);
} else (head)->rbh_root = child; color: if (color == 0) nexthop_tree_RB_REMOVE_COLOR
(head, parent, child); return (old); } __attribute__((__unused__
)) static struct nexthop * nexthop_tree_RB_INSERT(struct nexthop_tree
*head, struct nexthop *elm) { struct nexthop *tmp; struct nexthop
*parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root
; while (tmp) { parent = tmp; comp = (nexthop_compare)(elm, parent
); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (
comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp
); } do { (elm)->entry.rbe_parent = parent; (elm)->entry
.rbe_left = (elm)->entry.rbe_right = ((void *)0); (elm)->
entry.rbe_color = 1; } while (0); if (parent != ((void *)0)) {
if (comp < 0) (parent)->entry.rbe_left = elm; else (parent
)->entry.rbe_right = elm; do {} while (0); } else (head)->
rbh_root = elm; nexthop_tree_RB_INSERT_COLOR(head, elm); return
(((void *)0)); } __attribute__((__unused__)) static struct nexthop
* nexthop_tree_RB_FIND(struct nexthop_tree *head, struct nexthop
*elm) { struct nexthop *tmp = (head)->rbh_root; int comp;
while (tmp) { comp = nexthop_compare(elm, tmp); if (comp <
0) tmp = (tmp)->entry.rbe_left; else if (comp > 0) tmp
= (tmp)->entry.rbe_right; else return (tmp); } return (((
void *)0)); } __attribute__((__unused__)) static struct nexthop
* nexthop_tree_RB_NFIND(struct nexthop_tree *head, struct nexthop
*elm) { struct nexthop *tmp = (head)->rbh_root; struct nexthop
*res = ((void *)0); int comp; while (tmp) { comp = nexthop_compare
(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry
.rbe_left; } else if (comp > 0) tmp = (tmp)->entry.rbe_right
; else return (tmp); } return (res); } __attribute__((__unused__
)) static struct nexthop * nexthop_tree_RB_NEXT(struct nexthop
*elm) { if ((elm)->entry.rbe_right) { elm = (elm)->entry
.rbe_right; while ((elm)->entry.rbe_left) elm = (elm)->
entry.rbe_left; } else { if ((elm)->entry.rbe_parent &&
(elm == ((elm)->entry.rbe_parent)->entry.rbe_left)) elm
= (elm)->entry.rbe_parent; else { while ((elm)->entry.
rbe_parent && (elm == ((elm)->entry.rbe_parent)->
entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm = (elm
)->entry.rbe_parent; } } return (elm); } __attribute__((__unused__
)) static struct nexthop * nexthop_tree_RB_PREV(struct nexthop
*elm) { if ((elm)->entry.rbe_left) { elm = (elm)->entry
.rbe_left; while ((elm)->entry.rbe_right) elm = (elm)->
entry.rbe_right; } else { if ((elm)->entry.rbe_parent &&
(elm == ((elm)->entry.rbe_parent)->entry.rbe_right)) elm
= (elm)->entry.rbe_parent; else { while ((elm)->entry.
rbe_parent && (elm == ((elm)->entry.rbe_parent)->
entry.rbe_left)) elm = (elm)->entry.rbe_parent; elm = (elm
)->entry.rbe_parent; } } return (elm); } __attribute__((__unused__
)) static struct nexthop * nexthop_tree_RB_MINMAX(struct nexthop_tree
*head, int val) { struct nexthop *tmp = (head)->rbh_root;
struct nexthop *parent = ((void *)0); while (tmp) { parent =
tmp; if (val < 0) tmp = (tmp)->entry.rbe_left; else tmp
= (tmp)->entry.rbe_right; } return (parent); }
;
1648
1649void
1650nexthop_shutdown(void)
1651{
1652 struct nexthop *nh, *nnh;
1653
1654 RB_FOREACH_SAFE(nh, nexthop_tree, &nexthoptable, nnh)for ((nh) = nexthop_tree_RB_MINMAX(&nexthoptable, -1); ((
nh) != ((void *)0)) && ((nnh) = nexthop_tree_RB_NEXT(
nh), 1); (nh) = (nnh))
{
1655 nh->state = NEXTHOP_UNREACH;
1656 nexthop_unref(nh);
1657 }
1658
1659 RB_FOREACH(nh, nexthop_tree, &nexthoptable)for ((nh) = nexthop_tree_RB_MINMAX(&nexthoptable, -1); (nh
) != ((void *)0); (nh) = nexthop_tree_RB_NEXT(nh))
{
1660 log_warnx("%s: nexthop %s refcnt %d", __func__,
1661 log_addr(&nh->exit_nexthop), nh->refcnt);
1662 }
1663}
1664
1665int
1666nexthop_pending(void)
1667{
1668 return !TAILQ_EMPTY(&nexthop_runners)(((&nexthop_runners)->tqh_first) == ((void *)0));
1669}
1670
1671void
1672nexthop_runner(void)
1673{
1674 struct nexthop *nh;
1675 struct prefix *p;
1676 uint32_t j;
1677
1678 nh = TAILQ_FIRST(&nexthop_runners)((&nexthop_runners)->tqh_first);
1679 if (nh == NULL((void *)0))
1680 return;
1681
1682 /* remove from runnner queue */
1683 TAILQ_REMOVE(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next) != ((void *)0)) (nh)->
runner_l.tqe_next->runner_l.tqe_prev = (nh)->runner_l.tqe_prev
; else (&nexthop_runners)->tqh_last = (nh)->runner_l
.tqe_prev; *(nh)->runner_l.tqe_prev = (nh)->runner_l.tqe_next
; ; ; } while (0)
;
1684
1685 p = nh->next_prefix;
1686 for (j = 0; p != NULL((void *)0) && j < RDE_RUNNER_ROUNDS100; j++) {
1687 prefix_evaluate_nexthop(p, nh->state, nh->oldstate);
1688 p = LIST_NEXT(p, entry.list.nexthop)((p)->entry.list.nexthop.le_next);
1689 }
1690
1691 /* prep for next run, if not finished readd to tail of queue */
1692 nh->next_prefix = p;
1693 if (p != NULL((void *)0))
1694 TAILQ_INSERT_TAIL(&nexthop_runners, nh, runner_l)do { (nh)->runner_l.tqe_next = ((void *)0); (nh)->runner_l
.tqe_prev = (&nexthop_runners)->tqh_last; *(&nexthop_runners
)->tqh_last = (nh); (&nexthop_runners)->tqh_last = &
(nh)->runner_l.tqe_next; } while (0)
;
1695 else
1696 log_debug("nexthop %s update finished",
1697 log_addr(&nh->exit_nexthop));
1698}
1699
1700void
1701nexthop_update(struct kroute_nexthop *msg)
1702{
1703 struct nexthop *nh;
1704
1705 nh = nexthop_lookup(&msg->nexthop);
1706 if (nh == NULL((void *)0)) {
1707 log_warnx("nexthop_update: non-existent nexthop %s",
1708 log_addr(&msg->nexthop));
1709 return;
1710 }
1711
1712 nh->oldstate = nh->state;
1713 if (msg->valid)
1714 nh->state = NEXTHOP_REACH;
1715 else
1716 nh->state = NEXTHOP_UNREACH;
1717
1718 if (nh->oldstate == NEXTHOP_LOOKUP)
1719 /* drop reference which was hold during the lookup */
1720 if (nexthop_unref(nh))
1721 return; /* nh lost last ref, no work left */
1722
1723 if (nh->next_prefix) {
1724 /*
1725 * If nexthop_runner() is not finished with this nexthop
1726 * then ensure that all prefixes are updated by setting
1727 * the oldstate to NEXTHOP_FLAPPED.
1728 */
1729 nh->oldstate = NEXTHOP_FLAPPED;
1730 TAILQ_REMOVE(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next) != ((void *)0)) (nh)->
runner_l.tqe_next->runner_l.tqe_prev = (nh)->runner_l.tqe_prev
; else (&nexthop_runners)->tqh_last = (nh)->runner_l
.tqe_prev; *(nh)->runner_l.tqe_prev = (nh)->runner_l.tqe_next
; ; ; } while (0)
;
1731 }
1732
1733 if (msg->connected)
1734 nh->flags |= NEXTHOP_CONNECTED0x01;
1735
1736 nh->true_nexthop = msg->gateway;
1737 nh->nexthop_net = msg->net;
1738 nh->nexthop_netlen = msg->netlen;
1739
1740 nh->next_prefix = LIST_FIRST(&nh->prefix_h)((&nh->prefix_h)->lh_first);
1741 if (nh->next_prefix != NULL((void *)0)) {
1742 TAILQ_INSERT_HEAD(&nexthop_runners, nh, runner_l)do { if (((nh)->runner_l.tqe_next = (&nexthop_runners)
->tqh_first) != ((void *)0)) (&nexthop_runners)->tqh_first
->runner_l.tqe_prev = &(nh)->runner_l.tqe_next; else
(&nexthop_runners)->tqh_last = &(nh)->runner_l
.tqe_next; (&nexthop_runners)->tqh_first = (nh); (nh)->
runner_l.tqe_prev = &(&nexthop_runners)->tqh_first
; } while (0)
;
1743 log_debug("nexthop %s update starting",
1744 log_addr(&nh->exit_nexthop));
1745 }
1746}
1747
1748void
1749nexthop_modify(struct nexthop *setnh, enum action_types type, uint8_t aid,
1750 struct nexthop **nexthop, uint8_t *flags)
1751{
1752 switch (type) {
1753 case ACTION_SET_NEXTHOP_REJECT:
1754 *flags = NEXTHOP_REJECT0x02;
1755 break;
1756 case ACTION_SET_NEXTHOP_BLACKHOLE:
1757 *flags = NEXTHOP_BLACKHOLE0x04;
1758 break;
1759 case ACTION_SET_NEXTHOP_NOMODIFY:
1760 *flags = NEXTHOP_NOMODIFY0x08;
1761 break;
1762 case ACTION_SET_NEXTHOP_SELF:
1763 *flags = NEXTHOP_SELF0x01;
1764 break;
1765 case ACTION_SET_NEXTHOP_REF:
1766 /*
1767 * it is possible that a prefix matches but has the wrong
1768 * address family for the set nexthop. In this case ignore it.
1769 */
1770 if (aid != setnh->exit_nexthop.aid)
1771 break;
1772 nexthop_unref(*nexthop);
1773 *nexthop = nexthop_ref(setnh);
1774 *flags = 0;
1775 break;
1776 default:
1777 break;
1778 }
1779}
1780
1781void
1782nexthop_link(struct prefix *p)
1783{
1784 p->nhflags &= ~NEXTHOP_VALID0x80;
1785
1786 if (p->flags & PREFIX_FLAG_ADJOUT0x10) {
1787 /* All nexthops are valid in Adj-RIB-Out */
1788 p->nhflags |= NEXTHOP_VALID0x80;
1789 return;
1790 }
1791
1792 /* no need to link prefixes in RIBs that have no decision process */
1793 if (re_rib(prefix_re(p))->flags & F_RIB_NOEVALUATE0x0002)
1794 return;
1795
1796 /* self-announce networks use nexthop NULL and are valid as well */
1797 if (p->nexthop == NULL((void *)0) || p->nexthop->state == NEXTHOP_REACH)
1798 p->nhflags |= NEXTHOP_VALID0x80;
1799
1800 if (p->nexthop == NULL((void *)0))
1801 return;
1802 p->flags |= PREFIX_NEXTHOP_LINKED0x40;
1803 LIST_INSERT_HEAD(&p->nexthop->prefix_h, p, entry.list.nexthop)do { if (((p)->entry.list.nexthop.le_next = (&p->nexthop
->prefix_h)->lh_first) != ((void *)0)) (&p->nexthop
->prefix_h)->lh_first->entry.list.nexthop.le_prev = &
(p)->entry.list.nexthop.le_next; (&p->nexthop->prefix_h
)->lh_first = (p); (p)->entry.list.nexthop.le_prev = &
(&p->nexthop->prefix_h)->lh_first; } while (0)
;
1804}
1805
1806void
1807nexthop_unlink(struct prefix *p)
1808{
1809 p->nhflags &= ~NEXTHOP_VALID0x80;
1810
1811 if (p->nexthop == NULL((void *)0) || (p->flags & PREFIX_NEXTHOP_LINKED0x40) == 0)
1812 return;
1813
1814 if (p == p->nexthop->next_prefix) {
1815 p->nexthop->next_prefix = LIST_NEXT(p, entry.list.nexthop)((p)->entry.list.nexthop.le_next);
1816 /* remove nexthop from list if no prefixes left to update */
1817 if (p->nexthop->next_prefix == NULL((void *)0)) {
1818 TAILQ_REMOVE(&nexthop_runners, p->nexthop, runner_l)do { if (((p->nexthop)->runner_l.tqe_next) != ((void *)
0)) (p->nexthop)->runner_l.tqe_next->runner_l.tqe_prev
= (p->nexthop)->runner_l.tqe_prev; else (&nexthop_runners
)->tqh_last = (p->nexthop)->runner_l.tqe_prev; *(p->
nexthop)->runner_l.tqe_prev = (p->nexthop)->runner_l
.tqe_next; ; ; } while (0)
;
1819 log_debug("nexthop %s update finished",
1820 log_addr(&p->nexthop->exit_nexthop));
1821 }
1822 }
1823
1824 p->flags &= ~PREFIX_NEXTHOP_LINKED0x40;
1825 LIST_REMOVE(p, entry.list.nexthop)do { if ((p)->entry.list.nexthop.le_next != ((void *)0)) (
p)->entry.list.nexthop.le_next->entry.list.nexthop.le_prev
= (p)->entry.list.nexthop.le_prev; *(p)->entry.list.nexthop
.le_prev = (p)->entry.list.nexthop.le_next; ; ; } while (0
)
;
1826}
1827
1828struct nexthop *
1829nexthop_get(struct bgpd_addr *nexthop)
1830{
1831 struct nexthop *nh;
1832
1833 nh = nexthop_lookup(nexthop);
1834 if (nh == NULL((void *)0)) {
1835 nh = calloc(1, sizeof(*nh));
1836 if (nh == NULL((void *)0))
1837 fatal("nexthop_alloc");
1838 rdemem.nexthop_cnt++;
1839
1840 LIST_INIT(&nh->prefix_h)do { ((&nh->prefix_h)->lh_first) = ((void *)0); } while
(0)
;
1841 nh->state = NEXTHOP_LOOKUP;
1842 nexthop_ref(nh); /* take reference for lookup */
1843 nh->exit_nexthop = *nexthop;
1844 if (RB_INSERT(nexthop_tree, &nexthoptable, nh)nexthop_tree_RB_INSERT(&nexthoptable, nh) != NULL((void *)0))
1845 fatalx("nexthop tree inconsistency");
1846
1847 rde_send_nexthop(&nh->exit_nexthop, 1);
1848 }
1849
1850 return nexthop_ref(nh);
1851}
1852
1853struct nexthop *
1854nexthop_ref(struct nexthop *nexthop)
1855{
1856 if (nexthop)
1857 nexthop->refcnt++;
1858 return (nexthop);
1859}
1860
1861int
1862nexthop_unref(struct nexthop *nh)
1863{
1864 if (nh == NULL((void *)0))
1865 return (0);
1866 if (--nh->refcnt > 0)
1867 return (0);
1868
1869 /* sanity check */
1870 if (!LIST_EMPTY(&nh->prefix_h)(((&nh->prefix_h)->lh_first) == ((void *)0)) || nh->state == NEXTHOP_LOOKUP)
1871 fatalx("%s: refcnt error", __func__);
1872
1873 /* is nexthop update running? impossible, that is a refcnt error */
1874 if (nh->next_prefix)
1875 fatalx("%s: next_prefix not NULL", __func__);
1876
1877 RB_REMOVE(nexthop_tree, &nexthoptable, nh)nexthop_tree_RB_REMOVE(&nexthoptable, nh);
1878 rde_send_nexthop(&nh->exit_nexthop, 0);
1879
1880 rdemem.nexthop_cnt--;
1881 free(nh);
1882 return (1);
1883}
1884
1885int
1886nexthop_compare(struct nexthop *na, struct nexthop *nb)
1887{
1888 struct bgpd_addr *a, *b;
1889
1890 if (na == nb)
1891 return (0);
1892 if (na == NULL((void *)0))
1893 return (-1);
1894 if (nb == NULL((void *)0))
1895 return (1);
1896
1897 a = &na->exit_nexthop;
1898 b = &nb->exit_nexthop;
1899
1900 if (a->aid != b->aid)
1901 return (a->aid - b->aid);
1902
1903 switch (a->aid) {
1904 case AID_INET1:
1905 if (ntohl(a->v4.s_addr)(__uint32_t)(__builtin_constant_p(a->ba.v4.s_addr) ? (__uint32_t
)(((__uint32_t)(a->ba.v4.s_addr) & 0xff) << 24 |
((__uint32_t)(a->ba.v4.s_addr) & 0xff00) << 8 |
((__uint32_t)(a->ba.v4.s_addr) & 0xff0000) >> 8
| ((__uint32_t)(a->ba.v4.s_addr) & 0xff000000) >>
24) : __swap32md(a->ba.v4.s_addr))
> ntohl(b->v4.s_addr)(__uint32_t)(__builtin_constant_p(b->ba.v4.s_addr) ? (__uint32_t
)(((__uint32_t)(b->ba.v4.s_addr) & 0xff) << 24 |
((__uint32_t)(b->ba.v4.s_addr) & 0xff00) << 8 |
((__uint32_t)(b->ba.v4.s_addr) & 0xff0000) >> 8
| ((__uint32_t)(b->ba.v4.s_addr) & 0xff000000) >>
24) : __swap32md(b->ba.v4.s_addr))
)
1906 return (1);
1907 if (ntohl(a->v4.s_addr)(__uint32_t)(__builtin_constant_p(a->ba.v4.s_addr) ? (__uint32_t
)(((__uint32_t)(a->ba.v4.s_addr) & 0xff) << 24 |
((__uint32_t)(a->ba.v4.s_addr) & 0xff00) << 8 |
((__uint32_t)(a->ba.v4.s_addr) & 0xff0000) >> 8
| ((__uint32_t)(a->ba.v4.s_addr) & 0xff000000) >>
24) : __swap32md(a->ba.v4.s_addr))
< ntohl(b->v4.s_addr)(__uint32_t)(__builtin_constant_p(b->ba.v4.s_addr) ? (__uint32_t
)(((__uint32_t)(b->ba.v4.s_addr) & 0xff) << 24 |
((__uint32_t)(b->ba.v4.s_addr) & 0xff00) << 8 |
((__uint32_t)(b->ba.v4.s_addr) & 0xff0000) >> 8
| ((__uint32_t)(b->ba.v4.s_addr) & 0xff000000) >>
24) : __swap32md(b->ba.v4.s_addr))
)
1908 return (-1);
1909 return (0);
1910 case AID_INET62:
1911 return (memcmp(&a->v6ba.v6, &b->v6ba.v6, sizeof(struct in6_addr)));
1912 default:
1913 fatalx("nexthop_cmp: %s is unsupported", aid2str(a->aid));
1914 }
1915 return (-1);
1916}
1917
1918struct nexthop *
1919nexthop_lookup(struct bgpd_addr *nexthop)
1920{
1921 struct nexthop needle = { 0 };
1922
1923 needle.exit_nexthop = *nexthop;
1924 return RB_FIND(nexthop_tree, &nexthoptable, &needle)nexthop_tree_RB_FIND(&nexthoptable, &needle);
1925}