xref: /openbsd/usr.sbin/bgpd/mrt.c (revision bcd6516b)
1 /*	$OpenBSD: mrt.c,v 1.117 2024/05/22 08:41:14 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29 
30 #include "bgpd.h"
31 #include "rde.h"
32 #include "session.h"
33 
34 #include "mrt.h"
35 #include "log.h"
36 
37 static int	mrt_attr_dump(struct ibuf *, struct rde_aspath *,
38 		    struct rde_community *, struct bgpd_addr *, int);
39 static int	mrt_dump_entry_mp(struct mrt *, struct prefix *, uint16_t,
40 		    struct rde_peer*);
41 static int	mrt_dump_entry(struct mrt *, struct prefix *, uint16_t,
42 		    struct rde_peer*);
43 static int	mrt_dump_entry_v2(struct mrt *, struct rib_entry *, uint32_t);
44 static int	mrt_dump_peer(struct ibuf *, struct rde_peer *);
45 static int	mrt_dump_hdr_se(struct ibuf **, struct peer *, uint16_t,
46 		    uint16_t, uint32_t, int);
47 static int	mrt_dump_hdr_rde(struct ibuf **, uint16_t type, uint16_t,
48 		    uint32_t);
49 static int	mrt_open(struct mrt *, time_t);
50 
51 #define RDEIDX		0
52 #define SEIDX		1
53 #define TYPE2IDX(x)	((x == MRT_TABLE_DUMP ||			\
54 			    x == MRT_TABLE_DUMP_MP ||			\
55 			    x == MRT_TABLE_DUMP_V2) ? RDEIDX : SEIDX	\
56 			)
57 
58 static uint8_t
mrt_update_msg_guess_aid(uint8_t * pkg,uint16_t pkglen)59 mrt_update_msg_guess_aid(uint8_t *pkg, uint16_t pkglen)
60 {
61 	uint16_t wlen, alen, len, afi;
62 	uint8_t type, aid;
63 
64 	pkg += MSGSIZE_HEADER;
65 	pkglen -= MSGSIZE_HEADER;
66 
67 	if (pkglen < 4)
68 		goto bad;
69 
70 	memcpy(&wlen, pkg, 2);
71 	wlen = ntohs(wlen);
72 	pkg += 2;
73 	pkglen -= 2;
74 
75 	if (wlen > 0) {
76 		/* UPDATE has withdraw routes, therefore IPv4 */
77 		return AID_INET;
78 	}
79 
80 	memcpy(&alen, pkg, 2);
81 	alen = ntohs(alen);
82 	pkg += 2;
83 	pkglen -= 2;
84 
85 	if (alen < pkglen) {
86 		/* UPDATE has NLRI prefixes, therefore IPv4 */
87 		return AID_INET;
88 	}
89 
90 	if (wlen == 0 && alen == 0) {
91 		/* UPDATE is an IPv4 EoR marker */
92 		return AID_INET;
93 	}
94 
95 	/* bad attribute length */
96 	if (alen > pkglen)
97 		goto bad;
98 
99 	/* try to extract AFI/SAFI from the MP attributes */
100 	while (alen > 0) {
101 		if (alen < 3)
102 			goto bad;
103 		type = pkg[1];
104 		if (pkg[0] & ATTR_EXTLEN) {
105 			if (alen < 4)
106 				goto bad;
107 			memcpy(&len, pkg + 2, 2);
108 			len = ntohs(len);
109 			pkg += 4;
110 			alen -= 4;
111 		} else {
112 			len = pkg[2];
113 			pkg += 3;
114 			alen -= 3;
115 		}
116 		if (len > alen)
117 			goto bad;
118 
119 		if (type == ATTR_MP_REACH_NLRI ||
120 		    type == ATTR_MP_UNREACH_NLRI) {
121 			if (alen < 3)
122 				goto bad;
123 			memcpy(&afi, pkg, 2);
124 			afi = ntohs(afi);
125 			if (afi2aid(afi, pkg[2], &aid) == -1)
126 				goto bad;
127 			return aid;
128 		}
129 
130 		pkg += len;
131 		alen -= len;
132 	}
133 
134 bad:
135 	return AID_UNSPEC;
136 }
137 
138 static uint16_t
mrt_bgp_msg_subtype(struct mrt * mrt,void * pkg,uint16_t pkglen,struct peer * peer,enum msg_type msgtype,int in)139 mrt_bgp_msg_subtype(struct mrt *mrt, void *pkg, uint16_t pkglen,
140     struct peer *peer, enum msg_type msgtype, int in)
141 {
142 	uint16_t subtype = BGP4MP_MESSAGE;
143 	uint8_t aid, mask;
144 
145 	if (peer->capa.neg.as4byte)
146 		subtype = BGP4MP_MESSAGE_AS4;
147 
148 	if (msgtype != UPDATE)
149 		return subtype;
150 
151 	/*
152 	 * RFC8050 adjust types for add-path enabled sessions.
153 	 * It is necessary to extract the AID from UPDATES to decide
154 	 * if the add-path types are needed or not. The ADDPATH
155 	 * subtypes only matter for BGP UPDATES.
156 	 */
157 
158 	mask = in ? CAPA_AP_RECV : CAPA_AP_SEND;
159 	/* only guess if add-path could be active */
160 	if (peer->capa.neg.add_path[0] & mask) {
161 		aid = mrt_update_msg_guess_aid(pkg, pkglen);
162 		if (aid != AID_UNSPEC &&
163 		    (peer->capa.neg.add_path[aid] & mask)) {
164 			if (peer->capa.neg.as4byte)
165 				subtype = BGP4MP_MESSAGE_AS4_ADDPATH;
166 			else
167 				subtype = BGP4MP_MESSAGE_ADDPATH;
168 		}
169 	}
170 
171 	return subtype;
172 }
173 
174 void
mrt_dump_bgp_msg(struct mrt * mrt,void * pkg,uint16_t pkglen,struct peer * peer,enum msg_type msgtype)175 mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, uint16_t pkglen,
176     struct peer *peer, enum msg_type msgtype)
177 {
178 	struct ibuf	*buf;
179 	int		 in = 0;
180 	uint16_t	 subtype = BGP4MP_MESSAGE;
181 
182 	/* get the direction of the message to swap address and AS fields */
183 	if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN)
184 		in = 1;
185 
186 	subtype = mrt_bgp_msg_subtype(mrt, pkg, pkglen, peer, msgtype, in);
187 
188 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
189 	    pkglen, in) == -1)
190 		goto fail;
191 
192 	if (ibuf_add(buf, pkg, pkglen) == -1)
193 		goto fail;
194 
195 	ibuf_close(&mrt->wbuf, buf);
196 	return;
197 
198 fail:
199 	log_warn("%s: ibuf error", __func__);
200 	ibuf_free(buf);
201 }
202 
203 void
mrt_dump_state(struct mrt * mrt,uint16_t old_state,uint16_t new_state,struct peer * peer)204 mrt_dump_state(struct mrt *mrt, uint16_t old_state, uint16_t new_state,
205     struct peer *peer)
206 {
207 	struct ibuf	*buf;
208 	uint16_t	 subtype = BGP4MP_STATE_CHANGE;
209 
210 	if (peer->capa.neg.as4byte)
211 		subtype = BGP4MP_STATE_CHANGE_AS4;
212 
213 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype,
214 	    2 * sizeof(short), 0) == -1)
215 		goto fail;
216 
217 	if (ibuf_add_n16(buf, old_state) == -1)
218 		goto fail;
219 	if (ibuf_add_n16(buf, new_state) == -1)
220 		goto fail;
221 
222 	ibuf_close(&mrt->wbuf, buf);
223 	return;
224 
225 fail:
226 	log_warn("%s: ibuf error", __func__);
227 	ibuf_free(buf);
228 }
229 
230 static int
mrt_attr_dump(struct ibuf * buf,struct rde_aspath * a,struct rde_community * c,struct bgpd_addr * nexthop,int v2)231 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c,
232     struct bgpd_addr *nexthop, int v2)
233 {
234 	struct attr	*oa;
235 	u_char		*pdata;
236 	uint32_t	 tmp;
237 	int		 neednewpath = 0;
238 	uint16_t	 plen, afi;
239 	uint8_t		 l, safi;
240 
241 	/* origin */
242 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
243 	    &a->origin, 1) == -1)
244 		return (-1);
245 
246 	/* aspath */
247 	plen = aspath_length(a->aspath);
248 	pdata = aspath_dump(a->aspath);
249 
250 	if (!v2)
251 		pdata = aspath_deflate(pdata, &plen, &neednewpath);
252 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
253 	    plen) == -1) {
254 		if (!v2)
255 			free(pdata);
256 		return (-1);
257 	}
258 	if (!v2)
259 		free(pdata);
260 
261 	if (nexthop && nexthop->aid == AID_INET) {
262 		/* nexthop, already network byte order */
263 		if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
264 		    &nexthop->v4.s_addr, 4) ==	-1)
265 			return (-1);
266 	}
267 
268 	/* MED, non transitive */
269 	if (a->med != 0) {
270 		tmp = htonl(a->med);
271 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1)
272 			return (-1);
273 	}
274 
275 	/* local preference */
276 	tmp = htonl(a->lpref);
277 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
278 		return (-1);
279 
280 	/* communities */
281 	if (community_writebuf(c, ATTR_COMMUNITIES, 0, buf) == -1 ||
282 	    community_writebuf(c, ATTR_EXT_COMMUNITIES, 0, buf) == -1 ||
283 	    community_writebuf(c, ATTR_LARGE_COMMUNITIES, 0, buf) == -1)
284 		return (-1);
285 
286 	/* dump all other path attributes without modification */
287 	for (l = 0; l < a->others_len; l++) {
288 		if ((oa = a->others[l]) == NULL)
289 			break;
290 		if (attr_writebuf(buf, oa->flags, oa->type,
291 		    oa->data, oa->len) == -1)
292 			return (-1);
293 	}
294 
295 	if (nexthop && nexthop->aid != AID_INET) {
296 		struct ibuf *nhbuf;
297 
298 		if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL)
299 			return (-1);
300 		if (!v2) {
301 			if (aid2afi(nexthop->aid, &afi, &safi))
302 				goto fail;
303 			if (ibuf_add_n16(nhbuf, afi) == -1)
304 				goto fail;
305 			if (ibuf_add_n8(nhbuf, safi) == -1)
306 				goto fail;
307 		}
308 		switch (nexthop->aid) {
309 		case AID_INET6:
310 			if (ibuf_add_n8(nhbuf, sizeof(struct in6_addr)) == -1)
311 				goto fail;
312 			if (ibuf_add(nhbuf, &nexthop->v6,
313 			    sizeof(struct in6_addr)) == -1)
314 				goto fail;
315 			break;
316 		case AID_VPN_IPv4:
317 			if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
318 			    sizeof(struct in_addr)) == -1)
319 				goto fail;
320 			if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
321 				goto fail;
322 			if (ibuf_add(nhbuf, &nexthop->v4,
323 			    sizeof(nexthop->v4)) == -1)
324 				goto fail;
325 			break;
326 		case AID_VPN_IPv6:
327 			if (ibuf_add_n8(nhbuf, sizeof(uint64_t) +
328 			    sizeof(struct in6_addr)) == -1)
329 				goto fail;
330 			if (ibuf_add_n64(nhbuf, 0) == -1) /* set RD to 0 */
331 				goto fail;
332 			if (ibuf_add(nhbuf, &nexthop->v6,
333 			    sizeof(nexthop->v6)) == -1)
334 				goto fail;
335 			break;
336 		}
337 		if (!v2)
338 			if (ibuf_add_n8(nhbuf, 0) == -1)
339 				goto fail;
340 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
341 		    ibuf_data(nhbuf), ibuf_size(nhbuf)) == -1) {
342 fail:
343 			ibuf_free(nhbuf);
344 			return (-1);
345 		}
346 		ibuf_free(nhbuf);
347 	}
348 
349 	if (neednewpath) {
350 		pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
351 		if (plen != 0)
352 			if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE,
353 			    ATTR_AS4_PATH, pdata, plen) == -1) {
354 				free(pdata);
355 				return (-1);
356 			}
357 		free(pdata);
358 	}
359 
360 	return (0);
361 }
362 
363 static int
mrt_dump_entry_mp(struct mrt * mrt,struct prefix * p,uint16_t snum,struct rde_peer * peer)364 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, uint16_t snum,
365     struct rde_peer *peer)
366 {
367 	struct ibuf	*buf, *hbuf = NULL, *h2buf = NULL;
368 	struct nexthop	*n;
369 	struct bgpd_addr nexthop, *nh;
370 	uint16_t	 len;
371 	uint8_t		 aid;
372 
373 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
374 		log_warn("mrt_dump_entry_mp: ibuf_dynamic");
375 		return (-1);
376 	}
377 
378 	if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
379 	    NULL, 0) == -1)
380 		goto fail;
381 	len = ibuf_size(buf);
382 
383 	if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
384 	    MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE +
385 	    MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL)
386 		goto fail;
387 
388 	if (ibuf_add_n16(h2buf, peer->conf.local_short_as) == -1)
389 		goto fail;
390 	if (ibuf_add_n16(h2buf, peer->short_as) == -1)
391 		goto fail;
392 	if (ibuf_add_n16(h2buf, /* ifindex */ 0) == -1)
393 		goto fail;
394 
395 	/* XXX is this for peer self? */
396 	aid = peer->remote_addr.aid == AID_UNSPEC ? p->pt->aid :
397 	    peer->remote_addr.aid;
398 	switch (aid) {
399 	case AID_INET:
400 	case AID_VPN_IPv4:
401 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)
402 			goto fail;
403 		if (ibuf_add(h2buf, &peer->local_v4_addr.v4,
404 		    sizeof(peer->local_v4_addr.v4)) == -1 ||
405 		    ibuf_add(h2buf, &peer->remote_addr.v4,
406 		    sizeof(peer->remote_addr.v4)) == -1)
407 			goto fail;
408 		break;
409 	case AID_INET6:
410 	case AID_VPN_IPv6:
411 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)
412 			goto fail;
413 		if (ibuf_add(h2buf, &peer->local_v6_addr.v6,
414 		    sizeof(peer->local_v6_addr.v6)) == -1 ||
415 		    ibuf_add(h2buf, &peer->remote_addr.v6,
416 		    sizeof(peer->remote_addr.v6)) == -1)
417 			goto fail;
418 		break;
419 	default:
420 		log_warnx("king bula found new AF %d in %s", aid, __func__);
421 		goto fail;
422 	}
423 
424 	if (ibuf_add_n16(h2buf, 0) == -1)		/* view */
425 		goto fail;
426 	if (ibuf_add_n16(h2buf, 1) == -1)		/* status */
427 		goto fail;
428 	/* originated timestamp */
429 	if (ibuf_add_n32(h2buf, time(NULL) - (getmonotime() -
430 	    p->lastchange)) == -1)
431 		goto fail;
432 
433 	n = prefix_nexthop(p);
434 	if (n == NULL) {
435 		memset(&nexthop, 0, sizeof(struct bgpd_addr));
436 		nexthop.aid = p->pt->aid;
437 		nh = &nexthop;
438 	} else
439 		nh = &n->exit_nexthop;
440 
441 	switch (p->pt->aid) {
442 	case AID_INET:
443 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)	/* afi */
444 			goto fail;
445 		if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1)	/* safi */
446 			goto fail;
447 		if (ibuf_add_n8(h2buf, 4) == -1)		/* nhlen */
448 			goto fail;
449 		if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
450 			goto fail;
451 		break;
452 	case AID_INET6:
453 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)	/* afi */
454 			goto fail;
455 		if (ibuf_add_n8(h2buf, SAFI_UNICAST) == -1)	/* safi */
456 			goto fail;
457 		if (ibuf_add_n8(h2buf, 16) == -1)		/* nhlen */
458 			goto fail;
459 		if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
460 			goto fail;
461 		break;
462 	case AID_VPN_IPv4:
463 		if (ibuf_add_n16(h2buf, AFI_IPv4) == -1)	/* afi */
464 			goto fail;
465 		if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1)	/* safi */
466 			goto fail;
467 		if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
468 		    sizeof(struct in_addr)) == -1)
469 			goto fail;
470 		if (ibuf_add_n64(h2buf, 0) == -1)	/* set RD to 0 */
471 			goto fail;
472 		if (ibuf_add(h2buf, &nh->v4, sizeof(nh->v4)) == -1)
473 			goto fail;
474 		break;
475 	case AID_VPN_IPv6:
476 		if (ibuf_add_n16(h2buf, AFI_IPv6) == -1)	/* afi */
477 			goto fail;
478 		if (ibuf_add_n8(h2buf, SAFI_MPLSVPN) == -1)	/* safi */
479 			goto fail;
480 		if (ibuf_add_n8(h2buf, sizeof(uint64_t) +
481 		    sizeof(struct in6_addr)) == -1)
482 			goto fail;
483 		if (ibuf_add_n64(h2buf, 0) == -1)	/* set RD to 0 */
484 			goto fail;
485 		if (ibuf_add(h2buf, &nh->v6, sizeof(nh->v6)) == -1)
486 			goto fail;
487 		break;
488 	case AID_FLOWSPECv4:
489 	case AID_FLOWSPECv6:
490 		if (p->pt->aid == AID_FLOWSPECv4) {
491 			if (ibuf_add_n16(h2buf, AFI_IPv4) == -1) /* afi */
492 				goto fail;
493 		} else {
494 			if (ibuf_add_n16(h2buf, AFI_IPv6) == -1) /* afi */
495 				goto fail;
496 		}
497 		if (ibuf_add_n8(h2buf, SAFI_FLOWSPEC) == -1)	/* safi */
498 			goto fail;
499 		if (ibuf_add_n8(h2buf, 0) == -1)		/* nhlen */
500 			goto fail;
501 		break;
502 	default:
503 		log_warnx("king bula found new AF in %s", __func__);
504 		goto fail;
505 	}
506 
507 	if (pt_writebuf(h2buf, p->pt, 0, 0, 0) == -1)
508 		goto fail;
509 
510 	if (ibuf_add_n16(h2buf, len) == -1)
511 		goto fail;
512 	len += ibuf_size(h2buf);
513 
514 	if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY,
515 	    len) == -1)
516 		goto fail;
517 
518 	ibuf_close(&mrt->wbuf, hbuf);
519 	ibuf_close(&mrt->wbuf, h2buf);
520 	ibuf_close(&mrt->wbuf, buf);
521 
522 	return (len + MRT_HEADER_SIZE);
523 
524 fail:
525 	log_warn("%s: ibuf error", __func__);
526 	ibuf_free(hbuf);
527 	ibuf_free(h2buf);
528 	ibuf_free(buf);
529 	return (-1);
530 }
531 
532 static int
mrt_dump_entry(struct mrt * mrt,struct prefix * p,uint16_t snum,struct rde_peer * peer)533 mrt_dump_entry(struct mrt *mrt, struct prefix *p, uint16_t snum,
534     struct rde_peer *peer)
535 {
536 	struct ibuf	*buf, *hbuf = NULL;
537 	struct nexthop	*nexthop;
538 	struct bgpd_addr addr, *nh;
539 	size_t		 len;
540 	uint16_t	 subtype;
541 	uint8_t		 dummy;
542 
543 	if (p->pt->aid != peer->remote_addr.aid &&
544 	    p->pt->aid != AID_INET && p->pt->aid != AID_INET6)
545 		/* only able to dump pure IPv4/IPv6 */
546 		return (0);
547 
548 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
549 		log_warn("mrt_dump_entry: ibuf_dynamic");
550 		return (-1);
551 	}
552 
553 	nexthop = prefix_nexthop(p);
554 	if (nexthop == NULL) {
555 		memset(&addr, 0, sizeof(struct bgpd_addr));
556 		addr.aid = p->pt->aid;
557 		nh = &addr;
558 	} else
559 		nh = &nexthop->exit_nexthop;
560 	if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
561 	    nh, 0) == -1)
562 		goto fail;
563 
564 	len = ibuf_size(buf);
565 	aid2afi(p->pt->aid, &subtype, &dummy);
566 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1)
567 		goto fail;
568 
569 	if (ibuf_add_n16(hbuf, 0) == -1)
570 		goto fail;
571 	if (ibuf_add_n16(hbuf, snum) == -1)
572 		goto fail;
573 
574 	pt_getaddr(p->pt, &addr);
575 	switch (p->pt->aid) {
576 	case AID_INET:
577 		if (ibuf_add(hbuf, &addr.v4, sizeof(addr.v4)) == -1)
578 			goto fail;
579 		break;
580 	case AID_INET6:
581 		if (ibuf_add(hbuf, &addr.v6, sizeof(addr.v6)) == -1)
582 			goto fail;
583 		break;
584 	}
585 	if (ibuf_add_n8(hbuf, p->pt->prefixlen) == -1)
586 		goto fail;
587 
588 	if (ibuf_add_n8(hbuf, 1) == -1)		/* state */
589 		goto fail;
590 	/* originated timestamp */
591 	if (ibuf_add_n32(hbuf, time(NULL) - (getmonotime() -
592 	    p->lastchange)) == -1)
593 		goto fail;
594 	switch (p->pt->aid) {
595 	case AID_INET:
596 		if (ibuf_add(hbuf, &peer->remote_addr.v4,
597 		    sizeof(peer->remote_addr.v4)) == -1)
598 			goto fail;
599 		break;
600 	case AID_INET6:
601 		if (ibuf_add(hbuf, &peer->remote_addr.v6,
602 		    sizeof(peer->remote_addr.v6)) == -1)
603 			goto fail;
604 		break;
605 	}
606 	if (ibuf_add_n16(hbuf, peer->short_as) == -1)
607 		goto fail;
608 	if (ibuf_add_n16(hbuf, len) == -1)
609 		goto fail;
610 
611 	ibuf_close(&mrt->wbuf, hbuf);
612 	ibuf_close(&mrt->wbuf, buf);
613 
614 	return (len + MRT_HEADER_SIZE);
615 
616 fail:
617 	log_warn("%s: ibuf error", __func__);
618 	ibuf_free(hbuf);
619 	ibuf_free(buf);
620 	return (-1);
621 }
622 
623 static int
mrt_dump_entry_v2_rib(struct rib_entry * re,struct ibuf ** nb,struct ibuf ** apb,uint16_t * np,uint16_t * app)624 mrt_dump_entry_v2_rib(struct rib_entry *re, struct ibuf **nb, struct ibuf **apb,
625     uint16_t *np, uint16_t *app)
626 {
627 	struct bgpd_addr addr;
628 	struct ibuf *buf = NULL, **bp;
629 	struct ibuf *tbuf = NULL;
630 	struct prefix *p;
631 	int addpath;
632 
633 	*np = 0;
634 	*app = 0;
635 
636 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
637 		struct nexthop		*nexthop;
638 		struct bgpd_addr	*nh;
639 
640 		addpath = peer_has_add_path(prefix_peer(p), re->prefix->aid,
641 		    CAPA_AP_RECV);
642 
643 		if (addpath) {
644 			bp = apb;
645 			*app += 1;
646 		} else {
647 			bp = nb;
648 			*np += 1;
649 		}
650 		if ((buf = *bp) == NULL) {
651 			if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL)
652 				goto fail;
653 			*bp = buf;
654 		}
655 
656 		nexthop = prefix_nexthop(p);
657 		if (nexthop == NULL) {
658 			memset(&addr, 0, sizeof(struct bgpd_addr));
659 			addr.aid = re->prefix->aid;
660 			nh = &addr;
661 		} else
662 			nh = &nexthop->exit_nexthop;
663 
664 		if (ibuf_add_n16(buf, prefix_peer(p)->mrt_idx) == -1)
665 			goto fail;
666 		/* originated timestamp */
667 		if (ibuf_add_n32(buf, time(NULL) - (getmonotime() -
668 		    p->lastchange)) == -1)
669 			goto fail;
670 
671 		/* RFC8050: path-id if add-path is used */
672 		if (addpath)
673 			if (ibuf_add_n32(buf, p->path_id) == -1)
674 				goto fail;
675 
676 		if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL)
677 			goto fail;
678 		if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p),
679 		    nh, 1) == -1)
680 			goto fail;
681 		if (ibuf_add_n16(buf, ibuf_size(tbuf)) == -1)
682 			goto fail;
683 		if (ibuf_add_buf(buf, tbuf) == -1)
684 			goto fail;
685 		ibuf_free(tbuf);
686 		tbuf = NULL;
687 	}
688 
689 	return 0;
690 
691 fail:
692 	ibuf_free(tbuf);
693 	return -1;
694 }
695 
696 static int
mrt_dump_entry_v2(struct mrt * mrt,struct rib_entry * re,uint32_t snum)697 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, uint32_t snum)
698 {
699 	struct ibuf	*hbuf = NULL, *nbuf = NULL, *apbuf = NULL, *pbuf;
700 	size_t		 hlen, len;
701 	uint16_t	 subtype, apsubtype, nump, apnump, afi;
702 	uint8_t		 safi;
703 
704 	if ((pbuf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
705 		log_warn("%s: ibuf_dynamic", __func__);
706 		return -1;
707 	}
708 
709 	switch (re->prefix->aid) {
710 	case AID_INET:
711 		subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST;
712 		apsubtype = MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH;
713 		break;
714 	case AID_INET6:
715 		subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST;
716 		apsubtype = MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH;
717 		break;
718 	default:
719 		/*
720 		 * XXX The RFC defined the format for this type differently
721 		 * and it is prohibitly expensive to implement that format.
722 		 * Instead do what gobgp does and encode it like the other
723 		 * types.
724 		 */
725 		subtype = MRT_DUMP_V2_RIB_GENERIC;
726 		apsubtype = MRT_DUMP_V2_RIB_GENERIC_ADDPATH;
727 		aid2afi(re->prefix->aid, &afi, &safi);
728 
729 		/* first add 3-bytes AFI/SAFI */
730 		if (ibuf_add_n16(pbuf, afi) == -1)
731 			goto fail;
732 		if (ibuf_add_n8(pbuf, safi) == -1)
733 			goto fail;
734 		break;
735 	}
736 
737 	if (pt_writebuf(pbuf, re->prefix, 0, 0, 0) == -1)
738 		goto fail;
739 
740 	hlen = sizeof(snum) + sizeof(nump) + ibuf_size(pbuf);
741 
742 	if (mrt_dump_entry_v2_rib(re, &nbuf, &apbuf, &nump, &apnump))
743 		goto fail;
744 
745 	if (nump > 0) {
746 		len = ibuf_size(nbuf) + hlen;
747 		if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype,
748 		    len) == -1)
749 			goto fail;
750 
751 		if (ibuf_add_n32(hbuf, snum) == -1)
752 			goto fail;
753 		if (ibuf_add_buf(hbuf, pbuf) == -1)
754 			goto fail;
755 		if (ibuf_add_n16(hbuf, nump) == -1)
756 			goto fail;
757 
758 		ibuf_close(&mrt->wbuf, hbuf);
759 		ibuf_close(&mrt->wbuf, nbuf);
760 		hbuf = NULL;
761 		nbuf = NULL;
762 	}
763 
764 	if (apnump > 0) {
765 		len = ibuf_size(apbuf) + hlen;
766 		if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, apsubtype,
767 		    len) == -1)
768 			goto fail;
769 
770 		if (ibuf_add_n32(hbuf, snum) == -1)
771 			goto fail;
772 		if (ibuf_add_buf(hbuf, pbuf) == -1)
773 			goto fail;
774 		if (ibuf_add_n16(hbuf, apnump) == -1)
775 			goto fail;
776 
777 		ibuf_close(&mrt->wbuf, hbuf);
778 		ibuf_close(&mrt->wbuf, apbuf);
779 		hbuf = NULL;
780 		apbuf = NULL;
781 	}
782 
783 	ibuf_free(pbuf);
784 	return (0);
785 fail:
786 	log_warn("%s: ibuf error", __func__);
787 	ibuf_free(apbuf);
788 	ibuf_free(nbuf);
789 	ibuf_free(hbuf);
790 	ibuf_free(pbuf);
791 	return (-1);
792 }
793 
794 struct cb_arg {
795 	struct ibuf	*buf;
796 	int		 nump;
797 };
798 
799 static void
mrt_dump_v2_hdr_peer(struct rde_peer * peer,void * arg)800 mrt_dump_v2_hdr_peer(struct rde_peer *peer, void *arg)
801 {
802 	struct cb_arg *a = arg;
803 
804 	if (a->nump == -1)
805 		return;
806 	peer->mrt_idx = a->nump;
807 	if (mrt_dump_peer(a->buf, peer) == -1) {
808 		a->nump = -1;
809 		return;
810 	}
811 	a->nump++;
812 }
813 
814 int
mrt_dump_v2_hdr(struct mrt * mrt,struct bgpd_config * conf)815 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf)
816 {
817 	struct ibuf	*buf, *hbuf = NULL;
818 	size_t		 len, off;
819 	uint16_t	 nlen, nump;
820 	struct cb_arg	 arg;
821 
822 	if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
823 		log_warn("%s: ibuf_dynamic", __func__);
824 		return (-1);
825 	}
826 
827 	if (ibuf_add_n32(buf, conf->bgpid) == -1)
828 		goto fail;
829 	nlen = strlen(mrt->rib);
830 	if (nlen > 0)
831 		nlen += 1;
832 	if (ibuf_add_n16(buf, nlen) == -1)
833 		goto fail;
834 	if (ibuf_add(buf, mrt->rib, nlen) == -1)
835 		goto fail;
836 
837 	off = ibuf_size(buf);
838 	if (ibuf_add_zero(buf, sizeof(nump)) == -1)
839 		goto fail;
840 	arg.nump = 0;
841 	arg.buf = buf;
842 	peer_foreach(mrt_dump_v2_hdr_peer, &arg);
843 	if (arg.nump == -1)
844 		goto fail;
845 
846 	if (ibuf_set_n16(buf, off, arg.nump) == -1)
847 		goto fail;
848 
849 	len = ibuf_size(buf);
850 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2,
851 	    MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1)
852 		goto fail;
853 
854 	ibuf_close(&mrt->wbuf, hbuf);
855 	ibuf_close(&mrt->wbuf, buf);
856 
857 	return (0);
858 fail:
859 	log_warn("%s: ibuf error", __func__);
860 	ibuf_free(hbuf);
861 	ibuf_free(buf);
862 	return (-1);
863 }
864 
865 static int
mrt_dump_peer(struct ibuf * buf,struct rde_peer * peer)866 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
867 {
868 	uint8_t	type = 0;
869 
870 	if (peer->capa.as4byte)
871 		type |= MRT_DUMP_V2_PEER_BIT_A;
872 	if (peer->remote_addr.aid == AID_INET6)
873 		type |= MRT_DUMP_V2_PEER_BIT_I;
874 
875 	if (ibuf_add_n8(buf, type) == -1)
876 		goto fail;
877 	if (ibuf_add_n32(buf, peer->remote_bgpid) == -1)
878 		goto fail;
879 
880 	switch (peer->remote_addr.aid) {
881 	case AID_INET:
882 		if (ibuf_add(buf, &peer->remote_addr.v4,
883 		    sizeof(peer->remote_addr.v4)) == -1)
884 			goto fail;
885 		break;
886 	case AID_INET6:
887 		if (ibuf_add(buf, &peer->remote_addr.v6,
888 		    sizeof(peer->remote_addr.v6)) == -1)
889 			goto fail;
890 		break;
891 	case AID_UNSPEC: /* XXX special handling for peerself? */
892 		if (ibuf_add_n32(buf, 0) == -1)
893 			goto fail;
894 		break;
895 	default:
896 		log_warnx("king bula found new AF in %s", __func__);
897 		goto fail;
898 	}
899 
900 	if (peer->capa.as4byte) {
901 		if (ibuf_add_n32(buf, peer->conf.remote_as) == -1)
902 			goto fail;
903 	} else {
904 		if (ibuf_add_n16(buf, peer->short_as) == -1)
905 			goto fail;
906 	}
907 	return (0);
908 fail:
909 	log_warn("%s: ibuf error", __func__);
910 	return (-1);
911 }
912 
913 void
mrt_dump_upcall(struct rib_entry * re,void * ptr)914 mrt_dump_upcall(struct rib_entry *re, void *ptr)
915 {
916 	struct mrt		*mrtbuf = ptr;
917 	struct prefix		*p;
918 
919 	if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
920 		mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
921 		return;
922 	}
923 
924 	/*
925 	 * dump all prefixes even the inactive ones. That is the way zebra
926 	 * dumps the table so we do the same. If only the active route should
927 	 * be dumped p should be set to p = pt->active.
928 	 */
929 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
930 		if (mrtbuf->type == MRT_TABLE_DUMP)
931 			mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++,
932 			    prefix_peer(p));
933 		else
934 			mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++,
935 			    prefix_peer(p));
936 	}
937 }
938 
939 void
mrt_done(struct mrt * mrtbuf)940 mrt_done(struct mrt *mrtbuf)
941 {
942 	mrtbuf->state = MRT_STATE_REMOVE;
943 }
944 
945 static int
mrt_dump_hdr_se(struct ibuf ** bp,struct peer * peer,uint16_t type,uint16_t subtype,uint32_t len,int swap)946 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, uint16_t type,
947     uint16_t subtype, uint32_t len, int swap)
948 {
949 	struct timespec	time;
950 
951 	if ((*bp = ibuf_dynamic(MRT_ET_HEADER_SIZE, MRT_ET_HEADER_SIZE +
952 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL)
953 		return (-1);
954 
955 	clock_gettime(CLOCK_REALTIME, &time);
956 
957 	if (ibuf_add_n32(*bp, time.tv_sec) == -1)
958 		goto fail;
959 	if (ibuf_add_n16(*bp, type) == -1)
960 		goto fail;
961 	if (ibuf_add_n16(*bp, subtype) == -1)
962 		goto fail;
963 
964 	switch (peer->local.aid) {
965 	case AID_INET:
966 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
967 		    subtype == BGP4MP_MESSAGE_AS4 ||
968 		    subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
969 			len += MRT_BGP4MP_ET_AS4_IPv4_HEADER_SIZE;
970 		else
971 			len += MRT_BGP4MP_ET_IPv4_HEADER_SIZE;
972 		break;
973 	case AID_INET6:
974 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
975 		    subtype == BGP4MP_MESSAGE_AS4 ||
976 		    subtype == BGP4MP_MESSAGE_AS4_ADDPATH)
977 			len += MRT_BGP4MP_ET_AS4_IPv6_HEADER_SIZE;
978 		else
979 			len += MRT_BGP4MP_ET_IPv6_HEADER_SIZE;
980 		break;
981 	case 0:
982 		goto fail;
983 	default:
984 		log_warnx("king bula found new AF in %s", __func__);
985 		goto fail;
986 	}
987 
988 	if (ibuf_add_n32(*bp, len) == -1)
989 		goto fail;
990 	/* millisecond field use by the _ET format */
991 	if (ibuf_add_n32(*bp, time.tv_nsec / 1000) == -1)
992 		goto fail;
993 
994 	if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
995 	    subtype == BGP4MP_MESSAGE_AS4 ||
996 	    subtype == BGP4MP_MESSAGE_AS4_ADDPATH) {
997 		if (!swap)
998 			if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
999 				goto fail;
1000 		if (ibuf_add_n32(*bp, peer->conf.remote_as) == -1)
1001 			goto fail;
1002 		if (swap)
1003 			if (ibuf_add_n32(*bp, peer->conf.local_as) == -1)
1004 				goto fail;
1005 	} else {
1006 		if (!swap)
1007 			if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
1008 				goto fail;
1009 		if (ibuf_add_n16(*bp, peer->short_as) == -1)
1010 			goto fail;
1011 		if (swap)
1012 			if (ibuf_add_n16(*bp, peer->conf.local_short_as) == -1)
1013 				goto fail;
1014 	}
1015 
1016 	if (ibuf_add_n16(*bp, /* ifindex */ 0) == -1)
1017 		goto fail;
1018 
1019 	switch (peer->local.aid) {
1020 	case AID_INET:
1021 		if (ibuf_add_n16(*bp, AFI_IPv4) == -1)
1022 			goto fail;
1023 		if (!swap)
1024 			if (ibuf_add(*bp, &peer->local.v4,
1025 			    sizeof(peer->local.v4)) == -1)
1026 				goto fail;
1027 		if (ibuf_add(*bp, &peer->remote.v4,
1028 		    sizeof(peer->remote.v4)) == -1)
1029 			goto fail;
1030 		if (swap)
1031 			if (ibuf_add(*bp, &peer->local.v4,
1032 			    sizeof(peer->local.v4)) == -1)
1033 				goto fail;
1034 		break;
1035 	case AID_INET6:
1036 		if (ibuf_add_n16(*bp, AFI_IPv6) == -1)
1037 			goto fail;
1038 		if (!swap)
1039 			if (ibuf_add(*bp, &peer->local.v6,
1040 			    sizeof(peer->local.v6)) == -1)
1041 				goto fail;
1042 		if (ibuf_add(*bp, &peer->remote.v6,
1043 		    sizeof(peer->remote.v6)) == -1)
1044 			goto fail;
1045 		if (swap)
1046 			if (ibuf_add(*bp, &peer->local.v6,
1047 			    sizeof(peer->local.v6)) == -1)
1048 				goto fail;
1049 		break;
1050 	}
1051 
1052 	return (0);
1053 
1054 fail:
1055 	ibuf_free(*bp);
1056 	*bp = NULL;
1057 	return (-1);
1058 }
1059 
1060 int
mrt_dump_hdr_rde(struct ibuf ** bp,uint16_t type,uint16_t subtype,uint32_t len)1061 mrt_dump_hdr_rde(struct ibuf **bp, uint16_t type, uint16_t subtype,
1062     uint32_t len)
1063 {
1064 	struct timespec	time;
1065 
1066 	if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
1067 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
1068 	    NULL)
1069 		return (-1);
1070 
1071 	clock_gettime(CLOCK_REALTIME, &time);
1072 
1073 	if (ibuf_add_n32(*bp, time.tv_sec) == -1)
1074 		goto fail;
1075 	if (ibuf_add_n16(*bp, type) == -1)
1076 		goto fail;
1077 	if (ibuf_add_n16(*bp, subtype) == -1)
1078 		goto fail;
1079 
1080 	switch (type) {
1081 	case MSG_TABLE_DUMP:
1082 		switch (subtype) {
1083 		case AFI_IPv4:
1084 			len += MRT_DUMP_HEADER_SIZE;
1085 			break;
1086 		case AFI_IPv6:
1087 			len += MRT_DUMP_HEADER_SIZE_V6;
1088 			break;
1089 		}
1090 		if (ibuf_add_n32(*bp, len) == -1)
1091 			goto fail;
1092 		break;
1093 	case MSG_PROTOCOL_BGP4MP:
1094 	case MSG_TABLE_DUMP_V2:
1095 		if (ibuf_add_n32(*bp, len) == -1)
1096 			goto fail;
1097 		break;
1098 	default:
1099 		log_warnx("mrt_dump_hdr_rde: unsupported type");
1100 		goto fail;
1101 	}
1102 	return (0);
1103 
1104 fail:
1105 	ibuf_free(*bp);
1106 	*bp = NULL;
1107 	return (-1);
1108 }
1109 
1110 void
mrt_write(struct mrt * mrt)1111 mrt_write(struct mrt *mrt)
1112 {
1113 	int	r;
1114 
1115 	if ((r = ibuf_write(&mrt->wbuf)) == -1 && errno != EAGAIN) {
1116 		log_warn("mrt dump aborted, mrt_write");
1117 		mrt_clean(mrt);
1118 		mrt_done(mrt);
1119 	}
1120 }
1121 
1122 void
mrt_clean(struct mrt * mrt)1123 mrt_clean(struct mrt *mrt)
1124 {
1125 	close(mrt->wbuf.fd);
1126 	msgbuf_clear(&mrt->wbuf);
1127 }
1128 
1129 static struct imsgbuf	*mrt_imsgbuf[2];
1130 
1131 void
mrt_init(struct imsgbuf * rde,struct imsgbuf * se)1132 mrt_init(struct imsgbuf *rde, struct imsgbuf *se)
1133 {
1134 	mrt_imsgbuf[RDEIDX] = rde;
1135 	mrt_imsgbuf[SEIDX] = se;
1136 }
1137 
1138 int
mrt_open(struct mrt * mrt,time_t now)1139 mrt_open(struct mrt *mrt, time_t now)
1140 {
1141 	enum imsg_type	type;
1142 	int		fd;
1143 
1144 	if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file),
1145 	    MRT2MC(mrt)->name, localtime(&now)) == 0) {
1146 		log_warnx("mrt_open: strftime conversion failed");
1147 		return (-1);
1148 	}
1149 
1150 	fd = open(MRT2MC(mrt)->file,
1151 	    O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
1152 	if (fd == -1) {
1153 		log_warn("mrt_open %s", MRT2MC(mrt)->file);
1154 		return (1);
1155 	}
1156 
1157 	if (mrt->state == MRT_STATE_OPEN)
1158 		type = IMSG_MRT_OPEN;
1159 	else
1160 		type = IMSG_MRT_REOPEN;
1161 
1162 	if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd,
1163 	    mrt, sizeof(struct mrt)) == -1)
1164 		log_warn("mrt_open");
1165 
1166 	return (1);
1167 }
1168 
1169 time_t
mrt_timeout(struct mrt_head * mrt)1170 mrt_timeout(struct mrt_head *mrt)
1171 {
1172 	struct mrt	*m;
1173 	time_t		 now;
1174 	time_t		 timeout = -1;
1175 
1176 	now = time(NULL);
1177 	LIST_FOREACH(m, mrt, entry) {
1178 		if (m->state == MRT_STATE_RUNNING &&
1179 		    MRT2MC(m)->ReopenTimerInterval != 0) {
1180 			if (MRT2MC(m)->ReopenTimer <= now) {
1181 				mrt_open(m, now);
1182 				MRT2MC(m)->ReopenTimer =
1183 				    now + MRT2MC(m)->ReopenTimerInterval;
1184 			}
1185 			if (timeout == -1 ||
1186 			    MRT2MC(m)->ReopenTimer - now < timeout)
1187 				timeout = MRT2MC(m)->ReopenTimer - now;
1188 		}
1189 	}
1190 	return (timeout);
1191 }
1192 
1193 void
mrt_reconfigure(struct mrt_head * mrt)1194 mrt_reconfigure(struct mrt_head *mrt)
1195 {
1196 	struct mrt	*m, *xm;
1197 	time_t		 now;
1198 
1199 	now = time(NULL);
1200 	for (m = LIST_FIRST(mrt); m != NULL; m = xm) {
1201 		xm = LIST_NEXT(m, entry);
1202 		if (m->state == MRT_STATE_OPEN ||
1203 		    m->state == MRT_STATE_REOPEN) {
1204 			if (mrt_open(m, now) == -1)
1205 				continue;
1206 			if (MRT2MC(m)->ReopenTimerInterval != 0)
1207 				MRT2MC(m)->ReopenTimer =
1208 				    now + MRT2MC(m)->ReopenTimerInterval;
1209 			m->state = MRT_STATE_RUNNING;
1210 		}
1211 		if (m->state == MRT_STATE_REMOVE) {
1212 			if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)],
1213 			    IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) ==
1214 			    -1)
1215 				log_warn("mrt_reconfigure");
1216 			LIST_REMOVE(m, entry);
1217 			free(m);
1218 			continue;
1219 		}
1220 	}
1221 }
1222 
1223 void
mrt_handler(struct mrt_head * mrt)1224 mrt_handler(struct mrt_head *mrt)
1225 {
1226 	struct mrt	*m;
1227 	time_t		 now;
1228 
1229 	now = time(NULL);
1230 	LIST_FOREACH(m, mrt, entry) {
1231 		if (m->state == MRT_STATE_RUNNING &&
1232 		    (MRT2MC(m)->ReopenTimerInterval != 0 ||
1233 		     m->type == MRT_TABLE_DUMP ||
1234 		     m->type == MRT_TABLE_DUMP_MP ||
1235 		     m->type == MRT_TABLE_DUMP_V2)) {
1236 			if (mrt_open(m, now) == -1)
1237 				continue;
1238 			MRT2MC(m)->ReopenTimer =
1239 			    now + MRT2MC(m)->ReopenTimerInterval;
1240 		}
1241 	}
1242 }
1243 
1244 struct mrt *
mrt_get(struct mrt_head * c,struct mrt * m)1245 mrt_get(struct mrt_head *c, struct mrt *m)
1246 {
1247 	struct mrt	*t;
1248 
1249 	LIST_FOREACH(t, c, entry) {
1250 		if (t->type != m->type)
1251 			continue;
1252 		if (strcmp(t->rib, m->rib))
1253 			continue;
1254 		if (t->peer_id == m->peer_id &&
1255 		    t->group_id == m->group_id)
1256 			return (t);
1257 	}
1258 	return (NULL);
1259 }
1260 
1261 void
mrt_mergeconfig(struct mrt_head * xconf,struct mrt_head * nconf)1262 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf)
1263 {
1264 	struct mrt	*m, *xm;
1265 
1266 	/* both lists here are actually struct mrt_conifg nodes */
1267 	LIST_FOREACH(m, nconf, entry) {
1268 		if ((xm = mrt_get(xconf, m)) == NULL) {
1269 			/* NEW */
1270 			if ((xm = malloc(sizeof(struct mrt_config))) == NULL)
1271 				fatal("mrt_mergeconfig");
1272 			memcpy(xm, m, sizeof(struct mrt_config));
1273 			xm->state = MRT_STATE_OPEN;
1274 			LIST_INSERT_HEAD(xconf, xm, entry);
1275 		} else {
1276 			/* MERGE */
1277 			if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name,
1278 			    sizeof(MRT2MC(xm)->name)) >=
1279 			    sizeof(MRT2MC(xm)->name))
1280 				fatalx("mrt_mergeconfig: strlcpy");
1281 			MRT2MC(xm)->ReopenTimerInterval =
1282 			    MRT2MC(m)->ReopenTimerInterval;
1283 			xm->state = MRT_STATE_REOPEN;
1284 		}
1285 	}
1286 
1287 	LIST_FOREACH(xm, xconf, entry)
1288 		if (mrt_get(nconf, xm) == NULL)
1289 			/* REMOVE */
1290 			xm->state = MRT_STATE_REMOVE;
1291 
1292 	/* free config */
1293 	while ((m = LIST_FIRST(nconf)) != NULL) {
1294 		LIST_REMOVE(m, entry);
1295 		free(m);
1296 	}
1297 }
1298