]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/kernel_socket.c
17893a87b719a465c28c9e491bf3be11d3655946
1 /* Kernel communication using routing socket.
2 * Copyright (C) 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
26 #include "sockunion.h"
27 #include "connected.h"
35 #include "zebra/interface.h"
36 #include "zebra/zserv.h"
37 #include "zebra/debug.h"
39 /* Socket length roundup function. */
41 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
43 /* And this macro is wrapper for handling sa_len. */
45 #define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
47 #define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr))
48 #endif /* HAVE_SA_LEN */
50 /* Routing socket message types. */
51 struct message rtm_type_str
[] =
54 {RTM_DELETE
, "RTM_DELETE"},
55 {RTM_CHANGE
, "RTM_CHANGE"},
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"},
68 {RTM_OIFINFO
, "RTM_OIFINFO"},
69 #endif /* RTM_OIFINFO */
71 {RTM_NEWMADDR
, "RTM_NEWMADDR"},
72 #endif /* RTM_NEWMADDR */
74 {RTM_DELMADDR
, "RTM_DELMADDR"},
75 #endif /* RTM_DELMADDR */
77 {RTM_IFANNOUNCE
, "RTM_IFANNOUNCE"},
78 #endif /* RTM_IFANNOUNCE */
82 struct message rtm_flag_str
[] =
85 {RTF_GATEWAY
, "GATEWAY"},
87 {RTF_REJECT
, "REJECT"},
88 {RTF_DYNAMIC
, "DYNAMIC"},
89 {RTF_MODIFIED
, "MODIFIED"},
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"},
102 {RTF_PRCLONING
, "PRCLONING"},
103 #endif /* RTF_PRCLONING */
105 {RTF_WASCLONED
, "WASCLONED"},
106 #endif /* RTF_WASCLONED */
108 {RTF_PROTO3
, "PROTO3"},
109 #endif /* RTF_PROTO3 */
111 {RTF_PINNED
, "PINNED"},
112 #endif /* RTF_PINNED */
114 {RTF_LOCAL
, "LOCAL"},
115 #endif /* RTF_LOCAL */
117 {RTF_BROADCAST
, "BROADCAST"},
118 #endif /* RTF_BROADCAST */
120 {RTF_MULTICAST
, "MULTICAST"},
121 #endif /* RTF_MULTICAST */
125 /* Kernel routing update socket. */
126 int routing_sock
= -1;
128 /* Yes I'm checking ugly routing socket behavior. */
131 /* Supported address family check. */
133 af_check (int family
)
135 if (family
== AF_INET
)
138 if (family
== AF_INET6
)
140 #endif /* HAVE_IPV6 */
144 /* Dump routing table flag for debug purpose. */
146 rtm_flag_dump (int flag
)
149 static char buf
[BUFSIZ
];
152 for (mes
= rtm_flag_str
; mes
->key
!= 0; mes
++)
156 strlcat (buf
, mes
->str
, BUFSIZ
);
157 strlcat (buf
, " ", BUFSIZ
);
160 zlog_info ("Kernel: %s", buf
);
163 #ifdef RTM_IFANNOUNCE
164 /* Interface adding function */
166 ifan_read (struct if_announcemsghdr
*ifan
)
168 struct interface
*ifp
;
170 ifp
= if_lookup_by_index (ifan
->ifan_index
);
171 if (ifp
== NULL
&& ifan
->ifan_what
== IFAN_ARRIVAL
)
173 /* Create Interface */
174 ifp
= if_get_by_name (ifan
->ifan_name
);
175 ifp
->ifindex
= ifan
->ifan_index
;
179 else if (ifp
!= NULL
&& ifan
->ifan_what
== IFAN_DEPARTURE
)
181 if_delete_update (ifp
);
189 if (IS_ZEBRA_DEBUG_KERNEL
)
190 zlog_info ("interface %s index %d", ifp
->name
, ifp
->ifindex
);
194 #endif /* RTM_IFANNOUNCE */
196 /* Interface adding function called from interface_list. */
198 ifm_read (struct if_msghdr
*ifm
)
200 struct interface
*ifp
;
201 struct sockaddr_dl
*sdl
= NULL
;
203 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
206 ifp
= if_lookup_by_index (ifm
->ifm_index
);
210 /* Check interface's address.*/
211 if (! (ifm
->ifm_addrs
& RTA_IFP
))
213 zlog_warn ("There must be RTA_IFP address for ifindex %d\n",
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
);
227 #endif /* __bsdi__ */
230 /* Fetch hardware address. */
231 if (sdl
->sdl_family
!= AF_LINK
)
233 zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK");
236 memcpy (&ifp
->sdl
, sdl
, sizeof (struct sockaddr_dl
));
242 /* There is a case of promisc, allmulti flag modification. */
245 ifp
->flags
= ifm
->ifm_flags
;
246 if (! if_is_up (ifp
))
251 ifp
->flags
= ifm
->ifm_flags
;
257 #ifdef HAVE_NET_RT_IFLIST
258 ifp
->stats
= ifm
->ifm_data
;
259 #endif /* HAVE_NET_RT_IFLIST */
261 if (IS_ZEBRA_DEBUG_KERNEL
)
262 zlog_info ("interface %s index %d", ifp
->name
, ifp
->ifindex
);
267 /* Address read from struct ifa_msghdr. */
269 ifam_read_mesg (struct ifa_msghdr
*ifm
,
270 union sockunion
*addr
,
271 union sockunion
*mask
,
272 union sockunion
*dest
)
276 pnt
= (caddr_t
)(ifm
+ 1);
277 end
= ((caddr_t
)ifm
) + ifm
->ifam_msglen
;
279 #define IFAMADDRGET(X,R) \
280 if (ifm->ifam_addrs & (R)) \
282 int len = WRAPUP(pnt); \
283 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
284 memcpy ((caddr_t)(X), pnt, len); \
287 #define IFAMMASKGET(X,R) \
288 if (ifm->ifam_addrs & (R)) \
290 int len = WRAPUP(pnt); \
292 memcpy ((caddr_t)(X), pnt, len); \
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
));
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
);
311 /* Assert read up end point matches to end point */
313 zlog_warn ("ifam_read() does't read all socket data");
316 /* Interface's address information get. */
318 ifam_read (struct ifa_msghdr
*ifam
)
320 struct interface
*ifp
;
321 union sockunion addr
, mask
, gate
;
323 /* Check does this interface exist or not. */
324 ifp
= if_lookup_by_index (ifam
->ifam_index
);
327 zlog_warn ("no interface for index %d", ifam
->ifam_index
);
331 /* Allocate and read address information. */
332 ifam_read_mesg (ifam
, &addr
, &mask
, &gate
);
334 /* Check interface flag for implicit up of the interface. */
337 /* Add connected address. */
338 switch (sockunion_family (&addr
))
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
);
346 connected_delete_ipv4 (ifp
, 0, &addr
.sin
.sin_addr
,
347 ip_masklen (mask
.sin
.sin_addr
),
348 &gate
.sin
.sin_addr
, NULL
);
352 /* Unset interface index from link-local address when IPv6 stack
354 if (IN6_IS_ADDR_LINKLOCAL (&addr
.sin6
.sin6_addr
))
355 SET_IN6_LINKLOCAL_IFINDEX (addr
.sin6
.sin6_addr
, 0);
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
);
363 connected_delete_ipv6 (ifp
,
364 &addr
.sin6
.sin6_addr
,
365 ip6_masklen (mask
.sin6
.sin6_addr
),
366 &gate
.sin6
.sin6_addr
);
368 #endif /* HAVE_IPV6 */
370 /* Unsupported family silently ignore... */
376 /* Interface function for reading kernel routing table information. */
378 rtm_read_mesg (struct rt_msghdr
*rtm
,
379 union sockunion
*dest
,
380 union sockunion
*mask
,
381 union sockunion
*gate
)
385 /* Pnt points out socket data start point. */
386 pnt
= (caddr_t
)(rtm
+ 1);
387 end
= ((caddr_t
)rtm
) + rtm
->rtm_msglen
;
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
);
395 #define RTMADDRGET(X,R) \
396 if (rtm->rtm_addrs & (R)) \
398 int len = WRAPUP (pnt); \
399 if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \
400 memcpy ((caddr_t)(X), pnt, len); \
403 #define RTMMASKGET(X,R) \
404 if (rtm->rtm_addrs & (R)) \
406 int len = WRAPUP (pnt); \
408 memcpy ((caddr_t)(X), pnt, len); \
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
));
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
);
427 /* If there is netmask information set it's family same as
429 if (rtm
->rtm_addrs
& RTA_NETMASK
)
430 mask
->sa
.sa_family
= dest
->sa
.sa_family
;
432 /* Assert read up to the end of pointer. */
434 zlog (NULL
, LOG_WARNING
, "rtm_read() does't read all socket data.");
436 return rtm
->rtm_flags
;
440 rtm_read (struct rt_msghdr
*rtm
)
444 union sockunion dest
, mask
, gate
;
448 /* Discard self send message. */
449 if (rtm
->rtm_type
!= RTM_GET
450 && (rtm
->rtm_pid
== pid
|| rtm
->rtm_pid
== old_pid
))
453 /* Read destination and netmask and gateway from rtm message
455 flags
= rtm_read_mesg (rtm
, &dest
, &mask
, &gate
);
457 #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
458 if (flags
& RTF_CLONED
)
461 #ifdef RTF_WASCLONED /*freebsd*/
462 if (flags
& RTF_WASCLONED
)
466 if ((rtm
->rtm_type
== RTM_ADD
) && ! (flags
& RTF_UP
))
469 /* This is connected route. */
470 if (! (flags
& RTF_GATEWAY
))
473 if (flags
& RTF_PROTO1
)
474 SET_FLAG (zebra_flags
, ZEBRA_FLAG_SELFROUTE
);
476 /* This is persistent route. */
477 if (flags
& RTF_STATIC
)
478 SET_FLAG (zebra_flags
, ZEBRA_FLAG_STATIC
);
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
);
486 if (dest
.sa
.sa_family
== AF_INET
)
488 struct prefix_ipv4 p
;
491 p
.prefix
= dest
.sin
.sin_addr
;
492 if (flags
& RTF_HOST
)
493 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
495 p
.prefixlen
= ip_masklen (mask
.sin
.sin_addr
);
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);
501 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL
, zebra_flags
,
502 &p
, &gate
.sin
.sin_addr
, 0, 0);
505 if (dest
.sa
.sa_family
== AF_INET6
)
507 struct prefix_ipv6 p
;
508 unsigned int ifindex
= 0;
511 p
.prefix
= dest
.sin6
.sin6_addr
;
512 if (flags
& RTF_HOST
)
513 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
515 p
.prefixlen
= ip6_masklen (mask
.sin6
.sin6_addr
);
518 if (IN6_IS_ADDR_LINKLOCAL (&gate
.sin6
.sin6_addr
))
520 ifindex
= IN6_LINKLOCAL_IFINDEX (gate
.sin6
.sin6_addr
);
521 SET_IN6_LINKLOCAL_IFINDEX (gate
.sin6
.sin6_addr
, 0);
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);
529 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL
, zebra_flags
,
530 &p
, &gate
.sin6
.sin6_addr
, ifindex
, 0);
532 #endif /* HAVE_IPV6 */
535 /* Interface function for the kernel routing table updates. Support
536 for RTM_CHANGE will be needed. */
538 rtm_write (int message
,
539 union sockunion
*dest
,
540 union sockunion
*mask
,
541 union sockunion
*gate
,
548 struct interface
*ifp
;
549 struct sockaddr_in tmp_gate
;
551 struct sockaddr_in6 tmp_gate6
;
552 #endif /* HAVE_IPV6 */
554 /* Sequencial number of routing message. */
555 static int msg_seq
= 0;
557 /* Struct of rt_msghdr and buffer for storing socket's data. */
560 struct rt_msghdr rtm
;
564 memset (&tmp_gate
, 0, sizeof (struct sockaddr_in
));
565 tmp_gate
.sin_family
= AF_INET
;
567 tmp_gate
.sin_len
= sizeof (struct sockaddr_in
);
568 #endif /* HAVE_SIN_LEN */
571 memset (&tmp_gate6
, 0, sizeof (struct sockaddr_in6
));
572 tmp_gate6
.sin6_family
= AF_INET6
;
574 tmp_gate6
.sin6_len
= sizeof (struct sockaddr_in6
);
575 #endif /* SIN6_LEN */
576 #endif /* HAVE_IPV6 */
578 if (routing_sock
< 0)
579 return ZEBRA_ERR_EPERM
;
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
;
593 msg
.rtm
.rtm_rmx
.rmx_hopcount
= metric
;
594 msg
.rtm
.rtm_inits
|= RTV_HOPCOUNT
;
597 ifp
= if_lookup_by_index (index
);
599 if (gate
&& message
== RTM_ADD
)
600 msg
.rtm
.rtm_flags
|= RTF_GATEWAY
;
602 if (! gate
&& message
== RTM_ADD
&& ifp
&&
603 (ifp
->flags
& IFF_POINTOPOINT
) == 0)
604 msg
.rtm
.rtm_flags
|= RTF_CLONING
;
606 /* If no protocol specific gateway is specified, use link
607 address for gateway. */
612 zlog_warn ("no gateway found for interface index %d", index
);
615 gate
= (union sockunion
*) & ifp
->sdl
;
619 msg
.rtm
.rtm_addrs
|= RTA_NETMASK
;
620 else if (message
== RTM_ADD
)
621 msg
.rtm
.rtm_flags
|= RTF_HOST
;
623 /* Tagging route with flags */
624 msg
.rtm
.rtm_flags
|= (RTF_PROTO1
);
626 /* Additional flags. */
627 if (zebra_flags
& ZEBRA_FLAG_BLACKHOLE
)
628 msg
.rtm
.rtm_flags
|= RTF_BLACKHOLE
;
629 if (zebra_flags
& ZEBRA_FLAG_REJECT
)
630 msg
.rtm
.rtm_flags
|= RTF_REJECT
;
634 #define SOCKADDRSET(X,R) \
635 if (msg.rtm.rtm_addrs & (R)) \
637 int len = ROUNDUP ((X)->sa.sa_len); \
638 memcpy (pnt, (caddr_t)(X), len); \
642 #define SOCKADDRSET(X,R) \
643 if (msg.rtm.rtm_addrs & (R)) \
645 int len = ROUNDUP (sizeof((X)->sa)); \
646 memcpy (pnt, (caddr_t)(X), len); \
649 #endif /* HAVE_SIN_LEN */
651 pnt
= (caddr_t
) msg
.buf
;
653 /* Write each socket data into rtm message buffer */
654 SOCKADDRSET (dest
, RTA_DST
);
655 SOCKADDRSET (gate
, RTA_GATEWAY
);
656 SOCKADDRSET (mask
, RTA_NETMASK
);
658 msg
.rtm
.rtm_msglen
= pnt
- (caddr_t
) &msg
;
660 ret
= write (routing_sock
, &msg
, msg
.rtm
.rtm_msglen
);
662 if (ret
!= msg
.rtm
.rtm_msglen
)
665 return ZEBRA_ERR_RTEXIST
;
666 if (errno
== ENETUNREACH
)
667 return ZEBRA_ERR_RTUNREACH
;
669 zlog_warn ("write : %s (%d)", strerror (errno
), errno
);
677 #include "zebra/zserv.h"
679 extern struct thread_master
*master
;
681 /* For debug purpose. */
683 rtmsg_debug (struct rt_msghdr
*rtm
)
685 char *type
= "Unknown";
688 for (mes
= rtm_type_str
; mes
->str
; mes
++)
689 if (mes
->key
== rtm
->rtm_type
)
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
);
701 /* This is pretty gross, better suggestions welcome -- mhandler */
704 #define RTAX_MAX RTA_NUMBITS
707 #endif /* RTA_NUMBITS */
708 #endif /* RTAX_MAX */
710 /* Kernel routing table and interface updates via routing socket. */
712 kernel_read (struct thread
*thread
)
716 struct rt_msghdr
*rtm
;
720 /* Routing information. */
723 struct rt_msghdr rtm
;
724 struct sockaddr addr
[RTAX_MAX
];
727 /* Interface information. */
730 struct if_msghdr ifm
;
731 struct sockaddr addr
[RTAX_MAX
];
734 /* Interface address information. */
737 struct ifa_msghdr ifa
;
738 struct sockaddr addr
[RTAX_MAX
];
741 #ifdef RTM_IFANNOUNCE
742 /* Interface arrival/departure */
745 struct if_announcemsghdr ifan
;
746 struct sockaddr addr
[RTAX_MAX
];
748 #endif /* RTM_IFANNOUNCE */
752 /* Fetch routing socket. */
753 sock
= THREAD_FD (thread
);
755 nbytes
= read (sock
, &buf
, sizeof buf
);
759 if (nbytes
< 0 && errno
!= EWOULDBLOCK
&& errno
!= EAGAIN
)
760 zlog_warn ("routing socket error: %s", strerror (errno
));
764 thread_add_read (master
, kernel_read
, NULL
, sock
);
766 if (IS_ZEBRA_DEBUG_KERNEL
)
767 rtmsg_debug (&buf
.r
.rtm
);
771 switch (rtm
->rtm_type
)
778 ifm_read (&buf
.im
.ifm
);
782 ifam_read (&buf
.ia
.ifa
);
784 #ifdef RTM_IFANNOUNCE
786 ifan_read (&buf
.ian
.ifan
);
788 #endif /* RTM_IFANNOUNCE */
790 if (IS_ZEBRA_DEBUG_KERNEL
)
791 zlog_info("Unprocessed RTM_type: %d", rtm
->rtm_type
);
797 /* Make routing socket. */
801 routing_sock
= socket (AF_ROUTE
, SOCK_RAW
, 0);
803 if (routing_sock
< 0)
805 zlog_warn ("Can't init kernel routing socket");
809 if (fcntl (routing_sock
, F_SETFL
, O_NONBLOCK
) < 0)
810 zlog_warn ("Can't set O_NONBLOCK to routing socket");
812 /* kernel_read needs rewrite. */
813 thread_add_read (master
, kernel_read
, NULL
, routing_sock
);
816 /* Exported interface function. This function simply calls
817 routing_socket (). */