Bug Summary

File:src/usr.sbin/eigrpd/rde_dual.c
Warning:line 1055, column 2
Value stored to 'old_fdistance' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rde_dual.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/eigrpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/eigrpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/eigrpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/eigrpd/rde_dual.c
1/* $OpenBSD: rde_dual.c,v 1.28 2016/09/02 16:44:33 renato Exp $ */
2
3/*
4 * Copyright (c) 2015 Renato Westphal <renato@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
21#include <stdlib.h>
22#include <string.h>
23
24#include "eigrpd.h"
25#include "eigrpe.h"
26#include "rde.h"
27#include "log.h"
28
29static int dual_fsm(struct rt_node *, enum dual_event);
30static __inline int rt_compare(struct rt_node *, struct rt_node *);
31static struct rt_node *rt_find(struct eigrp *, struct rinfo *);
32static struct rt_node *rt_new(struct eigrp *, struct rinfo *);
33static struct eigrp_route *route_find(struct rde_nbr *, struct rt_node *);
34static struct eigrp_route *route_new(struct rt_node *, struct rde_nbr *,
35 struct rinfo *);
36static void route_del(struct rt_node *, struct eigrp_route *);
37static uint32_t safe_sum_uint32(uint32_t, uint32_t);
38static uint32_t safe_mul_uint32(uint32_t, uint32_t);
39static uint32_t route_composite_metric(uint8_t *, uint32_t, uint32_t,
40 uint8_t, uint8_t);
41static void route_update_metrics(struct eigrp *,
42 struct eigrp_route *, struct rinfo *);
43static void reply_outstanding_add(struct rt_node *,
44 struct rde_nbr *);
45static struct reply_node *reply_outstanding_find(struct rt_node *,
46 struct rde_nbr *);
47static void reply_outstanding_remove(struct reply_node *);
48static void reply_active_timer(int, short, void *);
49static void reply_active_start_timer(struct reply_node *);
50static void reply_active_stop_timer(struct reply_node *);
51static void reply_sia_timer(int, short, void *);
52static void reply_sia_start_timer(struct reply_node *);
53static void reply_sia_stop_timer(struct reply_node *);
54static void rinfo_fill_infinite(struct rt_node *, enum route_type,
55 struct rinfo *);
56static void rt_update_fib(struct rt_node *);
57static void rt_set_successor(struct rt_node *,
58 struct eigrp_route *);
59static struct eigrp_route *rt_get_successor_fc(struct rt_node *);
60static void rde_send_update(struct eigrp_iface *, struct rinfo *);
61static void rde_send_update_all(struct rt_node *, struct rinfo *);
62static void rde_send_query(struct eigrp_iface *, struct rinfo *,
63 int);
64static void rde_send_siaquery(struct rde_nbr *, struct rinfo *);
65static void rde_send_query_all(struct eigrp *, struct rt_node *,
66 int);
67static void rde_send_reply(struct rde_nbr *, struct rinfo *, int);
68static void rde_last_reply(struct rt_node *);
69static __inline int rde_nbr_compare(struct rde_nbr *, struct rde_nbr *);
70
71RB_GENERATE(rt_tree, rt_node, entry, rt_compare)void rt_tree_RB_INSERT_COLOR(struct rt_tree *head, struct rt_node
*elm) { struct rt_node *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; } void rt_tree_RB_REMOVE_COLOR(struct rt_tree
*head, struct rt_node *parent, struct rt_node *elm) { struct
rt_node *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 rt_node *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 rt_node *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; } struct rt_node * rt_tree_RB_REMOVE(struct rt_tree
*head, struct rt_node *elm) { struct rt_node *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 rt_node *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) rt_tree_RB_REMOVE_COLOR(head, parent, child); return (old
); } struct rt_node * rt_tree_RB_INSERT(struct rt_tree *head,
struct rt_node *elm) { struct rt_node *tmp; struct rt_node *
parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root
; while (tmp) { parent = tmp; comp = (rt_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; rt_tree_RB_INSERT_COLOR(head, elm); return ((
(void *)0)); } struct rt_node * rt_tree_RB_FIND(struct rt_tree
*head, struct rt_node *elm) { struct rt_node *tmp = (head)->
rbh_root; int comp; while (tmp) { comp = rt_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)); } struct rt_node * rt_tree_RB_NFIND(struct
rt_tree *head, struct rt_node *elm) { struct rt_node *tmp = (
head)->rbh_root; struct rt_node *res = ((void *)0); int comp
; while (tmp) { comp = rt_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); } struct rt_node * rt_tree_RB_NEXT(struct rt_node
*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); } struct rt_node * rt_tree_RB_PREV
(struct rt_node *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); } struct rt_node
* rt_tree_RB_MINMAX(struct rt_tree *head, int val) { struct rt_node
*tmp = (head)->rbh_root; struct rt_node *parent = ((void *
)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->
entry.rbe_left; else tmp = (tmp)->entry.rbe_right; } return
(parent); }
72RB_GENERATE(rde_nbr_head, rde_nbr, entry, rde_nbr_compare)void rde_nbr_head_RB_INSERT_COLOR(struct rde_nbr_head *head, struct
rde_nbr *elm) { struct rde_nbr *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; } void rde_nbr_head_RB_REMOVE_COLOR(struct
rde_nbr_head *head, struct rde_nbr *parent, struct rde_nbr *
elm) { struct rde_nbr *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_nbr *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_nbr *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; } struct rde_nbr
* rde_nbr_head_RB_REMOVE(struct rde_nbr_head *head, struct rde_nbr
*elm) { struct rde_nbr *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_nbr
*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) rde_nbr_head_RB_REMOVE_COLOR
(head, parent, child); return (old); } struct rde_nbr * rde_nbr_head_RB_INSERT
(struct rde_nbr_head *head, struct rde_nbr *elm) { struct rde_nbr
*tmp; struct rde_nbr *parent = ((void *)0); int comp = 0; tmp
= (head)->rbh_root; while (tmp) { parent = tmp; comp = (rde_nbr_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; rde_nbr_head_RB_INSERT_COLOR
(head, elm); return (((void *)0)); } struct rde_nbr * rde_nbr_head_RB_FIND
(struct rde_nbr_head *head, struct rde_nbr *elm) { struct rde_nbr
*tmp = (head)->rbh_root; int comp; while (tmp) { comp = rde_nbr_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)); } struct rde_nbr * rde_nbr_head_RB_NFIND
(struct rde_nbr_head *head, struct rde_nbr *elm) { struct rde_nbr
*tmp = (head)->rbh_root; struct rde_nbr *res = ((void *)0
); int comp; while (tmp) { comp = rde_nbr_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); } struct rde_nbr * rde_nbr_head_RB_NEXT
(struct rde_nbr *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); } struct rde_nbr
* rde_nbr_head_RB_PREV(struct rde_nbr *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); } struct rde_nbr * rde_nbr_head_RB_MINMAX
(struct rde_nbr_head *head, int val) { struct rde_nbr *tmp = (
head)->rbh_root; struct rde_nbr *parent = ((void *)0); while
(tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry.
rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent
); }
73
74struct rde_nbr_head rde_nbrs = RB_INITIALIZER(&rde_nbrs){ ((void *)0) };
75
76/*
77 * NOTE: events that don't cause a state transition aren't triggered to avoid
78 * too much verbosity and are here mostly for illustration purposes.
79 */
80static struct {
81 int state;
82 enum dual_event event;
83 int new_state;
84} dual_fsm_tbl[] = {
85 /* current state event resulting state */
86/* Passive */
87 {DUAL_STA_PASSIVE0x0001, DUAL_EVT_1, 0},
88 {DUAL_STA_PASSIVE0x0001, DUAL_EVT_2, 0},
89 {DUAL_STA_PASSIVE0x0001, DUAL_EVT_3, DUAL_STA_ACTIVE30x0010},
90 {DUAL_STA_PASSIVE0x0001, DUAL_EVT_4, DUAL_STA_ACTIVE10x0004},
91/* Active Oij=0 */
92 {DUAL_STA_ACTIVE00x0002, DUAL_EVT_5, DUAL_STA_ACTIVE20x0008},
93 {DUAL_STA_ACTIVE00x0002, DUAL_EVT_11, DUAL_STA_ACTIVE10x0004},
94 {DUAL_STA_ACTIVE00x0002, DUAL_EVT_14, DUAL_STA_PASSIVE0x0001},
95/* Active Oij=1 */
96 {DUAL_STA_ACTIVE10x0004, DUAL_EVT_5, DUAL_STA_ACTIVE20x0008},
97 {DUAL_STA_ACTIVE10x0004, DUAL_EVT_9, DUAL_STA_ACTIVE00x0002},
98 {DUAL_STA_ACTIVE10x0004, DUAL_EVT_15, DUAL_STA_PASSIVE0x0001},
99/* Active Oij=2 */
100 {DUAL_STA_ACTIVE20x0008, DUAL_EVT_12, DUAL_STA_ACTIVE30x0010},
101 {DUAL_STA_ACTIVE20x0008, DUAL_EVT_16, DUAL_STA_PASSIVE0x0001},
102/* Active Oij=3 */
103 {DUAL_STA_ACTIVE30x0010, DUAL_EVT_10, DUAL_STA_ACTIVE20x0008},
104 {DUAL_STA_ACTIVE30x0010, DUAL_EVT_13, DUAL_STA_PASSIVE0x0001},
105/* Active (all) */
106 {DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010), DUAL_EVT_6, 0},
107 {DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010), DUAL_EVT_7, 0},
108 {DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010), DUAL_EVT_8, 0},
109/* sentinel */
110 {-1, 0, 0},
111};
112
113static const char * const dual_event_names[] = {
114 "DUAL_EVT_1",
115 "DUAL_EVT_2",
116 "DUAL_EVT_3",
117 "DUAL_EVT_4",
118 "DUAL_EVT_5",
119 "DUAL_EVT_6",
120 "DUAL_EVT_7",
121 "DUAL_EVT_8",
122 "DUAL_EVT_9",
123 "DUAL_EVT_10",
124 "DUAL_EVT_11",
125 "DUAL_EVT_12",
126 "DUAL_EVT_13",
127 "DUAL_EVT_14",
128 "DUAL_EVT_15",
129 "DUAL_EVT_16"
130};
131
132static int
133dual_fsm(struct rt_node *rn, enum dual_event event)
134{
135 int old_state;
136 int new_state = 0;
137 int i;
138
139 old_state = rn->state;
140 for (i = 0; dual_fsm_tbl[i].state != -1; i++)
141 if ((dual_fsm_tbl[i].state & old_state) &&
142 (dual_fsm_tbl[i].event == event)) {
143 new_state = dual_fsm_tbl[i].new_state;
144 break;
145 }
146
147 if (dual_fsm_tbl[i].state == -1) {
148 /* event outside of the defined fsm, ignore it. */
149 log_warnx("%s: route %s, event %s not expected in state %s",
150 __func__, log_prefix(rn), dual_event_names[event],
151 dual_state_name(old_state));
152 return (0);
153 }
154
155 if (new_state != 0)
156 rn->state = new_state;
157
158 if (old_state != rn->state) {
159 log_debug("%s: event %s changing state for prefix %s "
160 "from %s to %s", __func__, dual_event_names[event],
161 log_prefix(rn), dual_state_name(old_state),
162 dual_state_name(rn->state));
163
164 if (old_state == DUAL_STA_PASSIVE0x0001 ||
165 new_state == DUAL_STA_PASSIVE0x0001)
166 rt_update_fib(rn);
167 }
168
169 return (0);
170}
171
172static __inline int
173rt_compare(struct rt_node *a, struct rt_node *b)
174{
175 int addrcmp;
176
177 addrcmp = eigrp_addrcmp(a->eigrp->af, &a->prefix, &b->prefix);
178 if (addrcmp != 0)
179 return (addrcmp);
180
181 if (a->prefixlen < b->prefixlen)
182 return (-1);
183 if (a->prefixlen > b->prefixlen)
184 return (1);
185
186 return (0);
187}
188
189static struct rt_node *
190rt_find(struct eigrp *eigrp, struct rinfo *ri)
191{
192 struct rt_node rn;
193
194 rn.eigrp = eigrp;
195 rn.prefix = ri->prefix;
196 rn.prefixlen = ri->prefixlen;
197
198 return (RB_FIND(rt_tree, &eigrp->topology, &rn)rt_tree_RB_FIND(&eigrp->topology, &rn));
199}
200
201static struct rt_node *
202rt_new(struct eigrp *eigrp, struct rinfo *ri)
203{
204 struct rt_node *rn;
205
206 if ((rn = calloc(1, sizeof(*rn))) == NULL((void *)0))
207 fatal("rt_new");
208
209 rn->eigrp = eigrp;
210 rn->prefix = ri->prefix;
211 rn->prefixlen = ri->prefixlen;
212 rn->state = DUAL_STA_PASSIVE0x0001;
213 TAILQ_INIT(&rn->routes)do { (&rn->routes)->tqh_first = ((void *)0); (&
rn->routes)->tqh_last = &(&rn->routes)->tqh_first
; } while (0)
;
214 TAILQ_INIT(&rn->rijk)do { (&rn->rijk)->tqh_first = ((void *)0); (&rn
->rijk)->tqh_last = &(&rn->rijk)->tqh_first
; } while (0)
;
215 rt_set_successor(rn, NULL((void *)0));
216
217 if (RB_INSERT(rt_tree, &eigrp->topology, rn)rt_tree_RB_INSERT(&eigrp->topology, rn) != NULL((void *)0)) {
218 log_warnx("%s failed for %s", __func__, log_prefix(rn));
219 free(rn);
220 return (NULL((void *)0));
221 }
222
223 log_debug("%s: prefix %s", __func__, log_prefix(rn));
224
225 return (rn);
226}
227
228void
229rt_del(struct rt_node *rn)
230{
231 struct eigrp_route *route;
232 struct reply_node *reply;
233
234 log_debug("%s: prefix %s", __func__, log_prefix(rn));
235
236 while ((reply = TAILQ_FIRST(&rn->rijk)((&rn->rijk)->tqh_first)) != NULL((void *)0))
237 reply_outstanding_remove(reply);
238 while ((route = TAILQ_FIRST(&rn->routes)((&rn->routes)->tqh_first)) != NULL((void *)0))
239 route_del(rn, route);
240 RB_REMOVE(rt_tree, &rn->eigrp->topology, rn)rt_tree_RB_REMOVE(&rn->eigrp->topology, rn);
241 free(rn);
242}
243
244static struct eigrp_route *
245route_find(struct rde_nbr *nbr, struct rt_node *rn)
246{
247 struct eigrp_route *route;
248
249 TAILQ_FOREACH(route, &rn->routes, entry)for((route) = ((&rn->routes)->tqh_first); (route) !=
((void *)0); (route) = ((route)->entry.tqe_next))
250 if (route->nbr == nbr)
251 return (route);
252
253 return (NULL((void *)0));
254}
255
256static struct eigrp_route *
257route_new(struct rt_node *rn, struct rde_nbr *nbr, struct rinfo *ri)
258{
259 struct eigrp *eigrp = rn->eigrp;
260 struct eigrp_route *route, *tmp;
261
262 if ((route = calloc(1, sizeof(*route))) == NULL((void *)0))
263 fatal("route_new");
264
265 route->nbr = nbr;
266 route->type = ri->type;
267 if (eigrp_addrisset(eigrp->af, &ri->nexthop))
268 route->nexthop = ri->nexthop;
269 else
270 route->nexthop = nbr->addr;
271 route_update_metrics(eigrp, route, ri);
272
273 /* order by nexthop */
274 TAILQ_FOREACH(tmp, &rn->routes, entry)for((tmp) = ((&rn->routes)->tqh_first); (tmp) != ((
void *)0); (tmp) = ((tmp)->entry.tqe_next))
275 if (eigrp_addrcmp(eigrp->af, &tmp->nexthop,
276 &route->nexthop) > 0)
277 break;
278 if (tmp)
279 TAILQ_INSERT_BEFORE(tmp, route, entry)do { (route)->entry.tqe_prev = (tmp)->entry.tqe_prev; (
route)->entry.tqe_next = (tmp); *(tmp)->entry.tqe_prev =
(route); (tmp)->entry.tqe_prev = &(route)->entry.tqe_next
; } while (0)
;
280 else
281 TAILQ_INSERT_TAIL(&rn->routes, route, entry)do { (route)->entry.tqe_next = ((void *)0); (route)->entry
.tqe_prev = (&rn->routes)->tqh_last; *(&rn->
routes)->tqh_last = (route); (&rn->routes)->tqh_last
= &(route)->entry.tqe_next; } while (0)
;
282
283 log_debug("%s: prefix %s via %s distance (%u/%u)", __func__,
284 log_prefix(rn), log_route_origin(eigrp->af, route->nbr),
285 route->distance, route->rdistance);
286
287 return (route);
288}
289
290static void
291route_del(struct rt_node *rn, struct eigrp_route *route)
292{
293 struct eigrp *eigrp = rn->eigrp;
294
295 log_debug("%s: prefix %s via %s", __func__, log_prefix(rn),
296 log_route_origin(eigrp->af, route->nbr));
297
298 if (route->flags & F_EIGRP_ROUTE_INSTALLED0x01)
299 rde_send_delete_kroute(rn, route);
300
301 TAILQ_REMOVE(&rn->routes, route, entry)do { if (((route)->entry.tqe_next) != ((void *)0)) (route)
->entry.tqe_next->entry.tqe_prev = (route)->entry.tqe_prev
; else (&rn->routes)->tqh_last = (route)->entry.
tqe_prev; *(route)->entry.tqe_prev = (route)->entry.tqe_next
; ; ; } while (0)
;
302 free(route);
303}
304
305static uint32_t
306safe_sum_uint32(uint32_t a, uint32_t b)
307{
308 uint64_t total;
309
310 total = (uint64_t) a + (uint64_t) b;
311
312 if (total >> 32)
313 return ((uint32_t )(~0));
314
315 return ((uint32_t) total);
316}
317
318static uint32_t
319safe_mul_uint32(uint32_t a, uint32_t b)
320{
321 uint64_t total;
322
323 total = (uint64_t) a * (uint64_t) b;
324
325 if (total >> 32)
326 return ((uint32_t )(~0));
327
328 return ((uint32_t) total);
329}
330
331uint32_t
332eigrp_composite_delay(uint32_t delay)
333{
334 /* cheap overflow protection */
335 delay = min(delay, (1 << 24) - 1)((delay) <= ((1 << 24) - 1) ? (delay) : ((1 <<
24) - 1))
;
336 return (delay * EIGRP_SCALING_FACTOR256);
337}
338
339uint32_t
340eigrp_real_delay(uint32_t delay)
341{
342 return (delay / EIGRP_SCALING_FACTOR256);
343}
344
345uint32_t
346eigrp_composite_bandwidth(uint32_t bandwidth)
347{
348 /* truncate before applying the scaling factor */
349 bandwidth = 10000000 / bandwidth;
350 return (EIGRP_SCALING_FACTOR256 * bandwidth);
351}
352
353uint32_t
354eigrp_real_bandwidth(uint32_t bandwidth)
355{
356 /*
357 * apply the scaling factor before the division and only then truncate.
358 * this is to keep consistent with what cisco does.
359 */
360 return ((EIGRP_SCALING_FACTOR256 * (uint32_t)10000000) / bandwidth);
361}
362
363static uint32_t
364route_composite_metric(uint8_t *kvalues, uint32_t delay, uint32_t bandwidth,
365 uint8_t load, uint8_t reliability)
366{
367 uint64_t distance;
368 uint32_t operand1, operand2, operand3;
369 double operand4;
370
371 /*
372 * Need to apply the scaling factor before any division to avoid
373 * losing information from truncation.
374 */
375 operand1 = safe_mul_uint32(kvalues[0] * EIGRP_SCALING_FACTOR256,
376 10000000 / bandwidth);
377 operand2 = safe_mul_uint32(kvalues[1] * EIGRP_SCALING_FACTOR256,
378 10000000 / bandwidth) / (256 - load);
379 operand3 = safe_mul_uint32(kvalues[2] * EIGRP_SCALING_FACTOR256, delay);
380
381 distance = (uint64_t) operand1 + (uint64_t) operand2 +
382 (uint64_t) operand3;
383
384 /* if K5 is set to zero, the last term of the formula is not used */
385 if (kvalues[4] != 0) {
386 operand4 = (double) kvalues[4] / (reliability + kvalues[3]);
387 /* no risk of overflow (64 bits), operand4 can be at most 255 */
388 distance *= operand4;
389 }
390
391 /* overflow protection */
392 if (distance >> 32)
393 distance = ((uint32_t )(~0));
394
395 return ((uint32_t) distance);
396}
397
398static void
399route_update_metrics(struct eigrp *eigrp, struct eigrp_route *route,
400 struct rinfo *ri)
401{
402 struct eigrp_iface *ei = route->nbr->ei;
403 uint32_t delay, bandwidth;
404 int mtu;
405
406 route->metric = ri->metric;
407 route->emetric = ri->emetric;
408 route->flags |= F_EIGRP_ROUTE_M_CHANGED0x02;
409
410 delay = eigrp_real_delay(route->metric.delay);
411 bandwidth = eigrp_real_bandwidth(route->metric.bandwidth);
412
413 if (route->nbr->flags & F_RDE_NBR_SELF0x01)
414 route->rdistance = 0;
415 else {
416 route->rdistance = route_composite_metric(eigrp->kvalues,
417 delay, bandwidth, route->metric.load,
418 route->metric.reliability);
419
420 /* update the delay */
421 delay = safe_sum_uint32(delay, ei->delay);
422 route->metric.delay = eigrp_composite_delay(delay);
423
424 /* update the bandwidth */
425 bandwidth = min(bandwidth, ei->bandwidth)((bandwidth) <= (ei->bandwidth) ? (bandwidth) : (ei->
bandwidth))
;
426 route->metric.bandwidth = eigrp_composite_bandwidth(bandwidth);
427
428 /* update the mtu */
429 mtu = min(metric_decode_mtu(route->metric.mtu), ei->iface->mtu)((metric_decode_mtu(route->metric.mtu)) <= (ei->iface
->mtu) ? (metric_decode_mtu(route->metric.mtu)) : (ei->
iface->mtu))
;
430 metric_encode_mtu(route->metric.mtu, mtu);
431
432 /* update the hop count */
433 if (route->metric.hop_count < UINT8_MAX0xff)
434 route->metric.hop_count++;
435 }
436
437 route->distance = route_composite_metric(eigrp->kvalues, delay,
438 bandwidth, DEFAULT_LOAD1, DEFAULT_RELIABILITY255);
439}
440
441static void
442reply_outstanding_add(struct rt_node *rn, struct rde_nbr *nbr)
443{
444 struct reply_node *reply;
445
446 if ((reply = calloc(1, sizeof(*reply))) == NULL((void *)0))
447 fatal("reply_outstanding_add");
448
449 evtimer_set(&reply->ev_active_timeout, reply_active_timer, reply)event_set(&reply->ev_active_timeout, -1, 0, reply_active_timer
, reply)
;
450 evtimer_set(&reply->ev_sia_timeout, reply_sia_timer, reply)event_set(&reply->ev_sia_timeout, -1, 0, reply_sia_timer
, reply)
;
451 reply->siaquery_sent = 0;
452 reply->siareply_recv = 0;
453 reply->rn = rn;
454 reply->nbr = nbr;
455 TAILQ_INSERT_TAIL(&rn->rijk, reply, rn_entry)do { (reply)->rn_entry.tqe_next = ((void *)0); (reply)->
rn_entry.tqe_prev = (&rn->rijk)->tqh_last; *(&rn
->rijk)->tqh_last = (reply); (&rn->rijk)->tqh_last
= &(reply)->rn_entry.tqe_next; } while (0)
;
456 TAILQ_INSERT_TAIL(&nbr->rijk, reply, nbr_entry)do { (reply)->nbr_entry.tqe_next = ((void *)0); (reply)->
nbr_entry.tqe_prev = (&nbr->rijk)->tqh_last; *(&
nbr->rijk)->tqh_last = (reply); (&nbr->rijk)->
tqh_last = &(reply)->nbr_entry.tqe_next; } while (0)
;
457
458 if (rn->eigrp->active_timeout > 0) {
459 reply_active_start_timer(reply);
460 reply_sia_start_timer(reply);
461 }
462}
463
464static struct reply_node *
465reply_outstanding_find(struct rt_node *rn, struct rde_nbr *nbr)
466{
467 struct reply_node *reply;
468
469 TAILQ_FOREACH(reply, &rn->rijk, rn_entry)for((reply) = ((&rn->rijk)->tqh_first); (reply) != (
(void *)0); (reply) = ((reply)->rn_entry.tqe_next))
470 if (reply->nbr == nbr)
471 return (reply);
472
473 return (NULL((void *)0));
474}
475
476static void
477reply_outstanding_remove(struct reply_node *reply)
478{
479 reply_active_stop_timer(reply);
480 reply_sia_stop_timer(reply);
481 TAILQ_REMOVE(&reply->rn->rijk, reply, rn_entry)do { if (((reply)->rn_entry.tqe_next) != ((void *)0)) (reply
)->rn_entry.tqe_next->rn_entry.tqe_prev = (reply)->rn_entry
.tqe_prev; else (&reply->rn->rijk)->tqh_last = (
reply)->rn_entry.tqe_prev; *(reply)->rn_entry.tqe_prev =
(reply)->rn_entry.tqe_next; ; ; } while (0)
;
482 TAILQ_REMOVE(&reply->nbr->rijk, reply, nbr_entry)do { if (((reply)->nbr_entry.tqe_next) != ((void *)0)) (reply
)->nbr_entry.tqe_next->nbr_entry.tqe_prev = (reply)->
nbr_entry.tqe_prev; else (&reply->nbr->rijk)->tqh_last
= (reply)->nbr_entry.tqe_prev; *(reply)->nbr_entry.tqe_prev
= (reply)->nbr_entry.tqe_next; ; ; } while (0)
;
483 free(reply);
484}
485
486/* ARGSUSED */
487static void
488reply_active_timer(int fd, short event, void *arg)
489{
490 struct reply_node *reply = arg;
491 struct rde_nbr *nbr = reply->nbr;
492
493 log_debug("%s: neighbor %s is stuck in active", __func__,
494 log_addr(nbr->eigrp->af, &nbr->addr));
495
496 rde_nbr_del(reply->nbr, 1);
497}
498
499static void
500reply_active_start_timer(struct reply_node *reply)
501{
502 struct eigrp *eigrp = reply->nbr->eigrp;
503 struct timeval tv;
504
505 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
506 tv.tv_sec = eigrp->active_timeout * 60;
507 if (evtimer_add(&reply->ev_active_timeout, &tv)event_add(&reply->ev_active_timeout, &tv) == -1)
508 fatal("reply_active_start_timer");
509}
510
511static void
512reply_active_stop_timer(struct reply_node *reply)
513{
514 if (evtimer_pending(&reply->ev_active_timeout, NULL)event_pending(&reply->ev_active_timeout, 0x01, ((void *
)0))
&&
515 evtimer_del(&reply->ev_active_timeout)event_del(&reply->ev_active_timeout) == -1)
516 fatal("reply_active_stop_timer");
517}
518
519/* ARGSUSED */
520static void
521reply_sia_timer(int fd, short event, void *arg)
522{
523 struct reply_node *reply = arg;
524 struct rde_nbr *nbr = reply->nbr;
525 struct rt_node *rn = reply->rn;
526 struct rinfo ri;
527
528 log_debug("%s: nbr %s prefix %s", __func__, log_addr(nbr->eigrp->af,
529 &nbr->addr), log_prefix(rn));
530
531 if (reply->siaquery_sent > 0 && reply->siareply_recv == 0) {
532 log_debug("%s: neighbor %s is stuck in active", __func__,
533 log_addr(nbr->eigrp->af, &nbr->addr));
534 rde_nbr_del(nbr, 1);
535 return;
536 }
537
538 /*
539 * draft-savage-eigrp-04 - Section 4.4.1.1:
540 * "Up to three SIA-QUERY packets for a specific destination may
541 * be sent, each at a value of one-half the ACTIVE time, so long
542 * as each are successfully acknowledged and met with an SIA-REPLY".
543 */
544 if (reply->siaquery_sent >= 3)
545 return;
546
547 reply->siaquery_sent++;
548 reply->siareply_recv = 0;
549
550 /* restart sia and active timeouts */
551 reply_sia_start_timer(reply);
552 reply_active_start_timer(reply);
553
554 /* send an sia-query */
555 rinfo_fill_successor(rn, &ri);
556 ri.metric.flags |= F_METRIC_ACTIVE0x04;
557 rde_send_siaquery(nbr, &ri);
558}
559
560static void
561reply_sia_start_timer(struct reply_node *reply)
562{
563 struct eigrp *eigrp = reply->nbr->eigrp;
564 struct timeval tv;
565
566 /*
567 * draft-savage-eigrp-04 - Section 4.4.1.1:
568 * "The SIA-QUERY packet SHOULD be sent on a per-destination basis
569 * at one-half of the ACTIVE timeout period."
570 */
571 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
572 tv.tv_sec = (eigrp->active_timeout * 60) / 2;
573 if (evtimer_add(&reply->ev_sia_timeout, &tv)event_add(&reply->ev_sia_timeout, &tv) == -1)
574 fatal("reply_sia_start_timer");
575}
576
577static void
578reply_sia_stop_timer(struct reply_node *reply)
579{
580 if (evtimer_pending(&reply->ev_sia_timeout, NULL)event_pending(&reply->ev_sia_timeout, 0x01, ((void *)0
))
&&
581 evtimer_del(&reply->ev_sia_timeout)event_del(&reply->ev_sia_timeout) == -1)
582 fatal("reply_sia_stop_timer");
583}
584
585void
586rinfo_fill_successor(struct rt_node *rn, struct rinfo *ri)
587{
588 if (rn->successor.nbr == NULL((void *)0)) {
589 rinfo_fill_infinite(rn, EIGRP_ROUTE_INTERNAL, ri);
590 return;
591 }
592
593 memset(ri, 0, sizeof(*ri));
594 ri->af = rn->eigrp->af;
595 ri->type = rn->successor.type;
596 ri->prefix = rn->prefix;
597 ri->prefixlen = rn->prefixlen;
598 ri->metric = rn->successor.metric;
599 if (ri->type == EIGRP_ROUTE_EXTERNAL)
600 ri->emetric = rn->successor.emetric;
601}
602
603static void
604rinfo_fill_infinite(struct rt_node *rn, enum route_type type, struct rinfo *ri)
605{
606 memset(ri, 0, sizeof(*ri));
607 ri->af = rn->eigrp->af;
608 ri->type = type;
609 ri->prefix = rn->prefix;
610 ri->prefixlen = rn->prefixlen;
611 ri->metric.delay = EIGRP_INFINITE_METRIC((uint32_t )(~0));
612}
613
614static void
615rt_update_fib(struct rt_node *rn)
616{
617 struct eigrp *eigrp = rn->eigrp;
618 uint8_t maximum_paths = eigrp->maximum_paths;
619 uint8_t variance = eigrp->variance;
620 int installed = 0;
621 struct eigrp_route *route;
622
623 if (rn->state == DUAL_STA_PASSIVE0x0001) {
624 /* no multipath for attached networks. */
625 if (rn->successor.nbr &&
626 (rn->successor.nbr->flags & F_RDE_NBR_LOCAL0x02))
627 return;
628
629 TAILQ_FOREACH(route, &rn->routes, entry)for((route) = ((&rn->routes)->tqh_first); (route) !=
((void *)0); (route) = ((route)->entry.tqe_next))
{
630 /* skip redistributed routes */
631 if (route->nbr->flags & F_RDE_NBR_REDIST0x04)
632 continue;
633
634 /*
635 * Only feasible successors and the successor itself
636 * are elegible to be installed.
637 */
638 if (route->rdistance >= rn->successor.fdistance)
639 goto uninstall;
640
641 if (route->distance >
642 (rn->successor.fdistance * variance))
643 goto uninstall;
644
645 if (installed >= maximum_paths)
646 goto uninstall;
647
648 installed++;
649
650 if ((route->flags & F_EIGRP_ROUTE_INSTALLED0x01) &&
651 !(route->flags & F_EIGRP_ROUTE_M_CHANGED0x02))
652 continue;
653
654 rde_send_change_kroute(rn, route);
655 continue;
656
657uninstall:
658 if (route->flags & F_EIGRP_ROUTE_INSTALLED0x01)
659 rde_send_delete_kroute(rn, route);
660 }
661 } else {
662 TAILQ_FOREACH(route, &rn->routes, entry)for((route) = ((&rn->routes)->tqh_first); (route) !=
((void *)0); (route) = ((route)->entry.tqe_next))
663 if (route->flags & F_EIGRP_ROUTE_INSTALLED0x01)
664 rde_send_delete_kroute(rn, route);
665 }
666}
667
668static void
669rt_set_successor(struct rt_node *rn, struct eigrp_route *successor)
670{
671 struct eigrp *eigrp = rn->eigrp;
672 struct eigrp_iface *ei;
673 struct summary_addr *summary;
674
675 if (successor == NULL((void *)0)) {
676 rn->successor.nbr = NULL((void *)0);
677 rn->successor.type = 0;
678 rn->successor.fdistance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
679 rn->successor.rdistance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
680 memset(&rn->successor.metric, 0,
681 sizeof(rn->successor.metric));
682 rn->successor.metric.delay = EIGRP_INFINITE_METRIC((uint32_t )(~0));
683 memset(&rn->successor.emetric, 0,
684 sizeof(rn->successor.emetric));
685 } else {
686 rn->successor.nbr = successor->nbr;
687 rn->successor.type = successor->type;
688 rn->successor.fdistance = successor->distance;
689 rn->successor.rdistance = successor->rdistance;
690 rn->successor.metric = successor->metric;
691 rn->successor.emetric = successor->emetric;
692 }
693
694 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry)for((ei) = ((&eigrp->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->e_entry.tqe_next))
{
695 summary = rde_summary_check(ei, &rn->prefix, rn->prefixlen);
696 if (summary)
697 rt_summary_set(eigrp, summary, &rn->successor.metric);
698 }
699}
700
701static struct eigrp_route *
702rt_get_successor_fc(struct rt_node *rn)
703{
704 struct eigrp_route *route, *successor = NULL((void *)0);
705 uint32_t distance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
706 int external_only = 1;
707
708 TAILQ_FOREACH(route, &rn->routes, entry)for((route) = ((&rn->routes)->tqh_first); (route) !=
((void *)0); (route) = ((route)->entry.tqe_next))
709 if (route->type == EIGRP_ROUTE_INTERNAL) {
710 /*
711 * connected routes should always be prefered over
712 * received routes independent of the metric.
713 */
714 if (route->nbr->flags & F_RDE_NBR_LOCAL0x02)
715 return (route);
716
717 external_only = 0;
718 }
719
720 TAILQ_FOREACH(route, &rn->routes, entry)for((route) = ((&rn->routes)->tqh_first); (route) !=
((void *)0); (route) = ((route)->entry.tqe_next))
{
721 /*
722 * draft-savage-eigrp-04 - Section 5.4.7:
723 * "Internal routes MUST be prefered over external routes
724 * independent of the metric."
725 */
726 if (route->type == EIGRP_ROUTE_EXTERNAL && !external_only)
727 continue;
728
729 /* pick the best route that meets the feasibility condition */
730 if (route->rdistance < rn->successor.fdistance &&
731 route->distance < distance) {
732 distance = route->distance;
733 successor = route;
734 }
735 }
736
737 return (successor);
738}
739
740struct summary_addr *
741rde_summary_check(struct eigrp_iface *ei, union eigrpd_addr *prefix,
742 uint8_t prefixlen)
743{
744 struct summary_addr *summary;
745
746 TAILQ_FOREACH(summary, &ei->summary_list, entry)for((summary) = ((&ei->summary_list)->tqh_first); (
summary) != ((void *)0); (summary) = ((summary)->entry.tqe_next
))
{
747 /* do not filter the summary itself */
748 if (summary->prefixlen == prefixlen &&
749 !eigrp_addrcmp(ei->eigrp->af, prefix, &summary->prefix))
750 return (NULL((void *)0));
751
752 if (summary->prefixlen <= prefixlen &&
753 !eigrp_prefixcmp(ei->eigrp->af, prefix, &summary->prefix,
754 summary->prefixlen))
755 return (summary);
756 }
757
758 return (NULL((void *)0));
759}
760
761static void
762rde_send_update(struct eigrp_iface *ei, struct rinfo *ri)
763{
764 if (ri->metric.hop_count >= ei->eigrp->maximum_hops ||
765 rde_summary_check(ei, &ri->prefix, ri->prefixlen))
766 ri->metric.delay = EIGRP_INFINITE_METRIC((uint32_t )(~0));
767
768 rde_imsg_compose_eigrpe(IMSG_SEND_MUPDATE, ei->ifaceid, 0,
769 ri, sizeof(*ri));
770 rde_imsg_compose_eigrpe(IMSG_SEND_MUPDATE_END, ei->ifaceid, 0,
771 NULL((void *)0), 0);
772}
773
774static void
775rde_send_update_all(struct rt_node *rn, struct rinfo *ri)
776{
777 struct eigrp *eigrp = rn->eigrp;
778 struct eigrp_iface *ei;
779
780 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry)for((ei) = ((&eigrp->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->e_entry.tqe_next))
{
781 /* respect split-horizon configuration */
782 if (rn->successor.nbr && rn->successor.nbr->ei == ei &&
783 ei->splithorizon)
784 continue;
785 rde_send_update(ei, ri);
786 }
787}
788
789static void
790rde_send_query(struct eigrp_iface *ei, struct rinfo *ri, int push)
791{
792 rde_imsg_compose_eigrpe(IMSG_SEND_MQUERY, ei->ifaceid, 0,
793 ri, sizeof(*ri));
794 if (push)
795 rde_imsg_compose_eigrpe(IMSG_SEND_MQUERY_END, ei->ifaceid,
796 0, NULL((void *)0), 0);
797}
798
799static void
800rde_send_siaquery(struct rde_nbr *nbr, struct rinfo *ri)
801{
802 rde_imsg_compose_eigrpe(IMSG_SEND_QUERY, nbr->peerid, 0,
803 ri, sizeof(*ri));
804 rde_imsg_compose_eigrpe(IMSG_SEND_SIAQUERY_END, nbr->peerid, 0,
805 NULL((void *)0), 0);
806}
807
808static void
809rde_send_query_all(struct eigrp *eigrp, struct rt_node *rn, int push)
810{
811 struct eigrp_iface *ei;
812 struct rde_nbr *nbr;
813 struct rinfo ri;
814
815 rinfo_fill_successor(rn, &ri);
816 ri.metric.flags |= F_METRIC_ACTIVE0x04;
817
818 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry)for((ei) = ((&eigrp->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->e_entry.tqe_next))
{
819 /* respect split-horizon configuration */
820 if (rn->successor.nbr && rn->successor.nbr->ei == ei &&
821 ei->splithorizon)
822 continue;
823
824 rde_send_query(ei, &ri, push);
825 }
826
827 RB_FOREACH(nbr, rde_nbr_head, &rde_nbrs)for ((nbr) = rde_nbr_head_RB_MINMAX(&rde_nbrs, -1); (nbr)
!= ((void *)0); (nbr) = rde_nbr_head_RB_NEXT(nbr))
828 if (nbr->ei->eigrp == eigrp && !(nbr->flags & F_RDE_NBR_SELF0x01)) {
829 /* respect split-horizon configuration */
830 if (rn->successor.nbr &&
831 rn->successor.nbr->ei == nbr->ei &&
832 nbr->ei->splithorizon)
833 continue;
834
835 reply_outstanding_add(rn, nbr);
836 }
837}
838
839void
840rde_flush_queries(void)
841{
842 struct eigrp *eigrp;
843 struct eigrp_iface *ei;
844
845 TAILQ_FOREACH(eigrp, &rdeconf->instances, entry)for((eigrp) = ((&rdeconf->instances)->tqh_first); (
eigrp) != ((void *)0); (eigrp) = ((eigrp)->entry.tqe_next)
)
846 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry)for((ei) = ((&eigrp->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->e_entry.tqe_next))
847 rde_imsg_compose_eigrpe(IMSG_SEND_MQUERY_END,
848 ei->ifaceid, 0, NULL((void *)0), 0);
849}
850
851static void
852rde_send_reply(struct rde_nbr *nbr, struct rinfo *ri, int siareply)
853{
854 int type;
855
856 if (ri->metric.hop_count >= nbr->eigrp->maximum_hops ||
857 rde_summary_check(nbr->ei, &ri->prefix, ri->prefixlen))
858 ri->metric.delay = EIGRP_INFINITE_METRIC((uint32_t )(~0));
859
860 if (!siareply)
861 type = IMSG_SEND_REPLY_END;
862 else
863 type = IMSG_SEND_SIAREPLY_END;
864
865 rde_imsg_compose_eigrpe(IMSG_SEND_REPLY, nbr->peerid, 0,
866 ri, sizeof(*ri));
867 rde_imsg_compose_eigrpe(type, nbr->peerid, 0, NULL((void *)0), 0);
868}
869
870void
871rde_check_update(struct rde_nbr *nbr, struct rinfo *ri)
872{
873 struct eigrp *eigrp = nbr->eigrp;
874 struct rt_node *rn;
875 struct eigrp_route *route, *successor;
876 uint32_t old_fdistance;
877 struct rinfo sri;
878
879 rn = rt_find(eigrp, ri);
880 if (rn == NULL((void *)0)) {
881 if (ri->metric.delay == EIGRP_INFINITE_METRIC((uint32_t )(~0)))
882 return;
883
884 rn = rt_new(eigrp, ri);
885 route = route_new(rn, nbr, ri);
886
887 old_fdistance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
888 } else {
889 old_fdistance = rn->successor.fdistance;
890
891 if (ri->metric.delay == EIGRP_INFINITE_METRIC((uint32_t )(~0))) {
892 route = route_find(nbr, rn);
893 if (route)
894 route_del(rn, route);
895 } else {
896 route = route_find(nbr, rn);
897 if (route == NULL((void *)0))
898 route = route_new(rn, nbr, ri);
899 else
900 route_update_metrics(eigrp, route, ri);
901 }
902 }
903
904 switch (rn->state) {
905 case DUAL_STA_PASSIVE0x0001:
906 successor = rt_get_successor_fc(rn);
907
908 /*
909 * go active if the successor was affected and no feasible
910 * successor exist.
911 */
912 if (successor == NULL((void *)0)) {
913 rde_send_query_all(eigrp, rn, 1);
914
915 dual_fsm(rn, DUAL_EVT_4);
916 } else {
917 rt_set_successor(rn, successor);
918 rt_update_fib(rn);
919
920 /* send update with new metric if necessary */
921 rinfo_fill_successor(rn, &sri);
922 if (rn->successor.fdistance != old_fdistance)
923 rde_send_update_all(rn, &sri);
924 }
925 break;
926 case DUAL_STA_ACTIVE10x0004:
927 /* XXX event 9 if cost increase? */
928 break;
929 case DUAL_STA_ACTIVE30x0010:
930 /* XXX event 10 if cost increase? */
931 break;
932 }
933
934 if ((rn->state & DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010)) && TAILQ_EMPTY(&rn->rijk)(((&rn->rijk)->tqh_first) == ((void *)0)))
935 rde_last_reply(rn);
936}
937
938void
939rde_check_query(struct rde_nbr *nbr, struct rinfo *ri, int siaquery)
940{
941 struct eigrp *eigrp = nbr->eigrp;
942 struct rt_node *rn;
943 struct eigrp_route *route, *successor;
944 uint32_t old_fdistance;
945 struct rinfo sri;
946 int reply_sent = 0;
947
948 /*
949 * draft-savage-eigrp-02 - Section 4.3:
950 * "When a query is received for a route that doesn't exist in our
951 * topology table, a reply with infinite metric is sent and an entry
952 * in the topology table is added with the metric in the QUERY if
953 * the metric is not an infinite value".
954 */
955 rn = rt_find(eigrp, ri);
956 if (rn == NULL((void *)0)) {
957 sri = *ri;
958 sri.metric.delay = EIGRP_INFINITE_METRIC((uint32_t )(~0));
959 rde_send_reply(nbr, &sri, 0);
960
961 if (ri->metric.delay == EIGRP_INFINITE_METRIC((uint32_t )(~0)))
962 return;
963
964 rn = rt_new(eigrp, ri);
965 route = route_new(rn, nbr, ri);
966 rt_set_successor(rn, route);
967 return;
968 }
969
970 old_fdistance = rn->successor.fdistance;
971
972 if (ri->metric.delay == EIGRP_INFINITE_METRIC((uint32_t )(~0))) {
973 route = route_find(nbr, rn);
974 if (route)
975 route_del(rn, route);
976 } else {
977 route = route_find(nbr, rn);
978 if (route == NULL((void *)0))
979 route = route_new(rn, nbr, ri);
980 else
981 route_update_metrics(eigrp, route, ri);
982 }
983
984 switch (rn->state) {
985 case DUAL_STA_PASSIVE0x0001:
986 successor = rt_get_successor_fc(rn);
987
988 /*
989 * go active if the successor was affected and no feasible
990 * successor exist.
991 */
992 if (successor == NULL((void *)0)) {
993 rde_send_query_all(eigrp, rn, 1);
994 dual_fsm(rn, DUAL_EVT_3);
995 } else {
996 rt_set_successor(rn, successor);
997 rt_update_fib(rn);
998
999 /* send reply */
1000 rinfo_fill_successor(rn, &sri);
1001 rde_send_reply(nbr, &sri, 0);
1002 reply_sent = 1;
1003
1004 /* send update with new metric if necessary */
1005 if (rn->successor.fdistance != old_fdistance)
1006 rde_send_update_all(rn, &sri);
1007 }
1008 break;
1009 case DUAL_STA_ACTIVE00x0002:
1010 case DUAL_STA_ACTIVE10x0004:
1011 if (nbr == rn->successor.nbr)
1012 dual_fsm(rn, DUAL_EVT_5);
1013 else {
1014 dual_fsm(rn, DUAL_EVT_6);
1015 rinfo_fill_successor(rn, &sri);
1016 sri.metric.flags |= F_METRIC_ACTIVE0x04;
1017 rde_send_reply(nbr, &sri, 0);
1018 reply_sent = 1;
1019 }
1020 break;
1021 case DUAL_STA_ACTIVE20x0008:
1022 case DUAL_STA_ACTIVE30x0010:
1023 if (nbr == rn->successor.nbr) {
1024 /* XXX not defined in the spec, do nothing? */
1025 } else {
1026 dual_fsm(rn, DUAL_EVT_6);
1027 rinfo_fill_successor(rn, &sri);
1028 sri.metric.flags |= F_METRIC_ACTIVE0x04;
1029 rde_send_reply(nbr, &sri, 0);
1030 reply_sent = 1;
1031 }
1032 break;
1033 }
1034
1035 if ((rn->state & DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010)) && TAILQ_EMPTY(&rn->rijk)(((&rn->rijk)->tqh_first) == ((void *)0)))
1036 rde_last_reply(rn);
1037
1038 if (siaquery && !reply_sent) {
1039 rinfo_fill_successor(rn, &sri);
1040 sri.metric.flags |= F_METRIC_ACTIVE0x04;
1041 rde_send_reply(nbr, &sri, 1);
1042 }
1043}
1044
1045static void
1046rde_last_reply(struct rt_node *rn)
1047{
1048 struct eigrp *eigrp = rn->eigrp;
1049 struct eigrp_route *successor;
1050 struct rde_nbr *old_successor;
1051 uint32_t old_fdistance;
1052 struct rinfo ri;
1053
1054 old_successor = rn->successor.nbr;
1055 old_fdistance = rn->successor.fdistance;
Value stored to 'old_fdistance' is never read
1056
1057 switch (rn->state) {
1058 case DUAL_STA_ACTIVE00x0002:
1059 successor = rt_get_successor_fc(rn);
1060 if (successor == NULL((void *)0)) {
1061 /* feasibility condition is not met */
1062 rde_send_query_all(eigrp, rn, 1);
1063 dual_fsm(rn, DUAL_EVT_11);
1064 break;
1065 }
1066
1067 /* update successor - feasibility condition is met */
1068 rt_set_successor(rn, successor);
1069
1070 /* advertise new successor to neighbors */
1071 rinfo_fill_successor(rn, &ri);
1072 rde_send_update_all(rn, &ri);
1073
1074 dual_fsm(rn, DUAL_EVT_14);
1075 break;
1076 case DUAL_STA_ACTIVE10x0004:
1077 /* update successor */
1078 rn->successor.fdistance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
1079 successor = rt_get_successor_fc(rn);
1080 rt_set_successor(rn, successor);
1081
1082 /* advertise new successor to neighbors */
1083 rinfo_fill_successor(rn, &ri);
1084 rde_send_update_all(rn, &ri);
1085
1086 dual_fsm(rn, DUAL_EVT_15);
1087 break;
1088 case DUAL_STA_ACTIVE20x0008:
1089 successor = rt_get_successor_fc(rn);
1090 if (successor == NULL((void *)0)) {
1091 /* feasibility condition is not met */
1092 rde_send_query_all(eigrp, rn, 1);
1093 dual_fsm(rn, DUAL_EVT_12);
1094 break;
1095 }
1096
1097 /* update successor - feasibility condition is met */
1098 rt_set_successor(rn, successor);
1099
1100 /* send a reply to the old successor */
1101 rinfo_fill_successor(rn, &ri);
1102 ri.metric.flags |= F_METRIC_ACTIVE0x04;
1103 if (old_successor)
1104 rde_send_reply(old_successor, &ri, 0);
1105
1106 /* advertise new successor to neighbors */
1107 rde_send_update_all(rn, &ri);
1108
1109 dual_fsm(rn, DUAL_EVT_16);
1110 break;
1111 case DUAL_STA_ACTIVE30x0010:
1112 /* update successor */
1113 rn->successor.fdistance = EIGRP_INFINITE_METRIC((uint32_t )(~0));
1114 successor = rt_get_successor_fc(rn);
1115 rt_set_successor(rn, successor);
1116
1117 /* send a reply to the old successor */
1118 rinfo_fill_successor(rn, &ri);
1119 ri.metric.flags |= F_METRIC_ACTIVE0x04;
1120 if (old_successor)
1121 rde_send_reply(old_successor, &ri, 0);
1122
1123 /* advertise new successor to neighbors */
1124 rde_send_update_all(rn, &ri);
1125
1126 dual_fsm(rn, DUAL_EVT_13);
1127 break;
1128 }
1129
1130 if (rn->state == DUAL_STA_PASSIVE0x0001 && rn->successor.nbr == NULL((void *)0))
1131 rt_del(rn);
1132}
1133
1134void
1135rde_check_reply(struct rde_nbr *nbr, struct rinfo *ri, int siareply)
1136{
1137 struct eigrp *eigrp = nbr->eigrp;
1138 struct rt_node *rn;
1139 struct reply_node *reply;
1140 struct eigrp_route *route;
1141
1142 rn = rt_find(eigrp, ri);
1143 if (rn == NULL((void *)0))
1144 return;
1145
1146 /* XXX ignore reply when the state is passive? */
1147 if (rn->state == DUAL_STA_PASSIVE0x0001)
1148 return;
1149
1150 reply = reply_outstanding_find(rn, nbr);
1151 if (reply == NULL((void *)0))
1152 return;
1153
1154 if (siareply) {
1155 reply->siareply_recv = 1;
1156 reply_active_start_timer(reply);
1157 return;
1158 }
1159
1160 if (ri->metric.delay == EIGRP_INFINITE_METRIC((uint32_t )(~0))) {
1161 route = route_find(nbr, rn);
1162 if (route)
1163 route_del(rn, route);
1164 } else {
1165 route = route_find(nbr, rn);
1166 if (route == NULL((void *)0))
1167 route = route_new(rn, nbr, ri);
1168 else
1169 route_update_metrics(eigrp, route, ri);
1170 }
1171
1172 reply_outstanding_remove(reply);
1173 if (TAILQ_EMPTY(&rn->rijk)(((&rn->rijk)->tqh_first) == ((void *)0)))
1174 rde_last_reply(rn);
1175}
1176
1177void
1178rde_check_link_down_rn(struct rde_nbr *nbr, struct rt_node *rn,
1179 struct eigrp_route *route)
1180{
1181 struct eigrp *eigrp = nbr->eigrp;
1182 struct reply_node *reply;
1183 struct eigrp_route *successor;
1184 uint32_t old_fdistance;
1185 struct rinfo ri;
1186 enum route_type type;
1187
1188 old_fdistance = rn->successor.fdistance;
1189
1190 type = route->type;
1191 route_del(rn, route);
1192
1193 switch (rn->state) {
1194 case DUAL_STA_PASSIVE0x0001:
1195 successor = rt_get_successor_fc(rn);
1196
1197 /*
1198 * go active if the successor was affected and no feasible
1199 * successor exist.
1200 */
1201 if (successor == NULL((void *)0)) {
1202 rde_send_query_all(eigrp, rn, 0);
1203
1204 dual_fsm(rn, DUAL_EVT_4);
1205 } else {
1206 rt_set_successor(rn, successor);
1207 rt_update_fib(rn);
1208
1209 /* send update with new metric if necessary */
1210 rinfo_fill_successor(rn, &ri);
1211 if (rn->successor.fdistance != old_fdistance)
1212 rde_send_update_all(rn, &ri);
1213 }
1214 break;
1215 case DUAL_STA_ACTIVE10x0004:
1216 if (nbr == rn->successor.nbr)
1217 dual_fsm(rn, DUAL_EVT_9);
1218 break;
1219 case DUAL_STA_ACTIVE30x0010:
1220 if (nbr == rn->successor.nbr)
1221 dual_fsm(rn, DUAL_EVT_10);
1222 break;
1223 }
1224
1225 if (rn->state & DUAL_STA_ACTIVE_ALL(0x0002 | 0x0004 | 0x0008 | 0x0010)) {
1226 reply = reply_outstanding_find(rn, nbr);
1227 if (reply) {
1228 rinfo_fill_infinite(rn, type, &ri);
1229 rde_check_reply(nbr, &ri, 0);
1230 }
1231 }
1232}
1233
1234void
1235rde_check_link_down_nbr(struct rde_nbr *nbr)
1236{
1237 struct eigrp *eigrp = nbr->eigrp;
1238 struct rt_node *rn, *safe;
1239 struct eigrp_route *route;
1240
1241 RB_FOREACH_SAFE(rn, rt_tree, &eigrp->topology, safe)for ((rn) = rt_tree_RB_MINMAX(&eigrp->topology, -1); (
(rn) != ((void *)0)) && ((safe) = rt_tree_RB_NEXT(rn)
, 1); (rn) = (safe))
{
1242 route = route_find(nbr, rn);
1243 if (route) {
1244 rde_check_link_down_rn(nbr, rn, route);
1245 if (rn->successor.nbr == nbr)
1246 rn->successor.nbr = NULL((void *)0);
1247 }
1248 }
1249}
1250
1251void
1252rde_check_link_down(unsigned int ifindex)
1253{
1254 struct rde_nbr *nbr;
1255
1256 RB_FOREACH(nbr, rde_nbr_head, &rde_nbrs)for ((nbr) = rde_nbr_head_RB_MINMAX(&rde_nbrs, -1); (nbr)
!= ((void *)0); (nbr) = rde_nbr_head_RB_NEXT(nbr))
1257 if (nbr->ei->iface->ifindex == ifindex)
1258 rde_check_link_down_nbr(nbr);
1259
1260 rde_flush_queries();
1261}
1262
1263void
1264rde_check_link_cost_change(struct rde_nbr *nbr, struct eigrp_iface *ei)
1265{
1266}
1267
1268static __inline int
1269rde_nbr_compare(struct rde_nbr *a, struct rde_nbr *b)
1270{
1271 return (a->peerid - b->peerid);
1272}
1273
1274struct rde_nbr *
1275rde_nbr_find(uint32_t peerid)
1276{
1277 struct rde_nbr n;
1278
1279 n.peerid = peerid;
1280
1281 return (RB_FIND(rde_nbr_head, &rde_nbrs, &n)rde_nbr_head_RB_FIND(&rde_nbrs, &n));
1282}
1283
1284struct rde_nbr *
1285rde_nbr_new(uint32_t peerid, struct rde_nbr *new)
1286{
1287 struct rde_nbr *nbr;
1288
1289 if ((nbr = calloc(1, sizeof(*nbr))) == NULL((void *)0))
1290 fatal("rde_nbr_new");
1291
1292 nbr->peerid = peerid;
1293 nbr->ifaceid = new->ifaceid;
1294 nbr->addr = new->addr;
1295 nbr->ei = eigrp_if_lookup_id(nbr->ifaceid);
1296 if (nbr->ei)
1297 nbr->eigrp = nbr->ei->eigrp;
1298 TAILQ_INIT(&nbr->rijk)do { (&nbr->rijk)->tqh_first = ((void *)0); (&nbr
->rijk)->tqh_last = &(&nbr->rijk)->tqh_first
; } while (0)
;
1299 nbr->flags = new->flags;
1300
1301 if (nbr->peerid != NBR_IDSELF1 &&
1302 RB_INSERT(rde_nbr_head, &rde_nbrs, nbr)rde_nbr_head_RB_INSERT(&rde_nbrs, nbr) != NULL((void *)0))
1303 fatalx("rde_nbr_new: RB_INSERT failed");
1304
1305 return (nbr);
1306}
1307
1308void
1309rde_nbr_del(struct rde_nbr *nbr, int peerterm)
1310{
1311 struct reply_node *reply;
1312
1313 if (peerterm)
1314 rde_imsg_compose_eigrpe(IMSG_NEIGHBOR_DOWN, nbr->peerid,
1315 0, NULL((void *)0), 0);
1316
1317 while((reply = TAILQ_FIRST(&nbr->rijk)((&nbr->rijk)->tqh_first)) != NULL((void *)0))
1318 reply_outstanding_remove(reply);
1319
1320 if (nbr->peerid != NBR_IDSELF1)
1321 RB_REMOVE(rde_nbr_head, &rde_nbrs, nbr)rde_nbr_head_RB_REMOVE(&rde_nbrs, nbr);
1322 free(nbr);
1323}