GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/rde.c Lines: 0 421 0.0 %
Date: 2017-11-07 Branches: 0 251 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rde.c,v 1.23 2016/09/02 16:46:29 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5
 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <net/route.h>
25
26
#include <errno.h>
27
#include <pwd.h>
28
#include <signal.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
33
#include "eigrpd.h"
34
#include "eigrpe.h"
35
#include "rde.h"
36
#include "log.h"
37
38
static void		 rde_sig_handler(int sig, short, void *);
39
static __dead void	 rde_shutdown(void);
40
static void		 rde_dispatch_imsg(int, short, void *);
41
static void		 rde_dispatch_parent(int, short, void *);
42
static struct redistribute *eigrp_redistribute(struct eigrp *, struct kroute *);
43
static void		 rt_redist_set(struct kroute *, int);
44
static void		 rt_snap(struct rde_nbr *);
45
static struct ctl_rt	*rt_to_ctl(struct rt_node *, struct eigrp_route *);
46
static void		 rt_dump(struct ctl_show_topology_req *, pid_t);
47
48
struct eigrpd_conf	*rdeconf;
49
50
static struct imsgev	*iev_eigrpe;
51
static struct imsgev	*iev_main;
52
53
/* ARGSUSED */
54
static void
55
rde_sig_handler(int sig, short event, void *arg)
56
{
57
	/*
58
	 * signal handler rules don't apply, libevent decouples for us
59
	 */
60
61
	switch (sig) {
62
	case SIGINT:
63
	case SIGTERM:
64
		rde_shutdown();
65
		/* NOTREACHED */
66
	default:
67
		fatalx("unexpected signal");
68
	}
69
}
70
71
/* route decision engine */
72
void
73
rde(int debug, int verbose)
74
{
75
	struct event		 ev_sigint, ev_sigterm;
76
	struct timeval		 now;
77
	struct passwd		*pw;
78
79
	rdeconf = config_new_empty();
80
81
	log_init(debug);
82
	log_verbose(verbose);
83
84
	if ((pw = getpwnam(EIGRPD_USER)) == NULL)
85
		fatal("getpwnam");
86
87
	if (chroot(pw->pw_dir) == -1)
88
		fatal("chroot");
89
	if (chdir("/") == -1)
90
		fatal("chdir(\"/\")");
91
92
	setproctitle("route decision engine");
93
	eigrpd_process = PROC_RDE_ENGINE;
94
95
	if (setgroups(1, &pw->pw_gid) ||
96
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
97
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
98
		fatal("can't drop privileges");
99
100
	if (pledge("stdio recvfd flock rpath cpath wpath", NULL) == -1)
101
		fatal("pledge");
102
103
	event_init();
104
105
	/* setup signal handler */
106
	signal_set(&ev_sigint, SIGINT, rde_sig_handler, NULL);
107
	signal_set(&ev_sigterm, SIGTERM, rde_sig_handler, NULL);
108
	signal_add(&ev_sigint, NULL);
109
	signal_add(&ev_sigterm, NULL);
110
	signal(SIGPIPE, SIG_IGN);
111
	signal(SIGHUP, SIG_IGN);
112
113
	/* setup pipe and event handler to the parent process */
114
	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
115
		fatal(NULL);
116
	imsg_init(&iev_main->ibuf, 3);
117
	iev_main->handler = rde_dispatch_parent;
118
	iev_main->events = EV_READ;
119
	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
120
	    iev_main->handler, iev_main);
121
	event_add(&iev_main->ev, NULL);
122
123
	gettimeofday(&now, NULL);
124
	global.uptime = now.tv_sec;
125
126
	event_dispatch();
127
128
	rde_shutdown();
129
}
130
131
static __dead void
132
rde_shutdown(void)
133
{
134
	/* close pipes */
135
	msgbuf_clear(&iev_eigrpe->ibuf.w);
136
	close(iev_eigrpe->ibuf.fd);
137
	msgbuf_clear(&iev_main->ibuf.w);
138
	close(iev_main->ibuf.fd);
139
140
	config_clear(rdeconf);
141
142
	free(iev_eigrpe);
143
	free(iev_main);
144
145
	log_info("route decision engine exiting");
146
	exit(0);
147
}
148
149
int
150
rde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
151
{
152
	return (imsg_compose_event(iev_main, type, 0, pid, -1,
153
	    data, datalen));
154
}
155
156
int
157
rde_imsg_compose_eigrpe(int type, uint32_t peerid, pid_t pid, void *data,
158
    uint16_t datalen)
159
{
160
	return (imsg_compose_event(iev_eigrpe, type, peerid, pid, -1,
161
	    data, datalen));
162
}
163
164
/* ARGSUSED */
165
static void
166
rde_dispatch_imsg(int fd, short event, void *bula)
167
{
168
	struct imsgev		*iev = bula;
169
	struct imsgbuf		*ibuf;
170
	struct imsg		 imsg;
171
	struct rde_nbr		*nbr;
172
	struct rde_nbr		 new;
173
	struct rinfo		 rinfo;
174
	ssize_t			 n;
175
	int			 shut = 0, verbose;
176
177
	ibuf = &iev->ibuf;
178
179
	if (event & EV_READ) {
180
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
181
			fatal("imsg_read error");
182
		if (n == 0)	/* connection closed */
183
			shut = 1;
184
	}
185
	if (event & EV_WRITE) {
186
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
187
			fatal("msgbuf_write");
188
		if (n == 0)	/* connection closed */
189
			shut = 1;
190
	}
191
192
	for (;;) {
193
		if ((n = imsg_get(ibuf, &imsg)) == -1)
194
			fatal("rde_dispatch_imsg: imsg_get error");
195
		if (n == 0)
196
			break;
197
198
		switch (imsg.hdr.type) {
199
		case IMSG_NEIGHBOR_UP:
200
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
201
			    sizeof(struct rde_nbr))
202
				fatalx("invalid size of neighbor request");
203
			memcpy(&new, imsg.data, sizeof(new));
204
205
			if (rde_nbr_find(imsg.hdr.peerid))
206
				fatalx("rde_dispatch_imsg: "
207
				    "neighbor already exists");
208
			rde_nbr_new(imsg.hdr.peerid, &new);
209
			break;
210
		case IMSG_NEIGHBOR_DOWN:
211
			nbr = rde_nbr_find(imsg.hdr.peerid);
212
			if (nbr == NULL) {
213
				log_debug("%s: cannot find rde neighbor",
214
				    __func__);
215
				break;
216
			}
217
218
			rde_check_link_down_nbr(nbr);
219
			rde_flush_queries();
220
			rde_nbr_del(rde_nbr_find(imsg.hdr.peerid), 0);
221
			break;
222
		case IMSG_RECV_UPDATE_INIT:
223
			nbr = rde_nbr_find(imsg.hdr.peerid);
224
			if (nbr == NULL) {
225
				log_debug("%s: cannot find rde neighbor",
226
				    __func__);
227
				break;
228
			}
229
230
			rt_snap(nbr);
231
			break;
232
		case IMSG_RECV_UPDATE:
233
		case IMSG_RECV_QUERY:
234
		case IMSG_RECV_REPLY:
235
		case IMSG_RECV_SIAQUERY:
236
		case IMSG_RECV_SIAREPLY:
237
			nbr = rde_nbr_find(imsg.hdr.peerid);
238
			if (nbr == NULL) {
239
				log_debug("%s: cannot find rde neighbor",
240
				    __func__);
241
				break;
242
			}
243
244
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
245
				fatalx("invalid size of rinfo");
246
			memcpy(&rinfo, imsg.data, sizeof(rinfo));
247
248
			switch (imsg.hdr.type) {
249
			case IMSG_RECV_UPDATE:
250
				rde_check_update(nbr, &rinfo);
251
				break;
252
			case IMSG_RECV_QUERY:
253
				rde_check_query(nbr, &rinfo, 0);
254
				break;
255
			case IMSG_RECV_REPLY:
256
				rde_check_reply(nbr, &rinfo, 0);
257
				break;
258
			case IMSG_RECV_SIAQUERY:
259
				rde_check_query(nbr, &rinfo, 1);
260
				break;
261
			case IMSG_RECV_SIAREPLY:
262
				rde_check_reply(nbr, &rinfo, 1);
263
				break;
264
			}
265
			break;
266
		case IMSG_CTL_SHOW_TOPOLOGY:
267
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
268
			    sizeof(struct ctl_show_topology_req)) {
269
				log_warnx("%s: wrong imsg len", __func__);
270
				break;
271
			}
272
273
			rt_dump(imsg.data, imsg.hdr.pid);
274
			rde_imsg_compose_eigrpe(IMSG_CTL_END, 0, imsg.hdr.pid,
275
			    NULL, 0);
276
			break;
277
		case IMSG_CTL_LOG_VERBOSE:
278
			/* already checked by eigrpe */
279
			memcpy(&verbose, imsg.data, sizeof(verbose));
280
			log_verbose(verbose);
281
			break;
282
		default:
283
			log_debug("rde_dispatch_imsg: unexpected imsg %d",
284
			    imsg.hdr.type);
285
			break;
286
		}
287
		imsg_free(&imsg);
288
	}
289
	if (!shut)
290
		imsg_event_add(iev);
291
	else {
292
		/* this pipe is dead, so remove the event handler */
293
		event_del(&iev->ev);
294
		event_loopexit(NULL);
295
	}
296
}
297
298
/* ARGSUSED */
299
static void
300
rde_dispatch_parent(int fd, short event, void *bula)
301
{
302
	static struct eigrpd_conf *nconf;
303
	static struct iface	*niface;
304
	static struct eigrp	*neigrp;
305
	struct eigrp_iface	*nei;
306
	struct imsg		 imsg;
307
	struct imsgev		*iev = bula;
308
	struct imsgbuf		*ibuf;
309
	struct kif		*kif;
310
	ssize_t			 n;
311
	int			 shut = 0;
312
313
	ibuf = &iev->ibuf;
314
315
	if (event & EV_READ) {
316
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
317
			fatal("imsg_read error");
318
		if (n == 0)	/* connection closed */
319
			shut = 1;
320
	}
321
	if (event & EV_WRITE) {
322
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
323
			fatal("msgbuf_write");
324
		if (n == 0)	/* connection closed */
325
			shut = 1;
326
	}
327
328
	for (;;) {
329
		if ((n = imsg_get(ibuf, &imsg)) == -1)
330
			fatal("rde_dispatch_parent: imsg_get error");
331
		if (n == 0)
332
			break;
333
334
		switch (imsg.hdr.type) {
335
		case IMSG_IFDOWN:
336
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
337
			    sizeof(struct kif))
338
				fatalx("IFDOWN imsg with wrong len");
339
			kif = imsg.data;
340
			rde_check_link_down(kif->ifindex);
341
			break;
342
		case IMSG_NETWORK_ADD:
343
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
344
			    sizeof(struct kroute))
345
				fatalx("IMSG_NETWORK_ADD imsg with wrong len");
346
			rt_redist_set(imsg.data, 0);
347
			break;
348
		case IMSG_NETWORK_DEL:
349
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
350
			    sizeof(struct kroute))
351
				fatalx("IMSG_NETWORK_DEL imsg with wrong len");
352
			rt_redist_set(imsg.data, 1);
353
			break;
354
		case IMSG_SOCKET_IPC:
355
			if (iev_eigrpe) {
356
				log_warnx("%s: received unexpected imsg fd "
357
				    "to eigrpe", __func__);
358
				break;
359
			}
360
			if ((fd = imsg.fd) == -1) {
361
				log_warnx("%s: expected to receive imsg fd to "
362
				    "eigrpe but didn't receive any", __func__);
363
				break;
364
			}
365
366
			iev_eigrpe = malloc(sizeof(struct imsgev));
367
			if (iev_eigrpe == NULL)
368
				fatal(NULL);
369
			imsg_init(&iev_eigrpe->ibuf, fd);
370
			iev_eigrpe->handler = rde_dispatch_imsg;
371
			iev_eigrpe->events = EV_READ;
372
			event_set(&iev_eigrpe->ev, iev_eigrpe->ibuf.fd,
373
			    iev_eigrpe->events, iev_eigrpe->handler,
374
			    iev_eigrpe);
375
			event_add(&iev_eigrpe->ev, NULL);
376
			break;
377
		case IMSG_RECONF_CONF:
378
			if ((nconf = malloc(sizeof(struct eigrpd_conf))) ==
379
			    NULL)
380
				fatal(NULL);
381
			memcpy(nconf, imsg.data, sizeof(struct eigrpd_conf));
382
383
			TAILQ_INIT(&nconf->iface_list);
384
			TAILQ_INIT(&nconf->instances);
385
			break;
386
		case IMSG_RECONF_INSTANCE:
387
			if ((neigrp = malloc(sizeof(struct eigrp))) == NULL)
388
				fatal(NULL);
389
			memcpy(neigrp, imsg.data, sizeof(struct eigrp));
390
391
			SIMPLEQ_INIT(&neigrp->redist_list);
392
			TAILQ_INIT(&neigrp->ei_list);
393
			RB_INIT(&neigrp->nbrs);
394
			RB_INIT(&neigrp->topology);
395
			TAILQ_INSERT_TAIL(&nconf->instances, neigrp, entry);
396
			break;
397
		case IMSG_RECONF_IFACE:
398
			niface = imsg.data;
399
			niface = if_lookup(nconf, niface->ifindex);
400
			if (niface)
401
				break;
402
403
			if ((niface = malloc(sizeof(struct iface))) == NULL)
404
				fatal(NULL);
405
			memcpy(niface, imsg.data, sizeof(struct iface));
406
407
			TAILQ_INIT(&niface->ei_list);
408
			TAILQ_INIT(&niface->addr_list);
409
			TAILQ_INSERT_TAIL(&nconf->iface_list, niface, entry);
410
			break;
411
		case IMSG_RECONF_EIGRP_IFACE:
412
			if (niface == NULL)
413
				break;
414
			if ((nei = malloc(sizeof(struct eigrp_iface))) == NULL)
415
				fatal(NULL);
416
			memcpy(nei, imsg.data, sizeof(struct eigrp_iface));
417
418
			nei->iface = niface;
419
			nei->eigrp = neigrp;
420
			TAILQ_INIT(&nei->nbr_list);
421
			TAILQ_INIT(&nei->update_list);
422
			TAILQ_INIT(&nei->query_list);
423
			TAILQ_INIT(&nei->summary_list);
424
			TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry);
425
			TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry);
426
			if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) !=
427
			    NULL)
428
				fatalx("rde_dispatch_parent: "
429
				    "RB_INSERT(ifaces_by_id) failed");
430
			break;
431
		case IMSG_RECONF_END:
432
			merge_config(rdeconf, nconf);
433
			nconf = NULL;
434
			break;
435
		default:
436
			log_debug("%s: unexpected imsg %d", __func__,
437
			    imsg.hdr.type);
438
			break;
439
		}
440
		imsg_free(&imsg);
441
	}
442
	if (!shut)
443
		imsg_event_add(iev);
444
	else {
445
		/* this pipe is dead, so remove the event handler */
446
		event_del(&iev->ev);
447
		event_loopexit(NULL);
448
	}
449
}
450
451
void
452
rde_instance_init(struct eigrp *eigrp)
453
{
454
	struct rde_nbr		 nbr;
455
456
	memset(&nbr, 0, sizeof(nbr));
457
	nbr.flags = F_RDE_NBR_SELF | F_RDE_NBR_REDIST;
458
	eigrp->rnbr_redist = rde_nbr_new(NBR_IDSELF, &nbr);
459
	eigrp->rnbr_redist->eigrp = eigrp;
460
	nbr.flags = F_RDE_NBR_SELF | F_RDE_NBR_SUMMARY;
461
	eigrp->rnbr_summary = rde_nbr_new(NBR_IDSELF, &nbr);
462
	eigrp->rnbr_summary->eigrp = eigrp;
463
}
464
465
void
466
rde_instance_del(struct eigrp *eigrp)
467
{
468
	struct rde_nbr		*nbr, *safe;
469
	struct rt_node		*rn;
470
471
	/* clear topology */
472
	while((rn = RB_MIN(rt_tree, &eigrp->topology)) != NULL)
473
		rt_del(rn);
474
475
	/* clear nbrs */
476
	RB_FOREACH_SAFE(nbr, rde_nbr_head, &rde_nbrs, safe)
477
		if (nbr->eigrp == eigrp)
478
			rde_nbr_del(nbr, 0);
479
	rde_nbr_del(eigrp->rnbr_redist, 0);
480
	rde_nbr_del(eigrp->rnbr_summary, 0);
481
482
	free(eigrp);
483
}
484
485
void
486
rde_send_change_kroute(struct rt_node *rn, struct eigrp_route *route)
487
{
488
	struct eigrp	*eigrp = route->nbr->eigrp;
489
	struct kroute	 kr;
490
	struct in6_addr	 lo6 = IN6ADDR_LOOPBACK_INIT;
491
492
	log_debug("%s: %s nbr %s", __func__, log_prefix(rn),
493
	    log_addr(eigrp->af, &route->nbr->addr));
494
495
	memset(&kr, 0, sizeof(kr));
496
	kr.af = eigrp->af;
497
	kr.prefix = rn->prefix;
498
	kr.prefixlen = rn->prefixlen;
499
	if (route->nbr->ei) {
500
		kr.nexthop = route->nexthop;
501
		kr.ifindex = route->nbr->ei->iface->ifindex;
502
	} else {
503
		switch (eigrp->af) {
504
		case AF_INET:
505
			kr.nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
506
			break;
507
		case AF_INET6:
508
			kr.nexthop.v6 = lo6;
509
			break;
510
		default:
511
			fatalx("rde_send_delete_kroute: unknown af");
512
			break;
513
		}
514
		kr.flags = F_BLACKHOLE;
515
	}
516
	if (route->type == EIGRP_ROUTE_EXTERNAL)
517
		kr.priority = rdeconf->fib_priority_external;
518
	else {
519
		if (route->nbr->flags & F_RDE_NBR_SUMMARY)
520
			kr.priority = rdeconf->fib_priority_summary;
521
		else
522
			kr.priority = rdeconf->fib_priority_internal;
523
	}
524
525
	rde_imsg_compose_parent(IMSG_KROUTE_CHANGE, 0, &kr, sizeof(kr));
526
527
	route->flags |= F_EIGRP_ROUTE_INSTALLED;
528
}
529
530
void
531
rde_send_delete_kroute(struct rt_node *rn, struct eigrp_route *route)
532
{
533
	struct eigrp	*eigrp = route->nbr->eigrp;
534
	struct kroute	 kr;
535
	struct in6_addr	 lo6 = IN6ADDR_LOOPBACK_INIT;
536
537
	log_debug("%s: %s nbr %s", __func__, log_prefix(rn),
538
	    log_addr(eigrp->af, &route->nbr->addr));
539
540
	memset(&kr, 0, sizeof(kr));
541
	kr.af = eigrp->af;
542
	kr.prefix = rn->prefix;
543
	kr.prefixlen = rn->prefixlen;
544
	if (route->nbr->ei) {
545
		kr.nexthop = route->nexthop;
546
		kr.ifindex = route->nbr->ei->iface->ifindex;
547
	} else {
548
		switch (eigrp->af) {
549
		case AF_INET:
550
			kr.nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
551
			break;
552
		case AF_INET6:
553
			kr.nexthop.v6 = lo6;
554
			break;
555
		default:
556
			fatalx("rde_send_delete_kroute: unknown af");
557
			break;
558
		}
559
		kr.flags = F_BLACKHOLE;
560
	}
561
	if (route->type == EIGRP_ROUTE_EXTERNAL)
562
		kr.priority = rdeconf->fib_priority_external;
563
	else {
564
		if (route->nbr->flags & F_RDE_NBR_SUMMARY)
565
			kr.priority = rdeconf->fib_priority_summary;
566
		else
567
			kr.priority = rdeconf->fib_priority_internal;
568
	}
569
570
	rde_imsg_compose_parent(IMSG_KROUTE_DELETE, 0, &kr, sizeof(kr));
571
572
	route->flags &= ~F_EIGRP_ROUTE_INSTALLED;
573
}
574
575
static struct redistribute *
576
eigrp_redistribute(struct eigrp *eigrp, struct kroute *kr)
577
{
578
	struct redistribute	*r;
579
	uint8_t			 is_default = 0;
580
	union eigrpd_addr	 addr;
581
582
	/* only allow the default route via REDIST_DEFAULT */
583
	if (!eigrp_addrisset(kr->af, &kr->prefix) && kr->prefixlen == 0)
584
		is_default = 1;
585
586
	SIMPLEQ_FOREACH(r, &eigrp->redist_list, entry) {
587
		switch (r->type & ~REDIST_NO) {
588
		case REDIST_STATIC:
589
			if (is_default)
590
				continue;
591
			if (kr->flags & F_STATIC)
592
				return (r->type & REDIST_NO ? NULL : r);
593
			break;
594
		case REDIST_RIP:
595
			if (is_default)
596
				continue;
597
			if (kr->priority == RTP_RIP)
598
				return (r->type & REDIST_NO ? NULL : r);
599
			break;
600
		case REDIST_OSPF:
601
			if (is_default)
602
				continue;
603
			if (kr->priority == RTP_OSPF)
604
				return (r->type & REDIST_NO ? NULL : r);
605
			break;
606
		case REDIST_CONNECTED:
607
			if (is_default)
608
				continue;
609
			if (kr->flags & F_CONNECTED)
610
				return (r->type & REDIST_NO ? NULL : r);
611
			break;
612
		case REDIST_ADDR:
613
			if (eigrp_addrisset(r->af, &r->addr) &&
614
			    r->prefixlen == 0) {
615
				if (is_default)
616
					return (r->type & REDIST_NO ? NULL : r);
617
				else
618
					return (0);
619
			}
620
621
			eigrp_applymask(kr->af, &addr, &kr->prefix,
622
			    r->prefixlen);
623
			if (eigrp_addrcmp(kr->af, &addr, &r->addr) == 0 &&
624
			    kr->prefixlen >= r->prefixlen)
625
				return (r->type & REDIST_NO ? NULL : r);
626
			break;
627
		case REDIST_DEFAULT:
628
			if (is_default)
629
				return (r->type & REDIST_NO ? NULL : r);
630
			break;
631
		}
632
	}
633
634
	return (NULL);
635
}
636
637
static void
638
rt_redist_set(struct kroute *kr, int withdraw)
639
{
640
	struct eigrp		*eigrp;
641
	struct redistribute	*r;
642
	struct redist_metric	*rmetric;
643
	struct rinfo		 ri;
644
645
	TAILQ_FOREACH(eigrp, &rdeconf->instances, entry) {
646
		if (eigrp->af != kr->af)
647
			continue;
648
649
		r = eigrp_redistribute(eigrp, kr);
650
		if (r == NULL)
651
			continue;
652
653
		if (r->metric)
654
			rmetric = r->metric;
655
		else if (eigrp->dflt_metric)
656
			rmetric = eigrp->dflt_metric;
657
		else
658
			continue;
659
660
		memset(&ri, 0, sizeof(ri));
661
		ri.af = kr->af;
662
		ri.type = EIGRP_ROUTE_EXTERNAL;
663
		ri.prefix = kr->prefix;
664
		ri.prefixlen = kr->prefixlen;
665
666
		/* metric */
667
		if (withdraw)
668
			ri.metric.delay = EIGRP_INFINITE_METRIC;
669
		else
670
			ri.metric.delay = eigrp_composite_delay(rmetric->delay);
671
		ri.metric.bandwidth =
672
		    eigrp_composite_bandwidth(rmetric->bandwidth);
673
		metric_encode_mtu(ri.metric.mtu, rmetric->mtu);
674
		ri.metric.hop_count = 0;
675
		ri.metric.reliability = rmetric->reliability;
676
		ri.metric.load = rmetric->load;
677
		ri.metric.tag = 0;
678
		ri.metric.flags = 0;
679
680
		/* external metric */
681
		ri.emetric.routerid = htonl(rdeconf->rtr_id.s_addr);
682
		ri.emetric.as = r->emetric.as;
683
		ri.emetric.tag = r->emetric.tag;
684
		ri.emetric.metric = r->emetric.metric;
685
		if (kr->priority == rdeconf->fib_priority_internal)
686
			ri.emetric.protocol = EIGRP_EXT_PROTO_EIGRP;
687
		else if (kr->priority == RTP_STATIC)
688
			ri.emetric.protocol = EIGRP_EXT_PROTO_STATIC;
689
		else if (kr->priority == RTP_RIP)
690
			ri.emetric.protocol = EIGRP_EXT_PROTO_RIP;
691
		else if (kr->priority == RTP_OSPF)
692
			ri.emetric.protocol = EIGRP_EXT_PROTO_OSPF;
693
		else
694
			ri.emetric.protocol = EIGRP_EXT_PROTO_CONN;
695
		ri.emetric.flags = 0;
696
697
		rde_check_update(eigrp->rnbr_redist, &ri);
698
	}
699
}
700
701
void
702
rt_summary_set(struct eigrp *eigrp, struct summary_addr *summary,
703
    struct classic_metric *metric)
704
{
705
	struct rinfo		 ri;
706
707
	memset(&ri, 0, sizeof(ri));
708
	ri.af = eigrp->af;
709
	ri.type = EIGRP_ROUTE_INTERNAL;
710
	ri.prefix = summary->prefix;
711
	ri.prefixlen = summary->prefixlen;
712
	ri.metric = *metric;
713
714
	rde_check_update(eigrp->rnbr_summary, &ri);
715
}
716
717
/* send all known routing information to new neighbor */
718
static void
719
rt_snap(struct rde_nbr *nbr)
720
{
721
	struct eigrp		*eigrp = nbr->eigrp;
722
	struct rt_node		*rn;
723
	struct rinfo		 ri;
724
725
	RB_FOREACH(rn, rt_tree, &eigrp->topology)
726
		if (rn->state == DUAL_STA_PASSIVE &&
727
		    !rde_summary_check(nbr->ei, &rn->prefix, rn->prefixlen)) {
728
			rinfo_fill_successor(rn, &ri);
729
			rde_imsg_compose_eigrpe(IMSG_SEND_UPDATE,
730
			    nbr->peerid, 0, &ri, sizeof(ri));
731
		}
732
733
	rde_imsg_compose_eigrpe(IMSG_SEND_UPDATE_END, nbr->peerid, 0,
734
	    NULL, 0);
735
}
736
737
static struct ctl_rt *
738
rt_to_ctl(struct rt_node *rn, struct eigrp_route *route)
739
{
740
	static struct ctl_rt	 rtctl;
741
742
	memset(&rtctl, 0, sizeof(rtctl));
743
	rtctl.af = route->nbr->eigrp->af;
744
	rtctl.as = route->nbr->eigrp->as;
745
	rtctl.prefix = rn->prefix;
746
	rtctl.prefixlen = rn->prefixlen;
747
	rtctl.type = route->type;
748
	rtctl.nexthop = route->nexthop;
749
	if (route->nbr->flags & F_RDE_NBR_REDIST)
750
		strlcpy(rtctl.ifname, "redistribute", sizeof(rtctl.ifname));
751
	else if (route->nbr->flags & F_RDE_NBR_SUMMARY)
752
		strlcpy(rtctl.ifname, "summary", sizeof(rtctl.ifname));
753
	else
754
		memcpy(rtctl.ifname, route->nbr->ei->iface->name,
755
		    sizeof(rtctl.ifname));
756
	rtctl.distance = route->distance;
757
	rtctl.rdistance = route->rdistance;
758
	rtctl.fdistance = rn->successor.fdistance;
759
	rtctl.state = rn->state;
760
	/* metric */
761
	rtctl.metric.delay = eigrp_real_delay(route->metric.delay);
762
	/* translate to microseconds */
763
	rtctl.metric.delay *= 10;
764
	rtctl.metric.bandwidth = eigrp_real_bandwidth(route->metric.bandwidth);
765
	rtctl.metric.mtu = metric_decode_mtu(route->metric.mtu);
766
	rtctl.metric.hop_count = route->metric.hop_count;
767
	rtctl.metric.reliability = route->metric.reliability;
768
	rtctl.metric.load = route->metric.load;
769
	/* external metric */
770
	rtctl.emetric = route->emetric;
771
772
	if (route->nbr == rn->successor.nbr)
773
		rtctl.flags |= F_CTL_RT_SUCCESSOR;
774
	else if (route->rdistance < rn->successor.fdistance)
775
		rtctl.flags |= F_CTL_RT_FSUCCESSOR;
776
777
	return (&rtctl);
778
}
779
780
static void
781
rt_dump(struct ctl_show_topology_req *treq, pid_t pid)
782
{
783
	struct eigrp		*eigrp;
784
	struct rt_node		*rn;
785
	struct eigrp_route	*route;
786
	struct ctl_rt		*rtctl;
787
	int			 first = 1;
788
789
	TAILQ_FOREACH(eigrp, &rdeconf->instances, entry) {
790
		RB_FOREACH(rn, rt_tree, &eigrp->topology) {
791
			if (eigrp_addrisset(treq->af, &treq->prefix) &&
792
			    eigrp_addrcmp(treq->af, &treq->prefix,
793
			    &rn->prefix))
794
				continue;
795
796
			if (treq->prefixlen &&
797
			    (treq->prefixlen != rn->prefixlen))
798
				continue;
799
800
			first = 1;
801
			TAILQ_FOREACH(route, &rn->routes, entry) {
802
				if (treq->flags & F_CTL_ACTIVE &&
803
				    !(rn->state & DUAL_STA_ACTIVE_ALL))
804
					continue;
805
				if (!(treq->flags & F_CTL_ALLLINKS) &&
806
				    route->rdistance >= rn->successor.fdistance)
807
					continue;
808
809
				rtctl = rt_to_ctl(rn, route);
810
				if (first) {
811
					rtctl->flags |= F_CTL_RT_FIRST;
812
					first = 0;
813
				}
814
				rde_imsg_compose_eigrpe(IMSG_CTL_SHOW_TOPOLOGY,
815
				    0, pid, rtctl, sizeof(*rtctl));
816
			}
817
		}
818
	}
819
}