GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/mrt.c Lines: 0 465 0.0 %
Date: 2016-12-06 Branches: 0 509 0.0 %

Line Branch Exec Source
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
}