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

Line Branch Exec Source
1
/*	$OpenBSD: rde.c,v 1.347 2016/07/21 10:13:58 claudio Exp $ */
2
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@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/socket.h>
21
#include <sys/time.h>
22
#include <sys/resource.h>
23
24
#include <errno.h>
25
#include <ifaddrs.h>
26
#include <pwd.h>
27
#include <poll.h>
28
#include <signal.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
#include <err.h>
34
35
#include "bgpd.h"
36
#include "mrt.h"
37
#include "rde.h"
38
#include "session.h"
39
40
#define PFD_PIPE_MAIN		0
41
#define PFD_PIPE_SESSION	1
42
#define PFD_PIPE_SESSION_CTL	2
43
#define PFD_PIPE_COUNT		3
44
45
void		 rde_sighdlr(int);
46
void		 rde_dispatch_imsg_session(struct imsgbuf *);
47
void		 rde_dispatch_imsg_parent(struct imsgbuf *);
48
int		 rde_update_dispatch(struct imsg *);
49
void		 rde_update_update(struct rde_peer *, struct rde_aspath *,
50
		     struct bgpd_addr *, u_int8_t);
51
void		 rde_update_withdraw(struct rde_peer *, struct bgpd_addr *,
52
		     u_int8_t);
53
int		 rde_attr_parse(u_char *, u_int16_t, struct rde_peer *,
54
		     struct rde_aspath *, struct mpattr *);
55
int		 rde_attr_add(struct rde_aspath *, u_char *, u_int16_t);
56
u_int8_t	 rde_attr_missing(struct rde_aspath *, int, u_int16_t);
57
int		 rde_get_mp_nexthop(u_char *, u_int16_t, u_int8_t,
58
		     struct rde_aspath *);
59
int		 rde_update_extract_prefix(u_char *, u_int16_t, void *,
60
		     u_int8_t, u_int8_t);
61
int		 rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *,
62
		     u_int8_t *);
63
int		 rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
64
		     u_int8_t *);
65
int		 rde_update_get_vpn4(u_char *, u_int16_t, struct bgpd_addr *,
66
		     u_int8_t *);
67
void		 rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
68
		     void *, u_int16_t);
69
void		 rde_update_log(const char *, u_int16_t,
70
		     const struct rde_peer *, const struct bgpd_addr *,
71
		     const struct bgpd_addr *, u_int8_t);
72
void		 rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *);
73
void		 rde_reflector(struct rde_peer *, struct rde_aspath *);
74
75
void		 rde_dump_rib_as(struct prefix *, struct rde_aspath *,pid_t,
76
		     int);
77
void		 rde_dump_filter(struct prefix *,
78
		     struct ctl_show_rib_request *);
79
void		 rde_dump_filterout(struct rde_peer *, struct prefix *,
80
		     struct ctl_show_rib_request *);
81
void		 rde_dump_upcall(struct rib_entry *, void *);
82
void		 rde_dump_prefix_upcall(struct rib_entry *, void *);
83
void		 rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t,
84
		     enum imsg_type);
85
void		 rde_dump_mrt_new(struct mrt *, pid_t, int);
86
void		 rde_dump_done(void *);
87
88
int		 rde_rdomain_import(struct rde_aspath *, struct rdomain *);
89
void		 rde_reload_done(void);
90
void		 rde_softreconfig_out(struct rib_entry *, void *);
91
void		 rde_softreconfig_in(struct rib_entry *, void *);
92
void		 rde_softreconfig_unload_peer(struct rib_entry *, void *);
93
void		 rde_up_dump_upcall(struct rib_entry *, void *);
94
void		 rde_update_queue_runner(void);
95
void		 rde_update6_queue_runner(u_int8_t);
96
97
void		 peer_init(u_int32_t);
98
void		 peer_shutdown(void);
99
int		 peer_localaddrs(struct rde_peer *, struct bgpd_addr *);
100
struct rde_peer	*peer_add(u_int32_t, struct peer_config *);
101
struct rde_peer	*peer_get(u_int32_t);
102
void		 peer_up(u_int32_t, struct session_up *);
103
void		 peer_down(u_int32_t);
104
void		 peer_flush(struct rde_peer *, u_int8_t);
105
void		 peer_stale(u_int32_t, u_int8_t);
106
void		 peer_recv_eor(struct rde_peer *, u_int8_t);
107
void		 peer_dump(u_int32_t, u_int8_t);
108
void		 peer_send_eor(struct rde_peer *, u_int8_t);
109
110
void		 network_add(struct network_config *, int);
111
void		 network_delete(struct network_config *, int);
112
void		 network_dump_upcall(struct rib_entry *, void *);
113
114
void		 rde_shutdown(void);
115
int		 sa_cmp(struct bgpd_addr *, struct sockaddr *);
116
117
volatile sig_atomic_t	 rde_quit = 0;
118
struct bgpd_config	*conf, *nconf;
119
time_t			 reloadtime;
120
struct rde_peer_head	 peerlist;
121
struct rde_peer		*peerself;
122
struct filter_head	*out_rules, *out_rules_tmp;
123
struct rdomain_head	*rdomains_l, *newdomains;
124
struct imsgbuf		*ibuf_se;
125
struct imsgbuf		*ibuf_se_ctl;
126
struct imsgbuf		*ibuf_main;
127
struct rde_memstats	 rdemem;
128
129
struct rde_dump_ctx {
130
	struct rib_context		ribctx;
131
	struct ctl_show_rib_request	req;
132
	sa_family_t			af;
133
};
134
135
struct rde_mrt_ctx {
136
	struct mrt		mrt;
137
	struct rib_context	ribctx;
138
	LIST_ENTRY(rde_mrt_ctx)	entry;
139
};
140
141
LIST_HEAD(, rde_mrt_ctx) rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts);
142
u_int rde_mrt_cnt;
143
144
void
145
rde_sighdlr(int sig)
146
{
147
	switch (sig) {
148
	case SIGINT:
149
	case SIGTERM:
150
		rde_quit = 1;
151
		break;
152
	}
153
}
154
155
u_int32_t	peerhashsize = 64;
156
u_int32_t	pathhashsize = 1024;
157
u_int32_t	attrhashsize = 512;
158
u_int32_t	nexthophashsize = 64;
159
160
void
161
rde_main(int debug, int verbose)
162
{
163
	struct passwd		*pw;
164
	struct pollfd		*pfd = NULL;
165
	struct rde_mrt_ctx	*mctx, *xmctx;
166
	void			*newp;
167
	u_int			 pfd_elms = 0, i, j;
168
	int			 timeout;
169
	u_int8_t		 aid;
170
171
	log_init(debug);
172
	log_verbose(verbose);
173
174
	if ((pw = getpwnam(BGPD_USER)) == NULL)
175
		fatal("getpwnam");
176
177
	if (chroot(pw->pw_dir) == -1)
178
		fatal("chroot");
179
	if (chdir("/") == -1)
180
		fatal("chdir(\"/\")");
181
182
	setproctitle("route decision engine");
183
	bgpd_process = PROC_RDE;
184
185
	if (setgroups(1, &pw->pw_gid) ||
186
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
187
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
188
		fatal("can't drop privileges");
189
190
	if (pledge("stdio route recvfd rpath wpath cpath", NULL) == -1)
191
		fatal("pledge");
192
193
	signal(SIGTERM, rde_sighdlr);
194
	signal(SIGINT, rde_sighdlr);
195
	signal(SIGPIPE, SIG_IGN);
196
	signal(SIGHUP, SIG_IGN);
197
	signal(SIGALRM, SIG_IGN);
198
	signal(SIGUSR1, SIG_IGN);
199
200
	/* initialize the RIB structures */
201
	if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
202
		fatal(NULL);
203
	imsg_init(ibuf_main, 3);
204
205
	pt_init();
206
	path_init(pathhashsize);
207
	aspath_init(pathhashsize);
208
	attr_init(attrhashsize);
209
	nexthop_init(nexthophashsize);
210
	peer_init(peerhashsize);
211
212
	out_rules = calloc(1, sizeof(struct filter_head));
213
	if (out_rules == NULL)
214
		fatal(NULL);
215
	TAILQ_INIT(out_rules);
216
	rdomains_l = calloc(1, sizeof(struct rdomain_head));
217
	if (rdomains_l == NULL)
218
		fatal(NULL);
219
	SIMPLEQ_INIT(rdomains_l);
220
	if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
221
		fatal(NULL);
222
	log_info("route decision engine ready");
223
224
	while (rde_quit == 0) {
225
		if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) {
226
			if ((newp = reallocarray(pfd,
227
			    PFD_PIPE_COUNT + rde_mrt_cnt,
228
			    sizeof(struct pollfd))) == NULL) {
229
				/* panic for now  */
230
				log_warn("could not resize pfd from %u -> %u"
231
				    " entries", pfd_elms, PFD_PIPE_COUNT +
232
				    rde_mrt_cnt);
233
				fatalx("exiting");
234
			}
235
			pfd = newp;
236
			pfd_elms = PFD_PIPE_COUNT + rde_mrt_cnt;
237
		}
238
		timeout = INFTIM;
239
		bzero(pfd, sizeof(struct pollfd) * pfd_elms);
240
241
		set_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main);
242
		set_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se);
243
		set_pollfd(&pfd[PFD_PIPE_SESSION_CTL], ibuf_se_ctl);
244
245
		if (rib_dump_pending() &&
246
		    ibuf_se_ctl && ibuf_se_ctl->w.queued == 0)
247
			timeout = 0;
248
249
		i = PFD_PIPE_COUNT;
250
		for (mctx = LIST_FIRST(&rde_mrts); mctx != 0; mctx = xmctx) {
251
			xmctx = LIST_NEXT(mctx, entry);
252
			if (mctx->mrt.wbuf.queued) {
253
				pfd[i].fd = mctx->mrt.wbuf.fd;
254
				pfd[i].events = POLLOUT;
255
				i++;
256
			} else if (mctx->mrt.state == MRT_STATE_REMOVE) {
257
				close(mctx->mrt.wbuf.fd);
258
				LIST_REMOVE(&mctx->ribctx, entry);
259
				LIST_REMOVE(mctx, entry);
260
				free(mctx);
261
				rde_mrt_cnt--;
262
			}
263
		}
264
265
		if (poll(pfd, i, timeout) == -1) {
266
			if (errno != EINTR)
267
				fatal("poll error");
268
			continue;
269
		}
270
271
		if (handle_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main) == -1)
272
			fatalx("Lost connection to parent");
273
		else
274
			rde_dispatch_imsg_parent(ibuf_main);
275
276
		if (handle_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se) == -1) {
277
			log_warnx("RDE: Lost connection to SE");
278
			msgbuf_clear(&ibuf_se->w);
279
			free(ibuf_se);
280
			ibuf_se = NULL;
281
		} else
282
			rde_dispatch_imsg_session(ibuf_se);
283
284
		if (handle_pollfd(&pfd[PFD_PIPE_SESSION_CTL], ibuf_se_ctl) ==
285
		    -1) {
286
			log_warnx("RDE: Lost connection to SE control");
287
			msgbuf_clear(&ibuf_se_ctl->w);
288
			free(ibuf_se_ctl);
289
			ibuf_se_ctl = NULL;
290
		} else
291
			rde_dispatch_imsg_session(ibuf_se_ctl);
292
293
		for (j = PFD_PIPE_COUNT, mctx = LIST_FIRST(&rde_mrts);
294
		    j < i && mctx != 0; j++) {
295
			if (pfd[j].fd == mctx->mrt.wbuf.fd &&
296
			    pfd[j].revents & POLLOUT)
297
				mrt_write(&mctx->mrt);
298
			mctx = LIST_NEXT(mctx, entry);
299
		}
300
301
		rde_update_queue_runner();
302
		for (aid = AID_INET6; aid < AID_MAX; aid++)
303
			rde_update6_queue_runner(aid);
304
		if (rib_dump_pending() &&
305
		    ibuf_se_ctl && ibuf_se_ctl->w.queued <= 10)
306
			rib_dump_runner();
307
	}
308
309
	/* do not clean up on shutdown on production, it takes ages. */
310
	if (debug)
311
		rde_shutdown();
312
313
	while ((mctx = LIST_FIRST(&rde_mrts)) != NULL) {
314
		msgbuf_clear(&mctx->mrt.wbuf);
315
		close(mctx->mrt.wbuf.fd);
316
		LIST_REMOVE(&mctx->ribctx, entry);
317
		LIST_REMOVE(mctx, entry);
318
		free(mctx);
319
	}
320
321
	if (ibuf_se)
322
		msgbuf_clear(&ibuf_se->w);
323
	free(ibuf_se);
324
	if (ibuf_se_ctl)
325
		msgbuf_clear(&ibuf_se_ctl->w);
326
	free(ibuf_se_ctl);
327
328
	msgbuf_clear(&ibuf_main->w);
329
	free(ibuf_main);
330
331
	log_info("route decision engine exiting");
332
	_exit(0);
333
}
334
335
struct network_config	 netconf_s, netconf_p;
336
struct filter_set_head	*session_set, *parent_set;
337
338
void
339
rde_dispatch_imsg_session(struct imsgbuf *ibuf)
340
{
341
	struct imsg		 imsg;
342
	struct peer		 p;
343
	struct peer_config	 pconf;
344
	struct session_up	 sup;
345
	struct ctl_show_rib	 csr;
346
	struct ctl_show_rib_request	req;
347
	struct rde_peer		*peer;
348
	struct rde_aspath	*asp;
349
	struct filter_set	*s;
350
	struct nexthop		*nh;
351
	u_int8_t		*asdata;
352
	ssize_t			 n;
353
	int			 verbose;
354
	u_int16_t		 len;
355
	u_int8_t		 aid;
356
357
	while (ibuf) {
358
		if ((n = imsg_get(ibuf, &imsg)) == -1)
359
			fatal("rde_dispatch_imsg_session: imsg_get error");
360
		if (n == 0)
361
			break;
362
363
		switch (imsg.hdr.type) {
364
		case IMSG_UPDATE:
365
			rde_update_dispatch(&imsg);
366
			break;
367
		case IMSG_SESSION_ADD:
368
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(pconf))
369
				fatalx("incorrect size of session request");
370
			memcpy(&pconf, imsg.data, sizeof(pconf));
371
			peer_add(imsg.hdr.peerid, &pconf);
372
			break;
373
		case IMSG_SESSION_UP:
374
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(sup))
375
				fatalx("incorrect size of session request");
376
			memcpy(&sup, imsg.data, sizeof(sup));
377
			peer_up(imsg.hdr.peerid, &sup);
378
			break;
379
		case IMSG_SESSION_DOWN:
380
			peer_down(imsg.hdr.peerid);
381
			break;
382
		case IMSG_SESSION_STALE:
383
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
384
				log_warnx("rde_dispatch: wrong imsg len");
385
				break;
386
			}
387
			memcpy(&aid, imsg.data, sizeof(aid));
388
			if (aid >= AID_MAX)
389
				fatalx("IMSG_SESSION_STALE: bad AID");
390
			peer_stale(imsg.hdr.peerid, aid);
391
			break;
392
		case IMSG_SESSION_FLUSH:
393
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
394
				log_warnx("rde_dispatch: wrong imsg len");
395
				break;
396
			}
397
			memcpy(&aid, imsg.data, sizeof(aid));
398
			if (aid >= AID_MAX)
399
				fatalx("IMSG_SESSION_FLUSH: bad AID");
400
			if ((peer = peer_get(imsg.hdr.peerid)) == NULL) {
401
				log_warnx("rde_dispatch: unknown peer id %d",
402
				    imsg.hdr.peerid);
403
				break;
404
			}
405
			peer_flush(peer, aid);
406
			break;
407
		case IMSG_SESSION_RESTARTED:
408
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
409
				log_warnx("rde_dispatch: wrong imsg len");
410
				break;
411
			}
412
			memcpy(&aid, imsg.data, sizeof(aid));
413
			if (aid >= AID_MAX)
414
				fatalx("IMSG_SESSION_RESTARTED: bad AID");
415
			if ((peer = peer_get(imsg.hdr.peerid)) == NULL) {
416
				log_warnx("rde_dispatch: unknown peer id %d",
417
				    imsg.hdr.peerid);
418
				break;
419
			}
420
			if (peer->staletime[aid])
421
				peer_flush(peer, aid);
422
			break;
423
		case IMSG_REFRESH:
424
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
425
				log_warnx("rde_dispatch: wrong imsg len");
426
				break;
427
			}
428
			memcpy(&aid, imsg.data, sizeof(aid));
429
			if (aid >= AID_MAX)
430
				fatalx("IMSG_REFRESH: bad AID");
431
			peer_dump(imsg.hdr.peerid, aid);
432
			break;
433
		case IMSG_NETWORK_ADD:
434
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
435
			    sizeof(struct network_config)) {
436
				log_warnx("rde_dispatch: wrong imsg len");
437
				break;
438
			}
439
			memcpy(&netconf_s, imsg.data, sizeof(netconf_s));
440
			TAILQ_INIT(&netconf_s.attrset);
441
			session_set = &netconf_s.attrset;
442
			break;
443
		case IMSG_NETWORK_ASPATH:
444
			if (imsg.hdr.len - IMSG_HEADER_SIZE <
445
			    sizeof(struct ctl_show_rib)) {
446
				log_warnx("rde_dispatch: wrong imsg len");
447
				bzero(&netconf_s, sizeof(netconf_s));
448
				break;
449
			}
450
			asdata = imsg.data;
451
			asdata += sizeof(struct ctl_show_rib);
452
			memcpy(&csr, imsg.data, sizeof(csr));
453
			if (csr.aspath_len + sizeof(csr) > imsg.hdr.len -
454
			    IMSG_HEADER_SIZE) {
455
				log_warnx("rde_dispatch: wrong aspath len");
456
				bzero(&netconf_s, sizeof(netconf_s));
457
				break;
458
			}
459
			asp = path_get();
460
			asp->lpref = csr.local_pref;
461
			asp->med = csr.med;
462
			asp->weight = csr.weight;
463
			asp->flags = csr.flags;
464
			asp->origin = csr.origin;
465
			asp->flags |= F_PREFIX_ANNOUNCED | F_ANN_DYNAMIC;
466
			asp->aspath = aspath_get(asdata, csr.aspath_len);
467
			netconf_s.asp = asp;
468
			break;
469
		case IMSG_NETWORK_ATTR:
470
			if (imsg.hdr.len <= IMSG_HEADER_SIZE) {
471
				log_warnx("rde_dispatch: wrong imsg len");
472
				break;
473
			}
474
			/* parse path attributes */
475
			len = imsg.hdr.len - IMSG_HEADER_SIZE;
476
			asp = netconf_s.asp;
477
			if (rde_attr_add(asp, imsg.data, len) == -1) {
478
				log_warnx("rde_dispatch: bad network "
479
				    "attribute");
480
				path_put(asp);
481
				bzero(&netconf_s, sizeof(netconf_s));
482
				break;
483
			}
484
			break;
485
		case IMSG_NETWORK_DONE:
486
			if (imsg.hdr.len != IMSG_HEADER_SIZE) {
487
				log_warnx("rde_dispatch: wrong imsg len");
488
				break;
489
			}
490
			session_set = NULL;
491
			switch (netconf_s.prefix.aid) {
492
			case AID_INET:
493
				if (netconf_s.prefixlen > 32)
494
					goto badnet;
495
				network_add(&netconf_s, 0);
496
				break;
497
			case AID_INET6:
498
				if (netconf_s.prefixlen > 128)
499
					goto badnet;
500
				network_add(&netconf_s, 0);
501
				break;
502
			case 0:
503
				/* something failed beforehands */
504
				break;
505
			default:
506
badnet:
507
				log_warnx("rde_dispatch: bad network");
508
				break;
509
			}
510
			break;
511
		case IMSG_NETWORK_REMOVE:
512
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
513
			    sizeof(struct network_config)) {
514
				log_warnx("rde_dispatch: wrong imsg len");
515
				break;
516
			}
517
			memcpy(&netconf_s, imsg.data, sizeof(netconf_s));
518
			TAILQ_INIT(&netconf_s.attrset);
519
			network_delete(&netconf_s, 0);
520
			break;
521
		case IMSG_NETWORK_FLUSH:
522
			if (imsg.hdr.len != IMSG_HEADER_SIZE) {
523
				log_warnx("rde_dispatch: wrong imsg len");
524
				break;
525
			}
526
			prefix_network_clean(peerself, time(NULL),
527
			    F_ANN_DYNAMIC);
528
			break;
529
		case IMSG_FILTER_SET:
530
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
531
			    sizeof(struct filter_set)) {
532
				log_warnx("rde_dispatch: wrong imsg len");
533
				break;
534
			}
535
			if (session_set == NULL) {
536
				log_warnx("rde_dispatch: "
537
				    "IMSG_FILTER_SET unexpected");
538
				break;
539
			}
540
			if ((s = malloc(sizeof(struct filter_set))) == NULL)
541
				fatal(NULL);
542
			memcpy(s, imsg.data, sizeof(struct filter_set));
543
			TAILQ_INSERT_TAIL(session_set, s, entry);
544
545
			if (s->type == ACTION_SET_NEXTHOP) {
546
				nh = nexthop_get(&s->action.nexthop);
547
				nh->refcnt++;
548
			}
549
			break;
550
		case IMSG_CTL_SHOW_NETWORK:
551
		case IMSG_CTL_SHOW_RIB:
552
		case IMSG_CTL_SHOW_RIB_AS:
553
		case IMSG_CTL_SHOW_RIB_COMMUNITY:
554
		case IMSG_CTL_SHOW_RIB_PREFIX:
555
			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) {
556
				log_warnx("rde_dispatch: wrong imsg len");
557
				break;
558
			}
559
			memcpy(&req, imsg.data, sizeof(req));
560
			rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type);
561
			break;
562
		case IMSG_CTL_SHOW_NEIGHBOR:
563
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
564
			    sizeof(struct peer)) {
565
				log_warnx("rde_dispatch: wrong imsg len");
566
				break;
567
			}
568
			memcpy(&p, imsg.data, sizeof(struct peer));
569
			peer = peer_get(p.conf.id);
570
			if (peer != NULL) {
571
				p.stats.prefix_cnt = peer->prefix_cnt;
572
				p.stats.prefix_rcvd_update =
573
				    peer->prefix_rcvd_update;
574
				p.stats.prefix_rcvd_withdraw =
575
				    peer->prefix_rcvd_withdraw;
576
				p.stats.prefix_rcvd_eor =
577
				    peer->prefix_rcvd_eor;
578
				p.stats.prefix_sent_update =
579
				    peer->prefix_sent_update;
580
				p.stats.prefix_sent_withdraw =
581
				    peer->prefix_sent_withdraw;
582
				p.stats.prefix_sent_eor =
583
				    peer->prefix_sent_eor;
584
			}
585
			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NEIGHBOR, 0,
586
			    imsg.hdr.pid, -1, &p, sizeof(struct peer));
587
			break;
588
		case IMSG_CTL_END:
589
			imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, imsg.hdr.pid,
590
			    -1, NULL, 0);
591
			break;
592
		case IMSG_CTL_SHOW_RIB_MEM:
593
			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0,
594
			    imsg.hdr.pid, -1, &rdemem, sizeof(rdemem));
595
			break;
596
		case IMSG_CTL_LOG_VERBOSE:
597
			/* already checked by SE */
598
			memcpy(&verbose, imsg.data, sizeof(verbose));
599
			log_verbose(verbose);
600
			break;
601
		default:
602
			break;
603
		}
604
		imsg_free(&imsg);
605
	}
606
}
607
608
void
609
rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
610
{
611
	static struct rdomain	*rd;
612
	struct imsg		 imsg;
613
	struct mrt		 xmrt;
614
	struct rde_rib		 rn;
615
	struct imsgbuf		*i;
616
	struct filter_head	*nr;
617
	struct filter_rule	*r;
618
	struct filter_set	*s;
619
	struct nexthop		*nh;
620
	int			 n, fd;
621
	u_int16_t		 rid;
622
623
	while (ibuf) {
624
		if ((n = imsg_get(ibuf, &imsg)) == -1)
625
			fatal("rde_dispatch_imsg_parent: imsg_get error");
626
		if (n == 0)
627
			break;
628
629
		switch (imsg.hdr.type) {
630
		case IMSG_SOCKET_CONN:
631
		case IMSG_SOCKET_CONN_CTL:
632
			if ((fd = imsg.fd) == -1) {
633
				log_warnx("expected to receive imsg fd to "
634
				    "SE but didn't receive any");
635
				break;
636
			}
637
			if ((i = malloc(sizeof(struct imsgbuf))) == NULL)
638
				fatal(NULL);
639
			imsg_init(i, fd);
640
			if (imsg.hdr.type == IMSG_SOCKET_CONN) {
641
				if (ibuf_se) {
642
					log_warnx("Unexpected imsg connection "
643
					    "to SE received");
644
					msgbuf_clear(&ibuf_se->w);
645
					free(ibuf_se);
646
				}
647
				ibuf_se = i;
648
			} else {
649
				if (ibuf_se_ctl) {
650
					log_warnx("Unexpected imsg ctl "
651
					    "connection to SE received");
652
					msgbuf_clear(&ibuf_se_ctl->w);
653
					free(ibuf_se_ctl);
654
				}
655
				ibuf_se_ctl = i;
656
			}
657
			break;
658
		case IMSG_NETWORK_ADD:
659
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
660
			    sizeof(struct network_config)) {
661
				log_warnx("rde_dispatch: wrong imsg len");
662
				break;
663
			}
664
			memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
665
			TAILQ_INIT(&netconf_p.attrset);
666
			parent_set = &netconf_p.attrset;
667
			break;
668
		case IMSG_NETWORK_DONE:
669
			parent_set = NULL;
670
			network_add(&netconf_p, 1);
671
			break;
672
		case IMSG_NETWORK_REMOVE:
673
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
674
			    sizeof(struct network_config)) {
675
				log_warnx("rde_dispatch: wrong imsg len");
676
				break;
677
			}
678
			memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
679
			TAILQ_INIT(&netconf_p.attrset);
680
			network_delete(&netconf_p, 1);
681
			break;
682
		case IMSG_RECONF_CONF:
683
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
684
			    sizeof(struct bgpd_config))
685
				fatalx("IMSG_RECONF_CONF bad len");
686
			reloadtime = time(NULL);
687
			out_rules_tmp = calloc(1, sizeof(struct filter_head));
688
			if (out_rules_tmp == NULL)
689
				fatal(NULL);
690
			TAILQ_INIT(out_rules_tmp);
691
			newdomains = calloc(1, sizeof(struct rdomain_head));
692
			if (newdomains == NULL)
693
				fatal(NULL);
694
			SIMPLEQ_INIT(newdomains);
695
			if ((nconf = malloc(sizeof(struct bgpd_config))) ==
696
			    NULL)
697
				fatal(NULL);
698
			memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
699
			for (rid = 0; rid < rib_size; rid++) {
700
				if (*ribs[rid].name == '\0')
701
					break;
702
				ribs[rid].state = RECONF_DELETE;
703
			}
704
			break;
705
		case IMSG_RECONF_RIB:
706
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
707
			    sizeof(struct rde_rib))
708
				fatalx("IMSG_RECONF_RIB bad len");
709
			memcpy(&rn, imsg.data, sizeof(rn));
710
			rid = rib_find(rn.name);
711
			if (rid == RIB_FAILED)
712
				rib_new(rn.name, rn.rtableid, rn.flags);
713
			else if (ribs[rid].rtableid != rn.rtableid ||
714
			    (ribs[rid].flags & F_RIB_HASNOFIB) !=
715
			    (rn.flags & F_RIB_HASNOFIB)) {
716
				struct filter_head	*in_rules;
717
				/*
718
				 * Big hammer in the F_RIB_HASNOFIB case but
719
				 * not often enough used to optimise it more.
720
				 * Need to save the filters so that they're not
721
				 * lost.
722
				 */
723
				in_rules = ribs[rid].in_rules;
724
				ribs[rid].in_rules = NULL;
725
				rib_free(&ribs[rid]);
726
				rib_new(rn.name, rn.rtableid, rn.flags);
727
				ribs[rid].in_rules = in_rules;
728
			} else
729
				ribs[rid].state = RECONF_KEEP;
730
			break;
731
		case IMSG_RECONF_FILTER:
732
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
733
			    sizeof(struct filter_rule))
734
				fatalx("IMSG_RECONF_FILTER bad len");
735
			if ((r = malloc(sizeof(struct filter_rule))) == NULL)
736
				fatal(NULL);
737
			memcpy(r, imsg.data, sizeof(struct filter_rule));
738
			TAILQ_INIT(&r->set);
739
			if ((r->peer.ribid = rib_find(r->rib)) == RIB_FAILED) {
740
				log_warnx("IMSG_RECONF_FILTER: filter rule "
741
				    "for nonexistent rib %s", r->rib);
742
				parent_set = NULL;
743
				free(r);
744
				break;
745
			}
746
			parent_set = &r->set;
747
			if (r->dir == DIR_IN) {
748
				nr = ribs[r->peer.ribid].in_rules_tmp;
749
				if (nr == NULL) {
750
					nr = calloc(1,
751
					    sizeof(struct filter_head));
752
					if (nr == NULL)
753
						fatal(NULL);
754
					TAILQ_INIT(nr);
755
					ribs[r->peer.ribid].in_rules_tmp = nr;
756
				}
757
				TAILQ_INSERT_TAIL(nr, r, entry);
758
			} else
759
				TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
760
			break;
761
		case IMSG_RECONF_RDOMAIN:
762
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
763
			    sizeof(struct rdomain))
764
				fatalx("IMSG_RECONF_RDOMAIN bad len");
765
			if ((rd = malloc(sizeof(struct rdomain))) == NULL)
766
				fatal(NULL);
767
			memcpy(rd, imsg.data, sizeof(struct rdomain));
768
			TAILQ_INIT(&rd->import);
769
			TAILQ_INIT(&rd->export);
770
			SIMPLEQ_INSERT_TAIL(newdomains, rd, entry);
771
			break;
772
		case IMSG_RECONF_RDOMAIN_EXPORT:
773
			if (rd == NULL) {
774
				log_warnx("rde_dispatch_imsg_parent: "
775
				    "IMSG_RECONF_RDOMAIN_EXPORT unexpected");
776
				break;
777
			}
778
			parent_set = &rd->export;
779
			break;
780
		case IMSG_RECONF_RDOMAIN_IMPORT:
781
			if (rd == NULL) {
782
				log_warnx("rde_dispatch_imsg_parent: "
783
				    "IMSG_RECONF_RDOMAIN_IMPORT unexpected");
784
				break;
785
			}
786
			parent_set = &rd->import;
787
			break;
788
		case IMSG_RECONF_RDOMAIN_DONE:
789
			parent_set = NULL;
790
			break;
791
		case IMSG_RECONF_DONE:
792
			if (nconf == NULL)
793
				fatalx("got IMSG_RECONF_DONE but no config");
794
			parent_set = NULL;
795
796
			rde_reload_done();
797
			break;
798
		case IMSG_NEXTHOP_UPDATE:
799
			nexthop_update(imsg.data);
800
			break;
801
		case IMSG_FILTER_SET:
802
			if (imsg.hdr.len > IMSG_HEADER_SIZE +
803
			    sizeof(struct filter_set))
804
				fatalx("IMSG_FILTER_SET bad len");
805
			if (parent_set == NULL) {
806
				log_warnx("rde_dispatch_imsg_parent: "
807
				    "IMSG_FILTER_SET unexpected");
808
				break;
809
			}
810
			if ((s = malloc(sizeof(struct filter_set))) == NULL)
811
				fatal(NULL);
812
			memcpy(s, imsg.data, sizeof(struct filter_set));
813
			TAILQ_INSERT_TAIL(parent_set, s, entry);
814
815
			if (s->type == ACTION_SET_NEXTHOP) {
816
				nh = nexthop_get(&s->action.nexthop);
817
				nh->refcnt++;
818
			}
819
			break;
820
		case IMSG_MRT_OPEN:
821
		case IMSG_MRT_REOPEN:
822
			if (imsg.hdr.len > IMSG_HEADER_SIZE +
823
			    sizeof(struct mrt)) {
824
				log_warnx("wrong imsg len");
825
				break;
826
			}
827
			memcpy(&xmrt, imsg.data, sizeof(xmrt));
828
			if ((fd = imsg.fd) == -1)
829
				log_warnx("expected to receive fd for mrt dump "
830
				    "but didn't receive any");
831
			else if (xmrt.type == MRT_TABLE_DUMP ||
832
			    xmrt.type == MRT_TABLE_DUMP_MP ||
833
			    xmrt.type == MRT_TABLE_DUMP_V2) {
834
				rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd);
835
			} else
836
				close(fd);
837
			break;
838
		case IMSG_MRT_CLOSE:
839
			/* ignore end message because a dump is atomic */
840
			break;
841
		default:
842
			break;
843
		}
844
		imsg_free(&imsg);
845
	}
846
}
847
848
/* handle routing updates from the session engine. */
849
int
850
rde_update_dispatch(struct imsg *imsg)
851
{
852
	struct bgpd_addr	 prefix;
853
	struct mpattr		 mpa;
854
	struct rde_peer		*peer;
855
	struct rde_aspath	*asp = NULL;
856
	u_char			*p, *mpp = NULL;
857
	int			 error = -1, pos = 0;
858
	u_int16_t		 afi, len, mplen;
859
	u_int16_t		 withdrawn_len;
860
	u_int16_t		 attrpath_len;
861
	u_int16_t		 nlri_len;
862
	u_int8_t		 aid, prefixlen, safi, subtype;
863
	u_int32_t		 fas;
864
865
	peer = peer_get(imsg->hdr.peerid);
866
	if (peer == NULL)	/* unknown peer, cannot happen */
867
		return (-1);
868
	if (peer->state != PEER_UP)
869
		return (-1);	/* peer is not yet up, cannot happen */
870
871
	p = imsg->data;
872
873
	if (imsg->hdr.len < IMSG_HEADER_SIZE + 2) {
874
		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
875
		return (-1);
876
	}
877
878
	memcpy(&len, p, 2);
879
	withdrawn_len = ntohs(len);
880
	p += 2;
881
	if (imsg->hdr.len < IMSG_HEADER_SIZE + 2 + withdrawn_len + 2) {
882
		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
883
		return (-1);
884
	}
885
886
	p += withdrawn_len;
887
	memcpy(&len, p, 2);
888
	attrpath_len = len = ntohs(len);
889
	p += 2;
890
	if (imsg->hdr.len <
891
	    IMSG_HEADER_SIZE + 2 + withdrawn_len + 2 + attrpath_len) {
892
		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
893
		return (-1);
894
	}
895
896
	nlri_len =
897
	    imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
898
	bzero(&mpa, sizeof(mpa));
899
900
	if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
901
		/* parse path attributes */
902
		asp = path_get();
903
		while (len > 0) {
904
			if ((pos = rde_attr_parse(p, len, peer, asp,
905
			    &mpa)) < 0)
906
				goto done;
907
			p += pos;
908
			len -= pos;
909
		}
910
911
		/* check for missing but necessary attributes */
912
		if ((subtype = rde_attr_missing(asp, peer->conf.ebgp,
913
		    nlri_len))) {
914
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
915
			    &subtype, sizeof(u_int8_t));
916
			goto done;
917
		}
918
919
		rde_as4byte_fixup(peer, asp);
920
921
		/* enforce remote AS if requested */
922
		if (asp->flags & F_ATTR_ASPATH &&
923
		    peer->conf.enforce_as == ENFORCE_AS_ON) {
924
			fas = aspath_neighbor(asp->aspath);
925
			if (peer->conf.remote_as != fas) {
926
			    log_peer_warnx(&peer->conf, "bad path, "
927
				"starting with %s, "
928
				"enforce neighbor-as enabled", log_as(fas));
929
			    rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
930
				    NULL, 0);
931
			    goto done;
932
			}
933
		}
934
935
		rde_reflector(peer, asp);
936
	}
937
938
	p = imsg->data;
939
	len = withdrawn_len;
940
	p += 2;
941
	/* withdraw prefix */
942
	while (len > 0) {
943
		if ((pos = rde_update_get_prefix(p, len, &prefix,
944
		    &prefixlen)) == -1) {
945
			/*
946
			 * the RFC does not mention what we should do in
947
			 * this case. Let's do the same as in the NLRI case.
948
			 */
949
			log_peer_warnx(&peer->conf, "bad withdraw prefix");
950
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
951
			    NULL, 0);
952
			goto done;
953
		}
954
		if (prefixlen > 32) {
955
			log_peer_warnx(&peer->conf, "bad withdraw prefix");
956
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
957
			    NULL, 0);
958
			goto done;
959
		}
960
961
		p += pos;
962
		len -= pos;
963
964
		if (peer->capa.mp[AID_INET] == 0) {
965
			log_peer_warnx(&peer->conf,
966
			    "bad withdraw, %s disabled", aid2str(AID_INET));
967
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
968
			    NULL, 0);
969
			goto done;
970
		}
971
972
		rde_update_withdraw(peer, &prefix, prefixlen);
973
	}
974
975
	if (attrpath_len == 0) {
976
		/* 0 = no NLRI information in this message */
977
		if (nlri_len != 0) {
978
			/* crap at end of update which should not be there */
979
			rde_update_err(peer, ERR_UPDATE,
980
			    ERR_UPD_ATTRLIST, NULL, 0);
981
			return (-1);
982
		}
983
		if (withdrawn_len == 0) {
984
			/* EoR marker */
985
			peer_recv_eor(peer, AID_INET);
986
		}
987
		return (0);
988
	}
989
990
	/* withdraw MP_UNREACH_NLRI if available */
991
	if (mpa.unreach_len != 0) {
992
		mpp = mpa.unreach;
993
		mplen = mpa.unreach_len;
994
		memcpy(&afi, mpp, 2);
995
		mpp += 2;
996
		mplen -= 2;
997
		afi = ntohs(afi);
998
		safi = *mpp++;
999
		mplen--;
1000
1001
		if (afi2aid(afi, safi, &aid) == -1) {
1002
			log_peer_warnx(&peer->conf,
1003
			    "bad AFI/SAFI pair in withdraw");
1004
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1005
			    NULL, 0);
1006
			goto done;
1007
		}
1008
1009
		if (peer->capa.mp[aid] == 0) {
1010
			log_peer_warnx(&peer->conf,
1011
			    "bad withdraw, %s disabled", aid2str(aid));
1012
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1013
			    NULL, 0);
1014
			goto done;
1015
		}
1016
1017
		if ((asp->flags & ~F_ATTR_MP_UNREACH) == 0 && mplen == 0) {
1018
			/* EoR marker */
1019
			peer_recv_eor(peer, aid);
1020
		}
1021
1022
		switch (aid) {
1023
		case AID_INET6:
1024
			while (mplen > 0) {
1025
				if ((pos = rde_update_get_prefix6(mpp, mplen,
1026
				    &prefix, &prefixlen)) == -1) {
1027
					log_peer_warnx(&peer->conf,
1028
					    "bad IPv6 withdraw prefix");
1029
					rde_update_err(peer, ERR_UPDATE,
1030
					    ERR_UPD_OPTATTR,
1031
					    mpa.unreach, mpa.unreach_len);
1032
					goto done;
1033
				}
1034
				if (prefixlen > 128) {
1035
					log_peer_warnx(&peer->conf,
1036
					    "bad IPv6 withdraw prefix");
1037
					rde_update_err(peer, ERR_UPDATE,
1038
					    ERR_UPD_OPTATTR,
1039
					    mpa.unreach, mpa.unreach_len);
1040
					goto done;
1041
				}
1042
1043
				mpp += pos;
1044
				mplen -= pos;
1045
1046
				rde_update_withdraw(peer, &prefix, prefixlen);
1047
			}
1048
			break;
1049
		case AID_VPN_IPv4:
1050
			while (mplen > 0) {
1051
				if ((pos = rde_update_get_vpn4(mpp, mplen,
1052
				    &prefix, &prefixlen)) == -1) {
1053
					log_peer_warnx(&peer->conf,
1054
					    "bad VPNv4 withdraw prefix");
1055
					rde_update_err(peer, ERR_UPDATE,
1056
					    ERR_UPD_OPTATTR,
1057
					    mpa.unreach, mpa.unreach_len);
1058
					goto done;
1059
				}
1060
				if (prefixlen > 32) {
1061
					log_peer_warnx(&peer->conf,
1062
					    "bad VPNv4 withdraw prefix");
1063
					rde_update_err(peer, ERR_UPDATE,
1064
					    ERR_UPD_OPTATTR,
1065
					    mpa.unreach, mpa.unreach_len);
1066
					goto done;
1067
				}
1068
1069
				mpp += pos;
1070
				mplen -= pos;
1071
1072
				rde_update_withdraw(peer, &prefix, prefixlen);
1073
			}
1074
			break;
1075
		default:
1076
			/* silently ignore unsupported multiprotocol AF */
1077
			break;
1078
		}
1079
1080
		if ((asp->flags & ~F_ATTR_MP_UNREACH) == 0) {
1081
			error = 0;
1082
			goto done;
1083
		}
1084
	}
1085
1086
	/* shift to NLRI information */
1087
	p += 2 + attrpath_len;
1088
1089
	/* aspath needs to be loop free nota bene this is not a hard error */
1090
	if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as))
1091
		asp->flags |= F_ATTR_LOOP;
1092
1093
	/* parse nlri prefix */
1094
	while (nlri_len > 0) {
1095
		if ((pos = rde_update_get_prefix(p, nlri_len, &prefix,
1096
		    &prefixlen)) == -1) {
1097
			log_peer_warnx(&peer->conf, "bad nlri prefix");
1098
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1099
			    NULL, 0);
1100
			goto done;
1101
		}
1102
		if (prefixlen > 32) {
1103
			log_peer_warnx(&peer->conf, "bad nlri prefix");
1104
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1105
			    NULL, 0);
1106
			goto done;
1107
		}
1108
1109
		p += pos;
1110
		nlri_len -= pos;
1111
1112
		if (peer->capa.mp[AID_INET] == 0) {
1113
			log_peer_warnx(&peer->conf,
1114
			    "bad update, %s disabled", aid2str(AID_INET));
1115
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1116
			    NULL, 0);
1117
			goto done;
1118
		}
1119
1120
		rde_update_update(peer, asp, &prefix, prefixlen);
1121
1122
		/* max prefix checker */
1123
		if (peer->conf.max_prefix &&
1124
		    peer->prefix_cnt >= peer->conf.max_prefix) {
1125
			log_peer_warnx(&peer->conf, "prefix limit reached"
1126
			    " (>%u/%u)", peer->prefix_cnt, peer->conf.max_prefix);
1127
			rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX,
1128
			    NULL, 0);
1129
			goto done;
1130
		}
1131
1132
	}
1133
1134
	/* add MP_REACH_NLRI if available */
1135
	if (mpa.reach_len != 0) {
1136
		mpp = mpa.reach;
1137
		mplen = mpa.reach_len;
1138
		memcpy(&afi, mpp, 2);
1139
		mpp += 2;
1140
		mplen -= 2;
1141
		afi = ntohs(afi);
1142
		safi = *mpp++;
1143
		mplen--;
1144
1145
		if (afi2aid(afi, safi, &aid) == -1) {
1146
			log_peer_warnx(&peer->conf,
1147
			    "bad AFI/SAFI pair in update");
1148
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1149
			    NULL, 0);
1150
			goto done;
1151
		}
1152
1153
		if (peer->capa.mp[aid] == 0) {
1154
			log_peer_warnx(&peer->conf,
1155
			    "bad update, %s disabled", aid2str(aid));
1156
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1157
			    NULL, 0);
1158
			goto done;
1159
		}
1160
1161
		/*
1162
		 * this works because asp is not linked.
1163
		 * But first unlock the previously locked nexthop.
1164
		 */
1165
		if (asp->nexthop) {
1166
			asp->nexthop->refcnt--;
1167
			(void)nexthop_delete(asp->nexthop);
1168
			asp->nexthop = NULL;
1169
		}
1170
		if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, asp)) == -1) {
1171
			log_peer_warnx(&peer->conf, "bad nlri prefix");
1172
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1173
			    mpa.reach, mpa.reach_len);
1174
			goto done;
1175
		}
1176
		mpp += pos;
1177
		mplen -= pos;
1178
1179
		switch (aid) {
1180
		case AID_INET6:
1181
			while (mplen > 0) {
1182
				if ((pos = rde_update_get_prefix6(mpp, mplen,
1183
				    &prefix, &prefixlen)) == -1) {
1184
					log_peer_warnx(&peer->conf,
1185
					    "bad IPv6 nlri prefix");
1186
					rde_update_err(peer, ERR_UPDATE,
1187
					    ERR_UPD_OPTATTR,
1188
					    mpa.reach, mpa.reach_len);
1189
					goto done;
1190
				}
1191
				if (prefixlen > 128) {
1192
					rde_update_err(peer, ERR_UPDATE,
1193
					    ERR_UPD_OPTATTR,
1194
					    mpa.reach, mpa.reach_len);
1195
					goto done;
1196
				}
1197
1198
				mpp += pos;
1199
				mplen -= pos;
1200
1201
				rde_update_update(peer, asp, &prefix,
1202
				    prefixlen);
1203
1204
				/* max prefix checker */
1205
				if (peer->conf.max_prefix &&
1206
				    peer->prefix_cnt >= peer->conf.max_prefix) {
1207
					log_peer_warnx(&peer->conf,
1208
					    "prefix limit reached"
1209
					    " (>%u/%u)", peer->prefix_cnt,
1210
					    peer->conf.max_prefix);
1211
					rde_update_err(peer, ERR_CEASE,
1212
					    ERR_CEASE_MAX_PREFIX, NULL, 0);
1213
					goto done;
1214
				}
1215
1216
			}
1217
			break;
1218
		case AID_VPN_IPv4:
1219
			while (mplen > 0) {
1220
				if ((pos = rde_update_get_vpn4(mpp, mplen,
1221
				    &prefix, &prefixlen)) == -1) {
1222
					log_peer_warnx(&peer->conf,
1223
					    "bad VPNv4 nlri prefix");
1224
					rde_update_err(peer, ERR_UPDATE,
1225
					    ERR_UPD_OPTATTR,
1226
					    mpa.reach, mpa.reach_len);
1227
					goto done;
1228
				}
1229
				if (prefixlen > 32) {
1230
					rde_update_err(peer, ERR_UPDATE,
1231
					    ERR_UPD_OPTATTR,
1232
					    mpa.reach, mpa.reach_len);
1233
					goto done;
1234
				}
1235
1236
				mpp += pos;
1237
				mplen -= pos;
1238
1239
				rde_update_update(peer, asp, &prefix,
1240
				    prefixlen);
1241
1242
				/* max prefix checker */
1243
				if (peer->conf.max_prefix &&
1244
				    peer->prefix_cnt >= peer->conf.max_prefix) {
1245
					log_peer_warnx(&peer->conf,
1246
					    "prefix limit reached"
1247
					    " (>%u/%u)", peer->prefix_cnt,
1248
					    peer->conf.max_prefix);
1249
					rde_update_err(peer, ERR_CEASE,
1250
					    ERR_CEASE_MAX_PREFIX, NULL, 0);
1251
					goto done;
1252
				}
1253
1254
			}
1255
			break;
1256
		default:
1257
			/* silently ignore unsupported multiprotocol AF */
1258
			break;
1259
		}
1260
	}
1261
1262
done:
1263
	if (attrpath_len != 0) {
1264
		/* unlock the previously locked entry */
1265
		if (asp->nexthop) {
1266
			asp->nexthop->refcnt--;
1267
			(void)nexthop_delete(asp->nexthop);
1268
		}
1269
		/* free allocated attribute memory that is no longer used */
1270
		path_put(asp);
1271
	}
1272
1273
	return (error);
1274
}
1275
1276
void
1277
rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
1278
    struct bgpd_addr *prefix, u_int8_t prefixlen)
1279
{
1280
	struct rde_aspath	*fasp;
1281
	enum filter_actions	 action;
1282
	int			 r = 0, f = 0;
1283
	u_int16_t		 i;
1284
1285
	peer->prefix_rcvd_update++;
1286
	/* add original path to the Adj-RIB-In */
1287
	if (peer->conf.softreconfig_in)
1288
		r += path_update(&ribs[0], peer, asp, prefix, prefixlen);
1289
1290
	for (i = 1; i < rib_size; i++) {
1291
		if (*ribs[i].name == '\0')
1292
			break;
1293
		/* input filter */
1294
		action = rde_filter(ribs[i].in_rules, &fasp, peer, asp, prefix,
1295
		    prefixlen, peer);
1296
1297
		if (fasp == NULL)
1298
			fasp = asp;
1299
1300
		if (action == ACTION_ALLOW) {
1301
			rde_update_log("update", i, peer,
1302
			    &fasp->nexthop->exit_nexthop, prefix, prefixlen);
1303
			r += path_update(&ribs[i], peer, fasp, prefix,
1304
			    prefixlen);
1305
		} else if (prefix_remove(&ribs[i], peer, prefix, prefixlen,
1306
		    0)) {
1307
			rde_update_log("filtered withdraw", i, peer,
1308
			    NULL, prefix, prefixlen);
1309
			f++;
1310
		}
1311
1312
		/* free modified aspath */
1313
		if (fasp != asp)
1314
			path_put(fasp);
1315
	}
1316
1317
	if (r)
1318
		peer->prefix_cnt++;
1319
	else if (f)
1320
		peer->prefix_cnt--;
1321
}
1322
1323
void
1324
rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
1325
    u_int8_t prefixlen)
1326
{
1327
	int r = 0;
1328
	u_int16_t i;
1329
1330
	peer->prefix_rcvd_withdraw++;
1331
1332
	for (i = rib_size - 1; ; i--) {
1333
		if (*ribs[i].name == '\0')
1334
			break;
1335
		if (prefix_remove(&ribs[i], peer, prefix, prefixlen, 0)) {
1336
			rde_update_log("withdraw", i, peer, NULL, prefix,
1337
			    prefixlen);
1338
			r++;
1339
		}
1340
		if (i == 0)
1341
			break;
1342
	}
1343
1344
	if (r)
1345
		peer->prefix_cnt--;
1346
}
1347
1348
/*
1349
 * BGP UPDATE parser functions
1350
 */
1351
1352
/* attribute parser specific makros */
1353
#define UPD_READ(t, p, plen, n) \
1354
	do { \
1355
		memcpy(t, p, n); \
1356
		p += n; \
1357
		plen += n; \
1358
	} while (0)
1359
1360
#define CHECK_FLAGS(s, t, m)	\
1361
	(((s) & ~(ATTR_DEFMASK | (m))) == (t))
1362
1363
int
1364
rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
1365
    struct rde_aspath *a, struct mpattr *mpa)
1366
{
1367
	struct bgpd_addr nexthop;
1368
	u_char		*op = p, *npath;
1369
	u_int32_t	 tmp32;
1370
	int		 error;
1371
	u_int16_t	 attr_len, nlen;
1372
	u_int16_t	 plen = 0;
1373
	u_int8_t	 flags;
1374
	u_int8_t	 type;
1375
	u_int8_t	 tmp8;
1376
1377
	if (len < 3) {
1378
bad_len:
1379
		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLEN, op, len);
1380
		return (-1);
1381
	}
1382
1383
	UPD_READ(&flags, p, plen, 1);
1384
	UPD_READ(&type, p, plen, 1);
1385
1386
	if (flags & ATTR_EXTLEN) {
1387
		if (len - plen < 2)
1388
			goto bad_len;
1389
		UPD_READ(&attr_len, p, plen, 2);
1390
		attr_len = ntohs(attr_len);
1391
	} else {
1392
		UPD_READ(&tmp8, p, plen, 1);
1393
		attr_len = tmp8;
1394
	}
1395
1396
	if (len - plen < attr_len)
1397
		goto bad_len;
1398
1399
	/* adjust len to the actual attribute size including header */
1400
	len = plen + attr_len;
1401
1402
	switch (type) {
1403
	case ATTR_UNDEF:
1404
		/* ignore and drop path attributes with a type code of 0 */
1405
		plen += attr_len;
1406
		break;
1407
	case ATTR_ORIGIN:
1408
		if (attr_len != 1)
1409
			goto bad_len;
1410
1411
		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
1412
bad_flags:
1413
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRFLAGS,
1414
			    op, len);
1415
			return (-1);
1416
		}
1417
1418
		UPD_READ(&a->origin, p, plen, 1);
1419
		if (a->origin > ORIGIN_INCOMPLETE) {
1420
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ORIGIN,
1421
			    op, len);
1422
			return (-1);
1423
		}
1424
		if (a->flags & F_ATTR_ORIGIN)
1425
			goto bad_list;
1426
		a->flags |= F_ATTR_ORIGIN;
1427
		break;
1428
	case ATTR_ASPATH:
1429
		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
1430
			goto bad_flags;
1431
		error = aspath_verify(p, attr_len, rde_as4byte(peer));
1432
		if (error == AS_ERR_SOFT) {
1433
			/*
1434
			 * soft errors like unexpected segment types are
1435
			 * not considered fatal and the path is just
1436
			 * marked invalid.
1437
			 */
1438
			a->flags |= F_ATTR_PARSE_ERR;
1439
			log_peer_warnx(&peer->conf, "bad ASPATH, "
1440
			    "path invalidated and prefix withdrawn");
1441
		} else if (error != 0) {
1442
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
1443
			    NULL, 0);
1444
			return (-1);
1445
		}
1446
		if (a->flags & F_ATTR_ASPATH)
1447
			goto bad_list;
1448
		if (rde_as4byte(peer)) {
1449
			npath = p;
1450
			nlen = attr_len;
1451
		} else
1452
			npath = aspath_inflate(p, attr_len, &nlen);
1453
		a->flags |= F_ATTR_ASPATH;
1454
		a->aspath = aspath_get(npath, nlen);
1455
		if (npath != p)
1456
			free(npath);
1457
		plen += attr_len;
1458
		break;
1459
	case ATTR_NEXTHOP:
1460
		if (attr_len != 4)
1461
			goto bad_len;
1462
		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
1463
			goto bad_flags;
1464
		if (a->flags & F_ATTR_NEXTHOP)
1465
			goto bad_list;
1466
		a->flags |= F_ATTR_NEXTHOP;
1467
1468
		bzero(&nexthop, sizeof(nexthop));
1469
		nexthop.aid = AID_INET;
1470
		UPD_READ(&nexthop.v4.s_addr, p, plen, 4);
1471
		/*
1472
		 * Check if the nexthop is a valid IP address. We consider
1473
		 * multicast and experimental addresses as invalid.
1474
		 */
1475
		tmp32 = ntohl(nexthop.v4.s_addr);
1476
		if (IN_MULTICAST(tmp32) || IN_BADCLASS(tmp32)) {
1477
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1478
			    op, len);
1479
			return (-1);
1480
		}
1481
		a->nexthop = nexthop_get(&nexthop);
1482
		/*
1483
		 * lock the nexthop because it is not yet linked else
1484
		 * withdraws may remove this nexthop which in turn would
1485
		 * cause a use after free error.
1486
		 */
1487
		a->nexthop->refcnt++;
1488
		break;
1489
	case ATTR_MED:
1490
		if (attr_len != 4)
1491
			goto bad_len;
1492
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
1493
			goto bad_flags;
1494
		if (a->flags & F_ATTR_MED)
1495
			goto bad_list;
1496
		a->flags |= F_ATTR_MED;
1497
1498
		UPD_READ(&tmp32, p, plen, 4);
1499
		a->med = ntohl(tmp32);
1500
		break;
1501
	case ATTR_LOCALPREF:
1502
		if (attr_len != 4)
1503
			goto bad_len;
1504
		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
1505
			goto bad_flags;
1506
		if (peer->conf.ebgp) {
1507
			/* ignore local-pref attr on non ibgp peers */
1508
			plen += 4;
1509
			break;
1510
		}
1511
		if (a->flags & F_ATTR_LOCALPREF)
1512
			goto bad_list;
1513
		a->flags |= F_ATTR_LOCALPREF;
1514
1515
		UPD_READ(&tmp32, p, plen, 4);
1516
		a->lpref = ntohl(tmp32);
1517
		break;
1518
	case ATTR_ATOMIC_AGGREGATE:
1519
		if (attr_len != 0)
1520
			goto bad_len;
1521
		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
1522
			goto bad_flags;
1523
		goto optattr;
1524
	case ATTR_AGGREGATOR:
1525
		if ((!rde_as4byte(peer) && attr_len != 6) ||
1526
		    (rde_as4byte(peer) && attr_len != 8)) {
1527
			/*
1528
			 * ignore attribute in case of error as per
1529
			 * draft-ietf-idr-optional-transitive-00.txt
1530
			 * but only if partial bit is set
1531
			 */
1532
			if ((flags & ATTR_PARTIAL) == 0)
1533
				goto bad_len;
1534
			log_peer_warnx(&peer->conf, "bad AGGREGATOR, "
1535
			    "partial attribute ignored");
1536
			plen += attr_len;
1537
			break;
1538
		}
1539
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
1540
		    ATTR_PARTIAL))
1541
			goto bad_flags;
1542
		if (!rde_as4byte(peer)) {
1543
			/* need to inflate aggregator AS to 4-byte */
1544
			u_char	t[8];
1545
			t[0] = t[1] = 0;
1546
			UPD_READ(&t[2], p, plen, 2);
1547
			UPD_READ(&t[4], p, plen, 4);
1548
			if (attr_optadd(a, flags, type, t,
1549
			    sizeof(t)) == -1)
1550
				goto bad_list;
1551
			break;
1552
		}
1553
		/* 4-byte ready server take the default route */
1554
		goto optattr;
1555
	case ATTR_COMMUNITIES:
1556
		if (attr_len % 4 != 0) {
1557
			/*
1558
			 * mark update as bad and withdraw all routes as per
1559
			 * draft-ietf-idr-optional-transitive-00.txt
1560
			 * but only if partial bit is set
1561
			 */
1562
			if ((flags & ATTR_PARTIAL) == 0)
1563
				goto bad_len;
1564
			a->flags |= F_ATTR_PARSE_ERR;
1565
			log_peer_warnx(&peer->conf, "bad COMMUNITIES, "
1566
			    "path invalidated and prefix withdrawn");
1567
		}
1568
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
1569
		    ATTR_PARTIAL))
1570
			goto bad_flags;
1571
		goto optattr;
1572
	case ATTR_EXT_COMMUNITIES:
1573
		if (attr_len % 8 != 0) {
1574
			/*
1575
			 * mark update as bad and withdraw all routes as per
1576
			 * draft-ietf-idr-optional-transitive-00.txt
1577
			 * but only if partial bit is set
1578
			 */
1579
			if ((flags & ATTR_PARTIAL) == 0)
1580
				goto bad_len;
1581
			a->flags |= F_ATTR_PARSE_ERR;
1582
			log_peer_warnx(&peer->conf, "bad EXT_COMMUNITIES, "
1583
			    "path invalidated and prefix withdrawn");
1584
		}
1585
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
1586
		    ATTR_PARTIAL))
1587
			goto bad_flags;
1588
		goto optattr;
1589
	case ATTR_ORIGINATOR_ID:
1590
		if (attr_len != 4)
1591
			goto bad_len;
1592
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
1593
			goto bad_flags;
1594
		goto optattr;
1595
	case ATTR_CLUSTER_LIST:
1596
		if (attr_len % 4 != 0)
1597
			goto bad_len;
1598
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
1599
			goto bad_flags;
1600
		goto optattr;
1601
	case ATTR_MP_REACH_NLRI:
1602
		if (attr_len < 4)
1603
			goto bad_len;
1604
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
1605
			goto bad_flags;
1606
		/* the validity is checked in rde_update_dispatch() */
1607
		if (a->flags & F_ATTR_MP_REACH)
1608
			goto bad_list;
1609
		a->flags |= F_ATTR_MP_REACH;
1610
1611
		mpa->reach = p;
1612
		mpa->reach_len = attr_len;
1613
		plen += attr_len;
1614
		break;
1615
	case ATTR_MP_UNREACH_NLRI:
1616
		if (attr_len < 3)
1617
			goto bad_len;
1618
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
1619
			goto bad_flags;
1620
		/* the validity is checked in rde_update_dispatch() */
1621
		if (a->flags & F_ATTR_MP_UNREACH)
1622
			goto bad_list;
1623
		a->flags |= F_ATTR_MP_UNREACH;
1624
1625
		mpa->unreach = p;
1626
		mpa->unreach_len = attr_len;
1627
		plen += attr_len;
1628
		break;
1629
	case ATTR_AS4_AGGREGATOR:
1630
		if (attr_len != 8) {
1631
			/* see ATTR_AGGREGATOR ... */
1632
			if ((flags & ATTR_PARTIAL) == 0)
1633
				goto bad_len;
1634
			log_peer_warnx(&peer->conf, "bad AS4_AGGREGATOR, "
1635
			    "partial attribute ignored");
1636
			plen += attr_len;
1637
			break;
1638
		}
1639
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
1640
		    ATTR_PARTIAL))
1641
			goto bad_flags;
1642
		a->flags |= F_ATTR_AS4BYTE_NEW;
1643
		goto optattr;
1644
	case ATTR_AS4_PATH:
1645
		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
1646
		    ATTR_PARTIAL))
1647
			goto bad_flags;
1648
		if ((error = aspath_verify(p, attr_len, 1)) != 0) {
1649
			/*
1650
			 * XXX RFC does not specify how to handle errors.
1651
			 * XXX Instead of dropping the session because of a
1652
			 * XXX bad path just mark the full update as having
1653
			 * XXX a parse error which makes the update no longer
1654
			 * XXX eligible and will not be considered for routing
1655
			 * XXX or redistribution.
1656
			 * XXX We follow draft-ietf-idr-optional-transitive
1657
			 * XXX by looking at the partial bit.
1658
			 * XXX Consider soft errors similar to a partial attr.
1659
			 */
1660
			if (flags & ATTR_PARTIAL || error == AS_ERR_SOFT) {
1661
				a->flags |= F_ATTR_PARSE_ERR;
1662
				log_peer_warnx(&peer->conf, "bad AS4_PATH, "
1663
				    "path invalidated and prefix withdrawn");
1664
				goto optattr;
1665
			} else {
1666
				rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
1667
				    NULL, 0);
1668
				return (-1);
1669
			}
1670
		}
1671
		a->flags |= F_ATTR_AS4BYTE_NEW;
1672
		goto optattr;
1673
	default:
1674
		if ((flags & ATTR_OPTIONAL) == 0) {
1675
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNKNWN_WK_ATTR,
1676
			    op, len);
1677
			return (-1);
1678
		}
1679
optattr:
1680
		if (attr_optadd(a, flags, type, p, attr_len) == -1) {
1681
bad_list:
1682
			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST,
1683
			    NULL, 0);
1684
			return (-1);
1685
		}
1686
1687
		plen += attr_len;
1688
		break;
1689
	}
1690
1691
	return (plen);
1692
}
1693
1694
int
1695
rde_attr_add(struct rde_aspath *a, u_char *p, u_int16_t len)
1696
{
1697
	u_int16_t	 attr_len;
1698
	u_int16_t	 plen = 0;
1699
	u_int8_t	 flags;
1700
	u_int8_t	 type;
1701
	u_int8_t	 tmp8;
1702
1703
	if (a == NULL)		/* no aspath, nothing to do */
1704
		return (0);
1705
	if (len < 3)
1706
		return (-1);
1707
1708
	UPD_READ(&flags, p, plen, 1);
1709
	UPD_READ(&type, p, plen, 1);
1710
1711
	if (flags & ATTR_EXTLEN) {
1712
		if (len - plen < 2)
1713
			return (-1);
1714
		UPD_READ(&attr_len, p, plen, 2);
1715
		attr_len = ntohs(attr_len);
1716
	} else {
1717
		UPD_READ(&tmp8, p, plen, 1);
1718
		attr_len = tmp8;
1719
	}
1720
1721
	if (len - plen < attr_len)
1722
		return (-1);
1723
1724
	if (attr_optadd(a, flags, type, p, attr_len) == -1)
1725
		return (-1);
1726
	return (0);
1727
}
1728
1729
#undef UPD_READ
1730
#undef CHECK_FLAGS
1731
1732
u_int8_t
1733
rde_attr_missing(struct rde_aspath *a, int ebgp, u_int16_t nlrilen)
1734
{
1735
	/* ATTR_MP_UNREACH_NLRI may be sent alone */
1736
	if (nlrilen == 0 && a->flags & F_ATTR_MP_UNREACH &&
1737
	    (a->flags & F_ATTR_MP_REACH) == 0)
1738
		return (0);
1739
1740
	if ((a->flags & F_ATTR_ORIGIN) == 0)
1741
		return (ATTR_ORIGIN);
1742
	if ((a->flags & F_ATTR_ASPATH) == 0)
1743
		return (ATTR_ASPATH);
1744
	if ((a->flags & F_ATTR_MP_REACH) == 0 &&
1745
	    (a->flags & F_ATTR_NEXTHOP) == 0)
1746
		return (ATTR_NEXTHOP);
1747
	if (!ebgp)
1748
		if ((a->flags & F_ATTR_LOCALPREF) == 0)
1749
			return (ATTR_LOCALPREF);
1750
	return (0);
1751
}
1752
1753
int
1754
rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int8_t aid,
1755
    struct rde_aspath *asp)
1756
{
1757
	struct bgpd_addr	nexthop;
1758
	u_int8_t		totlen, nhlen;
1759
1760
	if (len == 0)
1761
		return (-1);
1762
1763
	nhlen = *data++;
1764
	totlen = 1;
1765
	len--;
1766
1767
	if (nhlen > len)
1768
		return (-1);
1769
1770
	bzero(&nexthop, sizeof(nexthop));
1771
	nexthop.aid = aid;
1772
	switch (aid) {
1773
	case AID_INET6:
1774
		/*
1775
		 * RFC2545 describes that there may be a link-local
1776
		 * address carried in nexthop. Yikes!
1777
		 * This is not only silly, it is wrong and we just ignore
1778
		 * this link-local nexthop. The bgpd session doesn't run
1779
		 * over the link-local address so why should all other
1780
		 * traffic.
1781
		 */
1782
		if (nhlen != 16 && nhlen != 32) {
1783
			log_warnx("bad multiprotocol nexthop, bad size");
1784
			return (-1);
1785
		}
1786
		memcpy(&nexthop.v6.s6_addr, data, 16);
1787
		break;
1788
	case AID_VPN_IPv4:
1789
		/*
1790
		 * Neither RFC4364 nor RFC3107 specify the format of the
1791
		 * nexthop in an explicit way. The quality of RFC went down
1792
		 * the toilet the larger the number got.
1793
		 * RFC4364 is very confusing about VPN-IPv4 address and the
1794
		 * VPN-IPv4 prefix that carries also a MPLS label.
1795
		 * So the nexthop is a 12-byte address with a 64bit RD and
1796
		 * an IPv4 address following. In the nexthop case the RD can
1797
		 * be ignored.
1798
		 * Since the nexthop has to be in the main IPv4 table just
1799
		 * create an AID_INET nexthop. So we don't need to handle
1800
		 * AID_VPN_IPv4 in nexthop and kroute.
1801
		 */
1802
		if (nhlen != 12) {
1803
			log_warnx("bad multiprotocol nexthop, bad size");
1804
			return (-1);
1805
		}
1806
		data += sizeof(u_int64_t);
1807
		nexthop.aid = AID_INET;
1808
		memcpy(&nexthop.v4, data, sizeof(nexthop.v4));
1809
		break;
1810
	default:
1811
		log_warnx("bad multiprotocol nexthop, bad AID");
1812
		return (-1);
1813
	}
1814
1815
	asp->nexthop = nexthop_get(&nexthop);
1816
	/*
1817
	 * lock the nexthop because it is not yet linked else
1818
	 * withdraws may remove this nexthop which in turn would
1819
	 * cause a use after free error.
1820
	 */
1821
	asp->nexthop->refcnt++;
1822
1823
	/* ignore reserved (old SNPA) field as per RFC4760 */
1824
	totlen += nhlen + 1;
1825
	data += nhlen + 1;
1826
1827
	return (totlen);
1828
}
1829
1830
int
1831
rde_update_extract_prefix(u_char *p, u_int16_t len, void *va,
1832
    u_int8_t pfxlen, u_int8_t max)
1833
{
1834
	static u_char addrmask[] = {
1835
	    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
1836
	u_char		*a = va;
1837
	int		 i;
1838
	u_int16_t	 plen = 0;
1839
1840
	for (i = 0; pfxlen && i < max; i++) {
1841
		if (len <= plen)
1842
			return (-1);
1843
		if (pfxlen < 8) {
1844
			a[i] = *p++ & addrmask[pfxlen];
1845
			plen++;
1846
			break;
1847
		} else {
1848
			a[i] = *p++;
1849
			plen++;
1850
			pfxlen -= 8;
1851
		}
1852
	}
1853
	return (plen);
1854
}
1855
1856
int
1857
rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
1858
    u_int8_t *prefixlen)
1859
{
1860
	u_int8_t	 pfxlen;
1861
	int		 plen;
1862
1863
	if (len < 1)
1864
		return (-1);
1865
1866
	pfxlen = *p++;
1867
	len--;
1868
1869
	bzero(prefix, sizeof(struct bgpd_addr));
1870
	prefix->aid = AID_INET;
1871
	*prefixlen = pfxlen;
1872
1873
	if ((plen = rde_update_extract_prefix(p, len, &prefix->v4, pfxlen,
1874
	    sizeof(prefix->v4))) == -1)
1875
		return (-1);
1876
1877
	return (plen + 1);	/* pfxlen needs to be added */
1878
}
1879
1880
int
1881
rde_update_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
1882
    u_int8_t *prefixlen)
1883
{
1884
	int		plen;
1885
	u_int8_t	pfxlen;
1886
1887
	if (len < 1)
1888
		return (-1);
1889
1890
	pfxlen = *p++;
1891
	len--;
1892
1893
	bzero(prefix, sizeof(struct bgpd_addr));
1894
	prefix->aid = AID_INET6;
1895
	*prefixlen = pfxlen;
1896
1897
	if ((plen = rde_update_extract_prefix(p, len, &prefix->v6, pfxlen,
1898
	    sizeof(prefix->v6))) == -1)
1899
		return (-1);
1900
1901
	return (plen + 1);	/* pfxlen needs to be added */
1902
}
1903
1904
int
1905
rde_update_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
1906
    u_int8_t *prefixlen)
1907
{
1908
	int		 rv, done = 0;
1909
	u_int8_t	 pfxlen;
1910
	u_int16_t	 plen;
1911
1912
	if (len < 1)
1913
		return (-1);
1914
1915
	memcpy(&pfxlen, p, 1);
1916
	p += 1;
1917
	plen = 1;
1918
1919
	bzero(prefix, sizeof(struct bgpd_addr));
1920
1921
	/* label stack */
1922
	do {
1923
		if (len - plen < 3 || pfxlen < 3 * 8)
1924
			return (-1);
1925
		if (prefix->vpn4.labellen + 3U >
1926
		    sizeof(prefix->vpn4.labelstack))
1927
			return (-1);
1928
		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
1929
		prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
1930
		prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++;
1931
		if (prefix->vpn4.labelstack[prefix->vpn4.labellen] &
1932
		    BGP_MPLS_BOS)
1933
			done = 1;
1934
		prefix->vpn4.labellen++;
1935
		plen += 3;
1936
		pfxlen -= 3 * 8;
1937
	} while (!done);
1938
1939
	/* RD */
1940
	if (len - plen < (int)sizeof(u_int64_t) ||
1941
	    pfxlen < sizeof(u_int64_t) * 8)
1942
		return (-1);
1943
	memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t));
1944
	pfxlen -= sizeof(u_int64_t) * 8;
1945
	p += sizeof(u_int64_t);
1946
	plen += sizeof(u_int64_t);
1947
1948
	/* prefix */
1949
	prefix->aid = AID_VPN_IPv4;
1950
	*prefixlen = pfxlen;
1951
1952
	if ((rv = rde_update_extract_prefix(p, len, &prefix->vpn4.addr,
1953
	    pfxlen, sizeof(prefix->vpn4.addr))) == -1)
1954
		return (-1);
1955
1956
	return (plen + rv);
1957
}
1958
1959
void
1960
rde_update_err(struct rde_peer *peer, u_int8_t error, u_int8_t suberr,
1961
    void *data, u_int16_t size)
1962
{
1963
	struct ibuf	*wbuf;
1964
1965
	if ((wbuf = imsg_create(ibuf_se, IMSG_UPDATE_ERR, peer->conf.id, 0,
1966
	    size + sizeof(error) + sizeof(suberr))) == NULL)
1967
		fatal("%s %d imsg_create error", __func__, __LINE__);
1968
	if (imsg_add(wbuf, &error, sizeof(error)) == -1 ||
1969
	    imsg_add(wbuf, &suberr, sizeof(suberr)) == -1 ||
1970
	    imsg_add(wbuf, data, size) == -1)
1971
		fatal("%s %d imsg_add error", __func__, __LINE__);
1972
	imsg_close(ibuf_se, wbuf);
1973
	peer->state = PEER_ERR;
1974
}
1975
1976
void
1977
rde_update_log(const char *message, u_int16_t rid,
1978
    const struct rde_peer *peer, const struct bgpd_addr *next,
1979
    const struct bgpd_addr *prefix, u_int8_t prefixlen)
1980
{
1981
	char		*l = NULL;
1982
	char		*n = NULL;
1983
	char		*p = NULL;
1984
1985
	if ( !((conf->log & BGPD_LOG_UPDATES) ||
1986
	       (peer->conf.flags & PEERFLAG_LOG_UPDATES)) )
1987
		return;
1988
1989
	if (next != NULL)
1990
		if (asprintf(&n, " via %s", log_addr(next)) == -1)
1991
			n = NULL;
1992
	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
1993
		p = NULL;
1994
	l = log_fmt_peer(&peer->conf);
1995
	log_info("Rib %s: %s AS%s: %s %s%s", ribs[rid].name,
1996
	    l, log_as(peer->conf.remote_as), message,
1997
	    p ? p : "out of memory", n ? n : "");
1998
1999
	free(l);
2000
	free(n);
2001
	free(p);
2002
}
2003
2004
/*
2005
 * 4-Byte ASN helper function.
2006
 * Two scenarios need to be considered:
2007
 * - NEW session with NEW attributes present -> just remove the attributes
2008
 * - OLD session with NEW attributes present -> try to merge them
2009
 */
2010
void
2011
rde_as4byte_fixup(struct rde_peer *peer, struct rde_aspath *a)
2012
{
2013
	struct attr	*nasp, *naggr, *oaggr;
2014
	u_int32_t	 as;
2015
2016
	/*
2017
	 * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present
2018
	 * try to fixup the attributes.
2019
	 * Do not fixup if F_ATTR_PARSE_ERR is set.
2020
	 */
2021
	if (!(a->flags & F_ATTR_AS4BYTE_NEW) || a->flags & F_ATTR_PARSE_ERR)
2022
		return;
2023
2024
	/* first get the attributes */
2025
	nasp = attr_optget(a, ATTR_AS4_PATH);
2026
	naggr = attr_optget(a, ATTR_AS4_AGGREGATOR);
2027
2028
	if (rde_as4byte(peer)) {
2029
		/* NEW session using 4-byte ASNs */
2030
		if (nasp) {
2031
			log_peer_warnx(&peer->conf, "uses 4-byte ASN "
2032
			    "but sent AS4_PATH attribute.");
2033
			attr_free(a, nasp);
2034
		}
2035
		if (naggr) {
2036
			log_peer_warnx(&peer->conf, "uses 4-byte ASN "
2037
			    "but sent AS4_AGGREGATOR attribute.");
2038
			attr_free(a, naggr);
2039
		}
2040
		return;
2041
	}
2042
	/* OLD session using 2-byte ASNs */
2043
	/* try to merge the new attributes into the old ones */
2044
	if ((oaggr = attr_optget(a, ATTR_AGGREGATOR))) {
2045
		memcpy(&as, oaggr->data, sizeof(as));
2046
		if (ntohl(as) != AS_TRANS) {
2047
			/* per RFC ignore AS4_PATH and AS4_AGGREGATOR */
2048
			if (nasp)
2049
				attr_free(a, nasp);
2050
			if (naggr)
2051
				attr_free(a, naggr);
2052
			return;
2053
		}
2054
		if (naggr) {
2055
			/* switch over to new AGGREGATOR */
2056
			attr_free(a, oaggr);
2057
			if (attr_optadd(a, ATTR_OPTIONAL | ATTR_TRANSITIVE,
2058
			    ATTR_AGGREGATOR, naggr->data, naggr->len))
2059
				fatalx("attr_optadd failed but impossible");
2060
		}
2061
	}
2062
	/* there is no need for AS4_AGGREGATOR any more */
2063
	if (naggr)
2064
		attr_free(a, naggr);
2065
2066
	/* merge AS4_PATH with ASPATH */
2067
	if (nasp)
2068
		aspath_merge(a, nasp);
2069
}
2070
2071
2072
/*
2073
 * route reflector helper function
2074
 */
2075
void
2076
rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
2077
{
2078
	struct attr	*a;
2079
	u_int8_t	*p;
2080
	u_int16_t	 len;
2081
	u_int32_t	 id;
2082
2083
	/* do not consider updates with parse errors */
2084
	if (asp->flags & F_ATTR_PARSE_ERR)
2085
		return;
2086
2087
	/* check for originator id if eq router_id drop */
2088
	if ((a = attr_optget(asp, ATTR_ORIGINATOR_ID)) != NULL) {
2089
		if (memcmp(&conf->bgpid, a->data, sizeof(conf->bgpid)) == 0) {
2090
			/* this is coming from myself */
2091
			asp->flags |= F_ATTR_LOOP;
2092
			return;
2093
		}
2094
	} else if (conf->flags & BGPD_FLAG_REFLECTOR) {
2095
		if (peer->conf.ebgp)
2096
			id = conf->bgpid;
2097
		else
2098
			id = htonl(peer->remote_bgpid);
2099
		if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
2100
		    &id, sizeof(u_int32_t)) == -1)
2101
			fatalx("attr_optadd failed but impossible");
2102
	}
2103
2104
	/* check for own id in the cluster list */
2105
	if (conf->flags & BGPD_FLAG_REFLECTOR) {
2106
		if ((a = attr_optget(asp, ATTR_CLUSTER_LIST)) != NULL) {
2107
			for (len = 0; len < a->len;
2108
			    len += sizeof(conf->clusterid))
2109
				/* check if coming from my cluster */
2110
				if (memcmp(&conf->clusterid, a->data + len,
2111
				    sizeof(conf->clusterid)) == 0) {
2112
					asp->flags |= F_ATTR_LOOP;
2113
					return;
2114
				}
2115
2116
			/* prepend own clusterid by replacing attribute */
2117
			len = a->len + sizeof(conf->clusterid);
2118
			if (len < a->len)
2119
				fatalx("rde_reflector: cluster-list overflow");
2120
			if ((p = malloc(len)) == NULL)
2121
				fatal("rde_reflector");
2122
			memcpy(p, &conf->clusterid, sizeof(conf->clusterid));
2123
			memcpy(p + sizeof(conf->clusterid), a->data, a->len);
2124
			attr_free(asp, a);
2125
			if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
2126
			    p, len) == -1)
2127
				fatalx("attr_optadd failed but impossible");
2128
			free(p);
2129
		} else if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
2130
		    &conf->clusterid, sizeof(conf->clusterid)) == -1)
2131
			fatalx("attr_optadd failed but impossible");
2132
	}
2133
}
2134
2135
/*
2136
 * control specific functions
2137
 */
2138
void
2139
rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
2140
{
2141
	struct ctl_show_rib	 rib;
2142
	struct ibuf		*wbuf;
2143
	struct attr		*a;
2144
	void			*bp;
2145
	time_t			 staletime;
2146
	u_int8_t		 l;
2147
2148
	bzero(&rib, sizeof(rib));
2149
	rib.lastchange = p->lastchange;
2150
	rib.local_pref = asp->lpref;
2151
	rib.med = asp->med;
2152
	rib.weight = asp->weight;
2153
	strlcpy(rib.descr, asp->peer->conf.descr, sizeof(rib.descr));
2154
	memcpy(&rib.remote_addr, &asp->peer->remote_addr,
2155
	    sizeof(rib.remote_addr));
2156
	rib.remote_id = asp->peer->remote_bgpid;
2157
	if (asp->nexthop != NULL) {
2158
		memcpy(&rib.true_nexthop, &asp->nexthop->true_nexthop,
2159
		    sizeof(rib.true_nexthop));
2160
		memcpy(&rib.exit_nexthop, &asp->nexthop->exit_nexthop,
2161
		    sizeof(rib.exit_nexthop));
2162
	} else {
2163
		/* announced network may have a NULL nexthop */
2164
		bzero(&rib.true_nexthop, sizeof(rib.true_nexthop));
2165
		bzero(&rib.exit_nexthop, sizeof(rib.exit_nexthop));
2166
		rib.true_nexthop.aid = p->prefix->aid;
2167
		rib.exit_nexthop.aid = p->prefix->aid;
2168
	}
2169
	pt_getaddr(p->prefix, &rib.prefix);
2170
	rib.prefixlen = p->prefix->prefixlen;
2171
	rib.origin = asp->origin;
2172
	rib.flags = 0;
2173
	if (p->rib->active == p)
2174
		rib.flags |= F_PREF_ACTIVE;
2175
	if (!asp->peer->conf.ebgp)
2176
		rib.flags |= F_PREF_INTERNAL;
2177
	if (asp->flags & F_PREFIX_ANNOUNCED)
2178
		rib.flags |= F_PREF_ANNOUNCE;
2179
	if (asp->nexthop == NULL || asp->nexthop->state == NEXTHOP_REACH)
2180
		rib.flags |= F_PREF_ELIGIBLE;
2181
	if (asp->flags & F_ATTR_LOOP)
2182
		rib.flags &= ~F_PREF_ELIGIBLE;
2183
	staletime = asp->peer->staletime[p->prefix->aid];
2184
	if (staletime && p->lastchange <= staletime)
2185
		rib.flags |= F_PREF_STALE;
2186
	rib.aspath_len = aspath_length(asp->aspath);
2187
2188
	if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
2189
	    sizeof(rib) + rib.aspath_len)) == NULL)
2190
		return;
2191
	if (imsg_add(wbuf, &rib, sizeof(rib)) == -1 ||
2192
	    imsg_add(wbuf, aspath_dump(asp->aspath),
2193
	    rib.aspath_len) == -1)
2194
		return;
2195
	imsg_close(ibuf_se_ctl, wbuf);
2196
2197
	if (flags & F_CTL_DETAIL)
2198
		for (l = 0; l < asp->others_len; l++) {
2199
			if ((a = asp->others[l]) == NULL)
2200
				break;
2201
			if ((wbuf = imsg_create(ibuf_se_ctl,
2202
			    IMSG_CTL_SHOW_RIB_ATTR, 0, pid,
2203
			    attr_optlen(a))) == NULL)
2204
				return;
2205
			if ((bp = ibuf_reserve(wbuf, attr_optlen(a))) == NULL) {
2206
				ibuf_free(wbuf);
2207
				return;
2208
			}
2209
			if (attr_write(bp, attr_optlen(a), a->flags,
2210
			    a->type, a->data, a->len) == -1) {
2211
				ibuf_free(wbuf);
2212
				return;
2213
			}
2214
			imsg_close(ibuf_se_ctl, wbuf);
2215
		}
2216
}
2217
2218
void
2219
rde_dump_filterout(struct rde_peer *peer, struct prefix *p,
2220
    struct ctl_show_rib_request *req)
2221
{
2222
	struct bgpd_addr	 addr;
2223
	struct rde_aspath	*asp;
2224
	enum filter_actions	 a;
2225
2226
	if (up_test_update(peer, p) != 1)
2227
		return;
2228
2229
	pt_getaddr(p->prefix, &addr);
2230
	a = rde_filter(out_rules, &asp, peer, p->aspath, &addr,
2231
	    p->prefix->prefixlen, p->aspath->peer);
2232
	if (asp)
2233
		asp->peer = p->aspath->peer;
2234
	else
2235
		asp = p->aspath;
2236
2237
	if (a == ACTION_ALLOW)
2238
		rde_dump_rib_as(p, asp, req->pid, req->flags);
2239
2240
	if (asp != p->aspath)
2241
		path_put(asp);
2242
}
2243
2244
void
2245
rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
2246
{
2247
	struct rde_peer		*peer;
2248
2249
	if (req->flags & F_CTL_ADJ_IN ||
2250
	    !(req->flags & (F_CTL_ADJ_IN|F_CTL_ADJ_OUT))) {
2251
		if (req->peerid && req->peerid != p->aspath->peer->conf.id)
2252
			return;
2253
		if (req->type == IMSG_CTL_SHOW_RIB_AS &&
2254
		    !aspath_match(p->aspath->aspath->data,
2255
		    p->aspath->aspath->len, &req->as, req->as.as))
2256
			return;
2257
		if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
2258
		    !community_match(p->aspath, req->community.as,
2259
		    req->community.type))
2260
			return;
2261
		if ((req->flags & F_CTL_ACTIVE) && p->rib->active != p)
2262
			return;
2263
		rde_dump_rib_as(p, p->aspath, req->pid, req->flags);
2264
	} else if (req->flags & F_CTL_ADJ_OUT) {
2265
		if (p->rib->active != p)
2266
			/* only consider active prefix */
2267
			return;
2268
		if (req->peerid) {
2269
			if ((peer = peer_get(req->peerid)) != NULL)
2270
				rde_dump_filterout(peer, p, req);
2271
			return;
2272
		}
2273
	}
2274
}
2275
2276
void
2277
rde_dump_upcall(struct rib_entry *re, void *ptr)
2278
{
2279
	struct prefix		*p;
2280
	struct rde_dump_ctx	*ctx = ptr;
2281
2282
	LIST_FOREACH(p, &re->prefix_h, rib_l)
2283
		rde_dump_filter(p, &ctx->req);
2284
}
2285
2286
void
2287
rde_dump_prefix_upcall(struct rib_entry *re, void *ptr)
2288
{
2289
	struct rde_dump_ctx	*ctx = ptr;
2290
	struct prefix		*p;
2291
	struct pt_entry		*pt;
2292
	struct bgpd_addr	 addr;
2293
2294
	pt = re->prefix;
2295
	pt_getaddr(pt, &addr);
2296
	if (addr.aid != ctx->req.prefix.aid)
2297
		return;
2298
	if (ctx->req.prefixlen > pt->prefixlen)
2299
		return;
2300
	if (!prefix_compare(&ctx->req.prefix, &addr, ctx->req.prefixlen))
2301
		LIST_FOREACH(p, &re->prefix_h, rib_l)
2302
			rde_dump_filter(p, &ctx->req);
2303
}
2304
2305
void
2306
rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
2307
    enum imsg_type type)
2308
{
2309
	struct rde_dump_ctx	*ctx;
2310
	struct rib_entry	*re;
2311
	u_int			 error;
2312
	u_int16_t		 id;
2313
	u_int8_t		 hostplen;
2314
2315
	if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
2316
		log_warn("rde_dump_ctx_new");
2317
		error = CTL_RES_NOMEM;
2318
		imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
2319
		    sizeof(error));
2320
		return;
2321
	}
2322
	if ((id = rib_find(req->rib)) == RIB_FAILED) {
2323
		log_warnx("rde_dump_ctx_new: no such rib %s", req->rib);
2324
		error = CTL_RES_NOSUCHPEER;
2325
		imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
2326
		    sizeof(error));
2327
		free(ctx);
2328
		return;
2329
	}
2330
2331
	memcpy(&ctx->req, req, sizeof(struct ctl_show_rib_request));
2332
	ctx->req.pid = pid;
2333
	ctx->req.type = type;
2334
	ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS;
2335
	ctx->ribctx.ctx_rib = &ribs[id];
2336
	switch (ctx->req.type) {
2337
	case IMSG_CTL_SHOW_NETWORK:
2338
		ctx->ribctx.ctx_upcall = network_dump_upcall;
2339
		break;
2340
	case IMSG_CTL_SHOW_RIB:
2341
	case IMSG_CTL_SHOW_RIB_AS:
2342
	case IMSG_CTL_SHOW_RIB_COMMUNITY:
2343
		ctx->ribctx.ctx_upcall = rde_dump_upcall;
2344
		break;
2345
	case IMSG_CTL_SHOW_RIB_PREFIX:
2346
		if (req->flags & F_LONGER) {
2347
			ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall;
2348
			break;
2349
		}
2350
		switch (req->prefix.aid) {
2351
		case AID_INET:
2352
		case AID_VPN_IPv4:
2353
			hostplen = 32;
2354
			break;
2355
		case AID_INET6:
2356
			hostplen = 128;
2357
			break;
2358
		default:
2359
			fatalx("rde_dump_ctx_new: unknown af");
2360
		}
2361
		if (req->prefixlen == hostplen)
2362
			re = rib_lookup(&ribs[id], &req->prefix);
2363
		else
2364
			re = rib_get(&ribs[id], &req->prefix, req->prefixlen);
2365
		if (re)
2366
			rde_dump_upcall(re, ctx);
2367
		rde_dump_done(ctx);
2368
		return;
2369
	default:
2370
		fatalx("rde_dump_ctx_new: unsupported imsg type");
2371
	}
2372
	ctx->ribctx.ctx_done = rde_dump_done;
2373
	ctx->ribctx.ctx_arg = ctx;
2374
	ctx->ribctx.ctx_aid = ctx->req.aid;
2375
	rib_dump_r(&ctx->ribctx);
2376
}
2377
2378
void
2379
rde_dump_done(void *arg)
2380
{
2381
	struct rde_dump_ctx	*ctx = arg;
2382
2383
	imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
2384
	    -1, NULL, 0);
2385
	free(ctx);
2386
}
2387
2388
void
2389
rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
2390
{
2391
	struct rde_mrt_ctx	*ctx;
2392
	u_int16_t		 id;
2393
2394
	if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
2395
		log_warn("rde_dump_mrt_new");
2396
		return;
2397
	}
2398
	memcpy(&ctx->mrt, mrt, sizeof(struct mrt));
2399
	TAILQ_INIT(&ctx->mrt.wbuf.bufs);
2400
	ctx->mrt.wbuf.fd = fd;
2401
	ctx->mrt.state = MRT_STATE_RUNNING;
2402
	id = rib_find(ctx->mrt.rib);
2403
	if (id == RIB_FAILED) {
2404
		log_warnx("non existing RIB %s for mrt dump", ctx->mrt.rib);
2405
		free(ctx);
2406
		return;
2407
	}
2408
2409
	if (ctx->mrt.type == MRT_TABLE_DUMP_V2)
2410
		mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist);
2411
2412
	ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS;
2413
	ctx->ribctx.ctx_rib = &ribs[id];
2414
	ctx->ribctx.ctx_upcall = mrt_dump_upcall;
2415
	ctx->ribctx.ctx_done = mrt_done;
2416
	ctx->ribctx.ctx_arg = &ctx->mrt;
2417
	ctx->ribctx.ctx_aid = AID_UNSPEC;
2418
	LIST_INSERT_HEAD(&rde_mrts, ctx, entry);
2419
	rde_mrt_cnt++;
2420
	rib_dump_r(&ctx->ribctx);
2421
}
2422
2423
/*
2424
 * kroute specific functions
2425
 */
2426
int
2427
rde_rdomain_import(struct rde_aspath *asp, struct rdomain *rd)
2428
{
2429
	struct filter_set	*s;
2430
2431
	TAILQ_FOREACH(s, &rd->import, entry) {
2432
		if (community_ext_match(asp, &s->action.ext_community, 0))
2433
			return (1);
2434
	}
2435
	return (0);
2436
}
2437
2438
void
2439
rde_send_kroute(struct prefix *new, struct prefix *old, u_int16_t ribid)
2440
{
2441
	struct kroute_full	 kr;
2442
	struct bgpd_addr	 addr;
2443
	struct prefix		*p;
2444
	struct rdomain		*rd;
2445
	enum imsg_type		 type;
2446
2447
	/*
2448
	 * Make sure that self announce prefixes are not committed to the
2449
	 * FIB. If both prefixes are unreachable no update is needed.
2450
	 */
2451
	if ((old == NULL || old->aspath->flags & F_PREFIX_ANNOUNCED) &&
2452
	    (new == NULL || new->aspath->flags & F_PREFIX_ANNOUNCED))
2453
		return;
2454
2455
	if (new == NULL || new->aspath->flags & F_PREFIX_ANNOUNCED) {
2456
		type = IMSG_KROUTE_DELETE;
2457
		p = old;
2458
	} else {
2459
		type = IMSG_KROUTE_CHANGE;
2460
		p = new;
2461
	}
2462
2463
	pt_getaddr(p->prefix, &addr);
2464
	bzero(&kr, sizeof(kr));
2465
	memcpy(&kr.prefix, &addr, sizeof(kr.prefix));
2466
	kr.prefixlen = p->prefix->prefixlen;
2467
	if (p->aspath->flags & F_NEXTHOP_REJECT)
2468
		kr.flags |= F_REJECT;
2469
	if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
2470
		kr.flags |= F_BLACKHOLE;
2471
	if (type == IMSG_KROUTE_CHANGE)
2472
		memcpy(&kr.nexthop, &p->aspath->nexthop->true_nexthop,
2473
		    sizeof(kr.nexthop));
2474
	strlcpy(kr.label, rtlabel_id2name(p->aspath->rtlabelid),
2475
	    sizeof(kr.label));
2476
2477
	switch (addr.aid) {
2478
	case AID_VPN_IPv4:
2479
		if (ribid != 1)
2480
			/* not Loc-RIB, no update for VPNs */
2481
			break;
2482
2483
		SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
2484
			if (!rde_rdomain_import(p->aspath, rd))
2485
				continue;
2486
			/* must send exit_nexthop so that correct MPLS tunnel
2487
			 * is chosen
2488
			 */
2489
			if (type == IMSG_KROUTE_CHANGE)
2490
				memcpy(&kr.nexthop,
2491
				    &p->aspath->nexthop->exit_nexthop,
2492
				    sizeof(kr.nexthop));
2493
			if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1,
2494
			    &kr, sizeof(kr)) == -1)
2495
				fatal("%s %d imsg_compose error", __func__,
2496
				    __LINE__);
2497
		}
2498
		break;
2499
	default:
2500
		if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1,
2501
		    &kr, sizeof(kr)) == -1)
2502
			fatal("%s %d imsg_compose error", __func__, __LINE__);
2503
		break;
2504
	}
2505
}
2506
2507
/*
2508
 * pf table specific functions
2509
 */
2510
void
2511
rde_send_pftable(u_int16_t id, struct bgpd_addr *addr,
2512
    u_int8_t len, int del)
2513
{
2514
	struct pftable_msg pfm;
2515
2516
	if (id == 0)
2517
		return;
2518
2519
	/* do not run while cleaning up */
2520
	if (rde_quit)
2521
		return;
2522
2523
	bzero(&pfm, sizeof(pfm));
2524
	strlcpy(pfm.pftable, pftable_id2name(id), sizeof(pfm.pftable));
2525
	memcpy(&pfm.addr, addr, sizeof(pfm.addr));
2526
	pfm.len = len;
2527
2528
	if (imsg_compose(ibuf_main,
2529
	    del ? IMSG_PFTABLE_REMOVE : IMSG_PFTABLE_ADD,
2530
	    0, 0, -1, &pfm, sizeof(pfm)) == -1)
2531
		fatal("%s %d imsg_compose error", __func__, __LINE__);
2532
}
2533
2534
void
2535
rde_send_pftable_commit(void)
2536
{
2537
	/* do not run while cleaning up */
2538
	if (rde_quit)
2539
		return;
2540
2541
	if (imsg_compose(ibuf_main, IMSG_PFTABLE_COMMIT, 0, 0, -1, NULL, 0) ==
2542
	    -1)
2543
		fatal("%s %d imsg_compose error", __func__, __LINE__);
2544
}
2545
2546
/*
2547
 * nexthop specific functions
2548
 */
2549
void
2550
rde_send_nexthop(struct bgpd_addr *next, int valid)
2551
{
2552
	int			 type;
2553
2554
	if (valid)
2555
		type = IMSG_NEXTHOP_ADD;
2556
	else
2557
		type = IMSG_NEXTHOP_REMOVE;
2558
2559
	if (imsg_compose(ibuf_main, type, 0, 0, -1, next,
2560
	    sizeof(struct bgpd_addr)) == -1)
2561
		fatal("%s %d imsg_compose error", __func__, __LINE__);
2562
}
2563
2564
/*
2565
 * soft reconfig specific functions
2566
 */
2567
void
2568
rde_reload_done(void)
2569
{
2570
	struct rdomain		*rd;
2571
	struct rde_peer		*peer;
2572
	struct filter_head	*fh;
2573
	u_int16_t		 rid;
2574
2575
	/* first merge the main config */
2576
	if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
2577
	    != (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
2578
		log_warnx("change to/from route-collector "
2579
		    "mode ignored");
2580
		if (conf->flags & BGPD_FLAG_NO_EVALUATE)
2581
			nconf->flags |= BGPD_FLAG_NO_EVALUATE;
2582
		else
2583
			nconf->flags &= ~BGPD_FLAG_NO_EVALUATE;
2584
	}
2585
	memcpy(conf, nconf, sizeof(struct bgpd_config));
2586
	conf->listen_addrs = NULL;
2587
	conf->csock = NULL;
2588
	conf->rcsock = NULL;
2589
	free(nconf);
2590
	nconf = NULL;
2591
2592
	/* sync peerself with conf */
2593
	peerself->remote_bgpid = ntohl(conf->bgpid);
2594
	peerself->conf.local_as = conf->as;
2595
	peerself->conf.remote_as = conf->as;
2596
	peerself->short_as = conf->short_as;
2597
2598
	/* apply new set of rdomain, sync will be done later */
2599
	while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
2600
		SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
2601
		filterset_free(&rd->import);
2602
		filterset_free(&rd->export);
2603
		free(rd);
2604
	}
2605
	free(rdomains_l);
2606
	rdomains_l = newdomains;
2607
	/* XXX WHERE IS THE SYNC ??? */
2608
2609
	rde_filter_calc_skip_steps(out_rules_tmp);
2610
2611
	/*
2612
	 * make the new filter rules the active one but keep the old for
2613
	 * softrconfig. This is needed so that changes happening are using
2614
	 * the right filters.
2615
	 */
2616
	fh = out_rules;
2617
	out_rules = out_rules_tmp;
2618
	out_rules_tmp = fh;
2619
2620
	/* check if filter changed */
2621
	LIST_FOREACH(peer, &peerlist, peer_l) {
2622
		if (peer->conf.id == 0)
2623
			continue;
2624
		peer->reconf_out = 0;
2625
		peer->reconf_rib = 0;
2626
		if (peer->ribid != rib_find(peer->conf.rib)) {
2627
			rib_dump(&ribs[peer->ribid],
2628
			    rde_softreconfig_unload_peer, peer, AID_UNSPEC);
2629
			peer->ribid = rib_find(peer->conf.rib);
2630
			if (peer->ribid == RIB_FAILED)
2631
				fatalx("King Bula's peer met an unknown RIB");
2632
			peer->reconf_rib = 1;
2633
			continue;
2634
		}
2635
		if (peer->conf.softreconfig_out &&
2636
		    !rde_filter_equal(out_rules, out_rules_tmp, peer)) {
2637
			peer->reconf_out = 1;
2638
		}
2639
	}
2640
	/* bring ribs in sync */
2641
	for (rid = 0; rid < rib_size; rid++) {
2642
		if (*ribs[rid].name == '\0')
2643
			continue;
2644
		rde_filter_calc_skip_steps(ribs[rid].in_rules_tmp);
2645
2646
		/* flip rules, make new active */
2647
		fh = ribs[rid].in_rules;
2648
		ribs[rid].in_rules = ribs[rid].in_rules_tmp;
2649
		ribs[rid].in_rules_tmp = fh;
2650
2651
		switch (ribs[rid].state) {
2652
		case RECONF_DELETE:
2653
			rib_free(&ribs[rid]);
2654
			break;
2655
		case RECONF_KEEP:
2656
			if (rde_filter_equal(ribs[rid].in_rules,
2657
			    ribs[rid].in_rules_tmp, NULL))
2658
				/* rib is in sync */
2659
				break;
2660
			ribs[rid].state = RECONF_RELOAD;
2661
			/* FALLTHROUGH */
2662
		case RECONF_REINIT:
2663
			rib_dump(&ribs[0], rde_softreconfig_in, &ribs[rid],
2664
			    AID_UNSPEC);
2665
			break;
2666
		case RECONF_RELOAD:
2667
			log_warnx("Bad rib reload state");
2668
			/* FALLTHROUGH */
2669
		case RECONF_NONE:
2670
			break;
2671
		}
2672
	}
2673
	LIST_FOREACH(peer, &peerlist, peer_l) {
2674
		if (peer->reconf_out)
2675
			rib_dump(&ribs[peer->ribid], rde_softreconfig_out,
2676
			    peer, AID_UNSPEC);
2677
		else if (peer->reconf_rib)
2678
			/* dump the full table to neighbors that changed rib */
2679
			peer_dump(peer->conf.id, AID_UNSPEC);
2680
	}
2681
	filterlist_free(out_rules_tmp);
2682
	out_rules_tmp = NULL;
2683
	for (rid = 0; rid < rib_size; rid++) {
2684
		if (*ribs[rid].name == '\0')
2685
			continue;
2686
		filterlist_free(ribs[rid].in_rules_tmp);
2687
		ribs[rid].in_rules_tmp = NULL;
2688
		ribs[rid].state = RECONF_NONE;
2689
	}
2690
2691
	log_info("RDE reconfigured");
2692
	imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
2693
	    -1, NULL, 0);
2694
}
2695
2696
void
2697
rde_softreconfig_in(struct rib_entry *re, void *ptr)
2698
{
2699
	struct rib		*rib = ptr;
2700
	struct prefix		*p, *np;
2701
	struct pt_entry		*pt;
2702
	struct rde_peer		*peer;
2703
	struct rde_aspath	*asp, *oasp, *nasp;
2704
	enum filter_actions	 oa, na;
2705
	struct bgpd_addr	 addr;
2706
2707
	pt = re->prefix;
2708
	pt_getaddr(pt, &addr);
2709
	for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) {
2710
		/*
2711
		 * prefix_remove() and path_update() may change the object
2712
		 * so cache the values.
2713
		 */
2714
		np = LIST_NEXT(p, rib_l);
2715
		asp = p->aspath;
2716
		peer = asp->peer;
2717
2718
		/* check if prefix changed */
2719
		if (rib->state == RECONF_RELOAD) {
2720
			oa = rde_filter(rib->in_rules_tmp, &oasp, peer,
2721
			    asp, &addr, pt->prefixlen, peer);
2722
			oasp = oasp != NULL ? oasp : asp;
2723
		} else {
2724
			/* make sure we update everything for RECONF_REINIT */
2725
			oa = ACTION_DENY;
2726
			oasp = asp;
2727
		}
2728
		na = rde_filter(rib->in_rules, &nasp, peer, asp,
2729
		    &addr, pt->prefixlen, peer);
2730
		nasp = nasp != NULL ? nasp : asp;
2731
2732
		/* go through all 4 possible combinations */
2733
		/* if (oa == ACTION_DENY && na == ACTION_DENY) */
2734
			/* nothing todo */
2735
		if (oa == ACTION_DENY && na == ACTION_ALLOW) {
2736
			/* update Local-RIB */
2737
			path_update(rib, peer, nasp, &addr, pt->prefixlen);
2738
		} else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
2739
			/* remove from Local-RIB */
2740
			prefix_remove(rib, peer, &addr, pt->prefixlen, 0);
2741
		} else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
2742
			if (path_compare(nasp, oasp) != 0)
2743
				/* send update */
2744
				path_update(rib, peer, nasp, &addr,
2745
				    pt->prefixlen);
2746
		}
2747
2748
		if (oasp != asp)
2749
			path_put(oasp);
2750
		if (nasp != asp)
2751
			path_put(nasp);
2752
	}
2753
}
2754
2755
void
2756
rde_softreconfig_out(struct rib_entry *re, void *ptr)
2757
{
2758
	struct prefix		*p = re->active;
2759
	struct pt_entry		*pt;
2760
	struct rde_peer		*peer = ptr;
2761
	struct rde_aspath	*oasp, *nasp;
2762
	enum filter_actions	 oa, na;
2763
	struct bgpd_addr	 addr;
2764
2765
	if (peer->conf.id == 0)
2766
		fatalx("King Bula troubled by bad peer");
2767
2768
	if (p == NULL)
2769
		return;
2770
2771
	pt = re->prefix;
2772
	pt_getaddr(pt, &addr);
2773
2774
	if (up_test_update(peer, p) != 1)
2775
		return;
2776
2777
	oa = rde_filter(out_rules_tmp, &oasp, peer, p->aspath,
2778
	    &addr, pt->prefixlen, p->aspath->peer);
2779
	na = rde_filter(out_rules, &nasp, peer, p->aspath,
2780
	    &addr, pt->prefixlen, p->aspath->peer);
2781
	oasp = oasp != NULL ? oasp : p->aspath;
2782
	nasp = nasp != NULL ? nasp : p->aspath;
2783
2784
	/* go through all 4 possible combinations */
2785
	/* if (oa == ACTION_DENY && na == ACTION_DENY) */
2786
		/* nothing todo */
2787
	if (oa == ACTION_DENY && na == ACTION_ALLOW) {
2788
		/* send update */
2789
		up_generate(peer, nasp, &addr, pt->prefixlen);
2790
	} else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
2791
		/* send withdraw */
2792
		up_generate(peer, NULL, &addr, pt->prefixlen);
2793
	} else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
2794
		/* send update if path attributes changed */
2795
		if (path_compare(nasp, oasp) != 0)
2796
			up_generate(peer, nasp, &addr, pt->prefixlen);
2797
	}
2798
2799
	if (oasp != p->aspath)
2800
		path_put(oasp);
2801
	if (nasp != p->aspath)
2802
		path_put(nasp);
2803
}
2804
2805
void
2806
rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
2807
{
2808
	struct rde_peer		*peer = ptr;
2809
	struct prefix		*p = re->active;
2810
	struct pt_entry		*pt;
2811
	struct rde_aspath	*oasp;
2812
	enum filter_actions	 oa;
2813
	struct bgpd_addr	 addr;
2814
2815
	pt = re->prefix;
2816
	pt_getaddr(pt, &addr);
2817
2818
	/* check if prefix was announced */
2819
	if (up_test_update(peer, p) != 1)
2820
		return;
2821
2822
	oa = rde_filter(out_rules_tmp, &oasp, peer, p->aspath,
2823
	    &addr, pt->prefixlen, p->aspath->peer);
2824
	oasp = oasp != NULL ? oasp : p->aspath;
2825
2826
	if (oa == ACTION_DENY)
2827
		/* nothing todo */
2828
		goto done;
2829
2830
	/* send withdraw */
2831
	up_generate(peer, NULL, &addr, pt->prefixlen);
2832
done:
2833
	if (oasp != p->aspath)
2834
		path_put(oasp);
2835
}
2836
2837
/*
2838
 * update specific functions
2839
 */
2840
u_char	queue_buf[4096];
2841
2842
void
2843
rde_up_dump_upcall(struct rib_entry *re, void *ptr)
2844
{
2845
	struct rde_peer		*peer = ptr;
2846
2847
	if (re->ribid != peer->ribid)
2848
		fatalx("King Bula: monstrous evil horror.");
2849
	if (re->active == NULL)
2850
		return;
2851
	up_generate_updates(out_rules, peer, re->active, NULL);
2852
}
2853
2854
void
2855
rde_generate_updates(u_int16_t ribid, struct prefix *new, struct prefix *old)
2856
{
2857
	struct rde_peer			*peer;
2858
2859
	/*
2860
	 * If old is != NULL we know it was active and should be removed.
2861
	 * If new is != NULL we know it is reachable and then we should
2862
	 * generate an update.
2863
	 */
2864
	if (old == NULL && new == NULL)
2865
		return;
2866
2867
	LIST_FOREACH(peer, &peerlist, peer_l) {
2868
		if (peer->conf.id == 0)
2869
			continue;
2870
		if (peer->ribid != ribid)
2871
			continue;
2872
		if (peer->state != PEER_UP)
2873
			continue;
2874
		up_generate_updates(out_rules, peer, new, old);
2875
	}
2876
}
2877
2878
void
2879
rde_update_queue_runner(void)
2880
{
2881
	struct rde_peer		*peer;
2882
	int			 r, sent, max = RDE_RUNNER_ROUNDS, eor = 0;
2883
	u_int16_t		 len, wd_len, wpos;
2884
2885
	len = sizeof(queue_buf) - MSGSIZE_HEADER;
2886
	do {
2887
		sent = 0;
2888
		LIST_FOREACH(peer, &peerlist, peer_l) {
2889
			if (peer->conf.id == 0)
2890
				continue;
2891
			if (peer->state != PEER_UP)
2892
				continue;
2893
			/* first withdraws */
2894
			wpos = 2; /* reserve space for the length field */
2895
			r = up_dump_prefix(queue_buf + wpos, len - wpos - 2,
2896
			    &peer->withdraws[AID_INET], peer);
2897
			wd_len = r;
2898
			/* write withdraws length filed */
2899
			wd_len = htons(wd_len);
2900
			memcpy(queue_buf, &wd_len, 2);
2901
			wpos += r;
2902
2903
			/* now bgp path attributes */
2904
			r = up_dump_attrnlri(queue_buf + wpos, len - wpos,
2905
			    peer);
2906
			switch (r) {
2907
			case -1:
2908
				eor = 1;
2909
				if (wd_len == 0) {
2910
					/* no withdraws queued just send EoR */
2911
					peer_send_eor(peer, AID_INET);
2912
					continue;
2913
				}
2914
				break;
2915
			case 2:
2916
				if (wd_len == 0) {
2917
					/*
2918
					 * No packet to send. No withdraws and
2919
					 * no path attributes. Skip.
2920
					 */
2921
					continue;
2922
				}
2923
				/* FALLTHROUGH */
2924
			default:
2925
				wpos += r;
2926
				break;
2927
			}
2928
2929
			/* finally send message to SE */
2930
			if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
2931
			    0, -1, queue_buf, wpos) == -1)
2932
				fatal("%s %d imsg_compose error", __func__,
2933
				    __LINE__);
2934
			sent++;
2935
			if (eor) {
2936
				eor = 0;
2937
				peer_send_eor(peer, AID_INET);
2938
			}
2939
		}
2940
		max -= sent;
2941
	} while (sent != 0 && max > 0);
2942
}
2943
2944
void
2945
rde_update6_queue_runner(u_int8_t aid)
2946
{
2947
	struct rde_peer		*peer;
2948
	u_char			*b;
2949
	int			 r, sent, max = RDE_RUNNER_ROUNDS / 2;
2950
	u_int16_t		 len;
2951
2952
	/* first withdraws ... */
2953
	do {
2954
		sent = 0;
2955
		LIST_FOREACH(peer, &peerlist, peer_l) {
2956
			if (peer->conf.id == 0)
2957
				continue;
2958
			if (peer->state != PEER_UP)
2959
				continue;
2960
			len = sizeof(queue_buf) - MSGSIZE_HEADER;
2961
			b = up_dump_mp_unreach(queue_buf, &len, peer, aid);
2962
2963
			if (b == NULL)
2964
				continue;
2965
			/* finally send message to SE */
2966
			if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
2967
			    0, -1, b, len) == -1)
2968
				fatal("%s %d imsg_compose error", __func__,
2969
				    __LINE__);
2970
			sent++;
2971
		}
2972
		max -= sent;
2973
	} while (sent != 0 && max > 0);
2974
2975
	/* ... then updates */
2976
	max = RDE_RUNNER_ROUNDS / 2;
2977
	do {
2978
		sent = 0;
2979
		LIST_FOREACH(peer, &peerlist, peer_l) {
2980
			if (peer->conf.id == 0)
2981
				continue;
2982
			if (peer->state != PEER_UP)
2983
				continue;
2984
			len = sizeof(queue_buf) - MSGSIZE_HEADER;
2985
			r = up_dump_mp_reach(queue_buf, &len, peer, aid);
2986
			switch (r) {
2987
			case -2:
2988
				continue;
2989
			case -1:
2990
				peer_send_eor(peer, aid);
2991
				continue;
2992
			default:
2993
				b = queue_buf + r;
2994
				break;
2995
			}
2996
2997
			/* finally send message to SE */
2998
			if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
2999
			    0, -1, b, len) == -1)
3000
				fatal("%s %d imsg_compose error", __func__,
3001
				    __LINE__);
3002
			sent++;
3003
		}
3004
		max -= sent;
3005
	} while (sent != 0 && max > 0);
3006
}
3007
3008
/*
3009
 * generic helper function
3010
 */
3011
u_int32_t
3012
rde_local_as(void)
3013
{
3014
	return (conf->as);
3015
}
3016
3017
int
3018
rde_noevaluate(void)
3019
{
3020
	/* do not run while cleaning up */
3021
	if (rde_quit)
3022
		return (1);
3023
3024
	return (conf->flags & BGPD_FLAG_NO_EVALUATE);
3025
}
3026
3027
int
3028
rde_decisionflags(void)
3029
{
3030
	return (conf->flags & BGPD_FLAG_DECISION_MASK);
3031
}
3032
3033
int
3034
rde_as4byte(struct rde_peer *peer)
3035
{
3036
	return (peer->capa.as4byte);
3037
}
3038
3039
/*
3040
 * peer functions
3041
 */
3042
struct peer_table {
3043
	struct rde_peer_head	*peer_hashtbl;
3044
	u_int32_t		 peer_hashmask;
3045
} peertable;
3046
3047
#define PEER_HASH(x)		\
3048
	&peertable.peer_hashtbl[(x) & peertable.peer_hashmask]
3049
3050
void
3051
peer_init(u_int32_t hashsize)
3052
{
3053
	struct peer_config pc;
3054
	u_int32_t	 hs, i;
3055
3056
	for (hs = 1; hs < hashsize; hs <<= 1)
3057
		;
3058
	peertable.peer_hashtbl = calloc(hs, sizeof(struct rde_peer_head));
3059
	if (peertable.peer_hashtbl == NULL)
3060
		fatal("peer_init");
3061
3062
	for (i = 0; i < hs; i++)
3063
		LIST_INIT(&peertable.peer_hashtbl[i]);
3064
	LIST_INIT(&peerlist);
3065
3066
	peertable.peer_hashmask = hs - 1;
3067
3068
	bzero(&pc, sizeof(pc));
3069
	snprintf(pc.descr, sizeof(pc.descr), "LOCAL");
3070
3071
	peerself = peer_add(0, &pc);
3072
	if (peerself == NULL)
3073
		fatalx("peer_init add self");
3074
3075
	peerself->state = PEER_UP;
3076
}
3077
3078
void
3079
peer_shutdown(void)
3080
{
3081
	u_int32_t	i;
3082
3083
	for (i = 0; i <= peertable.peer_hashmask; i++)
3084
		if (!LIST_EMPTY(&peertable.peer_hashtbl[i]))
3085
			log_warnx("peer_free: free non-free table");
3086
3087
	free(peertable.peer_hashtbl);
3088
}
3089
3090
struct rde_peer *
3091
peer_get(u_int32_t id)
3092
{
3093
	struct rde_peer_head	*head;
3094
	struct rde_peer		*peer;
3095
3096
	head = PEER_HASH(id);
3097
3098
	LIST_FOREACH(peer, head, hash_l) {
3099
		if (peer->conf.id == id)
3100
			return (peer);
3101
	}
3102
	return (NULL);
3103
}
3104
3105
struct rde_peer *
3106
peer_add(u_int32_t id, struct peer_config *p_conf)
3107
{
3108
	struct rde_peer_head	*head;
3109
	struct rde_peer		*peer;
3110
3111
	if ((peer = peer_get(id))) {
3112
		memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
3113
		return (NULL);
3114
	}
3115
3116
	peer = calloc(1, sizeof(struct rde_peer));
3117
	if (peer == NULL)
3118
		fatal("peer_add");
3119
3120
	LIST_INIT(&peer->path_h);
3121
	memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
3122
	peer->remote_bgpid = 0;
3123
	peer->ribid = rib_find(peer->conf.rib);
3124
	if (peer->ribid == RIB_FAILED)
3125
		fatalx("King Bula's new peer met an unknown RIB");
3126
	peer->state = PEER_NONE;
3127
	up_init(peer);
3128
3129
	head = PEER_HASH(id);
3130
3131
	LIST_INSERT_HEAD(head, peer, hash_l);
3132
	LIST_INSERT_HEAD(&peerlist, peer, peer_l);
3133
3134
	return (peer);
3135
}
3136
3137
int
3138
peer_localaddrs(struct rde_peer *peer, struct bgpd_addr *laddr)
3139
{
3140
	struct ifaddrs	*ifap, *ifa, *match;
3141
3142
	if (getifaddrs(&ifap) == -1)
3143
		fatal("getifaddrs");
3144
3145
	for (match = ifap; match != NULL; match = match->ifa_next)
3146
		if (sa_cmp(laddr, match->ifa_addr) == 0)
3147
			break;
3148
3149
	if (match == NULL) {
3150
		log_warnx("peer_localaddrs: local address not found");
3151
		return (-1);
3152
	}
3153
3154
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
3155
		if (ifa->ifa_addr->sa_family == AF_INET &&
3156
		    strcmp(ifa->ifa_name, match->ifa_name) == 0) {
3157
			if (ifa->ifa_addr->sa_family ==
3158
			    match->ifa_addr->sa_family)
3159
				ifa = match;
3160
			sa2addr(ifa->ifa_addr, &peer->local_v4_addr);
3161
			break;
3162
		}
3163
	}
3164
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
3165
		if (ifa->ifa_addr->sa_family == AF_INET6 &&
3166
		    strcmp(ifa->ifa_name, match->ifa_name) == 0) {
3167
			/*
3168
			 * only accept global scope addresses except explicitly
3169
			 * specified.
3170
			 */
3171
			if (ifa->ifa_addr->sa_family ==
3172
			    match->ifa_addr->sa_family)
3173
				ifa = match;
3174
			else if (IN6_IS_ADDR_LINKLOCAL(
3175
			    &((struct sockaddr_in6 *)ifa->
3176
			    ifa_addr)->sin6_addr) ||
3177
			    IN6_IS_ADDR_SITELOCAL(
3178
			    &((struct sockaddr_in6 *)ifa->
3179
			    ifa_addr)->sin6_addr))
3180
				continue;
3181
			sa2addr(ifa->ifa_addr, &peer->local_v6_addr);
3182
			break;
3183
		}
3184
	}
3185
3186
	freeifaddrs(ifap);
3187
	return (0);
3188
}
3189
3190
void
3191
peer_up(u_int32_t id, struct session_up *sup)
3192
{
3193
	struct rde_peer	*peer;
3194
	u_int8_t	 i;
3195
3196
	peer = peer_get(id);
3197
	if (peer == NULL) {
3198
		log_warnx("peer_up: unknown peer id %d", id);
3199
		return;
3200
	}
3201
3202
	if (peer->state != PEER_DOWN && peer->state != PEER_NONE &&
3203
	    peer->state != PEER_UP) {
3204
		/*
3205
		 * There is a race condition when doing PEER_ERR -> PEER_DOWN.
3206
		 * So just do a full reset of the peer here.
3207
		 */
3208
		for (i = 0; i < AID_MAX; i++) {
3209
			peer->staletime[i] = 0;
3210
			peer_flush(peer, i);
3211
		}
3212
		up_down(peer);
3213
		peer->prefix_cnt = 0;
3214
		peer->state = PEER_DOWN;
3215
	}
3216
	peer->remote_bgpid = ntohl(sup->remote_bgpid);
3217
	peer->short_as = sup->short_as;
3218
	memcpy(&peer->remote_addr, &sup->remote_addr,
3219
	    sizeof(peer->remote_addr));
3220
	memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
3221
3222
	if (peer_localaddrs(peer, &sup->local_addr)) {
3223
		peer->state = PEER_DOWN;
3224
		imsg_compose(ibuf_se, IMSG_SESSION_DOWN, id, 0, -1, NULL, 0);
3225
		return;
3226
	}
3227
3228
	peer->state = PEER_UP;
3229
	up_init(peer);
3230
3231
	if (rde_noevaluate())
3232
		/*
3233
		 * no need to dump the table to the peer, there are no active
3234
		 * prefixes anyway. This is a speed up hack.
3235
		 */
3236
		return;
3237
3238
	for (i = 0; i < AID_MAX; i++) {
3239
		if (peer->capa.mp[i])
3240
			peer_dump(id, i);
3241
	}
3242
}
3243
3244
void
3245
peer_down(u_int32_t id)
3246
{
3247
	struct rde_peer		*peer;
3248
	struct rde_aspath	*asp, *nasp;
3249
3250
	peer = peer_get(id);
3251
	if (peer == NULL) {
3252
		log_warnx("peer_down: unknown peer id %d", id);
3253
		return;
3254
	}
3255
	peer->remote_bgpid = 0;
3256
	peer->state = PEER_DOWN;
3257
	up_down(peer);
3258
3259
	/* walk through per peer RIB list and remove all prefixes. */
3260
	for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
3261
		nasp = LIST_NEXT(asp, peer_l);
3262
		path_remove(asp);
3263
	}
3264
	LIST_INIT(&peer->path_h);
3265
	peer->prefix_cnt = 0;
3266
3267
	/* Deletions are performed in path_remove() */
3268
	rde_send_pftable_commit();
3269
3270
	LIST_REMOVE(peer, hash_l);
3271
	LIST_REMOVE(peer, peer_l);
3272
	free(peer);
3273
}
3274
3275
/*
3276
 * Flush all routes older then staletime. If staletime is 0 all routes will
3277
 * be flushed.
3278
 */
3279
void
3280
peer_flush(struct rde_peer *peer, u_int8_t aid)
3281
{
3282
	struct rde_aspath	*asp, *nasp;
3283
	u_int32_t		 rprefixes;
3284
3285
	rprefixes = 0;
3286
	/* walk through per peer RIB list and remove all stale prefixes. */
3287
	for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
3288
		nasp = LIST_NEXT(asp, peer_l);
3289
		rprefixes += path_remove_stale(asp, aid);
3290
	}
3291
3292
	/* Deletions are performed in path_remove() */
3293
	rde_send_pftable_commit();
3294
3295
	/* flushed no need to keep staletime */
3296
	peer->staletime[aid] = 0;
3297
3298
	if (peer->prefix_cnt > rprefixes)
3299
		peer->prefix_cnt -= rprefixes;
3300
	else
3301
		peer->prefix_cnt = 0;
3302
}
3303
3304
void
3305
peer_stale(u_int32_t id, u_int8_t aid)
3306
{
3307
	struct rde_peer		*peer;
3308
	time_t			 now;
3309
3310
	peer = peer_get(id);
3311
	if (peer == NULL) {
3312
		log_warnx("peer_stale: unknown peer id %d", id);
3313
		return;
3314
	}
3315
3316
	/* flush the now even staler routes out */
3317
	if (peer->staletime[aid])
3318
		peer_flush(peer, aid);
3319
	peer->staletime[aid] = now = time(NULL);
3320
3321
	/* make sure new prefixes start on a higher timestamp */
3322
	do {
3323
		sleep(1);
3324
	} while (now >= time(NULL));
3325
}
3326
3327
void
3328
peer_dump(u_int32_t id, u_int8_t aid)
3329
{
3330
	struct rde_peer		*peer;
3331
3332
	peer = peer_get(id);
3333
	if (peer == NULL) {
3334
		log_warnx("peer_dump: unknown peer id %d", id);
3335
		return;
3336
	}
3337
3338
	if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
3339
		up_generate_default(out_rules, peer, aid);
3340
	else
3341
		rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid);
3342
	if (peer->capa.grestart.restart)
3343
		up_generate_marker(peer, aid);
3344
}
3345
3346
/* End-of-RIB marker, RFC 4724 */
3347
void
3348
peer_recv_eor(struct rde_peer *peer, u_int8_t aid)
3349
{
3350
	peer->prefix_rcvd_eor++;
3351
3352
	/*
3353
	 * First notify SE to avert a possible race with the restart timeout.
3354
	 * If the timeout fires before this imsg is processed by the SE it will
3355
	 * result in the same operation since the timeout issues a FLUSH which
3356
	 * does the same as the RESTARTED action (flushing stale routes).
3357
	 * The logic in the SE is so that only one of FLUSH or RESTARTED will
3358
	 * be sent back to the RDE and so peer_flush is only called once.
3359
	 */
3360
	if (imsg_compose(ibuf_se, IMSG_SESSION_RESTARTED, peer->conf.id,
3361
	    0, -1, &aid, sizeof(aid)) == -1)
3362
		fatal("%s %d imsg_compose error", __func__, __LINE__);
3363
}
3364
3365
void
3366
peer_send_eor(struct rde_peer *peer, u_int8_t aid)
3367
{
3368
	u_int16_t	afi;
3369
	u_int8_t	safi;
3370
3371
	peer->prefix_sent_eor++;
3372
3373
	if (aid == AID_INET) {
3374
		u_char null[4];
3375
3376
		bzero(&null, 4);
3377
		if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
3378
		    0, -1, &null, 4) == -1)
3379
			fatal("%s %d imsg_compose error in peer_send_eor",
3380
			    __func__, __LINE__);
3381
	} else {
3382
		u_int16_t	i;
3383
		u_char		buf[10];
3384
3385
		if (aid2afi(aid, &afi, &safi) == -1)
3386
			fatalx("peer_send_eor: bad AID");
3387
3388
		i = 0;	/* v4 withdrawn len */
3389
		bcopy(&i, &buf[0], sizeof(i));
3390
		i = htons(6);	/* path attr len */
3391
		bcopy(&i, &buf[2], sizeof(i));
3392
		buf[4] = ATTR_OPTIONAL;
3393
		buf[5] = ATTR_MP_UNREACH_NLRI;
3394
		buf[6] = 3;	/* withdrawn len */
3395
		i = htons(afi);
3396
		bcopy(&i, &buf[7], sizeof(i));
3397
		buf[9] = safi;
3398
3399
		if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
3400
		    0, -1, &buf, 10) == -1)
3401
			fatal("%s %d imsg_compose error in peer_send_eor",
3402
			    __func__, __LINE__);
3403
	}
3404
}
3405
3406
/*
3407
 * network announcement stuff
3408
 */
3409
void
3410
network_add(struct network_config *nc, int flagstatic)
3411
{
3412
	struct rdomain		*rd;
3413
	struct rde_aspath	*asp;
3414
	struct filter_set_head	*vpnset = NULL;
3415
	in_addr_t		 prefix4;
3416
	u_int16_t		 i;
3417
3418
	if (nc->rtableid) {
3419
		SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
3420
			if (rd->rtableid != nc->rtableid)
3421
				continue;
3422
			switch (nc->prefix.aid) {
3423
			case AID_INET:
3424
				prefix4 = nc->prefix.v4.s_addr;
3425
				bzero(&nc->prefix, sizeof(nc->prefix));
3426
				nc->prefix.aid = AID_VPN_IPv4;
3427
				nc->prefix.vpn4.rd = rd->rd;
3428
				nc->prefix.vpn4.addr.s_addr = prefix4;
3429
				nc->prefix.vpn4.labellen = 3;
3430
				nc->prefix.vpn4.labelstack[0] =
3431
				    (rd->label >> 12) & 0xff;
3432
				nc->prefix.vpn4.labelstack[1] =
3433
				    (rd->label >> 4) & 0xff;
3434
				nc->prefix.vpn4.labelstack[2] =
3435
				    (rd->label << 4) & 0xf0;
3436
				nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
3437
				vpnset = &rd->export;
3438
				break;
3439
			default:
3440
				log_warnx("unable to VPNize prefix");
3441
				filterset_free(&nc->attrset);
3442
				return;
3443
			}
3444
			break;
3445
		}
3446
		if (rd == NULL) {
3447
			log_warnx("network_add: "
3448
			    "prefix %s/%u in non-existing rdomain %u",
3449
			    log_addr(&nc->prefix), nc->prefixlen, nc->rtableid);
3450
			return;
3451
		}
3452
	}
3453
3454
	if (nc->type == NETWORK_MRTCLONE) {
3455
		asp = nc->asp;
3456
	} else {
3457
		asp = path_get();
3458
		asp->aspath = aspath_get(NULL, 0);
3459
		asp->origin = ORIGIN_IGP;
3460
		asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
3461
		    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
3462
		/* the nexthop is unset unless a default set overrides it */
3463
	}
3464
	if (!flagstatic)
3465
		asp->flags |= F_ANN_DYNAMIC;
3466
	rde_apply_set(asp, &nc->attrset, nc->prefix.aid, peerself, peerself);
3467
	if (vpnset)
3468
		rde_apply_set(asp, vpnset, nc->prefix.aid, peerself, peerself);
3469
	for (i = 1; i < rib_size; i++) {
3470
		if (*ribs[i].name == '\0')
3471
			break;
3472
		path_update(&ribs[i], peerself, asp, &nc->prefix,
3473
		    nc->prefixlen);
3474
	}
3475
	path_put(asp);
3476
	filterset_free(&nc->attrset);
3477
}
3478
3479
void
3480
network_delete(struct network_config *nc, int flagstatic)
3481
{
3482
	struct rdomain	*rd;
3483
	in_addr_t	 prefix4;
3484
	u_int32_t	 flags = F_PREFIX_ANNOUNCED;
3485
	u_int32_t	 i;
3486
3487
	if (!flagstatic)
3488
		flags |= F_ANN_DYNAMIC;
3489
3490
	if (nc->rtableid) {
3491
		SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
3492
			if (rd->rtableid != nc->rtableid)
3493
				continue;
3494
			switch (nc->prefix.aid) {
3495
			case AID_INET:
3496
				prefix4 = nc->prefix.v4.s_addr;
3497
				bzero(&nc->prefix, sizeof(nc->prefix));
3498
				nc->prefix.aid = AID_VPN_IPv4;
3499
				nc->prefix.vpn4.rd = rd->rd;
3500
				nc->prefix.vpn4.addr.s_addr = prefix4;
3501
				nc->prefix.vpn4.labellen = 3;
3502
				nc->prefix.vpn4.labelstack[0] =
3503
				    (rd->label >> 12) & 0xff;
3504
				nc->prefix.vpn4.labelstack[1] =
3505
				    (rd->label >> 4) & 0xff;
3506
				nc->prefix.vpn4.labelstack[2] =
3507
				    (rd->label << 4) & 0xf0;
3508
				nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
3509
				break;
3510
			default:
3511
				log_warnx("unable to VPNize prefix");
3512
				return;
3513
			}
3514
		}
3515
	}
3516
3517
	for (i = rib_size - 1; i > 0; i--) {
3518
		if (*ribs[i].name == '\0')
3519
			break;
3520
		prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen,
3521
		    flags);
3522
	}
3523
}
3524
3525
void
3526
network_dump_upcall(struct rib_entry *re, void *ptr)
3527
{
3528
	struct prefix		*p;
3529
	struct kroute_full	 k;
3530
	struct bgpd_addr	 addr;
3531
	struct rde_dump_ctx	*ctx = ptr;
3532
3533
	LIST_FOREACH(p, &re->prefix_h, rib_l) {
3534
		if (!(p->aspath->flags & F_PREFIX_ANNOUNCED))
3535
			continue;
3536
		pt_getaddr(p->prefix, &addr);
3537
3538
		bzero(&k, sizeof(k));
3539
		memcpy(&k.prefix, &addr, sizeof(k.prefix));
3540
		if (p->aspath->nexthop == NULL ||
3541
		    p->aspath->nexthop->state != NEXTHOP_REACH)
3542
			k.nexthop.aid = k.prefix.aid;
3543
		else
3544
			memcpy(&k.nexthop, &p->aspath->nexthop->true_nexthop,
3545
			    sizeof(k.nexthop));
3546
		k.prefixlen = p->prefix->prefixlen;
3547
		k.flags = F_KERNEL;
3548
		if ((p->aspath->flags & F_ANN_DYNAMIC) == 0)
3549
			k.flags = F_STATIC;
3550
		if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
3551
		    ctx->req.pid, -1, &k, sizeof(k)) == -1)
3552
			log_warnx("network_dump_upcall: "
3553
			    "imsg_compose error");
3554
	}
3555
}
3556
3557
/* clean up */
3558
void
3559
rde_shutdown(void)
3560
{
3561
	struct rde_peer		*p;
3562
	u_int32_t		 i;
3563
3564
	/*
3565
	 * the decision process is turned off if rde_quit = 1 and
3566
	 * rde_shutdown depends on this.
3567
	 */
3568
3569
	/*
3570
	 * All peers go down
3571
	 */
3572
	for (i = 0; i <= peertable.peer_hashmask; i++)
3573
		while ((p = LIST_FIRST(&peertable.peer_hashtbl[i])) != NULL)
3574
			peer_down(p->conf.id);
3575
3576
	/* free filters */
3577
	filterlist_free(out_rules);
3578
	for (i = 0; i < rib_size; i++) {
3579
		if (*ribs[i].name == '\0')
3580
			break;
3581
		filterlist_free(ribs[i].in_rules);
3582
	}
3583
3584
	nexthop_shutdown();
3585
	path_shutdown();
3586
	aspath_shutdown();
3587
	attr_shutdown();
3588
	pt_shutdown();
3589
	peer_shutdown();
3590
}
3591
3592
int
3593
sa_cmp(struct bgpd_addr *a, struct sockaddr *b)
3594
{
3595
	struct sockaddr_in	*in_b;
3596
	struct sockaddr_in6	*in6_b;
3597
3598
	if (aid2af(a->aid) != b->sa_family)
3599
		return (1);
3600
3601
	switch (b->sa_family) {
3602
	case AF_INET:
3603
		in_b = (struct sockaddr_in *)b;
3604
		if (a->v4.s_addr != in_b->sin_addr.s_addr)
3605
			return (1);
3606
		break;
3607
	case AF_INET6:
3608
		in6_b = (struct sockaddr_in6 *)b;
3609
#ifdef __KAME__
3610
		/* directly stolen from sbin/ifconfig/ifconfig.c */
3611
		if (IN6_IS_ADDR_LINKLOCAL(&in6_b->sin6_addr)) {
3612
			in6_b->sin6_scope_id =
3613
			    ntohs(*(u_int16_t *)&in6_b->sin6_addr.s6_addr[2]);
3614
			in6_b->sin6_addr.s6_addr[2] =
3615
			    in6_b->sin6_addr.s6_addr[3] = 0;
3616
		}
3617
#endif
3618
		if (bcmp(&a->v6, &in6_b->sin6_addr,
3619
		    sizeof(struct in6_addr)))
3620
			return (1);
3621
		break;
3622
	default:
3623
		fatal("king bula sez: unknown address family");
3624
		/* NOTREACHED */
3625
	}
3626
3627
	return (0);
3628
}