1 /* $OpenBSD: rde_peer.c,v 1.6 2020/12/04 11:57:13 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
29 struct peer_table {
30 struct rde_peer_head *peer_hashtbl;
31 u_int32_t peer_hashmask;
32 } peertable;
33
34 #define PEER_HASH(x) \
35 &peertable.peer_hashtbl[(x) & peertable.peer_hashmask]
36
37 struct rde_peer_head peerlist;
38 struct rde_peer *peerself;
39
40 struct iq {
41 SIMPLEQ_ENTRY(iq) entry;
42 struct imsg imsg;
43 };
44
45 extern struct filter_head *out_rules;
46
47 void
peer_init(u_int32_t hashsize)48 peer_init(u_int32_t hashsize)
49 {
50 struct peer_config pc;
51 u_int32_t hs, i;
52
53 for (hs = 1; hs < hashsize; hs <<= 1)
54 ;
55 peertable.peer_hashtbl = calloc(hs, sizeof(struct rde_peer_head));
56 if (peertable.peer_hashtbl == NULL)
57 fatal("peer_init");
58
59 for (i = 0; i < hs; i++)
60 LIST_INIT(&peertable.peer_hashtbl[i]);
61 LIST_INIT(&peerlist);
62
63 peertable.peer_hashmask = hs - 1;
64
65 bzero(&pc, sizeof(pc));
66 snprintf(pc.descr, sizeof(pc.descr), "LOCAL");
67 pc.id = PEER_ID_SELF;
68
69 peerself = peer_add(PEER_ID_SELF, &pc);
70 if (peerself == NULL)
71 fatalx("peer_init add self");
72
73 peerself->state = PEER_UP;
74 }
75
76 void
peer_shutdown(void)77 peer_shutdown(void)
78 {
79 u_int32_t i;
80
81 for (i = 0; i <= peertable.peer_hashmask; i++)
82 if (!LIST_EMPTY(&peertable.peer_hashtbl[i]))
83 log_warnx("peer_free: free non-free table");
84
85 free(peertable.peer_hashtbl);
86 }
87
88 /*
89 * Traverse all peers calling callback for each peer.
90 */
91 void
peer_foreach(void (* callback)(struct rde_peer *,void *),void * arg)92 peer_foreach(void (*callback)(struct rde_peer *, void *), void *arg)
93 {
94 struct rde_peer *peer, *np;
95
96 LIST_FOREACH_SAFE(peer, &peerlist, peer_l, np)
97 callback(peer, arg);
98 }
99
100 /*
101 * Lookup a peer by peer_id, return NULL if not found.
102 */
103 struct rde_peer *
peer_get(u_int32_t id)104 peer_get(u_int32_t id)
105 {
106 struct rde_peer_head *head;
107 struct rde_peer *peer;
108
109 head = PEER_HASH(id);
110
111 LIST_FOREACH(peer, head, hash_l) {
112 if (peer->conf.id == id)
113 return (peer);
114 }
115 return (NULL);
116 }
117
118 /*
119 * Find next peer that matches neighbor options in *n.
120 * If peerid was set then pickup the lookup after that peer.
121 * Returns NULL if no more peers match.
122 */
123 struct rde_peer *
peer_match(struct ctl_neighbor * n,u_int32_t peerid)124 peer_match(struct ctl_neighbor *n, u_int32_t peerid)
125 {
126 struct rde_peer_head *head;
127 struct rde_peer *peer;
128 u_int32_t i = 0;
129
130 if (peerid != 0)
131 i = peerid & peertable.peer_hashmask;
132
133 while (i <= peertable.peer_hashmask) {
134 head = &peertable.peer_hashtbl[i];
135 LIST_FOREACH(peer, head, hash_l) {
136 /* skip peers until peerid is found */
137 if (peerid == peer->conf.id) {
138 peerid = 0;
139 continue;
140 }
141 if (peerid != 0)
142 continue;
143
144 if (rde_match_peer(peer, n))
145 return (peer);
146 }
147 i++;
148 }
149 return (NULL);
150 }
151
152 struct rde_peer *
peer_add(u_int32_t id,struct peer_config * p_conf)153 peer_add(u_int32_t id, struct peer_config *p_conf)
154 {
155 struct rde_peer_head *head;
156 struct rde_peer *peer;
157
158 if ((peer = peer_get(id))) {
159 memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
160 return (NULL);
161 }
162
163 peer = calloc(1, sizeof(struct rde_peer));
164 if (peer == NULL)
165 fatal("peer_add");
166
167 memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
168 peer->remote_bgpid = 0;
169 peer->loc_rib_id = rib_find(peer->conf.rib);
170 if (peer->loc_rib_id == RIB_NOTFOUND)
171 fatalx("King Bula's new peer met an unknown RIB");
172 peer->state = PEER_NONE;
173 SIMPLEQ_INIT(&peer->imsg_queue);
174
175 head = PEER_HASH(id);
176
177 LIST_INSERT_HEAD(head, peer, hash_l);
178 LIST_INSERT_HEAD(&peerlist, peer, peer_l);
179
180 return (peer);
181 }
182
183 /*
184 * Various RIB walker callbacks.
185 */
186 static void
peer_adjout_clear_upcall(struct prefix * p,void * arg)187 peer_adjout_clear_upcall(struct prefix *p, void *arg)
188 {
189 prefix_adjout_destroy(p);
190 }
191
192 static void
peer_adjout_stale_upcall(struct prefix * p,void * arg)193 peer_adjout_stale_upcall(struct prefix *p, void *arg)
194 {
195 if (p->flags & PREFIX_FLAG_DEAD) {
196 return;
197 } else if (p->flags & PREFIX_FLAG_WITHDRAW) {
198 /* no need to keep stale withdraws, they miss all attributes */
199 prefix_adjout_destroy(p);
200 return;
201 } else if (p->flags & PREFIX_FLAG_UPDATE) {
202 RB_REMOVE(prefix_tree, &prefix_peer(p)->updates[p->pt->aid], p);
203 p->flags &= ~PREFIX_FLAG_UPDATE;
204 }
205 p->flags |= PREFIX_FLAG_STALE;
206 }
207
208 struct peer_flush {
209 struct rde_peer *peer;
210 time_t staletime;
211 };
212
213 static void
peer_flush_upcall(struct rib_entry * re,void * arg)214 peer_flush_upcall(struct rib_entry *re, void *arg)
215 {
216 struct rde_peer *peer = ((struct peer_flush *)arg)->peer;
217 struct rde_aspath *asp;
218 struct bgpd_addr addr;
219 struct prefix *p, *np, *rp;
220 time_t staletime = ((struct peer_flush *)arg)->staletime;
221 u_int32_t i;
222 u_int8_t prefixlen;
223
224 pt_getaddr(re->prefix, &addr);
225 prefixlen = re->prefix->prefixlen;
226 LIST_FOREACH_SAFE(p, &re->prefix_h, entry.list.rib, np) {
227 if (peer != prefix_peer(p))
228 continue;
229 if (staletime && p->lastchange > staletime)
230 continue;
231
232 for (i = RIB_LOC_START; i < rib_size; i++) {
233 struct rib *rib = rib_byid(i);
234 if (rib == NULL)
235 continue;
236 rp = prefix_get(rib, peer, &addr, prefixlen);
237 if (rp) {
238 asp = prefix_aspath(rp);
239 if (asp && asp->pftableid)
240 rde_pftable_del(asp->pftableid, rp);
241
242 prefix_destroy(rp);
243 rde_update_log("flush", i, peer, NULL,
244 &addr, prefixlen);
245 }
246 }
247
248 prefix_destroy(p);
249 peer->prefix_cnt--;
250 break; /* optimization, only one match per peer possible */
251 }
252 }
253
254 static void
rde_up_adjout_force_upcall(struct prefix * p,void * ptr)255 rde_up_adjout_force_upcall(struct prefix *p, void *ptr)
256 {
257 if (p->flags & PREFIX_FLAG_STALE) {
258 /* remove stale entries */
259 prefix_adjout_destroy(p);
260 } else if (p->flags & PREFIX_FLAG_DEAD) {
261 /* ignore dead prefixes, they will go away soon */
262 } else if ((p->flags & PREFIX_FLAG_MASK) == 0) {
263 /* put entries on the update queue if not allready on a queue */
264 p->flags |= PREFIX_FLAG_UPDATE;
265 if (RB_INSERT(prefix_tree, &prefix_peer(p)->updates[p->pt->aid],
266 p) != NULL)
267 fatalx("%s: RB tree invariant violated", __func__);
268 }
269 }
270
271 static void
rde_up_adjout_force_done(void * ptr,u_int8_t aid)272 rde_up_adjout_force_done(void *ptr, u_int8_t aid)
273 {
274 struct rde_peer *peer = ptr;
275
276 /* Adj-RIB-Out ready, unthrottle peer and inject EOR */
277 peer->throttled = 0;
278 if (peer->capa.grestart.restart)
279 prefix_add_eor(peer, aid);
280 }
281
282 static void
rde_up_dump_upcall(struct rib_entry * re,void * ptr)283 rde_up_dump_upcall(struct rib_entry *re, void *ptr)
284 {
285 struct rde_peer *peer = ptr;
286
287 if (re->rib_id != peer->loc_rib_id)
288 fatalx("%s: Unexpected RIB %u != %u.", __func__, re->rib_id,
289 peer->loc_rib_id);
290 if (re->active == NULL)
291 return;
292 up_generate_updates(out_rules, peer, re->active, NULL);
293 }
294
295 static void
rde_up_dump_done(void * ptr,u_int8_t aid)296 rde_up_dump_done(void *ptr, u_int8_t aid)
297 {
298 struct rde_peer *peer = ptr;
299
300 /* force out all updates of Adj-RIB-Out for this peer */
301 if (prefix_dump_new(peer, aid, 0, peer, rde_up_adjout_force_upcall,
302 rde_up_adjout_force_done, NULL) == -1)
303 fatal("%s: prefix_dump_new", __func__);
304 }
305
306 /*
307 * Session got established, bring peer up, load RIBs do initial table dump.
308 */
309 int
peer_up(struct rde_peer * peer,struct session_up * sup)310 peer_up(struct rde_peer *peer, struct session_up *sup)
311 {
312 u_int8_t i;
313
314 if (peer->state == PEER_ERR) {
315 /*
316 * There is a race condition when doing PEER_ERR -> PEER_DOWN.
317 * So just do a full reset of the peer here.
318 */
319 if (prefix_dump_new(peer, AID_UNSPEC, 0, NULL,
320 peer_adjout_clear_upcall, NULL, NULL) == -1)
321 fatal("%s: prefix_dump_new", __func__);
322 peer_flush(peer, AID_UNSPEC, 0);
323 peer->prefix_cnt = 0;
324 peer->prefix_out_cnt = 0;
325 peer->state = PEER_DOWN;
326 }
327 peer->remote_bgpid = ntohl(sup->remote_bgpid);
328 peer->short_as = sup->short_as;
329 peer->remote_addr = sup->remote_addr;
330 peer->local_v4_addr = sup->local_v4_addr;
331 peer->local_v6_addr = sup->local_v6_addr;
332 memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
333
334 peer->state = PEER_UP;
335
336 for (i = 0; i < AID_MAX; i++) {
337 if (peer->capa.mp[i])
338 peer_dump(peer, i);
339 }
340
341 return (0);
342 }
343
344 /*
345 * Session dropped and no graceful restart is done. Stop everything for
346 * this peer and clean up.
347 */
348 void
peer_down(struct rde_peer * peer,void * bula)349 peer_down(struct rde_peer *peer, void *bula)
350 {
351 peer->remote_bgpid = 0;
352 peer->state = PEER_DOWN;
353 /* stop all pending dumps which may depend on this peer */
354 rib_dump_terminate(peer);
355
356 /* flush Adj-RIB-Out */
357 if (prefix_dump_new(peer, AID_UNSPEC, 0, NULL,
358 peer_adjout_clear_upcall, NULL, NULL) == -1)
359 fatal("%s: prefix_dump_new", __func__);
360
361 /* flush Adj-RIB-In */
362 peer_flush(peer, AID_UNSPEC, 0);
363 peer->prefix_cnt = 0;
364 peer->prefix_out_cnt = 0;
365
366 peer_imsg_flush(peer);
367
368 LIST_REMOVE(peer, hash_l);
369 LIST_REMOVE(peer, peer_l);
370 free(peer);
371 }
372
373 /*
374 * Flush all routes older then staletime. If staletime is 0 all routes will
375 * be flushed.
376 */
377 void
peer_flush(struct rde_peer * peer,u_int8_t aid,time_t staletime)378 peer_flush(struct rde_peer *peer, u_int8_t aid, time_t staletime)
379 {
380 struct peer_flush pf = { peer, staletime };
381
382 /* this dump must run synchronous, too much depends on that right now */
383 if (rib_dump_new(RIB_ADJ_IN, aid, 0, &pf, peer_flush_upcall,
384 NULL, NULL) == -1)
385 fatal("%s: rib_dump_new", __func__);
386
387 /* every route is gone so reset staletime */
388 if (aid == AID_UNSPEC) {
389 u_int8_t i;
390 for (i = 0; i < AID_MAX; i++)
391 peer->staletime[i] = 0;
392 } else {
393 peer->staletime[aid] = 0;
394 }
395 }
396
397 /*
398 * During graceful restart mark a peer as stale if the session goes down.
399 * For the specified AID the Adj-RIB-Out as marked stale and the staletime
400 * is set to the current timestamp for identifying stale routes in Adj-RIB-In.
401 */
402 void
peer_stale(struct rde_peer * peer,u_int8_t aid)403 peer_stale(struct rde_peer *peer, u_int8_t aid)
404 {
405 time_t now;
406
407 /* flush the now even staler routes out */
408 if (peer->staletime[aid])
409 peer_flush(peer, aid, peer->staletime[aid]);
410
411 peer->staletime[aid] = now = getmonotime();
412 peer->state = PEER_DOWN;
413
414 /* mark Adj-RIB-Out stale for this peer */
415 if (prefix_dump_new(peer, AID_UNSPEC, 0, NULL,
416 peer_adjout_stale_upcall, NULL, NULL) == -1)
417 fatal("%s: prefix_dump_new", __func__);
418
419 /* make sure new prefixes start on a higher timestamp */
420 while (now >= getmonotime())
421 sleep(1);
422 }
423
424 /*
425 * Load the Adj-RIB-Out of a peer normally called when a session is established.
426 * Once the Adj-RIB-Out is ready stale routes are removed from the Adj-RIB-Out
427 * and all routes are put on the update queue so they will be sent out.
428 */
429 void
peer_dump(struct rde_peer * peer,u_int8_t aid)430 peer_dump(struct rde_peer *peer, u_int8_t aid)
431 {
432 if (peer->conf.export_type == EXPORT_NONE) {
433 /* nothing to send apart from the marker */
434 if (peer->capa.grestart.restart)
435 prefix_add_eor(peer, aid);
436 } else if (peer->conf.export_type == EXPORT_DEFAULT_ROUTE) {
437 up_generate_default(out_rules, peer, aid);
438 rde_up_dump_done(peer, aid);
439 } else {
440 if (rib_dump_new(peer->loc_rib_id, aid, RDE_RUNNER_ROUNDS, peer,
441 rde_up_dump_upcall, rde_up_dump_done, NULL) == -1)
442 fatal("%s: rib_dump_new", __func__);
443 /* throttle peer until dump is done */
444 peer->throttled = 1;
445 }
446 }
447
448 /*
449 * move an imsg from src to dst, disconnecting any dynamic memory from src.
450 */
451 static void
imsg_move(struct imsg * dst,struct imsg * src)452 imsg_move(struct imsg *dst, struct imsg *src)
453 {
454 *dst = *src;
455 src->data = NULL; /* allocation was moved */
456 }
457
458 /*
459 * push an imsg onto the peer imsg queue.
460 */
461 void
peer_imsg_push(struct rde_peer * peer,struct imsg * imsg)462 peer_imsg_push(struct rde_peer *peer, struct imsg *imsg)
463 {
464 struct iq *iq;
465
466 if ((iq = calloc(1, sizeof(*iq))) == NULL)
467 fatal(NULL);
468 imsg_move(&iq->imsg, imsg);
469 SIMPLEQ_INSERT_TAIL(&peer->imsg_queue, iq, entry);
470 }
471
472 /*
473 * pop first imsg from peer imsg queue and move it into imsg argument.
474 * Returns 1 if an element is returned else 0.
475 */
476 int
peer_imsg_pop(struct rde_peer * peer,struct imsg * imsg)477 peer_imsg_pop(struct rde_peer *peer, struct imsg *imsg)
478 {
479 struct iq *iq;
480
481 iq = SIMPLEQ_FIRST(&peer->imsg_queue);
482 if (iq == NULL)
483 return 0;
484
485 imsg_move(imsg, &iq->imsg);
486
487 SIMPLEQ_REMOVE_HEAD(&peer->imsg_queue, entry);
488 free(iq);
489
490 return 1;
491 }
492
493 static void
peer_imsg_queued(struct rde_peer * peer,void * arg)494 peer_imsg_queued(struct rde_peer *peer, void *arg)
495 {
496 int *p = arg;
497
498 *p = *p || !SIMPLEQ_EMPTY(&peer->imsg_queue);
499 }
500
501 /*
502 * Check if any imsg are pending, return 0 if none are pending
503 */
504 int
peer_imsg_pending(void)505 peer_imsg_pending(void)
506 {
507 int pending = 0;
508
509 peer_foreach(peer_imsg_queued, &pending);
510
511 return pending;
512 }
513
514 /*
515 * flush all imsg queued for a peer.
516 */
517 void
peer_imsg_flush(struct rde_peer * peer)518 peer_imsg_flush(struct rde_peer *peer)
519 {
520 struct iq *iq;
521
522 while ((iq = SIMPLEQ_FIRST(&peer->imsg_queue)) != NULL) {
523 SIMPLEQ_REMOVE_HEAD(&peer->imsg_queue, entry);
524 free(iq);
525 }
526 }
527