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