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