]> git.proxmox.com Git - mirror_frr.git/blame - zebra/kernel_socket.c
2004-01-05 Greg Troxel <gdt@ahi.ir.bbn.com>
[mirror_frr.git] / zebra / kernel_socket.c
CommitLineData
718e3744 1/* Kernel communication using routing socket.
2 * Copyright (C) 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "if.h"
25#include "prefix.h"
26#include "sockunion.h"
27#include "connected.h"
28#include "memory.h"
29#include "ioctl.h"
30#include "log.h"
31#include "str.h"
32#include "table.h"
33#include "rib.h"
edd7c245 34#include "privs.h"
718e3744 35
36#include "zebra/interface.h"
37#include "zebra/zserv.h"
38#include "zebra/debug.h"
39
edd7c245 40extern struct zebra_privs_t zserv_privs;
9bcdb638 41extern struct zebra_t zebrad;
edd7c245 42
718e3744 43/* Socket length roundup function. */
44#define ROUNDUP(a) \
45 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
46
47/* And this macro is wrapper for handling sa_len. */
30be8028 48#if defined(HAVE_SA_LEN)
718e3744 49#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
30be8028 50#elif defined(HAVE_IPV6)
3e95a074 51#define WRAPUP(X) \
30be8028 52 do { \
3e95a074 53 (((struct sockaddr *)(X))->sa_family == AF_INET ? \
54 ROUNDUP(sizeof(struct sockaddr_in)):\
55 (((struct sockaddr *)(X))->sa_family == AF_INET6 ? \
56 ROUNDUP(sizeof(struct sockaddr_in6)) : \
57 (((struct sockaddr *)(X))->sa_family == AF_LINK ? \
30be8028 58 ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))) \
59 } while (0)
60#else /* HAVE_IPV6 */
61#define WRAPUP(X) \
62 (((struct sockaddr *)(X))->sa_family == AF_INET ? \
63 ROUNDUP(sizeof(struct sockaddr_in)):\
64 (((struct sockaddr *)(X))->sa_family == AF_LINK ? \
65 ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))
718e3744 66#endif /* HAVE_SA_LEN */
67
68/* Routing socket message types. */
69struct message rtm_type_str[] =
70{
71 {RTM_ADD, "RTM_ADD"},
72 {RTM_DELETE, "RTM_DELETE"},
73 {RTM_CHANGE, "RTM_CHANGE"},
74 {RTM_GET, "RTM_GET"},
75 {RTM_LOSING, "RTM_LOSING"},
76 {RTM_REDIRECT, "RTM_REDIRECT"},
77 {RTM_MISS, "RTM_MISS"},
78 {RTM_LOCK, "RTM_LOCK"},
79 {RTM_OLDADD, "RTM_OLDADD"},
80 {RTM_OLDDEL, "RTM_OLDDEL"},
81 {RTM_RESOLVE, "RTM_RESOLVE"},
82 {RTM_NEWADDR, "RTM_NEWADDR"},
83 {RTM_DELADDR, "RTM_DELADDR"},
84 {RTM_IFINFO, "RTM_IFINFO"},
85#ifdef RTM_OIFINFO
86 {RTM_OIFINFO, "RTM_OIFINFO"},
87#endif /* RTM_OIFINFO */
88#ifdef RTM_NEWMADDR
89 {RTM_NEWMADDR, "RTM_NEWMADDR"},
90#endif /* RTM_NEWMADDR */
91#ifdef RTM_DELMADDR
92 {RTM_DELMADDR, "RTM_DELMADDR"},
93#endif /* RTM_DELMADDR */
94#ifdef RTM_IFANNOUNCE
95 {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
96#endif /* RTM_IFANNOUNCE */
97 {0, NULL}
98};
99
100struct message rtm_flag_str[] =
101{
102 {RTF_UP, "UP"},
103 {RTF_GATEWAY, "GATEWAY"},
104 {RTF_HOST, "HOST"},
105 {RTF_REJECT, "REJECT"},
106 {RTF_DYNAMIC, "DYNAMIC"},
107 {RTF_MODIFIED, "MODIFIED"},
108 {RTF_DONE, "DONE"},
109#ifdef RTF_MASK
110 {RTF_MASK, "MASK"},
111#endif /* RTF_MASK */
112 {RTF_CLONING, "CLONING"},
113 {RTF_XRESOLVE, "XRESOLVE"},
114 {RTF_LLINFO, "LLINFO"},
115 {RTF_STATIC, "STATIC"},
116 {RTF_BLACKHOLE, "BLACKHOLE"},
117 {RTF_PROTO1, "PROTO1"},
118 {RTF_PROTO2, "PROTO2"},
119#ifdef RTF_PRCLONING
120 {RTF_PRCLONING, "PRCLONING"},
121#endif /* RTF_PRCLONING */
122#ifdef RTF_WASCLONED
123 {RTF_WASCLONED, "WASCLONED"},
124#endif /* RTF_WASCLONED */
125#ifdef RTF_PROTO3
126 {RTF_PROTO3, "PROTO3"},
127#endif /* RTF_PROTO3 */
128#ifdef RTF_PINNED
129 {RTF_PINNED, "PINNED"},
130#endif /* RTF_PINNED */
131#ifdef RTF_LOCAL
132 {RTF_LOCAL, "LOCAL"},
133#endif /* RTF_LOCAL */
134#ifdef RTF_BROADCAST
135 {RTF_BROADCAST, "BROADCAST"},
136#endif /* RTF_BROADCAST */
137#ifdef RTF_MULTICAST
138 {RTF_MULTICAST, "MULTICAST"},
139#endif /* RTF_MULTICAST */
140 {0, NULL}
141};
142
143/* Kernel routing update socket. */
144int routing_sock = -1;
145
146/* Yes I'm checking ugly routing socket behavior. */
147/* #define DEBUG */
148
149/* Supported address family check. */
150static int
151af_check (int family)
152{
153 if (family == AF_INET)
154 return 1;
155#ifdef HAVE_IPV6
156 if (family == AF_INET6)
157 return 1;
158#endif /* HAVE_IPV6 */
159 return 0;
160}
161\f
162/* Dump routing table flag for debug purpose. */
163void
164rtm_flag_dump (int flag)
165{
166 struct message *mes;
167 static char buf[BUFSIZ];
168
81dfcaa2 169 buf[0] = '0';
718e3744 170 for (mes = rtm_flag_str; mes->key != 0; mes++)
171 {
172 if (mes->key & flag)
173 {
174 strlcat (buf, mes->str, BUFSIZ);
175 strlcat (buf, " ", BUFSIZ);
176 }
177 }
178 zlog_info ("Kernel: %s", buf);
179}
180
181#ifdef RTM_IFANNOUNCE
182/* Interface adding function */
183int
184ifan_read (struct if_announcemsghdr *ifan)
185{
186 struct interface *ifp;
187
188 ifp = if_lookup_by_index (ifan->ifan_index);
189 if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
190 {
191 /* Create Interface */
192 ifp = if_get_by_name (ifan->ifan_name);
193 ifp->ifindex = ifan->ifan_index;
194
195 if_add_update (ifp);
196 }
197 else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
198 {
199 if_delete_update (ifp);
200 if_delete (ifp);
201 }
202
203 if_get_flags (ifp);
204 if_get_mtu (ifp);
205 if_get_metric (ifp);
206
207 if (IS_ZEBRA_DEBUG_KERNEL)
208 zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
209
210 return 0;
211}
212#endif /* RTM_IFANNOUNCE */
213
da26e3b6 214/*
215 * Handle struct if_msghdr obtained from reading routing socket or
216 * sysctl (from interface_list). There may or may not be sockaddrs
217 * present after the header.
218 */
718e3744 219int
220ifm_read (struct if_msghdr *ifm)
221{
3e95a074 222 struct interface *ifp = NULL;
718e3744 223 struct sockaddr_dl *sdl = NULL;
3e95a074 224 char ifname[IFNAMSIZ];
225
da26e3b6 226 /* paranoia: sanity check structure */
227 if (ifm->ifm_msglen < sizeof(struct if_msghdr))
228 {
229 zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n",
230 ifm->ifm_msglen);
231 return -1;
232 }
233
234 /*
235 * Check for a sockaddr_dl following the message.
236 */
3e95a074 237#ifdef SUNOS_5
238 int i;
239 struct sockaddr *sa;
240 u_char *cp = (u_char *)(ifm + 1);
718e3744 241
3e95a074 242 /*
243 * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions
244 * is 12 bytes larger than the 32 bit version, so make adjustment
245 * here.
246 */
247 sa = (struct sockaddr *)cp;
248 if (sa->sa_family == AF_UNSPEC)
249 cp = cp + 12;
250
251 for (i = 1; i != 0; i <<= 1)
252 {
253 if (i & ifm->ifm_addrs)
254 {
255 sa = (struct sockaddr *)cp;
256 cp += WRAPUP(sa);
257 if (i & RTA_IFP)
258 {
259 sdl = (struct sockaddr_dl *)sa;
260 break;
261 }
262 }
263 }
da26e3b6 264 /*
265 * After here, If RTA_IFP was set in ifm_addrs, sdl should point to
266 * the sockaddr_dl.
267 */
3e95a074 268#else
da26e3b6 269 /* sockaddrs_present? */
270 if (ifm->ifm_addrs)
271 {
272 if (ifm->ifm_addrs == RTA_IFP)
273 {
274 /* just the one we want */
275 sdl = (struct sockaddr_dl *)(ifm + 1);
276 }
277 else
278 {
279 /*
280 * Not strictly an error, but more complicated parsing than
281 * is implemented is required to handle this case.
282 */
283 zlog_err ("ifm_read: addrs %x != RTA_IFP (unhandled, ignoring)\n",
284 ifm->ifm_addrs);
285 return -1;
286 }
287 }
288 /*
289 * Past here, either ifm_addrs == 0 or ifm_addrs == RTA_IFP and sdl
290 * points to a RTA_IFP sockaddr.
291 */
3e95a074 292#endif
718e3744 293
da26e3b6 294 /* Check that sdl, if present, is actually a sockaddr_dl before use. */
295 if (sdl != NULL)
296 switch (sdl->sdl_family)
297 {
298 case AF_LINK:
299 /* Standard AF for link-layer address sockaddrs. */
300 case AF_DLI:
301 /*
302 * XXX Comment in NetBSD net/if_dl.h says AF_DLI, but this
303 * seems wrong. Accept it for now.
304 */
305 break;
306
307 default:
308 zlog_err ("ifm_read: sockaddr_dl bad AF %d\n",
309 sdl->sdl_family);
310 return -1;
311 }
312
3e95a074 313 /*
da26e3b6 314 * Look up on ifindex. This is useful if this is an up/down
315 * notification for an interface of which we are already aware.
316 * (This happens on NetBSD 1.6.2, for example.)
3e95a074 317 */
da26e3b6 318 if (ifp == NULL)
319 ifp = if_lookup_by_index (ifm->ifm_index);
320
321
322 /*
323 * If lookup by index was unsuccessful and we have a name, try
324 * looking up by name. Interfaces specified in the configuration
325 * file for which the ifindex has not been determined will have
326 * ifindex == -1, and such interfaces are found by this search, and
327 * then their ifindex values can be filled in.
328 */
329 if (ifp != NULL && sdl != NULL)
3e95a074 330 {
da26e3b6 331 /*
332 * paranoia: sanity check name length. nlen does not include
333 * trailing zero, but IFNAMSIZ max length does.
334 */
335 if (sdl->sdl_nlen >= IFNAMSIZ)
336 {
337 zlog_err ("ifm_read: illegal sdl_nlen %d\n", sdl->sdl_nlen);
338 return -1;
339 }
340
30be8028 341 memcpy (ifname, sdl->sdl_data, sdl->sdl_nlen);
3e95a074 342 ifname[sdl->sdl_nlen] = '\0';
343 ifp = if_lookup_by_name (ifname);
344 }
718e3744 345
da26e3b6 346 /*
347 * If ifp does not exist or has an invalid index (-1), create or
348 * fill in an interface.
349 */
3e95a074 350 if ((ifp == NULL) || (ifp->ifindex == -1))
718e3744 351 {
352 /* Check interface's address.*/
353 if (! (ifm->ifm_addrs & RTA_IFP))
354 {
da26e3b6 355 zlog_warn ("Interface index %d (new) missing RTA_IFP sockaddr\n",
718e3744 356 ifm->ifm_index);
357 return -1;
358 }
359
da26e3b6 360 /*
361 * paranoia: sdl-finding code above guarantees that sdl is
362 * non-NULL and valid if RTA_IFP is set in ifm_addrs, so this
363 * check is in theory not necessary.
364 */
365 if (sdl == NULL)
366 {
367 zlog_warn ("ifm_read: no sockaddr_dl present");
368 return -1;
369 }
370
3e95a074 371 if (ifp == NULL)
372 ifp = if_create (sdl->sdl_data, sdl->sdl_nlen);
718e3744 373
718e3744 374 ifp->ifindex = ifm->ifm_index;
375 ifp->flags = ifm->ifm_flags;
376#if defined(__bsdi__)
377 if_kvm_get_mtu (ifp);
378#else
379 if_get_mtu (ifp);
380#endif /* __bsdi__ */
381 if_get_metric (ifp);
382
383 /* Fetch hardware address. */
384 if (sdl->sdl_family != AF_LINK)
385 {
386 zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK");
387 return -1;
388 }
da26e3b6 389 /* XXX sockaddr_dl can be larger than base structure */
718e3744 390 memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
391
392 if_add_update (ifp);
393 }
394 else
da26e3b6 395 /*
396 * Interface structure exists. Adjust stored flags from
397 * notification. If interface has up->down or down->up
398 * transition, call state change routines (to adjust routes,
399 * notify routing daemons, etc.). (Other flag changes are stored
400 * but apparently do not trigger action.)
401 */
718e3744 402 {
718e3744 403 if (if_is_up (ifp))
404 {
405 ifp->flags = ifm->ifm_flags;
406 if (! if_is_up (ifp))
407 if_down (ifp);
408 }
409 else
410 {
411 ifp->flags = ifm->ifm_flags;
412 if (if_is_up (ifp))
413 if_up (ifp);
414 }
415 }
416
417#ifdef HAVE_NET_RT_IFLIST
418 ifp->stats = ifm->ifm_data;
419#endif /* HAVE_NET_RT_IFLIST */
420
421 if (IS_ZEBRA_DEBUG_KERNEL)
422 zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
423
424 return 0;
425}
426\f
427/* Address read from struct ifa_msghdr. */
428void
429ifam_read_mesg (struct ifa_msghdr *ifm,
430 union sockunion *addr,
431 union sockunion *mask,
432 union sockunion *dest)
433{
434 caddr_t pnt, end;
435
436 pnt = (caddr_t)(ifm + 1);
437 end = ((caddr_t)ifm) + ifm->ifam_msglen;
438
439#define IFAMADDRGET(X,R) \
440 if (ifm->ifam_addrs & (R)) \
441 { \
442 int len = WRAPUP(pnt); \
443 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
444 memcpy ((caddr_t)(X), pnt, len); \
445 pnt += len; \
446 }
447#define IFAMMASKGET(X,R) \
448 if (ifm->ifam_addrs & (R)) \
449 { \
450 int len = WRAPUP(pnt); \
451 if ((X) != NULL) \
452 memcpy ((caddr_t)(X), pnt, len); \
453 pnt += len; \
454 }
455
456 /* Be sure structure is cleared */
457 memset (mask, 0, sizeof (union sockunion));
458 memset (addr, 0, sizeof (union sockunion));
459 memset (dest, 0, sizeof (union sockunion));
460
461 /* We fetch each socket variable into sockunion. */
462 IFAMADDRGET (NULL, RTA_DST);
463 IFAMADDRGET (NULL, RTA_GATEWAY);
464 IFAMMASKGET (mask, RTA_NETMASK);
465 IFAMADDRGET (NULL, RTA_GENMASK);
466 IFAMADDRGET (NULL, RTA_IFP);
467 IFAMADDRGET (addr, RTA_IFA);
468 IFAMADDRGET (NULL, RTA_AUTHOR);
469 IFAMADDRGET (dest, RTA_BRD);
470
471 /* Assert read up end point matches to end point */
472 if (pnt != end)
473 zlog_warn ("ifam_read() does't read all socket data");
474}
475
476/* Interface's address information get. */
477int
478ifam_read (struct ifa_msghdr *ifam)
479{
480 struct interface *ifp;
481 union sockunion addr, mask, gate;
482
483 /* Check does this interface exist or not. */
484 ifp = if_lookup_by_index (ifam->ifam_index);
485 if (ifp == NULL)
486 {
487 zlog_warn ("no interface for index %d", ifam->ifam_index);
488 return -1;
489 }
490
491 /* Allocate and read address information. */
492 ifam_read_mesg (ifam, &addr, &mask, &gate);
493
494 /* Check interface flag for implicit up of the interface. */
495 if_refresh (ifp);
496
497 /* Add connected address. */
498 switch (sockunion_family (&addr))
499 {
500 case AF_INET:
501 if (ifam->ifam_type == RTM_NEWADDR)
502 connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr,
503 ip_masklen (mask.sin.sin_addr),
504 &gate.sin.sin_addr, NULL);
505 else
506 connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr,
507 ip_masklen (mask.sin.sin_addr),
508 &gate.sin.sin_addr, NULL);
509 break;
510#ifdef HAVE_IPV6
511 case AF_INET6:
512 /* Unset interface index from link-local address when IPv6 stack
513 is KAME. */
514 if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr))
515 SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
516
517 if (ifam->ifam_type == RTM_NEWADDR)
518 connected_add_ipv6 (ifp,
519 &addr.sin6.sin6_addr,
520 ip6_masklen (mask.sin6.sin6_addr),
521 &gate.sin6.sin6_addr);
522 else
523 connected_delete_ipv6 (ifp,
524 &addr.sin6.sin6_addr,
525 ip6_masklen (mask.sin6.sin6_addr),
526 &gate.sin6.sin6_addr);
527 break;
528#endif /* HAVE_IPV6 */
529 default:
530 /* Unsupported family silently ignore... */
531 break;
532 }
533 return 0;
534}
535\f
536/* Interface function for reading kernel routing table information. */
537int
538rtm_read_mesg (struct rt_msghdr *rtm,
539 union sockunion *dest,
540 union sockunion *mask,
541 union sockunion *gate)
542{
543 caddr_t pnt, end;
544
545 /* Pnt points out socket data start point. */
546 pnt = (caddr_t)(rtm + 1);
547 end = ((caddr_t)rtm) + rtm->rtm_msglen;
548
549 /* rt_msghdr version check. */
550 if (rtm->rtm_version != RTM_VERSION)
551 zlog (NULL, LOG_WARNING,
552 "Routing message version different %d should be %d."
553 "This may cause problem\n", rtm->rtm_version, RTM_VERSION);
554
555#define RTMADDRGET(X,R) \
556 if (rtm->rtm_addrs & (R)) \
557 { \
558 int len = WRAPUP (pnt); \
559 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
560 memcpy ((caddr_t)(X), pnt, len); \
561 pnt += len; \
562 }
563#define RTMMASKGET(X,R) \
564 if (rtm->rtm_addrs & (R)) \
565 { \
566 int len = WRAPUP (pnt); \
567 if ((X) != NULL) \
568 memcpy ((caddr_t)(X), pnt, len); \
569 pnt += len; \
570 }
571
572 /* Be sure structure is cleared */
573 memset (dest, 0, sizeof (union sockunion));
574 memset (gate, 0, sizeof (union sockunion));
575 memset (mask, 0, sizeof (union sockunion));
576
577 /* We fetch each socket variable into sockunion. */
578 RTMADDRGET (dest, RTA_DST);
579 RTMADDRGET (gate, RTA_GATEWAY);
580 RTMMASKGET (mask, RTA_NETMASK);
581 RTMADDRGET (NULL, RTA_GENMASK);
582 RTMADDRGET (NULL, RTA_IFP);
583 RTMADDRGET (NULL, RTA_IFA);
584 RTMADDRGET (NULL, RTA_AUTHOR);
585 RTMADDRGET (NULL, RTA_BRD);
586
587 /* If there is netmask information set it's family same as
588 destination family*/
589 if (rtm->rtm_addrs & RTA_NETMASK)
590 mask->sa.sa_family = dest->sa.sa_family;
591
592 /* Assert read up to the end of pointer. */
593 if (pnt != end)
594 zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
595
596 return rtm->rtm_flags;
597}
598
599void
600rtm_read (struct rt_msghdr *rtm)
601{
602 int flags;
603 u_char zebra_flags;
604 union sockunion dest, mask, gate;
605
606 zebra_flags = 0;
607
608 /* Discard self send message. */
609 if (rtm->rtm_type != RTM_GET
610 && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
611 return;
612
613 /* Read destination and netmask and gateway from rtm message
614 structure. */
615 flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
616
617#ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
618 if (flags & RTF_CLONED)
619 return;
620#endif
621#ifdef RTF_WASCLONED /*freebsd*/
622 if (flags & RTF_WASCLONED)
623 return;
624#endif
625
626 if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
627 return;
628
629 /* This is connected route. */
630 if (! (flags & RTF_GATEWAY))
631 return;
632
633 if (flags & RTF_PROTO1)
634 SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);
635
636 /* This is persistent route. */
637 if (flags & RTF_STATIC)
638 SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);
639
81dfcaa2 640 /* This is a reject or blackhole route */
641 if (flags & RTF_REJECT)
642 SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT);
643 if (flags & RTF_BLACKHOLE)
644 SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE);
645
718e3744 646 if (dest.sa.sa_family == AF_INET)
647 {
648 struct prefix_ipv4 p;
649
650 p.family = AF_INET;
651 p.prefix = dest.sin.sin_addr;
652 if (flags & RTF_HOST)
653 p.prefixlen = IPV4_MAX_PREFIXLEN;
654 else
655 p.prefixlen = ip_masklen (mask.sin.sin_addr);
656
657 if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
658 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
659 &p, &gate.sin.sin_addr, 0, 0, 0, 0);
660 else
661 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
662 &p, &gate.sin.sin_addr, 0, 0);
663 }
664#ifdef HAVE_IPV6
665 if (dest.sa.sa_family == AF_INET6)
666 {
667 struct prefix_ipv6 p;
668 unsigned int ifindex = 0;
669
670 p.family = AF_INET6;
671 p.prefix = dest.sin6.sin6_addr;
672 if (flags & RTF_HOST)
673 p.prefixlen = IPV6_MAX_PREFIXLEN;
674 else
675 p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);
676
677#ifdef KAME
678 if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
679 {
680 ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
681 SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
682 }
683#endif /* KAME */
684
685 if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
686 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
687 &p, &gate.sin6.sin6_addr, ifindex, 0);
688 else
689 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
690 &p, &gate.sin6.sin6_addr, ifindex, 0);
691 }
692#endif /* HAVE_IPV6 */
693}
694
695/* Interface function for the kernel routing table updates. Support
696 for RTM_CHANGE will be needed. */
697int
698rtm_write (int message,
699 union sockunion *dest,
700 union sockunion *mask,
701 union sockunion *gate,
702 unsigned int index,
703 int zebra_flags,
704 int metric)
705{
706 int ret;
707 caddr_t pnt;
708 struct interface *ifp;
709 struct sockaddr_in tmp_gate;
710#ifdef HAVE_IPV6
711 struct sockaddr_in6 tmp_gate6;
712#endif /* HAVE_IPV6 */
713
714 /* Sequencial number of routing message. */
715 static int msg_seq = 0;
716
717 /* Struct of rt_msghdr and buffer for storing socket's data. */
718 struct
719 {
720 struct rt_msghdr rtm;
721 char buf[512];
722 } msg;
723
724 memset (&tmp_gate, 0, sizeof (struct sockaddr_in));
725 tmp_gate.sin_family = AF_INET;
726#ifdef HAVE_SIN_LEN
727 tmp_gate.sin_len = sizeof (struct sockaddr_in);
728#endif /* HAVE_SIN_LEN */
729
730#ifdef HAVE_IPV6
731 memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6));
732 tmp_gate6.sin6_family = AF_INET6;
733#ifdef SIN6_LEN
734 tmp_gate6.sin6_len = sizeof (struct sockaddr_in6);
735#endif /* SIN6_LEN */
736#endif /* HAVE_IPV6 */
737
738 if (routing_sock < 0)
739 return ZEBRA_ERR_EPERM;
740
741 /* Clear and set rt_msghdr values */
742 memset (&msg, 0, sizeof (struct rt_msghdr));
743 msg.rtm.rtm_version = RTM_VERSION;
744 msg.rtm.rtm_type = message;
745 msg.rtm.rtm_seq = msg_seq++;
746 msg.rtm.rtm_addrs = RTA_DST;
747 msg.rtm.rtm_addrs |= RTA_GATEWAY;
748 msg.rtm.rtm_flags = RTF_UP;
749 msg.rtm.rtm_index = index;
750
751 if (metric != 0)
752 {
753 msg.rtm.rtm_rmx.rmx_hopcount = metric;
754 msg.rtm.rtm_inits |= RTV_HOPCOUNT;
755 }
756
757 ifp = if_lookup_by_index (index);
758
759 if (gate && message == RTM_ADD)
760 msg.rtm.rtm_flags |= RTF_GATEWAY;
761
762 if (! gate && message == RTM_ADD && ifp &&
763 (ifp->flags & IFF_POINTOPOINT) == 0)
764 msg.rtm.rtm_flags |= RTF_CLONING;
765
766 /* If no protocol specific gateway is specified, use link
767 address for gateway. */
768 if (! gate)
769 {
770 if (!ifp)
771 {
772 zlog_warn ("no gateway found for interface index %d", index);
773 return -1;
774 }
775 gate = (union sockunion *) & ifp->sdl;
776 }
777
778 if (mask)
779 msg.rtm.rtm_addrs |= RTA_NETMASK;
780 else if (message == RTM_ADD)
781 msg.rtm.rtm_flags |= RTF_HOST;
782
783 /* Tagging route with flags */
784 msg.rtm.rtm_flags |= (RTF_PROTO1);
785
786 /* Additional flags. */
787 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
788 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
81dfcaa2 789 if (zebra_flags & ZEBRA_FLAG_REJECT)
790 msg.rtm.rtm_flags |= RTF_REJECT;
791
718e3744 792
793#ifdef HAVE_SIN_LEN
794#define SOCKADDRSET(X,R) \
795 if (msg.rtm.rtm_addrs & (R)) \
796 { \
797 int len = ROUNDUP ((X)->sa.sa_len); \
798 memcpy (pnt, (caddr_t)(X), len); \
799 pnt += len; \
800 }
801#else
802#define SOCKADDRSET(X,R) \
803 if (msg.rtm.rtm_addrs & (R)) \
804 { \
805 int len = ROUNDUP (sizeof((X)->sa)); \
806 memcpy (pnt, (caddr_t)(X), len); \
807 pnt += len; \
808 }
809#endif /* HAVE_SIN_LEN */
810
811 pnt = (caddr_t) msg.buf;
812
813 /* Write each socket data into rtm message buffer */
814 SOCKADDRSET (dest, RTA_DST);
815 SOCKADDRSET (gate, RTA_GATEWAY);
816 SOCKADDRSET (mask, RTA_NETMASK);
817
818 msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
819
820 ret = write (routing_sock, &msg, msg.rtm.rtm_msglen);
821
822 if (ret != msg.rtm.rtm_msglen)
823 {
824 if (errno == EEXIST)
825 return ZEBRA_ERR_RTEXIST;
826 if (errno == ENETUNREACH)
827 return ZEBRA_ERR_RTUNREACH;
828
829 zlog_warn ("write : %s (%d)", strerror (errno), errno);
830 return -1;
831 }
832 return 0;
833}
834
835\f
836#include "thread.h"
837#include "zebra/zserv.h"
838
718e3744 839/* For debug purpose. */
840void
841rtmsg_debug (struct rt_msghdr *rtm)
842{
843 char *type = "Unknown";
844 struct message *mes;
845
846 for (mes = rtm_type_str; mes->str; mes++)
847 if (mes->key == rtm->rtm_type)
848 {
849 type = mes->str;
850 break;
851 }
852
853 zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
854 rtm_flag_dump (rtm->rtm_flags);
855 zlog_info ("Kernel: message seq %d", rtm->rtm_seq);
856 zlog_info ("Kernel: pid %d", rtm->rtm_pid);
857}
858
859/* This is pretty gross, better suggestions welcome -- mhandler */
860#ifndef RTAX_MAX
861#ifdef RTA_NUMBITS
862#define RTAX_MAX RTA_NUMBITS
863#else
864#define RTAX_MAX 8
865#endif /* RTA_NUMBITS */
866#endif /* RTAX_MAX */
867
868/* Kernel routing table and interface updates via routing socket. */
869int
870kernel_read (struct thread *thread)
871{
872 int sock;
873 int nbytes;
874 struct rt_msghdr *rtm;
875
876 union
877 {
878 /* Routing information. */
879 struct
880 {
881 struct rt_msghdr rtm;
882 struct sockaddr addr[RTAX_MAX];
883 } r;
884
885 /* Interface information. */
886 struct
887 {
888 struct if_msghdr ifm;
889 struct sockaddr addr[RTAX_MAX];
890 } im;
891
892 /* Interface address information. */
893 struct
894 {
895 struct ifa_msghdr ifa;
896 struct sockaddr addr[RTAX_MAX];
897 } ia;
898
899#ifdef RTM_IFANNOUNCE
900 /* Interface arrival/departure */
901 struct
902 {
903 struct if_announcemsghdr ifan;
904 struct sockaddr addr[RTAX_MAX];
905 } ian;
906#endif /* RTM_IFANNOUNCE */
907
908 } buf;
909
910 /* Fetch routing socket. */
911 sock = THREAD_FD (thread);
912
913 nbytes= read (sock, &buf, sizeof buf);
914
915 if (nbytes <= 0)
916 {
917 if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
918 zlog_warn ("routing socket error: %s", strerror (errno));
919 return 0;
920 }
921
9bcdb638 922 thread_add_read (zebrad.master, kernel_read, NULL, sock);
718e3744 923
726f9b2b 924 if (IS_ZEBRA_DEBUG_KERNEL)
925 rtmsg_debug (&buf.r.rtm);
718e3744 926
927 rtm = &buf.r.rtm;
928
da26e3b6 929 if (rtm->rtm_msglen != nbytes)
930 {
931 zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n",
932 rtm->rtm_msglen, nbytes, rtm->rtm_type);
933 return -1;
934 }
935
718e3744 936 switch (rtm->rtm_type)
937 {
938 case RTM_ADD:
939 case RTM_DELETE:
940 rtm_read (rtm);
941 break;
942 case RTM_IFINFO:
943 ifm_read (&buf.im.ifm);
944 break;
945 case RTM_NEWADDR:
946 case RTM_DELADDR:
947 ifam_read (&buf.ia.ifa);
948 break;
949#ifdef RTM_IFANNOUNCE
950 case RTM_IFANNOUNCE:
951 ifan_read (&buf.ian.ifan);
952 break;
953#endif /* RTM_IFANNOUNCE */
954 default:
726f9b2b 955 if (IS_ZEBRA_DEBUG_KERNEL)
956 zlog_info("Unprocessed RTM_type: %d", rtm->rtm_type);
718e3744 957 break;
958 }
959 return 0;
960}
961
962/* Make routing socket. */
963void
964routing_socket ()
965{
edd7c245 966 if ( zserv_privs.change (ZPRIVS_RAISE) )
967 zlog_err ("routing_socket: Can't raise privileges");
968
718e3744 969 routing_sock = socket (AF_ROUTE, SOCK_RAW, 0);
970
971 if (routing_sock < 0)
972 {
edd7c245 973 if ( zserv_privs.change (ZPRIVS_LOWER) )
974 zlog_err ("routing_socket: Can't lower privileges");
718e3744 975 zlog_warn ("Can't init kernel routing socket");
976 return;
977 }
978
979 if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
980 zlog_warn ("Can't set O_NONBLOCK to routing socket");
edd7c245 981 if ( zserv_privs.change (ZPRIVS_LOWER) )
982 zlog_err ("routing_socket: Can't lower privileges");
718e3744 983
984 /* kernel_read needs rewrite. */
9bcdb638 985 thread_add_read (zebrad.master, kernel_read, NULL, routing_sock);
718e3744 986}
987
988/* Exported interface function. This function simply calls
989 routing_socket (). */
990void
991kernel_init ()
992{
993 routing_socket ();
994}