Bug Summary

File:src/usr.sbin/bgpd/rde_peer.c
Warning:line 387, column 7
Although the value stored to 'p' is used in the enclosing expression, the value is never actually read from 'p'

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_peer.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_peer.c
1/* $OpenBSD: rde_peer.c,v 1.34 2023/11/07 11:17:35 claudio Exp $ */
2
3/*
4 * Copyright (c) 2019 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#include <sys/types.h>
19#include <sys/queue.h>
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "bgpd.h"
27#include "rde.h"
28
29struct peer_tree peertable;
30struct rde_peer *peerself;
31static long imsg_pending;
32
33CTASSERT(sizeof(peerself->recv_eor) * 8 > AID_MAX)extern char _ctassert[(sizeof(peerself->recv_eor) * 8 >
7) ? 1 : -1 ] __attribute__((__unused__))
;
34CTASSERT(sizeof(peerself->sent_eor) * 8 > AID_MAX)extern char _ctassert[(sizeof(peerself->sent_eor) * 8 >
7) ? 1 : -1 ] __attribute__((__unused__))
;
35
36struct iq {
37 SIMPLEQ_ENTRY(iq)struct { struct iq *sqe_next; } entry;
38 struct imsg imsg;
39};
40
41int
42peer_has_as4byte(struct rde_peer *peer)
43{
44 return (peer->capa.as4byte);
45}
46
47int
48peer_has_add_path(struct rde_peer *peer, uint8_t aid, int mode)
49{
50 if (aid > AID_MAX7)
51 return 0;
52 if (aid == AID_UNSPEC0) {
53 /* check if at capability is set for at least one AID */
54 for (aid = AID_MIN1; aid < AID_MAX7; aid++)
55 if (peer->capa.add_path[aid] & mode)
56 return 1;
57 return 0;
58 }
59 return (peer->capa.add_path[aid] & mode);
60}
61
62int
63peer_accept_no_as_set(struct rde_peer *peer)
64{
65 return (peer->flags & PEERFLAG_NO_AS_SET0x08);
66}
67
68void
69peer_init(struct filter_head *rules)
70{
71 struct peer_config pc;
72
73 RB_INIT(&peertable)do { (&peertable)->rbh_root = ((void *)0); } while (0);
74
75 memset(&pc, 0, sizeof(pc));
76 snprintf(pc.descr, sizeof(pc.descr), "LOCAL");
77 pc.id = PEER_ID_SELF1;
78
79 peerself = peer_add(PEER_ID_SELF1, &pc, rules);
80 peerself->state = PEER_UP;
81}
82
83void
84peer_shutdown(void)
85{
86 if (!RB_EMPTY(&peertable)((&peertable)->rbh_root == ((void *)0)))
87 log_warnx("%s: free non-free table", __func__);
88}
89
90/*
91 * Traverse all peers calling callback for each peer.
92 */
93void
94peer_foreach(void (*callback)(struct rde_peer *, void *), void *arg)
95{
96 struct rde_peer *peer, *np;
97
98 RB_FOREACH_SAFE(peer, peer_tree, &peertable, np)for ((peer) = peer_tree_RB_MINMAX(&peertable, -1); ((peer
) != ((void *)0)) && ((np) = peer_tree_RB_NEXT(peer),
1); (peer) = (np))
99 callback(peer, arg);
100}
101
102/*
103 * Lookup a peer by peer_id, return NULL if not found.
104 */
105struct rde_peer *
106peer_get(uint32_t id)
107{
108 struct rde_peer needle;
109
110 needle.conf.id = id;
111 return RB_FIND(peer_tree, &peertable, &needle)peer_tree_RB_FIND(&peertable, &needle);
112}
113
114/*
115 * Find next peer that matches neighbor options in *n.
116 * If peerid was set then pickup the lookup after that peer.
117 * Returns NULL if no more peers match.
118 */
119struct rde_peer *
120peer_match(struct ctl_neighbor *n, uint32_t peerid)
121{
122 struct rde_peer *peer;
123
124 if (peerid != 0) {
125 peer = peer_get(peerid);
126 if (peer)
127 peer = RB_NEXT(peer_tree, &peertable, peer)peer_tree_RB_NEXT(peer);
128 } else
129 peer = RB_MIN(peer_tree, &peertable)peer_tree_RB_MINMAX(&peertable, -1);
130
131 for (; peer != NULL((void *)0); peer = RB_NEXT(peer_tree, &peertable, peer)peer_tree_RB_NEXT(peer)) {
132 if (rde_match_peer(peer, n))
133 return peer;
134 }
135 return NULL((void *)0);
136}
137
138struct rde_peer *
139peer_add(uint32_t id, struct peer_config *p_conf, struct filter_head *rules)
140{
141 struct rde_peer *peer;
142 int conflict;
143
144 if ((peer = peer_get(id))) {
145 memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
146 return (peer);
147 }
148
149 peer = calloc(1, sizeof(struct rde_peer));
150 if (peer == NULL((void *)0))
151 fatal("peer_add");
152
153 memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
154 peer->remote_bgpid = 0;
155 peer->loc_rib_id = rib_find(peer->conf.rib);
156 if (peer->loc_rib_id == RIB_NOTFOUND0xffff)
157 fatalx("King Bula's new peer met an unknown RIB");
158 peer->state = PEER_NONE;
159 peer->eval = peer->conf.eval;
160 peer->role = peer->conf.role;
161 peer->export_type = peer->conf.export_type;
162 peer->flags = peer->conf.flags;
163 SIMPLEQ_INIT(&peer->imsg_queue)do { (&peer->imsg_queue)->sqh_first = ((void *)0); (
&peer->imsg_queue)->sqh_last = &(&peer->
imsg_queue)->sqh_first; } while (0)
;
164
165 peer_apply_out_filter(peer, rules);
166
167 /*
168 * Assign an even random unique transmit path id.
169 * Odd path_id_tx numbers are for peers using add-path recv.
170 */
171 do {
172 struct rde_peer *p;
173
174 conflict = 0;
175 peer->path_id_tx = arc4random() << 1;
176 RB_FOREACH(p, peer_tree, &peertable)for ((p) = peer_tree_RB_MINMAX(&peertable, -1); (p) != ((
void *)0); (p) = peer_tree_RB_NEXT(p))
{
177 if (p->path_id_tx == peer->path_id_tx) {
178 conflict = 1;
179 break;
180 }
181 }
182 } while (conflict);
183
184 if (RB_INSERT(peer_tree, &peertable, peer)peer_tree_RB_INSERT(&peertable, peer) != NULL((void *)0))
185 fatalx("rde peer table corrupted");
186
187 return (peer);
188}
189
190struct filter_head *
191peer_apply_out_filter(struct rde_peer *peer, struct filter_head *rules)
192{
193 struct filter_head *old;
194 struct filter_rule *fr, *new;
195
196 old = peer->out_rules;
197 if ((peer->out_rules = malloc(sizeof(*peer->out_rules))) == NULL((void *)0))
198 fatal(NULL((void *)0));
199 TAILQ_INIT(peer->out_rules)do { (peer->out_rules)->tqh_first = ((void *)0); (peer->
out_rules)->tqh_last = &(peer->out_rules)->tqh_first
; } while (0)
;
200
201 TAILQ_FOREACH(fr, rules, entry)for((fr) = ((rules)->tqh_first); (fr) != ((void *)0); (fr)
= ((fr)->entry.tqe_next))
{
202 if (rde_filter_skip_rule(peer, fr))
203 continue;
204
205 if ((new = malloc(sizeof(*new))) == NULL((void *)0))
206 fatal(NULL((void *)0));
207 memcpy(new, fr, sizeof(*new));
208 filterset_copy(&fr->set, &new->set);
209
210 TAILQ_INSERT_TAIL(peer->out_rules, new, entry)do { (new)->entry.tqe_next = ((void *)0); (new)->entry.
tqe_prev = (peer->out_rules)->tqh_last; *(peer->out_rules
)->tqh_last = (new); (peer->out_rules)->tqh_last = &
(new)->entry.tqe_next; } while (0)
;
211 }
212
213 return old;
214}
215
216static inline int
217peer_cmp(struct rde_peer *a, struct rde_peer *b)
218{
219 if (a->conf.id > b->conf.id)
220 return 1;
221 if (a->conf.id < b->conf.id)
222 return -1;
223 return 0;
224}
225
226RB_GENERATE(peer_tree, rde_peer, entry, peer_cmp)void peer_tree_RB_INSERT_COLOR(struct peer_tree *head, struct
rde_peer *elm) { struct rde_peer *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 peer_tree_RB_REMOVE_COLOR(struct peer_tree
*head, struct rde_peer *parent, struct rde_peer *elm) { struct
rde_peer *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_peer *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_peer *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_peer * peer_tree_RB_REMOVE
(struct peer_tree *head, struct rde_peer *elm) { struct rde_peer
*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_peer *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) peer_tree_RB_REMOVE_COLOR(head
, parent, child); return (old); } struct rde_peer * peer_tree_RB_INSERT
(struct peer_tree *head, struct rde_peer *elm) { struct rde_peer
*tmp; struct rde_peer *parent = ((void *)0); int comp = 0; tmp
= (head)->rbh_root; while (tmp) { parent = tmp; comp = (peer_cmp
)(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; peer_tree_RB_INSERT_COLOR(head
, elm); return (((void *)0)); } struct rde_peer * peer_tree_RB_FIND
(struct peer_tree *head, struct rde_peer *elm) { struct rde_peer
*tmp = (head)->rbh_root; int comp; while (tmp) { comp = peer_cmp
(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_peer * peer_tree_RB_NFIND
(struct peer_tree *head, struct rde_peer *elm) { struct rde_peer
*tmp = (head)->rbh_root; struct rde_peer *res = ((void *)
0); int comp; while (tmp) { comp = peer_cmp(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_peer * peer_tree_RB_NEXT(struct
rde_peer *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_peer
* peer_tree_RB_PREV(struct rde_peer *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_peer * peer_tree_RB_MINMAX(struct
peer_tree *head, int val) { struct rde_peer *tmp = (head)->
rbh_root; struct rde_peer *parent = ((void *)0); while (tmp) {
parent = tmp; if (val < 0) tmp = (tmp)->entry.rbe_left
; else tmp = (tmp)->entry.rbe_right; } return (parent); }
;
227
228static void
229peer_generate_update(struct rde_peer *peer, struct rib_entry *re,
230 struct prefix *newpath, struct prefix *oldpath,
231 enum eval_mode mode)
232{
233 uint8_t aid;
234
235 aid = re->prefix->aid;
236
237 /* skip ourself */
238 if (peer == peerself)
239 return;
240 if (peer->state != PEER_UP)
241 return;
242 /* skip peers using a different rib */
243 if (peer->loc_rib_id != re->rib_id)
244 return;
245 /* check if peer actually supports the address family */
246 if (peer->capa.mp[aid] == 0)
247 return;
248 /* skip peers with special export types */
249 if (peer->export_type == EXPORT_NONE ||
250 peer->export_type == EXPORT_DEFAULT_ROUTE)
251 return;
252
253 /* if reconf skip peers which don't need to reconfigure */
254 if (mode == EVAL_RECONF && peer->reconf_out == 0)
255 return;
256
257 /* handle peers with add-path */
258 if (peer_has_add_path(peer, aid, CAPA_AP_SEND0x02)) {
259 if (peer->eval.mode == ADDPATH_EVAL_ALL)
260 up_generate_addpath_all(peer, re, newpath, oldpath);
261 else
262 up_generate_addpath(peer, re);
263 return;
264 }
265
266 /* skip regular peers if the best path didn't change */
267 if (mode == EVAL_ALL && (peer->flags & PEERFLAG_EVALUATE_ALL0x04) == 0)
268 return;
269 up_generate_updates(peer, re);
270}
271
272void
273rde_generate_updates(struct rib_entry *re, struct prefix *newpath,
274 struct prefix *oldpath, enum eval_mode mode)
275{
276 struct rde_peer *peer;
277
278 RB_FOREACH(peer, peer_tree, &peertable)for ((peer) = peer_tree_RB_MINMAX(&peertable, -1); (peer)
!= ((void *)0); (peer) = peer_tree_RB_NEXT(peer))
279 peer_generate_update(peer, re, newpath, oldpath, mode);
280}
281
282/*
283 * Various RIB walker callbacks.
284 */
285static void
286peer_adjout_clear_upcall(struct prefix *p, void *arg)
287{
288 prefix_adjout_destroy(p);
289}
290
291static void
292peer_adjout_stale_upcall(struct prefix *p, void *arg)
293{
294 if (p->flags & PREFIX_FLAG_DEAD0x04) {
295 return;
296 } else if (p->flags & PREFIX_FLAG_WITHDRAW0x01) {
297 /* no need to keep stale withdraws, they miss all attributes */
298 prefix_adjout_destroy(p);
299 return;
300 } else if (p->flags & PREFIX_FLAG_UPDATE0x02) {
301 RB_REMOVE(prefix_tree, &prefix_peer(p)->updates[p->pt->aid], p)prefix_tree_RB_REMOVE(&prefix_peer(p)->updates[p->pt
->aid], p)
;
302 p->flags &= ~PREFIX_FLAG_UPDATE0x02;
303 }
304 p->flags |= PREFIX_FLAG_STALE0x08;
305}
306
307struct peer_flush {
308 struct rde_peer *peer;
309 time_t staletime;
310};
311
312static void
313peer_flush_upcall(struct rib_entry *re, void *arg)
314{
315 struct rde_peer *peer = ((struct peer_flush *)arg)->peer;
316 struct rde_aspath *asp;
317 struct bgpd_addr addr;
318 struct prefix *p, *np, *rp;
319 time_t staletime = ((struct peer_flush *)arg)->staletime;
320 uint32_t i;
321 uint8_t prefixlen;
322
323 pt_getaddr(re->prefix, &addr);
324 prefixlen = re->prefix->prefixlen;
325 TAILQ_FOREACH_SAFE(p, &re->prefix_h, entry.list.rib, np)for ((p) = ((&re->prefix_h)->tqh_first); (p) != ((void
*)0) && ((np) = ((p)->entry.list.rib.tqe_next), 1
); (p) = (np))
{
326 if (peer != prefix_peer(p))
327 continue;
328 if (staletime && p->lastchange > staletime)
329 continue;
330
331 for (i = RIB_LOC_START1; i < rib_size; i++) {
332 struct rib *rib = rib_byid(i);
333 if (rib == NULL((void *)0))
334 continue;
335 rp = prefix_get(rib, peer, p->path_id,
336 &addr, prefixlen);
337 if (rp) {
338 asp = prefix_aspath(rp);
339 if (asp && asp->pftableid)
340 rde_pftable_del(asp->pftableid, rp);
341
342 prefix_destroy(rp);
343 rde_update_log("flush", i, peer, NULL((void *)0),
344 &addr, prefixlen);
345 }
346 }
347
348 prefix_destroy(p);
349 peer->stats.prefix_cnt--;
350 }
351}
352
353static void
354rde_up_adjout_force_upcall(struct prefix *p, void *ptr)
355{
356 if (p->flags & PREFIX_FLAG_STALE0x08) {
357 /* remove stale entries */
358 prefix_adjout_destroy(p);
359 } else if (p->flags & PREFIX_FLAG_DEAD0x04) {
360 /* ignore dead prefixes, they will go away soon */
361 } else if ((p->flags & PREFIX_FLAG_MASK0x0f) == 0) {
362 /* put entries on the update queue if not allready on a queue */
363 p->flags |= PREFIX_FLAG_UPDATE0x02;
364 if (RB_INSERT(prefix_tree, &prefix_peer(p)->updates[p->pt->aid],prefix_tree_RB_INSERT(&prefix_peer(p)->updates[p->pt
->aid], p)
365 p)prefix_tree_RB_INSERT(&prefix_peer(p)->updates[p->pt
->aid], p)
!= NULL((void *)0))
366 fatalx("%s: RB tree invariant violated", __func__);
367 }
368}
369
370static void
371rde_up_adjout_force_done(void *ptr, uint8_t aid)
372{
373 struct rde_peer *peer = ptr;
374
375 /* Adj-RIB-Out ready, unthrottle peer and inject EOR */
376 peer->throttled = 0;
377 if (peer->capa.grestart.restart)
378 prefix_add_eor(peer, aid);
379}
380
381static void
382rde_up_dump_upcall(struct rib_entry *re, void *ptr)
383{
384 struct rde_peer *peer = ptr;
385 struct prefix *p;
386
387 if ((p = prefix_best(re)) == NULL((void *)0))
Although the value stored to 'p' is used in the enclosing expression, the value is never actually read from 'p'
388 /* no eligible prefix, not even for 'evaluate all' */
389 return;
390
391 peer_generate_update(peer, re, NULL((void *)0), NULL((void *)0), 0);
392}
393
394static void
395rde_up_dump_done(void *ptr, uint8_t aid)
396{
397 struct rde_peer *peer = ptr;
398
399 /* force out all updates of Adj-RIB-Out for this peer */
400 if (prefix_dump_new(peer, aid, 0, peer, rde_up_adjout_force_upcall,
401 rde_up_adjout_force_done, NULL((void *)0)) == -1)
402 fatal("%s: prefix_dump_new", __func__);
403}
404
405/*
406 * Session got established, bring peer up, load RIBs do initial table dump.
407 */
408void
409peer_up(struct rde_peer *peer, struct session_up *sup)
410{
411 uint8_t i;
412
413 if (peer->state == PEER_ERR) {
414 /*
415 * There is a race condition when doing PEER_ERR -> PEER_DOWN.
416 * So just do a full reset of the peer here.
417 */
418 rib_dump_terminate(peer);
419 peer_imsg_flush(peer);
420 if (prefix_dump_new(peer, AID_UNSPEC0, 0, NULL((void *)0),
421 peer_adjout_clear_upcall, NULL((void *)0), NULL((void *)0)) == -1)
422 fatal("%s: prefix_dump_new", __func__);
423 peer_flush(peer, AID_UNSPEC0, 0);
424 peer->stats.prefix_cnt = 0;
425 peer->stats.prefix_out_cnt = 0;
426 peer->state = PEER_DOWN;
427 }
428 peer->remote_bgpid = ntohl(sup->remote_bgpid)(__uint32_t)(__builtin_constant_p(sup->remote_bgpid) ? (__uint32_t
)(((__uint32_t)(sup->remote_bgpid) & 0xff) << 24
| ((__uint32_t)(sup->remote_bgpid) & 0xff00) <<
8 | ((__uint32_t)(sup->remote_bgpid) & 0xff0000) >>
8 | ((__uint32_t)(sup->remote_bgpid) & 0xff000000) >>
24) : __swap32md(sup->remote_bgpid))
;
429 peer->short_as = sup->short_as;
430 peer->remote_addr = sup->remote_addr;
431 peer->local_v4_addr = sup->local_v4_addr;
432 peer->local_v6_addr = sup->local_v6_addr;
433 peer->local_if_scope = sup->if_scope;
434 memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
435
436 /* clear eor markers depending on GR flags */
437 if (peer->capa.grestart.restart) {
438 peer->sent_eor = 0;
439 peer->recv_eor = 0;
440 } else {
441 /* no EOR expected */
442 peer->sent_eor = ~0;
443 peer->recv_eor = ~0;
444 }
445 peer->state = PEER_UP;
446
447 for (i = 0; i < AID_MAX7; i++) {
448 if (peer->capa.mp[i])
449 peer_dump(peer, i);
450 }
451}
452
453/*
454 * Session dropped and no graceful restart is done. Stop everything for
455 * this peer and clean up.
456 */
457void
458peer_down(struct rde_peer *peer, void *bula)
459{
460 peer->remote_bgpid = 0;
461 peer->state = PEER_DOWN;
462 /*
463 * stop all pending dumps which may depend on this peer
464 * and flush all pending imsg from the SE.
465 */
466 rib_dump_terminate(peer);
467 peer_imsg_flush(peer);
468
469 /* flush Adj-RIB-Out */
470 if (prefix_dump_new(peer, AID_UNSPEC0, 0, NULL((void *)0),
471 peer_adjout_clear_upcall, NULL((void *)0), NULL((void *)0)) == -1)
472 fatal("%s: prefix_dump_new", __func__);
473
474 /* flush Adj-RIB-In */
475 peer_flush(peer, AID_UNSPEC0, 0);
476 peer->stats.prefix_cnt = 0;
477 peer->stats.prefix_out_cnt = 0;
478
479 /* free filters */
480 filterlist_free(peer->out_rules);
481
482 RB_REMOVE(peer_tree, &peertable, peer)peer_tree_RB_REMOVE(&peertable, peer);
483 free(peer);
484}
485
486/*
487 * Flush all routes older then staletime. If staletime is 0 all routes will
488 * be flushed.
489 */
490void
491peer_flush(struct rde_peer *peer, uint8_t aid, time_t staletime)
492{
493 struct peer_flush pf = { peer, staletime };
494
495 /* this dump must run synchronous, too much depends on that right now */
496 if (rib_dump_new(RIB_ADJ_IN0, aid, 0, &pf, peer_flush_upcall,
497 NULL((void *)0), NULL((void *)0)) == -1)
498 fatal("%s: rib_dump_new", __func__);
499
500 /* every route is gone so reset staletime */
501 if (aid == AID_UNSPEC0) {
502 uint8_t i;
503 for (i = 0; i < AID_MAX7; i++)
504 peer->staletime[i] = 0;
505 } else {
506 peer->staletime[aid] = 0;
507 }
508}
509
510/*
511 * During graceful restart mark a peer as stale if the session goes down.
512 * For the specified AID the Adj-RIB-Out is marked stale and the staletime
513 * is set to the current timestamp for identifying stale routes in Adj-RIB-In.
514 */
515void
516peer_stale(struct rde_peer *peer, uint8_t aid, int flushall)
517{
518 time_t now;
519
520 /* flush the now even staler routes out */
521 if (peer->staletime[aid])
522 peer_flush(peer, aid, peer->staletime[aid]);
523
524 peer->staletime[aid] = now = getmonotime();
525 peer->state = PEER_DOWN;
526
527 /*
528 * stop all pending dumps which may depend on this peer
529 * and flush all pending imsg from the SE.
530 */
531 rib_dump_terminate(peer);
532 peer_imsg_flush(peer);
533
534 if (flushall)
535 peer_flush(peer, aid, 0);
536
537 /* XXX this is not quite correct */
538 /* mark Adj-RIB-Out stale for this peer */
539 if (prefix_dump_new(peer, aid, 0, NULL((void *)0),
540 peer_adjout_stale_upcall, NULL((void *)0), NULL((void *)0)) == -1)
541 fatal("%s: prefix_dump_new", __func__);
542
543 /* make sure new prefixes start on a higher timestamp */
544 while (now >= getmonotime())
545 sleep(1);
546}
547
548/*
549 * Load the Adj-RIB-Out of a peer normally called when a session is established.
550 * Once the Adj-RIB-Out is ready stale routes are removed from the Adj-RIB-Out
551 * and all routes are put on the update queue so they will be sent out.
552 */
553void
554peer_dump(struct rde_peer *peer, uint8_t aid)
555{
556 if (peer->capa.enhanced_rr && (peer->sent_eor & (1 << aid)))
557 rde_peer_send_rrefresh(peer, aid, ROUTE_REFRESH_BEGIN_RR1);
558
559 if (peer->export_type == EXPORT_NONE) {
560 /* nothing to send apart from the marker */
561 if (peer->capa.grestart.restart)
562 prefix_add_eor(peer, aid);
563 } else if (peer->export_type == EXPORT_DEFAULT_ROUTE) {
564 up_generate_default(peer, aid);
565 rde_up_dump_done(peer, aid);
566 } else if (aid == AID_FLOWSPECv45 || aid == AID_FLOWSPECv66) {
567 prefix_flowspec_dump(aid, peer, rde_up_dump_upcall,
568 rde_up_dump_done);
569 } else {
570 if (rib_dump_new(peer->loc_rib_id, aid, RDE_RUNNER_ROUNDS100, peer,
571 rde_up_dump_upcall, rde_up_dump_done, NULL((void *)0)) == -1)
572 fatal("%s: rib_dump_new", __func__);
573 /* throttle peer until dump is done */
574 peer->throttled = 1;
575 }
576}
577
578/*
579 * Start of an enhanced route refresh. Mark all routes as stale.
580 * Once the route refresh ends a End of Route Refresh message is sent
581 * which calls peer_flush() to remove all stale routes.
582 */
583void
584peer_begin_rrefresh(struct rde_peer *peer, uint8_t aid)
585{
586 time_t now;
587
588 /* flush the now even staler routes out */
589 if (peer->staletime[aid])
590 peer_flush(peer, aid, peer->staletime[aid]);
591
592 peer->staletime[aid] = now = getmonotime();
593
594 /* make sure new prefixes start on a higher timestamp */
595 while (now >= getmonotime())
596 sleep(1);
597}
598
599/*
600 * move an imsg from src to dst, disconnecting any dynamic memory from src.
601 */
602static void
603imsg_move(struct imsg *dst, struct imsg *src)
604{
605 *dst = *src;
606 memset(src, 0, sizeof(*src));
607}
608
609/*
610 * push an imsg onto the peer imsg queue.
611 */
612void
613peer_imsg_push(struct rde_peer *peer, struct imsg *imsg)
614{
615 struct iq *iq;
616
617 if ((iq = calloc(1, sizeof(*iq))) == NULL((void *)0))
618 fatal(NULL((void *)0));
619 imsg_move(&iq->imsg, imsg);
620 SIMPLEQ_INSERT_TAIL(&peer->imsg_queue, iq, entry)do { (iq)->entry.sqe_next = ((void *)0); *(&peer->imsg_queue
)->sqh_last = (iq); (&peer->imsg_queue)->sqh_last
= &(iq)->entry.sqe_next; } while (0)
;
621 imsg_pending++;
622}
623
624/*
625 * pop first imsg from peer imsg queue and move it into imsg argument.
626 * Returns 1 if an element is returned else 0.
627 */
628int
629peer_imsg_pop(struct rde_peer *peer, struct imsg *imsg)
630{
631 struct iq *iq;
632
633 iq = SIMPLEQ_FIRST(&peer->imsg_queue)((&peer->imsg_queue)->sqh_first);
634 if (iq == NULL((void *)0))
635 return 0;
636
637 imsg_move(imsg, &iq->imsg);
638
639 SIMPLEQ_REMOVE_HEAD(&peer->imsg_queue, entry)do { if (((&peer->imsg_queue)->sqh_first = (&peer
->imsg_queue)->sqh_first->entry.sqe_next) == ((void *
)0)) (&peer->imsg_queue)->sqh_last = &(&peer
->imsg_queue)->sqh_first; } while (0)
;
640 free(iq);
641 imsg_pending--;
642
643 return 1;
644}
645
646/*
647 * Check if any imsg are pending, return 0 if none are pending
648 */
649int
650peer_imsg_pending(void)
651{
652 return imsg_pending != 0;
653}
654
655/*
656 * flush all imsg queued for a peer.
657 */
658void
659peer_imsg_flush(struct rde_peer *peer)
660{
661 struct iq *iq;
662
663 while ((iq = SIMPLEQ_FIRST(&peer->imsg_queue)((&peer->imsg_queue)->sqh_first)) != NULL((void *)0)) {
664 SIMPLEQ_REMOVE_HEAD(&peer->imsg_queue, entry)do { if (((&peer->imsg_queue)->sqh_first = (&peer
->imsg_queue)->sqh_first->entry.sqe_next) == ((void *
)0)) (&peer->imsg_queue)->sqh_last = &(&peer
->imsg_queue)->sqh_first; } while (0)
;
665 free(iq);
666 imsg_pending--;
667 }
668}