xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/tables.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 /*
36  * Routing Table Management Daemon
37  */
38 #include "defs.h"
39 
40 boolean_t	install = _B_TRUE;	/* update kernel routing table */
41 struct rthash	*net_hashes[IPV6_ABITS + 1];
42 
43 /*
44  * Size of routing socket message used by in.ripngd which includes the header,
45  * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
46  * plus space for the RTA_IFP (a sockaddr_dl).
47  */
48 #define	RIPNG_RTM_MSGLEN	sizeof (struct rt_msghdr) +	\
49 				sizeof (struct sockaddr_in6) +	\
50 				sizeof (struct sockaddr_in6) +	\
51 				sizeof (struct sockaddr_in6) +	\
52 				sizeof (struct sockaddr_dl)
53 
54 static int	rtmseq;				/* rtm_seq sequence number */
55 static int	rtsock;				/* Routing socket */
56 static struct	rt_msghdr	*rt_msg;	/* Routing socket message */
57 static struct	sockaddr_in6	*rta_dst;	/* RTA_DST sockaddr */
58 static struct	sockaddr_in6	*rta_gateway;	/* RTA_GATEWAY sockaddr */
59 static struct	sockaddr_in6	*rta_netmask;	/* RTA_NETMASK sockaddr */
60 static struct	sockaddr_dl	*rta_ifp;	/* RTA_IFP sockaddr */
61 
62 /* simulate vax insque and remque instructions. */
63 
64 typedef struct vq {
65 	caddr_t	 fwd, back;
66 } vq_t;
67 
68 #define	insque(e, p)	((vq_t *)(e))->back = (caddr_t)(p); \
69 			((vq_t *)(e))->fwd = \
70 				(caddr_t)((vq_t *)((vq_t *)(p))->fwd); \
71 			((vq_t *)((vq_t *)(p))->fwd)->back = (caddr_t)(e); \
72 			((vq_t *)(p))->fwd = (caddr_t)(e);
73 
74 #define	remque(e)	((vq_t *)((vq_t *)(e))->back)->fwd =  \
75 				(caddr_t)((vq_t *)(e))->fwd; \
76 			((vq_t *)((vq_t *)(e))->fwd)->back = \
77 				(caddr_t)((vq_t *)(e))->back; \
78 			((vq_t *)(e))->fwd = NULL; \
79 			((vq_t *)(e))->back = NULL;
80 
81 static void
82 log_change(int level, struct rt_entry *orig, struct rt_entry *new)
83 {
84 	char buf1[INET6_ADDRSTRLEN];
85 	char buf2[INET6_ADDRSTRLEN];
86 	char buf3[INET6_ADDRSTRLEN];
87 
88 	(void) inet_ntop(AF_INET6, (void *) &new->rt_dst, buf1, sizeof (buf1));
89 	(void) inet_ntop(AF_INET6, (void *) &orig->rt_router, buf2,
90 	    sizeof (buf2));
91 	(void) inet_ntop(AF_INET6, (void *) &new->rt_router, buf3,
92 	    sizeof (buf3));
93 
94 	syslog(level, "\tdst %s from gw %s if %s to gw %s if %s metric %d",
95 	    buf1, buf2,
96 	    (orig->rt_ifp != NULL && orig->rt_ifp->int_name != NULL) ?
97 		orig->rt_ifp->int_name : "(noname)",
98 	    buf3,
99 	    (new->rt_ifp != NULL && new->rt_ifp->int_name != NULL) ?
100 		new->rt_ifp->int_name : "(noname)", new->rt_metric);
101 }
102 
103 static void
104 log_single(int level, struct rt_entry *rt)
105 {
106 	char buf1[INET6_ADDRSTRLEN];
107 	char buf2[INET6_ADDRSTRLEN];
108 
109 	(void) inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1));
110 	(void) inet_ntop(AF_INET6, (void *)&rt->rt_router, buf2, sizeof (buf2));
111 
112 	syslog(level, "\tdst %s gw %s if %s metric %d",
113 	    buf1, buf2,
114 	    (rt->rt_ifp != NULL && rt->rt_ifp->int_name != NULL) ?
115 		rt->rt_ifp->int_name : "(noname)",
116 	    rt->rt_metric);
117 }
118 
119 /*
120  * Computes a hash by XOR-ing the (up to sixteen) octets that make up an IPv6
121  * address.  This function assumes that that there are no one-bits in the
122  * address beyond the prefix length.
123  */
124 static uint8_t
125 rthash(struct in6_addr *dst, int prefix_length)
126 {
127 	uint8_t val = 0;
128 	int i;
129 
130 	for (i = 0; prefix_length > 0; prefix_length -= 8, i++)
131 		val ^= dst->s6_addr[i];
132 	return (val);
133 }
134 
135 /*
136  * Given a prefix length, fill in the struct in6_addr representing an IPv6
137  * netmask.
138  */
139 static void
140 rtmask_to_bits(uint_t prefix_length, struct in6_addr *prefix)
141 {
142 	uint_t mask = 0xff;
143 	int i;
144 
145 	bzero((caddr_t)prefix, sizeof (struct in6_addr));
146 	for (i = 0; prefix_length >= 8; prefix_length -= 8, i++)
147 		prefix->s6_addr[i] = 0xff;
148 	mask = (mask << (8 - prefix_length));
149 	if (mask != 0)
150 		prefix->s6_addr[i] = mask;
151 }
152 
153 void
154 rtcreate_prefix(struct in6_addr *p1, struct in6_addr *dst, int bits)
155 {
156 	uchar_t mask;
157 	int j;
158 
159 	for (j = 0; bits >= 8; bits -= 8, j++)
160 		dst->s6_addr[j] = p1->s6_addr[j];
161 
162 	if (bits != 0) {
163 		mask = 0xff << (8 - bits);
164 		dst->s6_addr[j] = p1->s6_addr[j] & mask;
165 		j++;
166 	}
167 
168 	for (; j < 16; j++)
169 		dst->s6_addr[j] = 0;
170 }
171 
172 /*
173  * Lookup dst in the tables for an exact match.
174  */
175 struct rt_entry *
176 rtlookup(struct in6_addr *dst, int prefix_length)
177 {
178 	struct rt_entry *rt;
179 	struct rthash *rh;
180 	uint_t	hash;
181 
182 	if (net_hashes[prefix_length] == NULL)
183 		return (NULL);
184 
185 	hash = rthash(dst, prefix_length);
186 
187 	rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
188 
189 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
190 		if (rt->rt_hash != hash)
191 			continue;
192 		if (IN6_ARE_ADDR_EQUAL(&rt->rt_dst, dst) &&
193 		    rt->rt_prefix_length == prefix_length)
194 			return (rt);
195 	}
196 	return (NULL);
197 }
198 
199 /*
200  * Given an IPv6 prefix (destination and prefix length), a gateway, an
201  * interface name and route flags, send down the requested command returning
202  * the return value and errno (in the case of error) from the write() on the
203  * routing socket.
204  */
205 static int
206 rtcmd(uchar_t type, struct in6_addr *dst, struct in6_addr *gateway,
207     uint_t prefix_length, char *name, int flags)
208 {
209 	int rlen;
210 
211 	rta_ifp->sdl_index = if_nametoindex(name);
212 	if (rta_ifp->sdl_index == 0)
213 		return (-1);
214 
215 	rta_dst->sin6_addr = *dst;
216 	rta_gateway->sin6_addr = *gateway;
217 	rtmask_to_bits(prefix_length, &rta_netmask->sin6_addr);
218 
219 	rt_msg->rtm_type = type;
220 	rt_msg->rtm_flags = flags;
221 	rt_msg->rtm_seq = ++rtmseq;
222 	rlen = write(rtsock, rt_msg, RIPNG_RTM_MSGLEN);
223 	if (rlen >= 0 && rlen < RIPNG_RTM_MSGLEN) {
224 		syslog(LOG_ERR,
225 		    "rtcmd: write to routing socket got only %d for rlen\n",
226 		    rlen);
227 	}
228 	return (rlen);
229 }
230 
231 void
232 rtadd(struct in6_addr *dst, struct in6_addr *gate, int prefix_length,
233     int metric, int tag, boolean_t ifroute, struct interface *ifp)
234 {
235 	struct rt_entry *rt;
236 	struct rthash *rh;
237 	uint_t hash;
238 	struct in6_addr pdst;
239 	int rlen;
240 
241 	if (metric >= HOPCNT_INFINITY)
242 		return;
243 
244 	if (net_hashes[prefix_length] == NULL) {
245 		struct rthash *trh;
246 
247 		rh = (struct rthash *)
248 		    calloc(ROUTEHASHSIZ, sizeof (struct rt_entry));
249 		if (rh == NULL)
250 			return;
251 		for (trh = rh; trh < &rh[ROUTEHASHSIZ]; trh++)
252 			trh->rt_forw = trh->rt_back = (struct rt_entry *)trh;
253 		net_hashes[prefix_length] = rh;
254 	}
255 	rtcreate_prefix(dst, &pdst, prefix_length);
256 
257 	hash = rthash(&pdst, prefix_length);
258 	rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
259 	rt = (struct rt_entry *)malloc(sizeof (*rt));
260 	if (rt == NULL) {
261 		/*
262 		 * In the event of an allocation failure, log the error and
263 		 * continue since on the next update another attempt will be
264 		 * made.
265 		 */
266 		syslog(LOG_ERR, "rtadd: malloc: %m");
267 		return;
268 	}
269 	rt->rt_hash = hash;
270 	rt->rt_dst = pdst;
271 	rt->rt_prefix_length = prefix_length;
272 	rt->rt_router = *gate;
273 	rt->rt_metric = metric;
274 	rt->rt_tag = tag;
275 	rt->rt_timer = 0;
276 	rt->rt_flags = RTF_UP;
277 	if (prefix_length == IPV6_ABITS)
278 		rt->rt_flags |= RTF_HOST;
279 	rt->rt_state = RTS_CHANGED;
280 	if (ifroute) {
281 		rt->rt_state |= RTS_INTERFACE;
282 		if (ifp->int_flags & RIP6_IFF_PRIVATE)
283 			rt->rt_state |= RTS_PRIVATE;
284 	} else {
285 		rt->rt_flags |= RTF_GATEWAY;
286 	}
287 	rt->rt_ifp = ifp;
288 
289 	insque(rt, rh);
290 	TRACE_ACTION("ADD", rt);
291 	/*
292 	 * If the RTM_ADD fails because the gateway is unreachable
293 	 * from this host, discard the entry.  This should never
294 	 * happen.
295 	 */
296 	if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
297 		rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
298 		    prefix_length, ifp->int_name, rt->rt_flags);
299 		if (rlen < 0) {
300 			if (errno != EEXIST) {
301 				syslog(LOG_ERR, "rtadd: RTM_ADD: %m");
302 				log_single(LOG_ERR, rt);
303 			}
304 			if (errno == ENETUNREACH) {
305 				TRACE_ACTION("DELETE", rt);
306 				remque(rt);
307 				free((char *)rt);
308 			}
309 		} else if (rlen < RIPNG_RTM_MSGLEN) {
310 			log_single(LOG_ERR, rt);
311 		}
312 	}
313 }
314 
315 /*
316  * Handle the case when the metric changes but the gateway is the same (or the
317  * interface index associated with the gateway changes), or when both gateway
318  * and metric changes, or when only the gateway changes but the existing route
319  * is more than one-half of EXPIRE_TIME in age. Note that routes with metric >=
320  * HOPCNT_INFINITY are not in the kernel.
321  */
322 void
323 rtchange(struct rt_entry *rt, struct in6_addr *gate, short metric,
324     struct interface *ifp)
325 {
326 	boolean_t dokern = _B_FALSE;
327 	boolean_t dokerndelete;
328 	boolean_t metricchanged = _B_FALSE;
329 	int oldmetric;
330 	struct rt_entry oldroute;
331 	int rlen;
332 
333 	if (metric >= HOPCNT_INFINITY) {
334 		rtdown(rt);
335 		return;
336 	}
337 
338 	if (!IN6_ARE_ADDR_EQUAL(&rt->rt_router, gate) || rt->rt_ifp != ifp)
339 		dokern = _B_TRUE;
340 	oldmetric = rt->rt_metric;
341 	if (oldmetric >= HOPCNT_INFINITY)
342 		dokerndelete = _B_FALSE;
343 	else
344 		dokerndelete = dokern;
345 	if (metric != rt->rt_metric)
346 		metricchanged = _B_TRUE;
347 	rt->rt_timer = 0;
348 	if (dokern || metricchanged) {
349 		TRACE_ACTION("CHANGE FROM", rt);
350 		if ((rt->rt_state & RTS_INTERFACE) && metric != 0) {
351 			rt->rt_state &= ~RTS_INTERFACE;
352 			if (rt->rt_ifp != NULL) {
353 				syslog(LOG_ERR,
354 				    "rtchange: changing route from "
355 				    "interface %s (timed out)",
356 				    (rt->rt_ifp->int_name != NULL) ?
357 					rt->rt_ifp->int_name : "(noname)");
358 			} else {
359 				syslog(LOG_ERR,
360 				    "rtchange: "
361 				    "changing route no interface for route");
362 			}
363 		}
364 		if (dokern) {
365 			oldroute = *rt;
366 			rt->rt_router = *gate;
367 			rt->rt_ifp = ifp;
368 		}
369 		rt->rt_metric = metric;
370 		if (!(rt->rt_state & RTS_INTERFACE))
371 			rt->rt_flags |= RTF_GATEWAY;
372 		else
373 			rt->rt_flags &= ~RTF_GATEWAY;
374 		rt->rt_state |= RTS_CHANGED;
375 		TRACE_ACTION("CHANGE TO", rt);
376 	}
377 	if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
378 		if (dokerndelete) {
379 			rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
380 			    rt->rt_prefix_length, rt->rt_ifp->int_name,
381 			    rt->rt_flags);
382 			if (rlen < 0) {
383 				if (errno != EEXIST) {
384 					syslog(LOG_ERR,
385 					    "rtchange: RTM_ADD: %m");
386 					log_change(LOG_ERR, rt,
387 					    (struct rt_entry *)&oldroute);
388 				}
389 			} else if (rlen < RIPNG_RTM_MSGLEN) {
390 				log_change(LOG_ERR, rt,
391 				    (struct rt_entry *)&oldroute);
392 			}
393 
394 			rlen = rtcmd(RTM_DELETE, &oldroute.rt_dst,
395 			    &oldroute.rt_router, oldroute.rt_prefix_length,
396 			    oldroute.rt_ifp->int_name, oldroute.rt_flags);
397 			if (rlen < 0) {
398 				syslog(LOG_ERR, "rtchange: RTM_DELETE: %m");
399 				log_change(LOG_ERR, rt,
400 				    (struct rt_entry *)&oldroute);
401 			} else if (rlen < RIPNG_RTM_MSGLEN) {
402 				log_change(LOG_ERR, rt,
403 				    (struct rt_entry *)&oldroute);
404 			}
405 		} else if (dokern || oldmetric >= HOPCNT_INFINITY) {
406 			rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
407 			    rt->rt_prefix_length, ifp->int_name, rt->rt_flags);
408 			if (rlen < 0 && errno != EEXIST) {
409 				syslog(LOG_ERR, "rtchange: RTM_ADD: %m");
410 				log_change(LOG_ERR, rt,
411 				    (struct rt_entry *)&oldroute);
412 			} else if (rlen < RIPNG_RTM_MSGLEN) {
413 				log_change(LOG_ERR, rt,
414 				    (struct rt_entry *)&oldroute);
415 			}
416 		}
417 	}
418 }
419 
420 void
421 rtdown(struct rt_entry *rt)
422 {
423 	int rlen;
424 
425 	if (rt->rt_metric != HOPCNT_INFINITY) {
426 		TRACE_ACTION("DELETE", rt);
427 		if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
428 			rlen = rtcmd(RTM_DELETE, &rt->rt_dst,
429 			    &rt->rt_router, rt->rt_prefix_length,
430 			    rt->rt_ifp->int_name, rt->rt_flags);
431 			if (rlen < 0) {
432 				syslog(LOG_ERR, "rtdown: RTM_DELETE: %m");
433 				log_single(LOG_ERR, rt);
434 			} else if (rlen < RIPNG_RTM_MSGLEN) {
435 				log_single(LOG_ERR, rt);
436 			}
437 		}
438 		rt->rt_metric = HOPCNT_INFINITY;
439 		rt->rt_state |= RTS_CHANGED;
440 	}
441 	if (rt->rt_timer < EXPIRE_TIME)
442 		rt->rt_timer = EXPIRE_TIME;
443 }
444 
445 void
446 rtdelete(struct rt_entry *rt)
447 {
448 
449 	if (rt->rt_state & RTS_INTERFACE) {
450 		if (rt->rt_ifp != NULL) {
451 			syslog(LOG_ERR,
452 			    "rtdelete: "
453 			    "deleting route to interface %s (timed out)",
454 			    (rt->rt_ifp->int_name != NULL) ?
455 				rt->rt_ifp->int_name : "(noname)");
456 			log_single(LOG_ERR, rt);
457 		}
458 	}
459 	rtdown(rt);
460 	remque(rt);
461 	free((char *)rt);
462 }
463 
464 /*
465  * Mark all the routes heard off a particular interface "down".  Unlike the
466  * routes managed by in.routed, all of these routes have an interface associated
467  * with them.
468  */
469 void
470 rtpurgeif(struct interface *ifp)
471 {
472 	struct rthash *rh;
473 	struct rt_entry *rt;
474 	int i;
475 
476 	for (i = IPV6_ABITS; i >= 0; i--) {
477 		if (net_hashes[i] == NULL)
478 			continue;
479 
480 		for (rh = net_hashes[i];
481 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
482 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
483 			    rt = rt->rt_forw) {
484 				if (rt->rt_ifp == ifp) {
485 					rtdown(rt);
486 					rt->rt_ifp = NULL;
487 					rt->rt_state &= ~RTS_INTERFACE;
488 				}
489 			}
490 		}
491 	}
492 }
493 
494 /*
495  * Called when the subnetmask has changed on one or more interfaces.
496  * Re-evaluates all non-interface routes by doing a rtchange so that
497  * routes that were believed to be host routes before the netmask change
498  * can be converted to network routes and vice versa.
499  */
500 void
501 rtchangeall(void)
502 {
503 	struct rthash *rh;
504 	struct rt_entry *rt;
505 	int i;
506 
507 	for (i = IPV6_ABITS; i >= 0; i--) {
508 		if (net_hashes[i] == NULL)
509 			continue;
510 
511 		for (rh = net_hashes[i];
512 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
513 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
514 			    rt = rt->rt_forw) {
515 				if ((rt->rt_state & RTS_INTERFACE) == 0) {
516 					rtchange(rt, &rt->rt_router,
517 					    rt->rt_metric, rt->rt_ifp);
518 				}
519 			}
520 		}
521 	}
522 }
523 
524 static void
525 rtdumpentry(FILE *fp, struct rt_entry *rt)
526 {
527 	char buf1[INET6_ADDRSTRLEN];
528 	static struct bits {
529 		ulong_t	t_bits;
530 		char	*t_name;
531 	} flagbits[] = {
532 		/* BEGIN CSTYLED */
533 		{ RTF_UP,		"UP" },
534 		{ RTF_GATEWAY,		"GATEWAY" },
535 		{ RTF_HOST,		"HOST" },
536 		{ 0,			NULL }
537 		/* END CSTYLED */
538 	}, statebits[] = {
539 		/* BEGIN CSTYLED */
540 		{ RTS_INTERFACE,	"INTERFACE" },
541 		{ RTS_CHANGED,		"CHANGED" },
542 		{ RTS_PRIVATE,		"PRIVATE" },
543 		{ 0,			NULL }
544 		/* END CSTYLED */
545 	};
546 	struct bits *p;
547 	boolean_t first;
548 	char c;
549 
550 	(void) fprintf(fp, "prefix %s/%d ",
551 	    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1)),
552 	    rt->rt_prefix_length);
553 	(void) fprintf(fp, "via %s metric %d timer %d",
554 	    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1, sizeof (buf1)),
555 	    rt->rt_metric, rt->rt_timer);
556 	if (rt->rt_ifp != NULL) {
557 		(void) fprintf(fp, " if %s",
558 		    (rt->rt_ifp->int_name != NULL) ?
559 			rt->rt_ifp->int_name : "(noname)");
560 	}
561 	(void) fprintf(fp, " state");
562 	c = ' ';
563 	for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
564 		if ((rt->rt_state & p->t_bits) == 0)
565 			continue;
566 		(void) fprintf(fp, "%c%s", c, p->t_name);
567 		if (first) {
568 			c = '|';
569 			first = _B_FALSE;
570 		}
571 	}
572 	if (first)
573 		(void) fprintf(fp, " 0");
574 	if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
575 		c = ' ';
576 		for (first = _B_TRUE, p = flagbits; p->t_bits > 0; p++) {
577 			if ((rt->rt_flags & p->t_bits) == 0)
578 				continue;
579 			(void) fprintf(fp, "%c%s", c, p->t_name);
580 			if (first) {
581 				c = '|';
582 				first = _B_FALSE;
583 			}
584 		}
585 	}
586 	(void) putc('\n', fp);
587 	(void) fflush(fp);
588 }
589 
590 static void
591 rtdump2(FILE *fp)
592 {
593 	struct rthash *rh;
594 	struct rt_entry *rt;
595 	int i;
596 
597 	for (i = IPV6_ABITS; i >= 0; i--) {
598 		if (net_hashes[i] == NULL)
599 			continue;
600 
601 		for (rh = net_hashes[i];
602 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
603 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
604 			    rt = rt->rt_forw) {
605 				rtdumpentry(fp, rt);
606 			}
607 		}
608 	}
609 }
610 
611 void
612 rtdump(void)
613 {
614 	if (ftrace != NULL)
615 		rtdump2(ftrace);
616 	else
617 		rtdump2(stderr);
618 }
619 
620 /*
621  * Create a routing socket for sending RTM_ADD and RTM_DELETE messages and
622  * initialize the routing socket message header and as much of the sockaddrs
623  * as possible.
624  */
625 void
626 setup_rtsock(void)
627 {
628 	char *cp;
629 	int off = 0;
630 
631 	rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
632 	if (rtsock < 0) {
633 		syslog(LOG_ERR, "setup_rtsock: socket: %m");
634 		exit(EXIT_FAILURE);
635 	}
636 
637 	/* We don't want to listen to our own messages */
638 	if (setsockopt(rtsock, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
639 	    sizeof (off)) < 0) {
640 		syslog(LOG_ERR, "setup_rtsock: setsockopt: SO_USELOOPBACK: %m");
641 		exit(EXIT_FAILURE);
642 	}
643 
644 	/*
645 	 * Allocate storage for the routing socket message.
646 	 */
647 	rt_msg = (struct rt_msghdr *)malloc(RIPNG_RTM_MSGLEN);
648 	if (rt_msg == NULL) {
649 		syslog(LOG_ERR, "setup_rtsock: malloc: %m");
650 		exit(EXIT_FAILURE);
651 	}
652 
653 	/*
654 	 * Initialize the routing socket message by zero-filling it and then
655 	 * setting the fields where are constant through the lifetime of the
656 	 * process.
657 	 */
658 	bzero(rt_msg, RIPNG_RTM_MSGLEN);
659 	rt_msg->rtm_msglen = RIPNG_RTM_MSGLEN;
660 	rt_msg->rtm_version = RTM_VERSION;
661 	rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
662 	rt_msg->rtm_pid = getpid();
663 	if (rt_msg->rtm_pid < 0) {
664 		syslog(LOG_ERR, "setup_rtsock: getpid: %m");
665 		exit(EXIT_FAILURE);
666 	}
667 
668 	/*
669 	 * Initialize the constant portion of the RTA_DST sockaddr.
670 	 */
671 	cp = (char *)rt_msg + sizeof (struct rt_msghdr);
672 	rta_dst = (struct sockaddr_in6 *)cp;
673 	rta_dst->sin6_family = AF_INET6;
674 
675 	/*
676 	 * Initialize the constant portion of the RTA_GATEWAY sockaddr.
677 	 */
678 	cp += sizeof (struct sockaddr_in6);
679 	rta_gateway = (struct sockaddr_in6 *)cp;
680 	rta_gateway->sin6_family = AF_INET6;
681 
682 	/*
683 	 * Initialize the constant portion of the RTA_NETMASK sockaddr.
684 	 */
685 	cp += sizeof (struct sockaddr_in6);
686 	rta_netmask = (struct sockaddr_in6 *)cp;
687 	rta_netmask->sin6_family = AF_INET6;
688 
689 	/*
690 	 * Initialize the constant portion of the RTA_IFP sockaddr.
691 	 */
692 	cp += sizeof (struct sockaddr_in6);
693 	rta_ifp = (struct sockaddr_dl *)cp;
694 	rta_ifp->sdl_family = AF_LINK;
695 }
696