xref: /openbsd-src/usr.sbin/bgpd/mrt.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: mrt.c,v 1.81 2015/12/30 12:06:56 benno 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 
36 int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *, int);
37 int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t,
38     struct rde_peer*);
39 int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*);
40 int mrt_dump_entry_v2(struct mrt *, struct rib_entry *, u_int32_t);
41 int mrt_dump_peer(struct ibuf *, struct rde_peer *);
42 int mrt_dump_hdr_se(struct ibuf **, struct peer *, u_int16_t, u_int16_t,
43     u_int32_t, int);
44 int mrt_dump_hdr_rde(struct ibuf **, u_int16_t type, u_int16_t, u_int32_t);
45 int mrt_open(struct mrt *, time_t);
46 
47 #define DUMP_BYTE(x, b)							\
48 	do {								\
49 		u_char		t = (b);				\
50 		if (ibuf_add((x), &t, sizeof(t)) == -1) {		\
51 			log_warn("mrt_dump1: ibuf_add error");		\
52 			goto fail;					\
53 		}							\
54 	} while (0)
55 
56 #define DUMP_SHORT(x, s)						\
57 	do {								\
58 		u_int16_t	t;					\
59 		t = htons((s));						\
60 		if (ibuf_add((x), &t, sizeof(t)) == -1) {		\
61 			log_warn("mrt_dump2: ibuf_add error");		\
62 			goto fail;					\
63 		}							\
64 	} while (0)
65 
66 #define DUMP_LONG(x, l)							\
67 	do {								\
68 		u_int32_t	t;					\
69 		t = htonl((l));						\
70 		if (ibuf_add((x), &t, sizeof(t)) == -1) {		\
71 			log_warn("mrt_dump3: ibuf_add error");		\
72 			goto fail;					\
73 		}							\
74 	} while (0)
75 
76 #define DUMP_NLONG(x, l)						\
77 	do {								\
78 		u_int32_t	t = (l);				\
79 		if (ibuf_add((x), &t, sizeof(t)) == -1) {		\
80 			log_warn("mrt_dump4: ibuf_add error");		\
81 			goto fail;					\
82 		}							\
83 	} while (0)
84 
85 #define RDEIDX		0
86 #define SEIDX		1
87 #define TYPE2IDX(x)	((x == MRT_TABLE_DUMP ||			\
88 			    x == MRT_TABLE_DUMP_MP ||			\
89 			    x == MRT_TABLE_DUMP_V2) ? RDEIDX : SEIDX	\
90 			)
91 
92 void
93 mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen,
94     struct peer *peer)
95 {
96 	struct ibuf	*buf;
97 	int		 incoming = 0;
98 	u_int16_t	 subtype = BGP4MP_MESSAGE;
99 
100 	if (peer->capa.neg.as4byte)
101 		subtype = BGP4MP_MESSAGE_AS4;
102 
103 	/* get the direction of the message to swap address and AS fields */
104 	if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN)
105 		incoming = 1;
106 
107 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype,
108 	    pkglen, incoming) == -1)
109 		return;
110 
111 	if (ibuf_add(buf, pkg, pkglen) == -1) {
112 		log_warn("mrt_dump_bgp_msg: ibuf_add error");
113 		ibuf_free(buf);
114 		return;
115 	}
116 
117 	ibuf_close(&mrt->wbuf, buf);
118 }
119 
120 void
121 mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state,
122     struct peer *peer)
123 {
124 	struct ibuf	*buf;
125 	u_int16_t	 subtype = BGP4MP_STATE_CHANGE;
126 
127 	if (peer->capa.neg.as4byte)
128 		subtype = BGP4MP_STATE_CHANGE_AS4;
129 
130 	if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype,
131 	    2 * sizeof(short), 0) == -1)
132 		return;
133 
134 	DUMP_SHORT(buf, old_state);
135 	DUMP_SHORT(buf, new_state);
136 
137 	ibuf_close(&mrt->wbuf, buf);
138 	return;
139 
140 fail:
141 	ibuf_free(buf);
142 }
143 
144 int
145 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop,
146     int v2)
147 {
148 	struct attr	*oa;
149 	u_char		*pdata;
150 	u_int32_t	 tmp;
151 	int		 neednewpath = 0;
152 	u_int16_t	 plen, afi;
153 	u_int8_t	 l, safi;
154 
155 	/* origin */
156 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
157 	    &a->origin, 1) == -1)
158 		return (-1);
159 
160 	/* aspath */
161 	pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
162 	if (!v2)
163 		pdata = aspath_deflate(pdata, &plen, &neednewpath);
164 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
165 	    plen) == -1) {
166 		free(pdata);
167 		return (-1);
168 	}
169 	free(pdata);
170 
171 	if (nexthop && nexthop->aid == AID_INET) {
172 		/* nexthop, already network byte order */
173 		if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
174 		    &nexthop->v4.s_addr, 4) ==	-1)
175 			return (-1);
176 	}
177 
178 	/* MED, non transitive */
179 	if (a->med != 0) {
180 		tmp = htonl(a->med);
181 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1)
182 			return (-1);
183 	}
184 
185 	/* local preference */
186 	tmp = htonl(a->lpref);
187 	if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
188 		return (-1);
189 
190 	/* dump all other path attributes without modification */
191 	for (l = 0; l < a->others_len; l++) {
192 		if ((oa = a->others[l]) == NULL)
193 			break;
194 		if (attr_writebuf(buf, oa->flags, oa->type,
195 		    oa->data, oa->len) == -1)
196 			return (-1);
197 	}
198 
199 	if (nexthop && nexthop->aid != AID_INET) {
200 		struct ibuf *nhbuf;
201 
202 		if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL)
203 			return (-1);
204 		if (!v2) {
205 			if (aid2afi(nexthop->aid, &afi, &safi))
206 				return (-1);
207 			DUMP_SHORT(nhbuf, afi);
208 			DUMP_BYTE(nhbuf, safi);
209 		}
210 		switch (nexthop->aid) {
211 		case AID_INET6:
212 			DUMP_BYTE(nhbuf, sizeof(struct in6_addr));
213 			if (ibuf_add(nhbuf, &nexthop->v6,
214 			    sizeof(struct in6_addr)) == -1) {
215 			}
216 			break;
217 		case AID_VPN_IPv4:
218 			DUMP_BYTE(nhbuf, sizeof(u_int64_t) +
219 			    sizeof(struct in_addr));
220 			DUMP_NLONG(nhbuf, 0);	/* set RD to 0 */
221 			DUMP_NLONG(nhbuf, 0);
222 			DUMP_NLONG(nhbuf, nexthop->v4.s_addr);
223 			break;
224 		}
225 		if (!v2)
226 			DUMP_BYTE(nhbuf, 0);
227 		if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
228 		    nhbuf->buf, ibuf_size(nhbuf)) == -1) {
229 fail:
230 			ibuf_free(nhbuf);
231 			return (-1);
232 		}
233 		ibuf_free(nhbuf);
234 	}
235 
236 	if (neednewpath) {
237 		pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
238 		if (plen != 0)
239 			if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE,
240 			    ATTR_AS4_PATH, pdata, plen) == -1) {
241 				free(pdata);
242 				return (-1);
243 			}
244 		free(pdata);
245 	}
246 
247 	return (0);
248 }
249 
250 int
251 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
252     struct rde_peer *peer)
253 {
254 	struct ibuf	*buf, *hbuf = NULL, *h2buf = NULL;
255 	struct bgpd_addr addr, nexthop, *nh;
256 	u_int16_t	 len;
257 	u_int8_t	 aid;
258 
259 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
260 		log_warn("mrt_dump_entry_mp: ibuf_dynamic");
261 		return (-1);
262 	}
263 
264 	if (mrt_attr_dump(buf, p->aspath, NULL, 0) == -1) {
265 		log_warnx("mrt_dump_entry_mp: mrt_attr_dump error");
266 		goto fail;
267 	}
268 	len = ibuf_size(buf);
269 
270 	if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE +
271 	    MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE +
272 	    MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL) {
273 		log_warn("mrt_dump_entry_mp: ibuf_dynamic");
274 		goto fail;
275 	}
276 
277 	DUMP_SHORT(h2buf, rde_local_as());
278 	DUMP_SHORT(h2buf, peer->short_as);
279 	DUMP_SHORT(h2buf, /* ifindex */ 0);
280 
281 	/* XXX is this for peer self? */
282 	aid = peer->remote_addr.aid == AID_UNSPEC ? p->prefix->aid :
283 	     peer->remote_addr.aid;
284 	switch (aid) {
285 	case AID_INET:
286 		DUMP_SHORT(h2buf, AFI_IPv4);
287 		DUMP_NLONG(h2buf, peer->local_v4_addr.v4.s_addr);
288 		DUMP_NLONG(h2buf, peer->remote_addr.v4.s_addr);
289 		break;
290 	case AID_INET6:
291 		DUMP_SHORT(h2buf, AFI_IPv6);
292 		if (ibuf_add(h2buf, &peer->local_v6_addr.v6,
293 		    sizeof(struct in6_addr)) == -1 ||
294 		    ibuf_add(h2buf, &peer->remote_addr.v6,
295 		    sizeof(struct in6_addr)) == -1) {
296 			log_warn("mrt_dump_entry_mp: ibuf_add error");
297 			goto fail;
298 		}
299 		break;
300 	default:
301 		log_warnx("king bula found new AF in mrt_dump_entry_mp");
302 		goto fail;
303 	}
304 
305 	DUMP_SHORT(h2buf, 0);		/* view */
306 	DUMP_SHORT(h2buf, 1);		/* status */
307 	DUMP_LONG(h2buf, p->lastchange);	/* originated */
308 
309 	pt_getaddr(p->prefix, &addr);
310 
311 	if (p->aspath->nexthop == NULL) {
312 		bzero(&nexthop, sizeof(struct bgpd_addr));
313 		nexthop.aid = addr.aid;
314 		nh = &nexthop;
315 	} else
316 		nh = &p->aspath->nexthop->exit_nexthop;
317 
318 	switch (addr.aid) {
319 	case AID_INET:
320 		DUMP_SHORT(h2buf, AFI_IPv4);	/* afi */
321 		DUMP_BYTE(h2buf, SAFI_UNICAST);	/* safi */
322 		DUMP_BYTE(h2buf, 4);		/* nhlen */
323 		DUMP_NLONG(h2buf, nh->v4.s_addr);	/* nexthop */
324 		break;
325 	case AID_INET6:
326 		DUMP_SHORT(h2buf, AFI_IPv6);	/* afi */
327 		DUMP_BYTE(h2buf, SAFI_UNICAST);	/* safi */
328 		DUMP_BYTE(h2buf, 16);		/* nhlen */
329 		if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) {
330 			log_warn("mrt_dump_entry_mp: ibuf_add error");
331 			goto fail;
332 		}
333 		break;
334 	default:
335 		log_warnx("king bula found new AF in mrt_dump_entry_mp");
336 		goto fail;
337 	}
338 
339 	if (prefix_writebuf(h2buf, &addr, p->prefix->prefixlen) == -1) {
340 		log_warn("mrt_dump_entry_mp: prefix_writebuf error");
341 		goto fail;
342 	}
343 
344 	DUMP_SHORT(h2buf, len);
345 	len += ibuf_size(h2buf);
346 
347 	if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY,
348 	    len) == -1)
349 		goto fail;
350 
351 	ibuf_close(&mrt->wbuf, hbuf);
352 	ibuf_close(&mrt->wbuf, h2buf);
353 	ibuf_close(&mrt->wbuf, buf);
354 
355 	return (len + MRT_HEADER_SIZE);
356 
357 fail:
358 	ibuf_free(hbuf);
359 	ibuf_free(h2buf);
360 	ibuf_free(buf);
361 	return (-1);
362 }
363 
364 int
365 mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
366     struct rde_peer *peer)
367 {
368 	struct ibuf	*buf, *hbuf;
369 	struct bgpd_addr addr, *nh;
370 	size_t		 len;
371 	u_int16_t	 subtype;
372 	u_int8_t	 dummy;
373 
374 	if (p->prefix->aid != peer->remote_addr.aid &&
375 	    p->prefix->aid != AID_INET && p->prefix->aid != AID_INET6)
376 		/* only able to dump pure IPv4/IPv6 */
377 		return (0);
378 
379 	if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
380 		log_warn("mrt_dump_entry: ibuf_dynamic");
381 		return (-1);
382 	}
383 
384 	if (p->aspath->nexthop == NULL) {
385 		bzero(&addr, sizeof(struct bgpd_addr));
386 		addr.aid = p->prefix->aid;
387 		nh = &addr;
388 	} else
389 		nh = &p->aspath->nexthop->exit_nexthop;
390 	if (mrt_attr_dump(buf, p->aspath, nh, 0) == -1) {
391 		log_warnx("mrt_dump_entry: mrt_attr_dump error");
392 		ibuf_free(buf);
393 		return (-1);
394 	}
395 	len = ibuf_size(buf);
396 	aid2afi(p->prefix->aid, &subtype, &dummy);
397 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) {
398 		ibuf_free(buf);
399 		return (-1);
400 	}
401 
402 	DUMP_SHORT(hbuf, 0);
403 	DUMP_SHORT(hbuf, snum);
404 
405 	pt_getaddr(p->prefix, &addr);
406 	switch (p->prefix->aid) {
407 	case AID_INET:
408 		DUMP_NLONG(hbuf, addr.v4.s_addr);
409 		break;
410 	case AID_INET6:
411 		if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) {
412 			log_warn("mrt_dump_entry: ibuf_add error");
413 			goto fail;
414 		}
415 		break;
416 	}
417 	DUMP_BYTE(hbuf, p->prefix->prefixlen);
418 
419 	DUMP_BYTE(hbuf, 1);		/* state */
420 	DUMP_LONG(hbuf, p->lastchange);	/* originated */
421 	switch (p->prefix->aid) {
422 	case AID_INET:
423 		DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr);
424 		break;
425 	case AID_INET6:
426 		if (ibuf_add(hbuf, &peer->remote_addr.v6,
427 		    sizeof(struct in6_addr)) == -1) {
428 			log_warn("mrt_dump_entry: ibuf_add error");
429 			goto fail;
430 		}
431 		break;
432 	}
433 	DUMP_SHORT(hbuf, peer->short_as);
434 	DUMP_SHORT(hbuf, len);
435 
436 	ibuf_close(&mrt->wbuf, hbuf);
437 	ibuf_close(&mrt->wbuf, buf);
438 
439 	return (len + MRT_HEADER_SIZE);
440 
441 fail:
442 	ibuf_free(hbuf);
443 	ibuf_free(buf);
444 	return (-1);
445 }
446 
447 int
448 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum)
449 {
450 	struct ibuf	*buf, *hbuf = NULL;
451 	struct prefix	*p;
452 	struct bgpd_addr addr;
453 	size_t		 len, off;
454 	u_int16_t	 subtype, nump;
455 
456 	switch (re->prefix->aid) {
457 	case AID_INET:
458 		subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST;
459 		break;
460 	case AID_INET6:
461 		subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST;
462 		break;
463 	default:
464 		subtype = MRT_DUMP_V2_RIB_GENERIC;
465 		break;
466 	}
467 
468 	if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
469 		log_warn("%s: ibuf_dynamic", __func__);
470 		return (-1);
471 	}
472 
473 	DUMP_LONG(buf, snum);
474 	pt_getaddr(re->prefix, &addr);
475 	if (subtype == MRT_DUMP_V2_RIB_GENERIC) {
476 		u_int16_t afi;
477 		u_int8_t safi;
478 
479 		aid2afi(re->prefix->aid, &afi, &safi);
480 		DUMP_SHORT(buf, afi);
481 		DUMP_BYTE(buf, safi);
482 	}
483 	if (prefix_writebuf(buf, &addr, re->prefix->prefixlen) == -1) {
484 		log_warn("%s: prefix_writebuf error", __func__);
485 		goto fail;
486 	}
487 
488 	off = ibuf_size(buf);
489 	if (ibuf_reserve(buf, sizeof(nump)) == NULL) {
490 		log_warn("%s: ibuf_reserve error", __func__);
491 		goto fail;
492 	}
493 	nump = 0;
494 	LIST_FOREACH(p, &re->prefix_h, rib_l) {
495 		struct bgpd_addr	*nh;
496 		struct ibuf		*tbuf;
497 
498 		if (p->aspath->nexthop == NULL) {
499 			bzero(&addr, sizeof(struct bgpd_addr));
500 			addr.aid = p->prefix->aid;
501 			nh = &addr;
502 		} else
503 			nh = &p->aspath->nexthop->exit_nexthop;
504 
505 		DUMP_SHORT(buf, p->aspath->peer->mrt_idx);
506 		DUMP_LONG(buf, p->lastchange); /* originated */
507 
508 		if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
509 			log_warn("%s: ibuf_dynamic", __func__);
510 			return (-1);
511 		}
512 		if (mrt_attr_dump(tbuf, p->aspath, nh, 1) == -1) {
513 			log_warnx("%s: mrt_attr_dump error", __func__);
514 			ibuf_free(buf);
515 			return (-1);
516 		}
517 		len = ibuf_size(tbuf);
518 		DUMP_SHORT(buf, (u_int16_t)len);
519 		if (ibuf_add(buf, tbuf->buf, ibuf_size(tbuf)) == -1) {
520 			log_warn("%s: ibuf_add error", __func__);
521 			ibuf_free(tbuf);
522 			return (-1);
523 		}
524 		ibuf_free(tbuf);
525 		nump++;
526 	}
527 	nump = htons(nump);
528 	memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump));
529 
530 	len = ibuf_size(buf);
531 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, len) == -1) {
532 		ibuf_free(buf);
533 		return (-1);
534 	}
535 
536 	ibuf_close(&mrt->wbuf, hbuf);
537 	ibuf_close(&mrt->wbuf, buf);
538 
539 	return (0);
540 fail:
541 	ibuf_free(hbuf);
542 	ibuf_free(buf);
543 	return (-1);
544 }
545 
546 int
547 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf,
548     struct rde_peer_head *ph)
549 {
550 	struct rde_peer	*peer;
551 	struct ibuf	*buf, *hbuf = NULL;
552 	size_t		 len, off;
553 	u_int16_t	 nlen, nump;
554 
555 	if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
556 		log_warn("%s: ibuf_dynamic", __func__);
557 		return (-1);
558 	}
559 
560 	DUMP_NLONG(buf, conf->bgpid);
561 	nlen = strlen(mrt->rib);
562 	if (nlen > 0)
563 		nlen += 1;
564 	DUMP_SHORT(buf, nlen);
565 	if (ibuf_add(buf, mrt->rib, nlen) == -1) {
566 		log_warn("%s: ibuf_add error", __func__);
567 		goto fail;
568 	}
569 
570 	off = ibuf_size(buf);
571 	if (ibuf_reserve(buf, sizeof(nump)) == NULL) {
572 		log_warn("%s: ibuf_reserve error", __func__);
573 		goto fail;
574 	}
575 	nump = 0;
576 	LIST_FOREACH(peer, ph, peer_l) {
577 		peer->mrt_idx = nump;
578 		if (mrt_dump_peer(buf, peer) == -1)
579 			goto fail;
580 		nump++;
581 	}
582 	nump = htons(nump);
583 	memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump));
584 
585 	len = ibuf_size(buf);
586 	if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2,
587 	    MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1)
588 		goto fail;
589 
590 	ibuf_close(&mrt->wbuf, hbuf);
591 	ibuf_close(&mrt->wbuf, buf);
592 
593 	return (0);
594 fail:
595 	ibuf_free(hbuf);
596 	ibuf_free(buf);
597 	return (-1);
598 }
599 
600 int
601 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
602 {
603 	u_int8_t	type = 0;
604 
605 	if (peer->capa.as4byte)
606 		type |= MRT_DUMP_V2_PEER_BIT_A;
607 	if (peer->remote_addr.aid == AID_INET6)
608 		type |= MRT_DUMP_V2_PEER_BIT_I;
609 
610 	DUMP_BYTE(buf, type);
611 	DUMP_LONG(buf, peer->remote_bgpid);
612 
613 	switch (peer->remote_addr.aid) {
614 	case AID_INET:
615 		DUMP_NLONG(buf, peer->remote_addr.v4.s_addr);
616 		break;
617 	case AID_INET6:
618 		if (ibuf_add(buf, &peer->remote_addr.v6,
619 		    sizeof(struct in6_addr)) == -1) {
620 			log_warn("mrt_dump_peer: ibuf_add error");
621 			goto fail;
622 		}
623 		break;
624 	case AID_UNSPEC: /* XXX special handling for peer_self? */
625 		DUMP_NLONG(buf, 0);
626 		break;
627 	default:
628 		log_warnx("king bula found new AF in mrt_dump_entry_mp");
629 		goto fail;
630 	}
631 
632 	if (peer->capa.as4byte)
633 		DUMP_LONG(buf, peer->conf.remote_as);
634 	else
635 		DUMP_SHORT(buf, peer->short_as);
636 
637 	return (0);
638 fail:
639 	return (-1);
640 }
641 
642 void
643 mrt_dump_upcall(struct rib_entry *re, void *ptr)
644 {
645 	struct mrt		*mrtbuf = ptr;
646 	struct prefix		*p;
647 
648 	if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
649 		mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
650 		return;
651 	}
652 
653 	/*
654 	 * dump all prefixes even the inactive ones. That is the way zebra
655 	 * dumps the table so we do the same. If only the active route should
656 	 * be dumped p should be set to p = pt->active.
657 	 */
658 	LIST_FOREACH(p, &re->prefix_h, rib_l) {
659 		if (mrtbuf->type == MRT_TABLE_DUMP)
660 			mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++,
661 			    p->aspath->peer);
662 		else
663 			mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++,
664 			    p->aspath->peer);
665 	}
666 }
667 
668 void
669 mrt_done(void *ptr)
670 {
671 	struct mrt		*mrtbuf = ptr;
672 
673 	mrtbuf->state = MRT_STATE_REMOVE;
674 }
675 
676 int
677 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, u_int16_t type,
678     u_int16_t subtype, u_int32_t len, int swap)
679 {
680 	time_t		now;
681 
682 	if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
683 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) {
684 		log_warn("mrt_dump_hdr_se: ibuf_dynamic error");
685 		return (-1);
686 	}
687 
688 	now = time(NULL);
689 
690 	DUMP_LONG(*bp, now);
691 	DUMP_SHORT(*bp, type);
692 	DUMP_SHORT(*bp, subtype);
693 
694 	switch (peer->sa_local.ss_family) {
695 	case AF_INET:
696 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
697 		    subtype == BGP4MP_MESSAGE_AS4)
698 			len += MRT_BGP4MP_AS4_IPv4_HEADER_SIZE;
699 		else
700 			len += MRT_BGP4MP_IPv4_HEADER_SIZE;
701 		break;
702 	case AF_INET6:
703 		if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
704 		    subtype == BGP4MP_MESSAGE_AS4)
705 			len += MRT_BGP4MP_AS4_IPv6_HEADER_SIZE;
706 		else
707 			len += MRT_BGP4MP_IPv6_HEADER_SIZE;
708 		break;
709 	case 0:
710 		goto fail;
711 	default:
712 		log_warnx("king bula found new AF in mrt_dump_hdr_se");
713 		goto fail;
714 	}
715 
716 	DUMP_LONG(*bp, len);
717 
718 	if (subtype == BGP4MP_STATE_CHANGE_AS4 ||
719 	    subtype == BGP4MP_MESSAGE_AS4) {
720 		if (!swap)
721 			DUMP_LONG(*bp, peer->conf.local_as);
722 		DUMP_LONG(*bp, peer->conf.remote_as);
723 		if (swap)
724 			DUMP_LONG(*bp, peer->conf.local_as);
725 	} else {
726 		if (!swap)
727 			DUMP_SHORT(*bp, peer->conf.local_short_as);
728 		DUMP_SHORT(*bp, peer->short_as);
729 		if (swap)
730 			DUMP_SHORT(*bp, peer->conf.local_short_as);
731 	}
732 
733 	DUMP_SHORT(*bp, /* ifindex */ 0);
734 
735 	switch (peer->sa_local.ss_family) {
736 	case AF_INET:
737 		DUMP_SHORT(*bp, AFI_IPv4);
738 		if (!swap)
739 			DUMP_NLONG(*bp, ((struct sockaddr_in *)
740 			    &peer->sa_local)->sin_addr.s_addr);
741 		DUMP_NLONG(*bp,
742 		    ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr);
743 		if (swap)
744 			DUMP_NLONG(*bp, ((struct sockaddr_in *)
745 			    &peer->sa_local)->sin_addr.s_addr);
746 		break;
747 	case AF_INET6:
748 		DUMP_SHORT(*bp, AFI_IPv6);
749 		if (!swap)
750 			if (ibuf_add(*bp, &((struct sockaddr_in6 *)
751 			    &peer->sa_local)->sin6_addr,
752 			    sizeof(struct in6_addr)) == -1) {
753 				log_warn("mrt_dump_hdr_se: ibuf_add error");
754 				goto fail;
755 			}
756 		if (ibuf_add(*bp,
757 		    &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr,
758 		    sizeof(struct in6_addr)) == -1) {
759 			log_warn("mrt_dump_hdr_se: ibuf_add error");
760 			goto fail;
761 		}
762 		if (swap)
763 			if (ibuf_add(*bp, &((struct sockaddr_in6 *)
764 			    &peer->sa_local)->sin6_addr,
765 			    sizeof(struct in6_addr)) == -1) {
766 				log_warn("mrt_dump_hdr_se: ibuf_add error");
767 				goto fail;
768 			}
769 		break;
770 	}
771 
772 	return (0);
773 
774 fail:
775 	ibuf_free(*bp);
776 	return (-1);
777 }
778 
779 int
780 mrt_dump_hdr_rde(struct ibuf **bp, u_int16_t type, u_int16_t subtype,
781     u_int32_t len)
782 {
783 	time_t		 now;
784 
785 	if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
786 	    MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
787 	    NULL) {
788 		log_warn("mrt_dump_hdr_rde: ibuf_dynamic error");
789 		return (-1);
790 	}
791 
792 	now = time(NULL);
793 	DUMP_LONG(*bp, now);
794 	DUMP_SHORT(*bp, type);
795 	DUMP_SHORT(*bp, subtype);
796 
797 	switch (type) {
798 	case MSG_TABLE_DUMP:
799 		switch (subtype) {
800 		case AFI_IPv4:
801 			len += MRT_DUMP_HEADER_SIZE;
802 			break;
803 		case AFI_IPv6:
804 			len += MRT_DUMP_HEADER_SIZE_V6;
805 			break;
806 		}
807 		DUMP_LONG(*bp, len);
808 		break;
809 	case MSG_PROTOCOL_BGP4MP:
810 	case MSG_TABLE_DUMP_V2:
811 		DUMP_LONG(*bp, len);
812 		break;
813 	default:
814 		log_warnx("mrt_dump_hdr_rde: unsupported type");
815 		goto fail;
816 	}
817 	return (0);
818 
819 fail:
820 	ibuf_free(*bp);
821 	return (-1);
822 }
823 
824 void
825 mrt_write(struct mrt *mrt)
826 {
827 	int	r;
828 
829 	if ((r = ibuf_write(&mrt->wbuf)) < 0 && errno != EAGAIN) {
830 		log_warn("mrt dump aborted, mrt_write");
831 		mrt_clean(mrt);
832 		mrt_done(mrt);
833 	}
834 }
835 
836 void
837 mrt_clean(struct mrt *mrt)
838 {
839 	struct ibuf	*b;
840 
841 	close(mrt->wbuf.fd);
842 	while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) {
843 		TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry);
844 		ibuf_free(b);
845 	}
846 	mrt->wbuf.queued = 0;
847 }
848 
849 static struct imsgbuf	*mrt_imsgbuf[2];
850 
851 void
852 mrt_init(struct imsgbuf *rde, struct imsgbuf *se)
853 {
854 	mrt_imsgbuf[RDEIDX] = rde;
855 	mrt_imsgbuf[SEIDX] = se;
856 }
857 
858 int
859 mrt_open(struct mrt *mrt, time_t now)
860 {
861 	enum imsg_type	type;
862 	int		fd;
863 
864 	if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file),
865 	    MRT2MC(mrt)->name, localtime(&now)) == 0) {
866 		log_warnx("mrt_open: strftime conversion failed");
867 		return (-1);
868 	}
869 
870 	fd = open(MRT2MC(mrt)->file,
871 	    O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644);
872 	if (fd == -1) {
873 		log_warn("mrt_open %s", MRT2MC(mrt)->file);
874 		return (1);
875 	}
876 
877 	if (mrt->state == MRT_STATE_OPEN)
878 		type = IMSG_MRT_OPEN;
879 	else
880 		type = IMSG_MRT_REOPEN;
881 
882 	if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd,
883 	    mrt, sizeof(struct mrt)) == -1)
884 		log_warn("mrt_open");
885 
886 	return (1);
887 }
888 
889 int
890 mrt_timeout(struct mrt_head *mrt)
891 {
892 	struct mrt	*m;
893 	time_t		 now;
894 	int		 timeout = MRT_MAX_TIMEOUT;
895 
896 	now = time(NULL);
897 	LIST_FOREACH(m, mrt, entry) {
898 		if (m->state == MRT_STATE_RUNNING &&
899 		    MRT2MC(m)->ReopenTimerInterval != 0) {
900 			if (MRT2MC(m)->ReopenTimer <= now) {
901 				mrt_open(m, now);
902 				MRT2MC(m)->ReopenTimer =
903 				    now + MRT2MC(m)->ReopenTimerInterval;
904 			}
905 			if (MRT2MC(m)->ReopenTimer - now < timeout)
906 				timeout = MRT2MC(m)->ReopenTimer - now;
907 		}
908 	}
909 	return (timeout > 0 ? timeout : 0);
910 }
911 
912 void
913 mrt_reconfigure(struct mrt_head *mrt)
914 {
915 	struct mrt	*m, *xm;
916 	time_t		 now;
917 
918 	now = time(NULL);
919 	for (m = LIST_FIRST(mrt); m != NULL; m = xm) {
920 		xm = LIST_NEXT(m, entry);
921 		if (m->state == MRT_STATE_OPEN ||
922 		    m->state == MRT_STATE_REOPEN) {
923 			if (mrt_open(m, now) == -1)
924 				continue;
925 			if (MRT2MC(m)->ReopenTimerInterval != 0)
926 				MRT2MC(m)->ReopenTimer =
927 				    now + MRT2MC(m)->ReopenTimerInterval;
928 			m->state = MRT_STATE_RUNNING;
929 		}
930 		if (m->state == MRT_STATE_REMOVE) {
931 			if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)],
932 			    IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) ==
933 			    -1)
934 				log_warn("mrt_reconfigure");
935 			LIST_REMOVE(m, entry);
936 			free(m);
937 			continue;
938 		}
939 	}
940 }
941 
942 void
943 mrt_handler(struct mrt_head *mrt)
944 {
945 	struct mrt	*m;
946 	time_t		 now;
947 
948 	now = time(NULL);
949 	LIST_FOREACH(m, mrt, entry) {
950 		if (m->state == MRT_STATE_RUNNING &&
951 		    (MRT2MC(m)->ReopenTimerInterval != 0 ||
952 		     m->type == MRT_TABLE_DUMP ||
953 		     m->type == MRT_TABLE_DUMP_MP ||
954 		     m->type == MRT_TABLE_DUMP_V2)) {
955 			if (mrt_open(m, now) == -1)
956 				continue;
957 			MRT2MC(m)->ReopenTimer =
958 			    now + MRT2MC(m)->ReopenTimerInterval;
959 		}
960 	}
961 }
962 
963 struct mrt *
964 mrt_get(struct mrt_head *c, struct mrt *m)
965 {
966 	struct mrt	*t;
967 
968 	LIST_FOREACH(t, c, entry) {
969 		if (t->type != m->type)
970 			continue;
971 		if (strcmp(t->rib, m->rib))
972 			continue;
973 		if (t->peer_id == m->peer_id &&
974 		    t->group_id == m->group_id)
975 			return (t);
976 	}
977 	return (NULL);
978 }
979 
980 int
981 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf)
982 {
983 	struct mrt	*m, *xm;
984 
985 	/* both lists here are actually struct mrt_conifg nodes */
986 	LIST_FOREACH(m, nconf, entry) {
987 		if ((xm = mrt_get(xconf, m)) == NULL) {
988 			/* NEW */
989 			if ((xm = malloc(sizeof(struct mrt_config))) == NULL)
990 				fatal("mrt_mergeconfig");
991 			memcpy(xm, m, sizeof(struct mrt_config));
992 			xm->state = MRT_STATE_OPEN;
993 			LIST_INSERT_HEAD(xconf, xm, entry);
994 		} else {
995 			/* MERGE */
996 			if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name,
997 			    sizeof(MRT2MC(xm)->name)) >=
998 			    sizeof(MRT2MC(xm)->name))
999 				fatalx("mrt_mergeconfig: strlcpy");
1000 			MRT2MC(xm)->ReopenTimerInterval =
1001 			    MRT2MC(m)->ReopenTimerInterval;
1002 			xm->state = MRT_STATE_REOPEN;
1003 		}
1004 	}
1005 
1006 	LIST_FOREACH(xm, xconf, entry)
1007 		if (mrt_get(nconf, xm) == NULL)
1008 			/* REMOVE */
1009 			xm->state = MRT_STATE_REMOVE;
1010 
1011 	/* free config */
1012 	while ((m = LIST_FIRST(nconf)) != NULL) {
1013 		LIST_REMOVE(m, entry);
1014 		free(m);
1015 	}
1016 
1017 	return (0);
1018 }
1019