GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/mrt.c Lines: 4 493 0.8 %
Date: 2017-11-13 Branches: 3 669 0.4 %

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