blob: a47f4f6361a71a8ff897740a9d2dab4c09913e28 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
34
35#include "zebra/interface.h"
36#include "zebra/zserv.h"
37#include "zebra/debug.h"
38
39/* Socket length roundup function. */
40#define ROUNDUP(a) \
41 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
42
43/* And this macro is wrapper for handling sa_len. */
44#ifdef HAVE_SA_LEN
45#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
46#else
47#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr))
48#endif /* HAVE_SA_LEN */
49
50/* Routing socket message types. */
51struct message rtm_type_str[] =
52{
53 {RTM_ADD, "RTM_ADD"},
54 {RTM_DELETE, "RTM_DELETE"},
55 {RTM_CHANGE, "RTM_CHANGE"},
56 {RTM_GET, "RTM_GET"},
57 {RTM_LOSING, "RTM_LOSING"},
58 {RTM_REDIRECT, "RTM_REDIRECT"},
59 {RTM_MISS, "RTM_MISS"},
60 {RTM_LOCK, "RTM_LOCK"},
61 {RTM_OLDADD, "RTM_OLDADD"},
62 {RTM_OLDDEL, "RTM_OLDDEL"},
63 {RTM_RESOLVE, "RTM_RESOLVE"},
64 {RTM_NEWADDR, "RTM_NEWADDR"},
65 {RTM_DELADDR, "RTM_DELADDR"},
66 {RTM_IFINFO, "RTM_IFINFO"},
67#ifdef RTM_OIFINFO
68 {RTM_OIFINFO, "RTM_OIFINFO"},
69#endif /* RTM_OIFINFO */
70#ifdef RTM_NEWMADDR
71 {RTM_NEWMADDR, "RTM_NEWMADDR"},
72#endif /* RTM_NEWMADDR */
73#ifdef RTM_DELMADDR
74 {RTM_DELMADDR, "RTM_DELMADDR"},
75#endif /* RTM_DELMADDR */
76#ifdef RTM_IFANNOUNCE
77 {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"},
78#endif /* RTM_IFANNOUNCE */
79 {0, NULL}
80};
81
82struct message rtm_flag_str[] =
83{
84 {RTF_UP, "UP"},
85 {RTF_GATEWAY, "GATEWAY"},
86 {RTF_HOST, "HOST"},
87 {RTF_REJECT, "REJECT"},
88 {RTF_DYNAMIC, "DYNAMIC"},
89 {RTF_MODIFIED, "MODIFIED"},
90 {RTF_DONE, "DONE"},
91#ifdef RTF_MASK
92 {RTF_MASK, "MASK"},
93#endif /* RTF_MASK */
94 {RTF_CLONING, "CLONING"},
95 {RTF_XRESOLVE, "XRESOLVE"},
96 {RTF_LLINFO, "LLINFO"},
97 {RTF_STATIC, "STATIC"},
98 {RTF_BLACKHOLE, "BLACKHOLE"},
99 {RTF_PROTO1, "PROTO1"},
100 {RTF_PROTO2, "PROTO2"},
101#ifdef RTF_PRCLONING
102 {RTF_PRCLONING, "PRCLONING"},
103#endif /* RTF_PRCLONING */
104#ifdef RTF_WASCLONED
105 {RTF_WASCLONED, "WASCLONED"},
106#endif /* RTF_WASCLONED */
107#ifdef RTF_PROTO3
108 {RTF_PROTO3, "PROTO3"},
109#endif /* RTF_PROTO3 */
110#ifdef RTF_PINNED
111 {RTF_PINNED, "PINNED"},
112#endif /* RTF_PINNED */
113#ifdef RTF_LOCAL
114 {RTF_LOCAL, "LOCAL"},
115#endif /* RTF_LOCAL */
116#ifdef RTF_BROADCAST
117 {RTF_BROADCAST, "BROADCAST"},
118#endif /* RTF_BROADCAST */
119#ifdef RTF_MULTICAST
120 {RTF_MULTICAST, "MULTICAST"},
121#endif /* RTF_MULTICAST */
122 {0, NULL}
123};
124
125/* Kernel routing update socket. */
126int routing_sock = -1;
127
128/* Yes I'm checking ugly routing socket behavior. */
129/* #define DEBUG */
130
131/* Supported address family check. */
132static int
133af_check (int family)
134{
135 if (family == AF_INET)
136 return 1;
137#ifdef HAVE_IPV6
138 if (family == AF_INET6)
139 return 1;
140#endif /* HAVE_IPV6 */
141 return 0;
142}
143
144/* Dump routing table flag for debug purpose. */
145void
146rtm_flag_dump (int flag)
147{
148 struct message *mes;
149 static char buf[BUFSIZ];
150
151 for (mes = rtm_flag_str; mes->key != 0; mes++)
152 {
153 if (mes->key & flag)
154 {
155 strlcat (buf, mes->str, BUFSIZ);
156 strlcat (buf, " ", BUFSIZ);
157 }
158 }
159 zlog_info ("Kernel: %s", buf);
160}
161
162#ifdef RTM_IFANNOUNCE
163/* Interface adding function */
164int
165ifan_read (struct if_announcemsghdr *ifan)
166{
167 struct interface *ifp;
168
169 ifp = if_lookup_by_index (ifan->ifan_index);
170 if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
171 {
172 /* Create Interface */
173 ifp = if_get_by_name (ifan->ifan_name);
174 ifp->ifindex = ifan->ifan_index;
175
176 if_add_update (ifp);
177 }
178 else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
179 {
180 if_delete_update (ifp);
181 if_delete (ifp);
182 }
183
184 if_get_flags (ifp);
185 if_get_mtu (ifp);
186 if_get_metric (ifp);
187
188 if (IS_ZEBRA_DEBUG_KERNEL)
189 zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
190
191 return 0;
192}
193#endif /* RTM_IFANNOUNCE */
194
195/* Interface adding function called from interface_list. */
196int
197ifm_read (struct if_msghdr *ifm)
198{
199 struct interface *ifp;
200 struct sockaddr_dl *sdl = NULL;
201
202 sdl = (struct sockaddr_dl *)(ifm + 1);
203
204 /* Use sdl index. */
205 ifp = if_lookup_by_index (ifm->ifm_index);
206
207 if (ifp == NULL)
208 {
209 /* Check interface's address.*/
210 if (! (ifm->ifm_addrs & RTA_IFP))
211 {
212 zlog_warn ("There must be RTA_IFP address for ifindex %d\n",
213 ifm->ifm_index);
214 return -1;
215 }
216
217 ifp = if_create ();
218
219 strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen);
220 ifp->ifindex = ifm->ifm_index;
221 ifp->flags = ifm->ifm_flags;
222#if defined(__bsdi__)
223 if_kvm_get_mtu (ifp);
224#else
225 if_get_mtu (ifp);
226#endif /* __bsdi__ */
227 if_get_metric (ifp);
228
229 /* Fetch hardware address. */
230 if (sdl->sdl_family != AF_LINK)
231 {
232 zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK");
233 return -1;
234 }
235 memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
236
237 if_add_update (ifp);
238 }
239 else
240 {
241 /* There is a case of promisc, allmulti flag modification. */
242 if (if_is_up (ifp))
243 {
244 ifp->flags = ifm->ifm_flags;
245 if (! if_is_up (ifp))
246 if_down (ifp);
247 }
248 else
249 {
250 ifp->flags = ifm->ifm_flags;
251 if (if_is_up (ifp))
252 if_up (ifp);
253 }
254 }
255
256#ifdef HAVE_NET_RT_IFLIST
257 ifp->stats = ifm->ifm_data;
258#endif /* HAVE_NET_RT_IFLIST */
259
260 if (IS_ZEBRA_DEBUG_KERNEL)
261 zlog_info ("interface %s index %d", ifp->name, ifp->ifindex);
262
263 return 0;
264}
265
266/* Address read from struct ifa_msghdr. */
267void
268ifam_read_mesg (struct ifa_msghdr *ifm,
269 union sockunion *addr,
270 union sockunion *mask,
271 union sockunion *dest)
272{
273 caddr_t pnt, end;
274
275 pnt = (caddr_t)(ifm + 1);
276 end = ((caddr_t)ifm) + ifm->ifam_msglen;
277
278#define IFAMADDRGET(X,R) \
279 if (ifm->ifam_addrs & (R)) \
280 { \
281 int len = WRAPUP(pnt); \
282 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
283 memcpy ((caddr_t)(X), pnt, len); \
284 pnt += len; \
285 }
286#define IFAMMASKGET(X,R) \
287 if (ifm->ifam_addrs & (R)) \
288 { \
289 int len = WRAPUP(pnt); \
290 if ((X) != NULL) \
291 memcpy ((caddr_t)(X), pnt, len); \
292 pnt += len; \
293 }
294
295 /* Be sure structure is cleared */
296 memset (mask, 0, sizeof (union sockunion));
297 memset (addr, 0, sizeof (union sockunion));
298 memset (dest, 0, sizeof (union sockunion));
299
300 /* We fetch each socket variable into sockunion. */
301 IFAMADDRGET (NULL, RTA_DST);
302 IFAMADDRGET (NULL, RTA_GATEWAY);
303 IFAMMASKGET (mask, RTA_NETMASK);
304 IFAMADDRGET (NULL, RTA_GENMASK);
305 IFAMADDRGET (NULL, RTA_IFP);
306 IFAMADDRGET (addr, RTA_IFA);
307 IFAMADDRGET (NULL, RTA_AUTHOR);
308 IFAMADDRGET (dest, RTA_BRD);
309
310 /* Assert read up end point matches to end point */
311 if (pnt != end)
312 zlog_warn ("ifam_read() does't read all socket data");
313}
314
315/* Interface's address information get. */
316int
317ifam_read (struct ifa_msghdr *ifam)
318{
319 struct interface *ifp;
320 union sockunion addr, mask, gate;
321
322 /* Check does this interface exist or not. */
323 ifp = if_lookup_by_index (ifam->ifam_index);
324 if (ifp == NULL)
325 {
326 zlog_warn ("no interface for index %d", ifam->ifam_index);
327 return -1;
328 }
329
330 /* Allocate and read address information. */
331 ifam_read_mesg (ifam, &addr, &mask, &gate);
332
333 /* Check interface flag for implicit up of the interface. */
334 if_refresh (ifp);
335
336 /* Add connected address. */
337 switch (sockunion_family (&addr))
338 {
339 case AF_INET:
340 if (ifam->ifam_type == RTM_NEWADDR)
341 connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr,
342 ip_masklen (mask.sin.sin_addr),
343 &gate.sin.sin_addr, NULL);
344 else
345 connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr,
346 ip_masklen (mask.sin.sin_addr),
347 &gate.sin.sin_addr, NULL);
348 break;
349#ifdef HAVE_IPV6
350 case AF_INET6:
351 /* Unset interface index from link-local address when IPv6 stack
352 is KAME. */
353 if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr))
354 SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
355
356 if (ifam->ifam_type == RTM_NEWADDR)
357 connected_add_ipv6 (ifp,
358 &addr.sin6.sin6_addr,
359 ip6_masklen (mask.sin6.sin6_addr),
360 &gate.sin6.sin6_addr);
361 else
362 connected_delete_ipv6 (ifp,
363 &addr.sin6.sin6_addr,
364 ip6_masklen (mask.sin6.sin6_addr),
365 &gate.sin6.sin6_addr);
366 break;
367#endif /* HAVE_IPV6 */
368 default:
369 /* Unsupported family silently ignore... */
370 break;
371 }
372 return 0;
373}
374
375/* Interface function for reading kernel routing table information. */
376int
377rtm_read_mesg (struct rt_msghdr *rtm,
378 union sockunion *dest,
379 union sockunion *mask,
380 union sockunion *gate)
381{
382 caddr_t pnt, end;
383
384 /* Pnt points out socket data start point. */
385 pnt = (caddr_t)(rtm + 1);
386 end = ((caddr_t)rtm) + rtm->rtm_msglen;
387
388 /* rt_msghdr version check. */
389 if (rtm->rtm_version != RTM_VERSION)
390 zlog (NULL, LOG_WARNING,
391 "Routing message version different %d should be %d."
392 "This may cause problem\n", rtm->rtm_version, RTM_VERSION);
393
394#define RTMADDRGET(X,R) \
395 if (rtm->rtm_addrs & (R)) \
396 { \
397 int len = WRAPUP (pnt); \
398 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
399 memcpy ((caddr_t)(X), pnt, len); \
400 pnt += len; \
401 }
402#define RTMMASKGET(X,R) \
403 if (rtm->rtm_addrs & (R)) \
404 { \
405 int len = WRAPUP (pnt); \
406 if ((X) != NULL) \
407 memcpy ((caddr_t)(X), pnt, len); \
408 pnt += len; \
409 }
410
411 /* Be sure structure is cleared */
412 memset (dest, 0, sizeof (union sockunion));
413 memset (gate, 0, sizeof (union sockunion));
414 memset (mask, 0, sizeof (union sockunion));
415
416 /* We fetch each socket variable into sockunion. */
417 RTMADDRGET (dest, RTA_DST);
418 RTMADDRGET (gate, RTA_GATEWAY);
419 RTMMASKGET (mask, RTA_NETMASK);
420 RTMADDRGET (NULL, RTA_GENMASK);
421 RTMADDRGET (NULL, RTA_IFP);
422 RTMADDRGET (NULL, RTA_IFA);
423 RTMADDRGET (NULL, RTA_AUTHOR);
424 RTMADDRGET (NULL, RTA_BRD);
425
426 /* If there is netmask information set it's family same as
427 destination family*/
428 if (rtm->rtm_addrs & RTA_NETMASK)
429 mask->sa.sa_family = dest->sa.sa_family;
430
431 /* Assert read up to the end of pointer. */
432 if (pnt != end)
433 zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data.");
434
435 return rtm->rtm_flags;
436}
437
438void
439rtm_read (struct rt_msghdr *rtm)
440{
441 int flags;
442 u_char zebra_flags;
443 union sockunion dest, mask, gate;
444
445 zebra_flags = 0;
446
447 /* Discard self send message. */
448 if (rtm->rtm_type != RTM_GET
449 && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
450 return;
451
452 /* Read destination and netmask and gateway from rtm message
453 structure. */
454 flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
455
456#ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
457 if (flags & RTF_CLONED)
458 return;
459#endif
460#ifdef RTF_WASCLONED /*freebsd*/
461 if (flags & RTF_WASCLONED)
462 return;
463#endif
464
465 if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP))
466 return;
467
468 /* This is connected route. */
469 if (! (flags & RTF_GATEWAY))
470 return;
471
472 if (flags & RTF_PROTO1)
473 SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE);
474
475 /* This is persistent route. */
476 if (flags & RTF_STATIC)
477 SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC);
478
479 if (dest.sa.sa_family == AF_INET)
480 {
481 struct prefix_ipv4 p;
482
483 p.family = AF_INET;
484 p.prefix = dest.sin.sin_addr;
485 if (flags & RTF_HOST)
486 p.prefixlen = IPV4_MAX_PREFIXLEN;
487 else
488 p.prefixlen = ip_masklen (mask.sin.sin_addr);
489
490 if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
491 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
492 &p, &gate.sin.sin_addr, 0, 0, 0, 0);
493 else
494 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
495 &p, &gate.sin.sin_addr, 0, 0);
496 }
497#ifdef HAVE_IPV6
498 if (dest.sa.sa_family == AF_INET6)
499 {
500 struct prefix_ipv6 p;
501 unsigned int ifindex = 0;
502
503 p.family = AF_INET6;
504 p.prefix = dest.sin6.sin6_addr;
505 if (flags & RTF_HOST)
506 p.prefixlen = IPV6_MAX_PREFIXLEN;
507 else
508 p.prefixlen = ip6_masklen (mask.sin6.sin6_addr);
509
510#ifdef KAME
511 if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr))
512 {
513 ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr);
514 SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0);
515 }
516#endif /* KAME */
517
518 if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
519 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
520 &p, &gate.sin6.sin6_addr, ifindex, 0);
521 else
522 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
523 &p, &gate.sin6.sin6_addr, ifindex, 0);
524 }
525#endif /* HAVE_IPV6 */
526}
527
528/* Interface function for the kernel routing table updates. Support
529 for RTM_CHANGE will be needed. */
530int
531rtm_write (int message,
532 union sockunion *dest,
533 union sockunion *mask,
534 union sockunion *gate,
535 unsigned int index,
536 int zebra_flags,
537 int metric)
538{
539 int ret;
540 caddr_t pnt;
541 struct interface *ifp;
542 struct sockaddr_in tmp_gate;
543#ifdef HAVE_IPV6
544 struct sockaddr_in6 tmp_gate6;
545#endif /* HAVE_IPV6 */
546
547 /* Sequencial number of routing message. */
548 static int msg_seq = 0;
549
550 /* Struct of rt_msghdr and buffer for storing socket's data. */
551 struct
552 {
553 struct rt_msghdr rtm;
554 char buf[512];
555 } msg;
556
557 memset (&tmp_gate, 0, sizeof (struct sockaddr_in));
558 tmp_gate.sin_family = AF_INET;
559#ifdef HAVE_SIN_LEN
560 tmp_gate.sin_len = sizeof (struct sockaddr_in);
561#endif /* HAVE_SIN_LEN */
562
563#ifdef HAVE_IPV6
564 memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6));
565 tmp_gate6.sin6_family = AF_INET6;
566#ifdef SIN6_LEN
567 tmp_gate6.sin6_len = sizeof (struct sockaddr_in6);
568#endif /* SIN6_LEN */
569#endif /* HAVE_IPV6 */
570
571 if (routing_sock < 0)
572 return ZEBRA_ERR_EPERM;
573
574 /* Clear and set rt_msghdr values */
575 memset (&msg, 0, sizeof (struct rt_msghdr));
576 msg.rtm.rtm_version = RTM_VERSION;
577 msg.rtm.rtm_type = message;
578 msg.rtm.rtm_seq = msg_seq++;
579 msg.rtm.rtm_addrs = RTA_DST;
580 msg.rtm.rtm_addrs |= RTA_GATEWAY;
581 msg.rtm.rtm_flags = RTF_UP;
582 msg.rtm.rtm_index = index;
583
584 if (metric != 0)
585 {
586 msg.rtm.rtm_rmx.rmx_hopcount = metric;
587 msg.rtm.rtm_inits |= RTV_HOPCOUNT;
588 }
589
590 ifp = if_lookup_by_index (index);
591
592 if (gate && message == RTM_ADD)
593 msg.rtm.rtm_flags |= RTF_GATEWAY;
594
595 if (! gate && message == RTM_ADD && ifp &&
596 (ifp->flags & IFF_POINTOPOINT) == 0)
597 msg.rtm.rtm_flags |= RTF_CLONING;
598
599 /* If no protocol specific gateway is specified, use link
600 address for gateway. */
601 if (! gate)
602 {
603 if (!ifp)
604 {
605 zlog_warn ("no gateway found for interface index %d", index);
606 return -1;
607 }
608 gate = (union sockunion *) & ifp->sdl;
609 }
610
611 if (mask)
612 msg.rtm.rtm_addrs |= RTA_NETMASK;
613 else if (message == RTM_ADD)
614 msg.rtm.rtm_flags |= RTF_HOST;
615
616 /* Tagging route with flags */
617 msg.rtm.rtm_flags |= (RTF_PROTO1);
618
619 /* Additional flags. */
620 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
621 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
622
623#ifdef HAVE_SIN_LEN
624#define SOCKADDRSET(X,R) \
625 if (msg.rtm.rtm_addrs & (R)) \
626 { \
627 int len = ROUNDUP ((X)->sa.sa_len); \
628 memcpy (pnt, (caddr_t)(X), len); \
629 pnt += len; \
630 }
631#else
632#define SOCKADDRSET(X,R) \
633 if (msg.rtm.rtm_addrs & (R)) \
634 { \
635 int len = ROUNDUP (sizeof((X)->sa)); \
636 memcpy (pnt, (caddr_t)(X), len); \
637 pnt += len; \
638 }
639#endif /* HAVE_SIN_LEN */
640
641 pnt = (caddr_t) msg.buf;
642
643 /* Write each socket data into rtm message buffer */
644 SOCKADDRSET (dest, RTA_DST);
645 SOCKADDRSET (gate, RTA_GATEWAY);
646 SOCKADDRSET (mask, RTA_NETMASK);
647
648 msg.rtm.rtm_msglen = pnt - (caddr_t) &msg;
649
650 ret = write (routing_sock, &msg, msg.rtm.rtm_msglen);
651
652 if (ret != msg.rtm.rtm_msglen)
653 {
654 if (errno == EEXIST)
655 return ZEBRA_ERR_RTEXIST;
656 if (errno == ENETUNREACH)
657 return ZEBRA_ERR_RTUNREACH;
658
659 zlog_warn ("write : %s (%d)", strerror (errno), errno);
660 return -1;
661 }
662 return 0;
663}
664
665
666#include "thread.h"
667#include "zebra/zserv.h"
668
669extern struct thread_master *master;
670
671/* For debug purpose. */
672void
673rtmsg_debug (struct rt_msghdr *rtm)
674{
675 char *type = "Unknown";
676 struct message *mes;
677
678 for (mes = rtm_type_str; mes->str; mes++)
679 if (mes->key == rtm->rtm_type)
680 {
681 type = mes->str;
682 break;
683 }
684
685 zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
686 rtm_flag_dump (rtm->rtm_flags);
687 zlog_info ("Kernel: message seq %d", rtm->rtm_seq);
688 zlog_info ("Kernel: pid %d", rtm->rtm_pid);
689}
690
691/* This is pretty gross, better suggestions welcome -- mhandler */
692#ifndef RTAX_MAX
693#ifdef RTA_NUMBITS
694#define RTAX_MAX RTA_NUMBITS
695#else
696#define RTAX_MAX 8
697#endif /* RTA_NUMBITS */
698#endif /* RTAX_MAX */
699
700/* Kernel routing table and interface updates via routing socket. */
701int
702kernel_read (struct thread *thread)
703{
704 int sock;
705 int nbytes;
706 struct rt_msghdr *rtm;
707
708 union
709 {
710 /* Routing information. */
711 struct
712 {
713 struct rt_msghdr rtm;
714 struct sockaddr addr[RTAX_MAX];
715 } r;
716
717 /* Interface information. */
718 struct
719 {
720 struct if_msghdr ifm;
721 struct sockaddr addr[RTAX_MAX];
722 } im;
723
724 /* Interface address information. */
725 struct
726 {
727 struct ifa_msghdr ifa;
728 struct sockaddr addr[RTAX_MAX];
729 } ia;
730
731#ifdef RTM_IFANNOUNCE
732 /* Interface arrival/departure */
733 struct
734 {
735 struct if_announcemsghdr ifan;
736 struct sockaddr addr[RTAX_MAX];
737 } ian;
738#endif /* RTM_IFANNOUNCE */
739
740 } buf;
741
742 /* Fetch routing socket. */
743 sock = THREAD_FD (thread);
744
745 nbytes= read (sock, &buf, sizeof buf);
746
747 if (nbytes <= 0)
748 {
749 if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
750 zlog_warn ("routing socket error: %s", strerror (errno));
751 return 0;
752 }
753
754 thread_add_read (master, kernel_read, NULL, sock);
755
756#ifdef DEBUG
757 rtmsg_debug (&buf.r.rtm);
758#endif /* DEBUG */
759
760 rtm = &buf.r.rtm;
761
762 switch (rtm->rtm_type)
763 {
764 case RTM_ADD:
765 case RTM_DELETE:
766 rtm_read (rtm);
767 break;
768 case RTM_IFINFO:
769 ifm_read (&buf.im.ifm);
770 break;
771 case RTM_NEWADDR:
772 case RTM_DELADDR:
773 ifam_read (&buf.ia.ifa);
774 break;
775#ifdef RTM_IFANNOUNCE
776 case RTM_IFANNOUNCE:
777 ifan_read (&buf.ian.ifan);
778 break;
779#endif /* RTM_IFANNOUNCE */
780 default:
781 break;
782 }
783 return 0;
784}
785
786/* Make routing socket. */
787void
788routing_socket ()
789{
790 routing_sock = socket (AF_ROUTE, SOCK_RAW, 0);
791
792 if (routing_sock < 0)
793 {
794 zlog_warn ("Can't init kernel routing socket");
795 return;
796 }
797
798 if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
799 zlog_warn ("Can't set O_NONBLOCK to routing socket");
800
801 /* kernel_read needs rewrite. */
802 thread_add_read (master, kernel_read, NULL, routing_sock);
803}
804
805/* Exported interface function. This function simply calls
806 routing_socket (). */
807void
808kernel_init ()
809{
810 routing_socket ();
811}