4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
31 #include <net/route.h>
37 #include <sys/fcntl.h>
47 * routing_events.c - this file contains routines to retrieve routing socket
48 * events and package them for high level processing.
51 #define RTMBUFSZ sizeof (struct rt_msghdr) + \
52 (RTAX_MAX * sizeof (struct sockaddr_storage))
54 static void printaddrs(int, void *);
55 static char *printaddr(void **);
56 static void *getaddr(int, int, void *);
57 static void setaddr(int, int *, void *, struct sockaddr
*);
61 /* Routing information. */
65 struct sockaddr_storage addr
[RTAX_MAX
];
68 /* Interface information. */
72 struct sockaddr_storage addr
[RTAX_MAX
];
75 /* Interface address information. */
78 struct ifa_msghdr ifa
;
79 struct sockaddr_storage addr
[RTAX_MAX
];
83 static int v4_sock
= -1;
84 static int v6_sock
= -1;
85 static pthread_t v4_routing
, v6_routing
;
91 static char typestr
[12]; /* strlen("type ") + enough for an int */
103 (void) snprintf(typestr
, sizeof (typestr
), "type %d", type
);
110 routing_events_v4(void *arg
)
113 union rtm_buf buffer
;
114 struct rt_msghdr
*rtm
;
115 struct ifa_msghdr
*ifa
;
116 char *addrs
, *if_name
;
117 struct sockaddr_dl
*addr_dl
;
118 struct sockaddr
*addr
, *netmask
;
119 nwamd_event_t ip_event
;
121 nlog(LOG_DEBUG
, "v4 routing socket %d", v4_sock
);
125 n
= read(v4_sock
, &buffer
, sizeof (buffer
));
126 if (n
== -1 && errno
== EAGAIN
) {
128 } else if (n
== -1) {
129 nlog(LOG_ERR
, "error reading routing socket "
131 /* Low likelihood. What's recovery path? */
135 if (rtm
->rtm_msglen
< n
) {
136 nlog(LOG_ERR
, "only read %d bytes from "
137 "routing socket but message claims to be "
138 "of length %d", rtm
->rtm_msglen
);
142 if (rtm
->rtm_version
!= RTM_VERSION
) {
143 nlog(LOG_ERR
, "tossing routing message of "
144 "version %d type %d", rtm
->rtm_version
,
149 if (rtm
->rtm_msglen
!= n
) {
150 nlog(LOG_DEBUG
, "routing message of %d size came from "
151 "read of %d on socket %d", rtm
->rtm_msglen
,
155 switch (rtm
->rtm_type
) {
162 addrs
= (char *)ifa
+ sizeof (*ifa
);
164 nlog(LOG_DEBUG
, "v4 routing message %s: "
165 "index %d flags %x", rtmtype_str(rtm
->rtm_type
),
166 ifa
->ifam_index
, ifa
->ifam_flags
);
168 if ((addr
= (struct sockaddr
*)getaddr(RTA_IFA
,
169 ifa
->ifam_addrs
, addrs
)) == NULL
)
172 /* Ignore routing socket messages for 0.0.0.0 */
174 if (((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
176 nlog(LOG_DEBUG
, "routing_events_v4: "
177 "tossing message for 0.0.0.0");
181 if ((netmask
= (struct sockaddr
*)getaddr(RTA_NETMASK
,
182 ifa
->ifam_addrs
, addrs
)) == NULL
)
185 if ((addr_dl
= (struct sockaddr_dl
*)getaddr
186 (RTA_IFP
, ifa
->ifam_addrs
, addrs
)) == NULL
)
189 * We don't use the lladdr in this structure so we can
192 addr_dl
->sdl_data
[addr_dl
->sdl_nlen
] = 0;
193 if_name
= addr_dl
->sdl_data
; /* no lifnum */
195 if (ifa
->ifam_index
== 0) {
196 nlog(LOG_DEBUG
, "tossing index 0 message");
199 if (ifa
->ifam_type
!= rtm
->rtm_type
) {
201 "routing_events_v4: unhandled type %d",
206 printaddrs(ifa
->ifam_addrs
, addrs
);
208 /* Create and enqueue IF_STATE event */
209 ip_event
= nwamd_event_init_if_state(if_name
,
211 (rtm
->rtm_type
== RTM_NEWADDR
||
212 rtm
->rtm_type
== RTM_CHGADDR
? B_TRUE
: B_FALSE
),
214 if (ip_event
!= NULL
)
215 nwamd_event_enqueue(ip_event
);
225 routing_events_v6(void *arg
)
228 union rtm_buf buffer
;
229 struct rt_msghdr
*rtm
;
230 struct ifa_msghdr
*ifa
;
231 char *addrs
, *if_name
;
232 struct sockaddr_dl
*addr_dl
;
233 struct sockaddr
*addr
, *netmask
;
234 nwamd_event_t ip_event
;
236 nlog(LOG_DEBUG
, "v6 routing socket %d", v6_sock
);
241 n
= read(v6_sock
, &buffer
, sizeof (buffer
));
242 if (n
== -1 && errno
== EAGAIN
) {
244 } else if (n
== -1) {
245 nlog(LOG_ERR
, "error reading routing socket "
247 /* Low likelihood. What's recovery path? */
251 if (rtm
->rtm_msglen
< n
) {
252 nlog(LOG_ERR
, "only read %d bytes from "
253 "routing socket but message claims to be "
254 "of length %d", rtm
->rtm_msglen
);
258 if (rtm
->rtm_version
!= RTM_VERSION
) {
259 nlog(LOG_ERR
, "tossing routing message of "
260 "version %d type %d", rtm
->rtm_version
,
265 if (rtm
->rtm_msglen
!= n
) {
266 nlog(LOG_DEBUG
, "routing message of %d size came from "
267 "read of %d on socket %d", rtm
->rtm_msglen
,
271 switch (rtm
->rtm_type
) {
278 addrs
= (char *)ifa
+ sizeof (*ifa
);
280 nlog(LOG_DEBUG
, "v6 routing message %s: "
281 "index %d flags %x", rtmtype_str(rtm
->rtm_type
),
282 ifa
->ifam_index
, ifa
->ifam_flags
);
284 if ((addr
= (struct sockaddr
*)getaddr(RTA_IFA
,
285 ifa
->ifam_addrs
, addrs
)) == NULL
)
288 /* Ignore routing socket messages for :: & linklocal */
290 if (IN6_IS_ADDR_UNSPECIFIED(
291 &((struct sockaddr_in6
*)addr
)->sin6_addr
)) {
292 nlog(LOG_INFO
, "routing_events_v6: "
293 "tossing message for ::");
297 if (IN6_IS_ADDR_LINKLOCAL(
298 &((struct sockaddr_in6
*)addr
)->sin6_addr
)) {
299 nlog(LOG_INFO
, "routing_events_v6: "
300 "tossing message for link local address");
305 (struct sockaddr
*)getaddr(RTA_NETMASK
,
306 ifa
->ifam_addrs
, addrs
)) == NULL
)
309 if ((addr_dl
= (struct sockaddr_dl
*)getaddr
310 (RTA_IFP
, ifa
->ifam_addrs
, addrs
)) == NULL
)
313 * We don't use the lladdr in this structure so we can
316 addr_dl
->sdl_data
[addr_dl
->sdl_nlen
] = 0;
317 if_name
= addr_dl
->sdl_data
; /* no lifnum */
319 if (ifa
->ifam_index
== 0) {
320 nlog(LOG_DEBUG
, "tossing index 0 message");
323 if (ifa
->ifam_type
!= rtm
->rtm_type
) {
325 "routing_events_v6: unhandled type %d",
330 printaddrs(ifa
->ifam_addrs
, addrs
);
332 /* Create and enqueue IF_STATE event */
333 ip_event
= nwamd_event_init_if_state(if_name
,
335 (rtm
->rtm_type
== RTM_NEWADDR
||
336 rtm
->rtm_type
== RTM_CHGADDR
? B_TRUE
: B_FALSE
),
338 if (ip_event
!= NULL
)
339 nwamd_event_enqueue(ip_event
);
349 nwamd_routing_events_init(void)
354 * Initialize routing sockets here so that we know the routing threads
355 * (and any requests to add a route) will be working with a valid socket
356 * by the time we start handling events.
358 v4_sock
= socket(AF_ROUTE
, SOCK_RAW
, AF_INET
);
360 pfail("failed to open v4 routing socket: %m");
362 v6_sock
= socket(AF_ROUTE
, SOCK_RAW
, AF_INET6
);
364 pfail("failed to open v6 routing socket: %m");
366 (void) pthread_attr_init(&attr
);
367 (void) pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
368 if (pthread_create(&v4_routing
, &attr
, routing_events_v4
, NULL
) != 0 ||
369 pthread_create(&v6_routing
, &attr
, routing_events_v6
, NULL
) != 0)
370 pfail("routing thread creation failed");
371 (void) pthread_attr_destroy(&attr
);
375 nwamd_routing_events_fini(void)
377 (void) pthread_cancel(v4_routing
);
378 (void) pthread_cancel(v6_routing
);
382 nwamd_add_route(struct sockaddr
*dest
, struct sockaddr
*mask
,
383 struct sockaddr
*gateway
, const char *ifname
)
385 char rtbuf
[RTMBUFSZ
];
386 /* LINTED E_BAD_PTR_CAST_ALIGN */
387 struct rt_msghdr
*rtm
= (struct rt_msghdr
*)rtbuf
;
388 void *addrs
= rtbuf
+ sizeof (struct rt_msghdr
);
389 struct sockaddr_dl sdl
;
393 af
= gateway
->sa_family
;
395 /* retrieve the index value for the interface */
396 if ((index
= if_nametoindex(ifname
)) == 0) {
397 nlog(LOG_ERR
, "nwamd_add_route: if_nametoindex failed on %s",
402 (void) bzero(&sdl
, sizeof (struct sockaddr_dl
));
403 sdl
.sdl_family
= AF_LINK
;
404 sdl
.sdl_index
= index
;
406 (void) bzero(rtm
, RTMBUFSZ
);
407 rtm
->rtm_pid
= getpid();
408 rtm
->rtm_type
= RTM_ADD
;
409 rtm
->rtm_flags
= RTF_UP
| RTF_STATIC
| RTF_GATEWAY
;
410 rtm
->rtm_version
= RTM_VERSION
;
411 rtm
->rtm_seq
= ++seq
;
412 rtm
->rtm_msglen
= sizeof (rtbuf
);
413 setaddr(RTA_DST
, &rtm
->rtm_addrs
, &addrs
, dest
);
414 setaddr(RTA_GATEWAY
, &rtm
->rtm_addrs
, &addrs
, gateway
);
415 setaddr(RTA_NETMASK
, &rtm
->rtm_addrs
, &addrs
, mask
);
416 setaddr(RTA_IFP
, &rtm
->rtm_addrs
, &addrs
, (struct sockaddr
*)&sdl
);
418 if ((rlen
= write(af
== AF_INET
? v4_sock
: v6_sock
,
419 rtbuf
, rtm
->rtm_msglen
)) < 0) {
420 nlog(LOG_ERR
, "nwamd_add_route: "
421 "got error %s writing to routing socket", strerror(errno
));
422 } else if (rlen
< rtm
->rtm_msglen
) {
423 nlog(LOG_ERR
, "nwamd_add_route: "
424 "only wrote %d bytes of %d to routing socket\n",
425 rlen
, rtm
->rtm_msglen
);
430 printaddr(void **address
)
432 static char buffer
[80];
433 sa_family_t family
= *(sa_family_t
*)*address
;
434 struct sockaddr_in
*s4
= *address
;
435 struct sockaddr_in6
*s6
= *address
;
436 struct sockaddr_dl
*dl
= *address
;
440 (void) inet_ntop(AF_UNSPEC
, &s4
->sin_addr
, buffer
,
442 *address
= (char *)*address
+ sizeof (*s4
);
445 (void) inet_ntop(AF_INET
, &s4
->sin_addr
, buffer
,
447 *address
= (char *)*address
+ sizeof (*s4
);
450 (void) inet_ntop(AF_INET6
, &s6
->sin6_addr
, buffer
,
452 *address
= (char *)*address
+ sizeof (*s6
);
455 (void) snprintf(buffer
, sizeof (buffer
), "link %.*s",
456 dl
->sdl_nlen
, dl
->sdl_data
);
457 *address
= (char *)*address
+ sizeof (*dl
);
461 * We can't reliably update the size of this thing
462 * because we don't know what its type is. So bump
463 * it by a sockaddr_in and see what happens. The
464 * caller should really make sure this never happens.
466 *address
= (char *)*address
+ sizeof (*s4
);
467 (void) snprintf(buffer
, sizeof (buffer
),
468 "unknown address family %d", family
);
475 printaddrs(int mask
, void *address
)
480 nlog(LOG_DEBUG
, "destination address: %s", printaddr(&address
));
481 if (mask
& RTA_GATEWAY
)
482 nlog(LOG_DEBUG
, "gateway address: %s", printaddr(&address
));
483 if (mask
& RTA_NETMASK
)
484 nlog(LOG_DEBUG
, "netmask: %s", printaddr(&address
));
485 if (mask
& RTA_GENMASK
)
486 nlog(LOG_DEBUG
, "cloning mask: %s", printaddr(&address
));
488 nlog(LOG_DEBUG
, "interface name: %s", printaddr(&address
));
490 nlog(LOG_DEBUG
, "interface address: %s", printaddr(&address
));
491 if (mask
& RTA_AUTHOR
)
492 nlog(LOG_DEBUG
, "author: %s", printaddr(&address
));
494 nlog(LOG_DEBUG
, "broadcast address: %s", printaddr(&address
));
498 nextaddr(void **address
)
500 sa_family_t family
= *(sa_family_t
*)*address
;
505 *address
= (char *)*address
+ sizeof (struct sockaddr_in
);
508 *address
= (char *)*address
+ sizeof (struct sockaddr_in6
);
511 *address
= (char *)*address
+ sizeof (struct sockaddr_dl
);
514 nlog(LOG_ERR
, "unknown af (%d) while parsing rtm", family
);
520 getaddr(int addrid
, int mask
, void *addresses
)
525 if ((mask
& addrid
) == 0)
528 for (i
= 1; i
< addrid
; i
<<= 1) {
536 setaddr(int addrid
, int *maskp
, void *addressesp
, struct sockaddr
*address
)
538 struct sockaddr
*p
= *((struct sockaddr
**)addressesp
);
542 switch (address
->sa_family
) {
544 (void) memcpy(p
, address
, sizeof (struct sockaddr_in
));
547 (void) memcpy(p
, address
, sizeof (struct sockaddr_in6
));
550 (void) memcpy(p
, address
, sizeof (struct sockaddr_dl
));
553 nlog(LOG_ERR
, "setaddr: unknown af (%d) while setting addr",
557 nextaddr(addressesp
);