Annotation of embedaddon/quagga/zebra/rt_netlink.c, revision 1.1.1.1
1.1 misho 1: /* Kernel routing table updates using netlink over GNU/Linux system.
2: * Copyright (C) 1997, 98, 99 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: /* Hack for GNU libc version 2. */
25: #ifndef MSG_TRUNC
26: #define MSG_TRUNC 0x20
27: #endif /* MSG_TRUNC */
28:
29: #include "linklist.h"
30: #include "if.h"
31: #include "log.h"
32: #include "prefix.h"
33: #include "connected.h"
34: #include "table.h"
35: #include "rib.h"
36: #include "thread.h"
37: #include "privs.h"
38:
39: #include "zebra/zserv.h"
40: #include "zebra/rt.h"
41: #include "zebra/redistribute.h"
42: #include "zebra/interface.h"
43: #include "zebra/debug.h"
44:
45: /* Socket interface to kernel */
46: struct nlsock
47: {
48: int sock;
49: int seq;
50: struct sockaddr_nl snl;
51: const char *name;
52: } netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
53: netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
54:
55: static const struct message nlmsg_str[] = {
56: {RTM_NEWROUTE, "RTM_NEWROUTE"},
57: {RTM_DELROUTE, "RTM_DELROUTE"},
58: {RTM_GETROUTE, "RTM_GETROUTE"},
59: {RTM_NEWLINK, "RTM_NEWLINK"},
60: {RTM_DELLINK, "RTM_DELLINK"},
61: {RTM_GETLINK, "RTM_GETLINK"},
62: {RTM_NEWADDR, "RTM_NEWADDR"},
63: {RTM_DELADDR, "RTM_DELADDR"},
64: {RTM_GETADDR, "RTM_GETADDR"},
65: {0, NULL}
66: };
67:
68: static const char *nexthop_types_desc[] =
69: {
70: "none",
71: "Directly connected",
72: "Interface route",
73: "IPv4 nexthop",
74: "IPv4 nexthop with ifindex",
75: "IPv4 nexthop with ifname",
76: "IPv6 nexthop",
77: "IPv6 nexthop with ifindex",
78: "IPv6 nexthop with ifname",
79: "Null0 nexthop",
80: };
81:
82: extern struct zebra_t zebrad;
83:
84: extern struct zebra_privs_t zserv_privs;
85:
86: extern u_int32_t nl_rcvbufsize;
87:
88: /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
89: names and ifindex values. */
90: static void
91: set_ifindex(struct interface *ifp, unsigned int ifi_index)
92: {
93: struct interface *oifp;
94:
95: if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
96: {
97: if (ifi_index == IFINDEX_INTERNAL)
98: zlog_err("Netlink is setting interface %s ifindex to reserved "
99: "internal value %u", ifp->name, ifi_index);
100: else
101: {
102: if (IS_ZEBRA_DEBUG_KERNEL)
103: zlog_debug("interface index %d was renamed from %s to %s",
104: ifi_index, oifp->name, ifp->name);
105: if (if_is_up(oifp))
106: zlog_err("interface rename detected on up interface: index %d "
107: "was renamed from %s to %s, results are uncertain!",
108: ifi_index, oifp->name, ifp->name);
109: if_delete_update(oifp);
110: }
111: }
112: ifp->ifindex = ifi_index;
113: }
114:
115: static int
116: netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
117: {
118: u_int32_t oldsize;
119: socklen_t newlen = sizeof(newsize);
120: socklen_t oldlen = sizeof(oldsize);
121: int ret;
122:
123: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
124: if (ret < 0)
125: {
126: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
127: safe_strerror (errno));
128: return -1;
129: }
130:
131: ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
132: sizeof(nl_rcvbufsize));
133: if (ret < 0)
134: {
135: zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
136: safe_strerror (errno));
137: return -1;
138: }
139:
140: ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
141: if (ret < 0)
142: {
143: zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
144: safe_strerror (errno));
145: return -1;
146: }
147:
148: zlog (NULL, LOG_INFO,
149: "Setting netlink socket receive buffer size: %u -> %u",
150: oldsize, newsize);
151: return 0;
152: }
153:
154: /* Make socket for Linux netlink interface. */
155: static int
156: netlink_socket (struct nlsock *nl, unsigned long groups)
157: {
158: int ret;
159: struct sockaddr_nl snl;
160: int sock;
161: int namelen;
162: int save_errno;
163:
164: sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
165: if (sock < 0)
166: {
167: zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
168: safe_strerror (errno));
169: return -1;
170: }
171:
172: memset (&snl, 0, sizeof snl);
173: snl.nl_family = AF_NETLINK;
174: snl.nl_groups = groups;
175:
176: /* Bind the socket to the netlink structure for anything. */
177: if (zserv_privs.change (ZPRIVS_RAISE))
178: {
179: zlog (NULL, LOG_ERR, "Can't raise privileges");
180: return -1;
181: }
182:
183: ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
184: save_errno = errno;
185: if (zserv_privs.change (ZPRIVS_LOWER))
186: zlog (NULL, LOG_ERR, "Can't lower privileges");
187:
188: if (ret < 0)
189: {
190: zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
191: nl->name, snl.nl_groups, safe_strerror (save_errno));
192: close (sock);
193: return -1;
194: }
195:
196: /* multiple netlink sockets will have different nl_pid */
197: namelen = sizeof snl;
198: ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
199: if (ret < 0 || namelen != sizeof snl)
200: {
201: zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
202: safe_strerror (errno));
203: close (sock);
204: return -1;
205: }
206:
207: nl->snl = snl;
208: nl->sock = sock;
209: return ret;
210: }
211:
212: /* Get type specified information from netlink. */
213: static int
214: netlink_request (int family, int type, struct nlsock *nl)
215: {
216: int ret;
217: struct sockaddr_nl snl;
218: int save_errno;
219:
220: struct
221: {
222: struct nlmsghdr nlh;
223: struct rtgenmsg g;
224: } req;
225:
226:
227: /* Check netlink socket. */
228: if (nl->sock < 0)
229: {
230: zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
231: return -1;
232: }
233:
234: memset (&snl, 0, sizeof snl);
235: snl.nl_family = AF_NETLINK;
236:
237: memset (&req, 0, sizeof req);
238: req.nlh.nlmsg_len = sizeof req;
239: req.nlh.nlmsg_type = type;
240: req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
241: req.nlh.nlmsg_pid = nl->snl.nl_pid;
242: req.nlh.nlmsg_seq = ++nl->seq;
243: req.g.rtgen_family = family;
244:
245: /* linux appears to check capabilities on every message
246: * have to raise caps for every message sent
247: */
248: if (zserv_privs.change (ZPRIVS_RAISE))
249: {
250: zlog (NULL, LOG_ERR, "Can't raise privileges");
251: return -1;
252: }
253:
254: ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
255: (struct sockaddr *) &snl, sizeof snl);
256: save_errno = errno;
257:
258: if (zserv_privs.change (ZPRIVS_LOWER))
259: zlog (NULL, LOG_ERR, "Can't lower privileges");
260:
261: if (ret < 0)
262: {
263: zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
264: safe_strerror (save_errno));
265: return -1;
266: }
267:
268: return 0;
269: }
270:
271: /* Receive message from netlink interface and pass those information
272: to the given function. */
273: static int
274: netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
275: struct nlsock *nl)
276: {
277: int status;
278: int ret = 0;
279: int error;
280:
281: while (1)
282: {
283: char buf[4096];
284: struct iovec iov = { buf, sizeof buf };
285: struct sockaddr_nl snl;
286: struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
287: struct nlmsghdr *h;
288:
289: status = recvmsg (nl->sock, &msg, 0);
290: if (status < 0)
291: {
292: if (errno == EINTR)
293: continue;
294: if (errno == EWOULDBLOCK || errno == EAGAIN)
295: break;
296: zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
297: nl->name, safe_strerror(errno));
298: continue;
299: }
300:
301: if (status == 0)
302: {
303: zlog (NULL, LOG_ERR, "%s EOF", nl->name);
304: return -1;
305: }
306:
307: if (msg.msg_namelen != sizeof snl)
308: {
309: zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
310: nl->name, msg.msg_namelen);
311: return -1;
312: }
313:
314: for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
315: h = NLMSG_NEXT (h, status))
316: {
317: /* Finish of reading. */
318: if (h->nlmsg_type == NLMSG_DONE)
319: return ret;
320:
321: /* Error handling. */
322: if (h->nlmsg_type == NLMSG_ERROR)
323: {
324: struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
325: int errnum = err->error;
326: int msg_type = err->msg.nlmsg_type;
327:
328: /* If the error field is zero, then this is an ACK */
329: if (err->error == 0)
330: {
331: if (IS_ZEBRA_DEBUG_KERNEL)
332: {
333: zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
334: __FUNCTION__, nl->name,
335: lookup (nlmsg_str, err->msg.nlmsg_type),
336: err->msg.nlmsg_type, err->msg.nlmsg_seq,
337: err->msg.nlmsg_pid);
338: }
339:
340: /* return if not a multipart message, otherwise continue */
341: if (!(h->nlmsg_flags & NLM_F_MULTI))
342: {
343: return 0;
344: }
345: continue;
346: }
347:
348: if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
349: {
350: zlog (NULL, LOG_ERR, "%s error: message truncated",
351: nl->name);
352: return -1;
353: }
354:
355: /* Deal with errors that occur because of races in link handling */
356: if (nl == &netlink_cmd
357: && ((msg_type == RTM_DELROUTE &&
358: (-errnum == ENODEV || -errnum == ESRCH))
359: || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
360: {
361: if (IS_ZEBRA_DEBUG_KERNEL)
362: zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
363: nl->name, safe_strerror (-errnum),
364: lookup (nlmsg_str, msg_type),
365: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
366: return 0;
367: }
368:
369: zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
370: nl->name, safe_strerror (-errnum),
371: lookup (nlmsg_str, msg_type),
372: msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
373: return -1;
374: }
375:
376: /* OK we got netlink message. */
377: if (IS_ZEBRA_DEBUG_KERNEL)
378: zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
379: nl->name,
380: lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
381: h->nlmsg_seq, h->nlmsg_pid);
382:
383: /* skip unsolicited messages originating from command socket */
384: if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
385: {
386: if (IS_ZEBRA_DEBUG_KERNEL)
387: zlog_debug ("netlink_parse_info: %s packet comes from %s",
388: netlink_cmd.name, nl->name);
389: continue;
390: }
391:
392: error = (*filter) (&snl, h);
393: if (error < 0)
394: {
395: zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
396: ret = error;
397: }
398: }
399:
400: /* After error care. */
401: if (msg.msg_flags & MSG_TRUNC)
402: {
403: zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
404: continue;
405: }
406: if (status)
407: {
408: zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
409: status);
410: return -1;
411: }
412: }
413: return ret;
414: }
415:
416: /* Utility function for parse rtattr. */
417: static void
418: netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
419: int len)
420: {
421: while (RTA_OK (rta, len))
422: {
423: if (rta->rta_type <= max)
424: tb[rta->rta_type] = rta;
425: rta = RTA_NEXT (rta, len);
426: }
427: }
428:
429: /* Called from interface_lookup_netlink(). This function is only used
430: during bootstrap. */
431: static int
432: netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
433: {
434: int len;
435: struct ifinfomsg *ifi;
436: struct rtattr *tb[IFLA_MAX + 1];
437: struct interface *ifp;
438: char *name;
439: int i;
440:
441: ifi = NLMSG_DATA (h);
442:
443: if (h->nlmsg_type != RTM_NEWLINK)
444: return 0;
445:
446: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
447: if (len < 0)
448: return -1;
449:
450: /* Looking up interface name. */
451: memset (tb, 0, sizeof tb);
452: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
453:
454: #ifdef IFLA_WIRELESS
455: /* check for wireless messages to ignore */
456: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
457: {
458: if (IS_ZEBRA_DEBUG_KERNEL)
459: zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
460: return 0;
461: }
462: #endif /* IFLA_WIRELESS */
463:
464: if (tb[IFLA_IFNAME] == NULL)
465: return -1;
466: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
467:
468: /* Add interface. */
469: ifp = if_get_by_name (name);
470: set_ifindex(ifp, ifi->ifi_index);
471: ifp->flags = ifi->ifi_flags & 0x0000fffff;
472: ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
473: ifp->metric = 1;
474:
475: /* Hardware type and address. */
476: ifp->hw_type = ifi->ifi_type;
477:
478: if (tb[IFLA_ADDRESS])
479: {
480: int hw_addr_len;
481:
482: hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
483:
484: if (hw_addr_len > INTERFACE_HWADDR_MAX)
485: zlog_warn ("Hardware address is too large: %d", hw_addr_len);
486: else
487: {
488: ifp->hw_addr_len = hw_addr_len;
489: memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
490:
491: for (i = 0; i < hw_addr_len; i++)
492: if (ifp->hw_addr[i] != 0)
493: break;
494:
495: if (i == hw_addr_len)
496: ifp->hw_addr_len = 0;
497: else
498: ifp->hw_addr_len = hw_addr_len;
499: }
500: }
501:
502: if_add_update (ifp);
503:
504: return 0;
505: }
506:
507: /* Lookup interface IPv4/IPv6 address. */
508: static int
509: netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
510: {
511: int len;
512: struct ifaddrmsg *ifa;
513: struct rtattr *tb[IFA_MAX + 1];
514: struct interface *ifp;
515: void *addr;
516: void *broad;
517: u_char flags = 0;
518: char *label = NULL;
519:
520: ifa = NLMSG_DATA (h);
521:
522: if (ifa->ifa_family != AF_INET
523: #ifdef HAVE_IPV6
524: && ifa->ifa_family != AF_INET6
525: #endif /* HAVE_IPV6 */
526: )
527: return 0;
528:
529: if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
530: return 0;
531:
532: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
533: if (len < 0)
534: return -1;
535:
536: memset (tb, 0, sizeof tb);
537: netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
538:
539: ifp = if_lookup_by_index (ifa->ifa_index);
540: if (ifp == NULL)
541: {
542: zlog_err ("netlink_interface_addr can't find interface by index %d",
543: ifa->ifa_index);
544: return -1;
545: }
546:
547: if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
548: {
549: char buf[BUFSIZ];
550: zlog_debug ("netlink_interface_addr %s %s:",
551: lookup (nlmsg_str, h->nlmsg_type), ifp->name);
552: if (tb[IFA_LOCAL])
553: zlog_debug (" IFA_LOCAL %s/%d",
554: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
555: buf, BUFSIZ), ifa->ifa_prefixlen);
556: if (tb[IFA_ADDRESS])
557: zlog_debug (" IFA_ADDRESS %s/%d",
558: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
559: buf, BUFSIZ), ifa->ifa_prefixlen);
560: if (tb[IFA_BROADCAST])
561: zlog_debug (" IFA_BROADCAST %s/%d",
562: inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
563: buf, BUFSIZ), ifa->ifa_prefixlen);
564: if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
565: zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
566:
567: if (tb[IFA_CACHEINFO])
568: {
569: struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
570: zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
571: ci->ifa_prefered, ci->ifa_valid);
572: }
573: }
574:
575: /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
576: if (tb[IFA_LOCAL] == NULL)
577: tb[IFA_LOCAL] = tb[IFA_ADDRESS];
578: if (tb[IFA_ADDRESS] == NULL)
579: tb[IFA_ADDRESS] = tb[IFA_LOCAL];
580:
581: /* local interface address */
582: addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
583:
584: /* is there a peer address? */
585: if (tb[IFA_ADDRESS] &&
586: memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
587: {
588: broad = RTA_DATA(tb[IFA_ADDRESS]);
589: SET_FLAG (flags, ZEBRA_IFA_PEER);
590: }
591: else
592: /* seeking a broadcast address */
593: broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
594:
595: /* addr is primary key, SOL if we don't have one */
596: if (addr == NULL)
597: {
598: zlog_debug ("%s: NULL address", __func__);
599: return -1;
600: }
601:
602: /* Flags. */
603: if (ifa->ifa_flags & IFA_F_SECONDARY)
604: SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
605:
606: /* Label */
607: if (tb[IFA_LABEL])
608: label = (char *) RTA_DATA (tb[IFA_LABEL]);
609:
610: if (ifp && label && strcmp (ifp->name, label) == 0)
611: label = NULL;
612:
613: /* Register interface address to the interface. */
614: if (ifa->ifa_family == AF_INET)
615: {
616: if (h->nlmsg_type == RTM_NEWADDR)
617: connected_add_ipv4 (ifp, flags,
618: (struct in_addr *) addr, ifa->ifa_prefixlen,
619: (struct in_addr *) broad, label);
620: else
621: connected_delete_ipv4 (ifp, flags,
622: (struct in_addr *) addr, ifa->ifa_prefixlen,
623: (struct in_addr *) broad);
624: }
625: #ifdef HAVE_IPV6
626: if (ifa->ifa_family == AF_INET6)
627: {
628: if (h->nlmsg_type == RTM_NEWADDR)
629: connected_add_ipv6 (ifp, flags,
630: (struct in6_addr *) addr, ifa->ifa_prefixlen,
631: (struct in6_addr *) broad, label);
632: else
633: connected_delete_ipv6 (ifp,
634: (struct in6_addr *) addr, ifa->ifa_prefixlen,
635: (struct in6_addr *) broad);
636: }
637: #endif /* HAVE_IPV6 */
638:
639: return 0;
640: }
641:
642: /* Looking up routing table by netlink interface. */
643: static int
644: netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
645: {
646: int len;
647: struct rtmsg *rtm;
648: struct rtattr *tb[RTA_MAX + 1];
649: u_char flags = 0;
650:
651: char anyaddr[16] = { 0 };
652:
653: int index;
654: int table;
655: int metric;
656:
657: void *dest;
658: void *gate;
659: void *src;
660:
661: rtm = NLMSG_DATA (h);
662:
663: if (h->nlmsg_type != RTM_NEWROUTE)
664: return 0;
665: if (rtm->rtm_type != RTN_UNICAST)
666: return 0;
667:
668: table = rtm->rtm_table;
669: #if 0 /* we weed them out later in rib_weed_tables () */
670: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
671: return 0;
672: #endif
673:
674: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
675: if (len < 0)
676: return -1;
677:
678: memset (tb, 0, sizeof tb);
679: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
680:
681: if (rtm->rtm_flags & RTM_F_CLONED)
682: return 0;
683: if (rtm->rtm_protocol == RTPROT_REDIRECT)
684: return 0;
685: if (rtm->rtm_protocol == RTPROT_KERNEL)
686: return 0;
687:
688: if (rtm->rtm_src_len != 0)
689: return 0;
690:
691: /* Route which inserted by Zebra. */
692: if (rtm->rtm_protocol == RTPROT_ZEBRA)
693: flags |= ZEBRA_FLAG_SELFROUTE;
694:
695: index = 0;
696: metric = 0;
697: dest = NULL;
698: gate = NULL;
699: src = NULL;
700:
701: if (tb[RTA_OIF])
702: index = *(int *) RTA_DATA (tb[RTA_OIF]);
703:
704: if (tb[RTA_DST])
705: dest = RTA_DATA (tb[RTA_DST]);
706: else
707: dest = anyaddr;
708:
709: if (tb[RTA_PREFSRC])
710: src = RTA_DATA (tb[RTA_PREFSRC]);
711:
712: /* Multipath treatment is needed. */
713: if (tb[RTA_GATEWAY])
714: gate = RTA_DATA (tb[RTA_GATEWAY]);
715:
716: if (tb[RTA_PRIORITY])
717: metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
718:
719: if (rtm->rtm_family == AF_INET)
720: {
721: struct prefix_ipv4 p;
722: p.family = AF_INET;
723: memcpy (&p.prefix, dest, 4);
724: p.prefixlen = rtm->rtm_dst_len;
725:
726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
727: }
728: #ifdef HAVE_IPV6
729: if (rtm->rtm_family == AF_INET6)
730: {
731: struct prefix_ipv6 p;
732: p.family = AF_INET6;
733: memcpy (&p.prefix, dest, 16);
734: p.prefixlen = rtm->rtm_dst_len;
735:
736: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
737: metric, 0);
738: }
739: #endif /* HAVE_IPV6 */
740:
741: return 0;
742: }
743:
744: static const struct message rtproto_str[] = {
745: {RTPROT_REDIRECT, "redirect"},
746: {RTPROT_KERNEL, "kernel"},
747: {RTPROT_BOOT, "boot"},
748: {RTPROT_STATIC, "static"},
749: {RTPROT_GATED, "GateD"},
750: {RTPROT_RA, "router advertisement"},
751: {RTPROT_MRT, "MRT"},
752: {RTPROT_ZEBRA, "Zebra"},
753: #ifdef RTPROT_BIRD
754: {RTPROT_BIRD, "BIRD"},
755: #endif /* RTPROT_BIRD */
756: {0, NULL}
757: };
758:
759: /* Routing information change from the kernel. */
760: static int
761: netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
762: {
763: int len;
764: struct rtmsg *rtm;
765: struct rtattr *tb[RTA_MAX + 1];
766:
767: char anyaddr[16] = { 0 };
768:
769: int index;
770: int table;
771: int metric;
772:
773: void *dest;
774: void *gate;
775: void *src;
776:
777: rtm = NLMSG_DATA (h);
778:
779: if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
780: {
781: /* If this is not route add/delete message print warning. */
782: zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
783: return 0;
784: }
785:
786: /* Connected route. */
787: if (IS_ZEBRA_DEBUG_KERNEL)
788: zlog_debug ("%s %s %s proto %s",
789: h->nlmsg_type ==
790: RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
791: rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
792: rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
793: lookup (rtproto_str, rtm->rtm_protocol));
794:
795: if (rtm->rtm_type != RTN_UNICAST)
796: {
797: return 0;
798: }
799:
800: table = rtm->rtm_table;
801: if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
802: {
803: return 0;
804: }
805:
806: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
807: if (len < 0)
808: return -1;
809:
810: memset (tb, 0, sizeof tb);
811: netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
812:
813: if (rtm->rtm_flags & RTM_F_CLONED)
814: return 0;
815: if (rtm->rtm_protocol == RTPROT_REDIRECT)
816: return 0;
817: if (rtm->rtm_protocol == RTPROT_KERNEL)
818: return 0;
819:
820: if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
821: return 0;
822:
823: if (rtm->rtm_src_len != 0)
824: {
825: zlog_warn ("netlink_route_change(): no src len");
826: return 0;
827: }
828:
829: index = 0;
830: metric = 0;
831: dest = NULL;
832: gate = NULL;
833: src = NULL;
834:
835: if (tb[RTA_OIF])
836: index = *(int *) RTA_DATA (tb[RTA_OIF]);
837:
838: if (tb[RTA_DST])
839: dest = RTA_DATA (tb[RTA_DST]);
840: else
841: dest = anyaddr;
842:
843: if (tb[RTA_GATEWAY])
844: gate = RTA_DATA (tb[RTA_GATEWAY]);
845:
846: if (tb[RTA_PREFSRC])
847: src = RTA_DATA (tb[RTA_PREFSRC]);
848:
849: if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
850: metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
851:
852: if (rtm->rtm_family == AF_INET)
853: {
854: struct prefix_ipv4 p;
855: p.family = AF_INET;
856: memcpy (&p.prefix, dest, 4);
857: p.prefixlen = rtm->rtm_dst_len;
858:
859: if (IS_ZEBRA_DEBUG_KERNEL)
860: {
861: if (h->nlmsg_type == RTM_NEWROUTE)
862: zlog_debug ("RTM_NEWROUTE %s/%d",
863: inet_ntoa (p.prefix), p.prefixlen);
864: else
865: zlog_debug ("RTM_DELROUTE %s/%d",
866: inet_ntoa (p.prefix), p.prefixlen);
867: }
868:
869: if (h->nlmsg_type == RTM_NEWROUTE)
870: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0);
871: else
872: rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
873: }
874:
875: #ifdef HAVE_IPV6
876: if (rtm->rtm_family == AF_INET6)
877: {
878: struct prefix_ipv6 p;
879: char buf[BUFSIZ];
880:
881: p.family = AF_INET6;
882: memcpy (&p.prefix, dest, 16);
883: p.prefixlen = rtm->rtm_dst_len;
884:
885: if (IS_ZEBRA_DEBUG_KERNEL)
886: {
887: if (h->nlmsg_type == RTM_NEWROUTE)
888: zlog_debug ("RTM_NEWROUTE %s/%d",
889: inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
890: p.prefixlen);
891: else
892: zlog_debug ("RTM_DELROUTE %s/%d",
893: inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
894: p.prefixlen);
895: }
896:
897: if (h->nlmsg_type == RTM_NEWROUTE)
898: rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0);
899: else
900: rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
901: }
902: #endif /* HAVE_IPV6 */
903:
904: return 0;
905: }
906:
907: static int
908: netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
909: {
910: int len;
911: struct ifinfomsg *ifi;
912: struct rtattr *tb[IFLA_MAX + 1];
913: struct interface *ifp;
914: char *name;
915:
916: ifi = NLMSG_DATA (h);
917:
918: if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
919: {
920: /* If this is not link add/delete message so print warning. */
921: zlog_warn ("netlink_link_change: wrong kernel message %d\n",
922: h->nlmsg_type);
923: return 0;
924: }
925:
926: len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
927: if (len < 0)
928: return -1;
929:
930: /* Looking up interface name. */
931: memset (tb, 0, sizeof tb);
932: netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
933:
934: #ifdef IFLA_WIRELESS
935: /* check for wireless messages to ignore */
936: if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
937: {
938: if (IS_ZEBRA_DEBUG_KERNEL)
939: zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
940: return 0;
941: }
942: #endif /* IFLA_WIRELESS */
943:
944: if (tb[IFLA_IFNAME] == NULL)
945: return -1;
946: name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
947:
948: /* Add interface. */
949: if (h->nlmsg_type == RTM_NEWLINK)
950: {
951: ifp = if_lookup_by_name (name);
952:
953: if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
954: {
955: if (ifp == NULL)
956: ifp = if_get_by_name (name);
957:
958: set_ifindex(ifp, ifi->ifi_index);
959: ifp->flags = ifi->ifi_flags & 0x0000fffff;
960: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
961: ifp->metric = 1;
962:
963: /* If new link is added. */
964: if_add_update (ifp);
965: }
966: else
967: {
968: /* Interface status change. */
969: set_ifindex(ifp, ifi->ifi_index);
970: ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
971: ifp->metric = 1;
972:
973: if (if_is_operative (ifp))
974: {
975: ifp->flags = ifi->ifi_flags & 0x0000fffff;
976: if (!if_is_operative (ifp))
977: if_down (ifp);
978: else
979: /* Must notify client daemons of new interface status. */
980: zebra_interface_up_update (ifp);
981: }
982: else
983: {
984: ifp->flags = ifi->ifi_flags & 0x0000fffff;
985: if (if_is_operative (ifp))
986: if_up (ifp);
987: }
988: }
989: }
990: else
991: {
992: /* RTM_DELLINK. */
993: ifp = if_lookup_by_name (name);
994:
995: if (ifp == NULL)
996: {
997: zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
998: name);
999: return 0;
1000: }
1001:
1002: if_delete_update (ifp);
1003: }
1004:
1005: return 0;
1006: }
1007:
1008: static int
1009: netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1010: {
1011: /* JF: Ignore messages that aren't from the kernel */
1012: if ( snl->nl_pid != 0 )
1013: {
1014: zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1015: return 0;
1016: }
1017:
1018: switch (h->nlmsg_type)
1019: {
1020: case RTM_NEWROUTE:
1021: return netlink_route_change (snl, h);
1022: break;
1023: case RTM_DELROUTE:
1024: return netlink_route_change (snl, h);
1025: break;
1026: case RTM_NEWLINK:
1027: return netlink_link_change (snl, h);
1028: break;
1029: case RTM_DELLINK:
1030: return netlink_link_change (snl, h);
1031: break;
1032: case RTM_NEWADDR:
1033: return netlink_interface_addr (snl, h);
1034: break;
1035: case RTM_DELADDR:
1036: return netlink_interface_addr (snl, h);
1037: break;
1038: default:
1039: zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1040: break;
1041: }
1042: return 0;
1043: }
1044:
1045: /* Interface lookup by netlink socket. */
1046: int
1047: interface_lookup_netlink (void)
1048: {
1049: int ret;
1050:
1051: /* Get interface information. */
1052: ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1053: if (ret < 0)
1054: return ret;
1055: ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1056: if (ret < 0)
1057: return ret;
1058:
1059: /* Get IPv4 address of the interfaces. */
1060: ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1061: if (ret < 0)
1062: return ret;
1063: ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1064: if (ret < 0)
1065: return ret;
1066:
1067: #ifdef HAVE_IPV6
1068: /* Get IPv6 address of the interfaces. */
1069: ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1070: if (ret < 0)
1071: return ret;
1072: ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1073: if (ret < 0)
1074: return ret;
1075: #endif /* HAVE_IPV6 */
1076:
1077: return 0;
1078: }
1079:
1080: /* Routing table read function using netlink interface. Only called
1081: bootstrap time. */
1082: int
1083: netlink_route_read (void)
1084: {
1085: int ret;
1086:
1087: /* Get IPv4 routing table. */
1088: ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1089: if (ret < 0)
1090: return ret;
1091: ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1092: if (ret < 0)
1093: return ret;
1094:
1095: #ifdef HAVE_IPV6
1096: /* Get IPv6 routing table. */
1097: ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1098: if (ret < 0)
1099: return ret;
1100: ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1101: if (ret < 0)
1102: return ret;
1103: #endif /* HAVE_IPV6 */
1104:
1105: return 0;
1106: }
1107:
1108: /* Utility function comes from iproute2.
1109: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1110: static int
1111: addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1112: {
1113: int len;
1114: struct rtattr *rta;
1115:
1116: len = RTA_LENGTH (alen);
1117:
1118: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1119: return -1;
1120:
1121: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
1122: rta->rta_type = type;
1123: rta->rta_len = len;
1124: memcpy (RTA_DATA (rta), data, alen);
1125: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1126:
1127: return 0;
1128: }
1129:
1130: static int
1131: rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1132: {
1133: int len;
1134: struct rtattr *subrta;
1135:
1136: len = RTA_LENGTH (alen);
1137:
1138: if (RTA_ALIGN (rta->rta_len) + len > maxlen)
1139: return -1;
1140:
1141: subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
1142: subrta->rta_type = type;
1143: subrta->rta_len = len;
1144: memcpy (RTA_DATA (subrta), data, alen);
1145: rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1146:
1147: return 0;
1148: }
1149:
1150: /* Utility function comes from iproute2.
1151: Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1152: static int
1153: addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1154: {
1155: int len;
1156: struct rtattr *rta;
1157:
1158: len = RTA_LENGTH (4);
1159:
1160: if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1161: return -1;
1162:
1163: rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
1164: rta->rta_type = type;
1165: rta->rta_len = len;
1166: memcpy (RTA_DATA (rta), &data, 4);
1167: n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1168:
1169: return 0;
1170: }
1171:
1172: static int
1173: netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1174: {
1175: zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1176: return 0;
1177: }
1178:
1179: /* sendmsg() to netlink socket then recvmsg(). */
1180: static int
1181: netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1182: {
1183: int status;
1184: struct sockaddr_nl snl;
1185: struct iovec iov = { (void *) n, n->nlmsg_len };
1186: struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
1187: int save_errno;
1188:
1189: memset (&snl, 0, sizeof snl);
1190: snl.nl_family = AF_NETLINK;
1191:
1192: n->nlmsg_seq = ++nl->seq;
1193:
1194: /* Request an acknowledgement by setting NLM_F_ACK */
1195: n->nlmsg_flags |= NLM_F_ACK;
1196:
1197: if (IS_ZEBRA_DEBUG_KERNEL)
1198: zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
1199: lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1200: n->nlmsg_seq);
1201:
1202: /* Send message to netlink interface. */
1203: if (zserv_privs.change (ZPRIVS_RAISE))
1204: zlog (NULL, LOG_ERR, "Can't raise privileges");
1205: status = sendmsg (nl->sock, &msg, 0);
1206: save_errno = errno;
1207: if (zserv_privs.change (ZPRIVS_LOWER))
1208: zlog (NULL, LOG_ERR, "Can't lower privileges");
1209:
1210: if (status < 0)
1211: {
1212: zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
1213: safe_strerror (save_errno));
1214: return -1;
1215: }
1216:
1217:
1218: /*
1219: * Get reply from netlink socket.
1220: * The reply should either be an acknowlegement or an error.
1221: */
1222: return netlink_parse_info (netlink_talk_filter, nl);
1223: }
1224:
1225: /* Routing table change via netlink interface. */
1226: static int
1227: netlink_route (int cmd, int family, void *dest, int length, void *gate,
1228: int index, int zebra_flags, int table)
1229: {
1230: int ret;
1231: int bytelen;
1232: struct sockaddr_nl snl;
1233: int discard;
1234:
1235: struct
1236: {
1237: struct nlmsghdr n;
1238: struct rtmsg r;
1239: char buf[1024];
1240: } req;
1241:
1242: memset (&req, 0, sizeof req);
1243:
1244: bytelen = (family == AF_INET ? 4 : 16);
1245:
1246: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1247: req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1248: req.n.nlmsg_type = cmd;
1249: req.r.rtm_family = family;
1250: req.r.rtm_table = table;
1251: req.r.rtm_dst_len = length;
1252: req.r.rtm_protocol = RTPROT_ZEBRA;
1253: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1254:
1255: if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1256: || (zebra_flags & ZEBRA_FLAG_REJECT))
1257: discard = 1;
1258: else
1259: discard = 0;
1260:
1261: if (cmd == RTM_NEWROUTE)
1262: {
1263: if (discard)
1264: {
1265: if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1266: req.r.rtm_type = RTN_BLACKHOLE;
1267: else if (zebra_flags & ZEBRA_FLAG_REJECT)
1268: req.r.rtm_type = RTN_UNREACHABLE;
1269: else
1270: assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1271: }
1272: else
1273: req.r.rtm_type = RTN_UNICAST;
1274: }
1275:
1276: if (dest)
1277: addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1278:
1279: if (!discard)
1280: {
1281: if (gate)
1282: addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
1283: if (index > 0)
1284: addattr32 (&req.n, sizeof req, RTA_OIF, index);
1285: }
1286:
1287: /* Destination netlink address. */
1288: memset (&snl, 0, sizeof snl);
1289: snl.nl_family = AF_NETLINK;
1290:
1291: /* Talk to netlink socket. */
1292: ret = netlink_talk (&req.n, &netlink_cmd);
1293: if (ret < 0)
1294: return -1;
1295:
1296: return 0;
1297: }
1298:
1299: /* Routing table change via netlink interface. */
1300: static int
1301: netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
1302: int family)
1303: {
1304: int bytelen;
1305: struct sockaddr_nl snl;
1306: struct nexthop *nexthop = NULL;
1307: int nexthop_num = 0;
1308: int discard;
1309:
1310: struct
1311: {
1312: struct nlmsghdr n;
1313: struct rtmsg r;
1314: char buf[1024];
1315: } req;
1316:
1317: memset (&req, 0, sizeof req);
1318:
1319: bytelen = (family == AF_INET ? 4 : 16);
1320:
1321: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1322: req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1323: req.n.nlmsg_type = cmd;
1324: req.r.rtm_family = family;
1325: req.r.rtm_table = rib->table;
1326: req.r.rtm_dst_len = p->prefixlen;
1327: req.r.rtm_protocol = RTPROT_ZEBRA;
1328: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1329:
1330: if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
1331: discard = 1;
1332: else
1333: discard = 0;
1334:
1335: if (cmd == RTM_NEWROUTE)
1336: {
1337: if (discard)
1338: {
1339: if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1340: req.r.rtm_type = RTN_BLACKHOLE;
1341: else if (rib->flags & ZEBRA_FLAG_REJECT)
1342: req.r.rtm_type = RTN_UNREACHABLE;
1343: else
1344: assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1345: }
1346: else
1347: req.r.rtm_type = RTN_UNICAST;
1348: }
1349:
1350: addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1351:
1352: /* Metric. */
1353: addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1354:
1355: if (discard)
1356: {
1357: if (cmd == RTM_NEWROUTE)
1358: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1359: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1360: goto skip;
1361: }
1362:
1363: /* Multipath case. */
1364: if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1365: {
1366: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1367: {
1368:
1369: if ((cmd == RTM_NEWROUTE
1370: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1371: || (cmd == RTM_DELROUTE
1372: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1373: {
1374:
1375: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1376: {
1377: if (IS_ZEBRA_DEBUG_KERNEL)
1378: {
1379: zlog_debug
1380: ("netlink_route_multipath() (recursive, 1 hop): "
1381: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1382: #ifdef HAVE_IPV6
1383: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1384: inet6_ntoa (p->u.prefix6),
1385: #else
1386: inet_ntoa (p->u.prefix4),
1387: #endif /* HAVE_IPV6 */
1388:
1389: p->prefixlen, nexthop_types_desc[nexthop->rtype]);
1390: }
1391:
1392: if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1393: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1394: {
1395: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1396: &nexthop->rgate.ipv4, bytelen);
1397: if (nexthop->src.ipv4.s_addr)
1398: addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1399: &nexthop->src.ipv4, bytelen);
1400: if (IS_ZEBRA_DEBUG_KERNEL)
1401: zlog_debug("netlink_route_multipath() (recursive, "
1402: "1 hop): nexthop via %s if %u",
1403: inet_ntoa (nexthop->rgate.ipv4),
1404: nexthop->rifindex);
1405: }
1406: #ifdef HAVE_IPV6
1407: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1408: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1409: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1410: {
1411: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1412: &nexthop->rgate.ipv6, bytelen);
1413:
1414: if (IS_ZEBRA_DEBUG_KERNEL)
1415: zlog_debug("netlink_route_multipath() (recursive, "
1416: "1 hop): nexthop via %s if %u",
1417: inet6_ntoa (nexthop->rgate.ipv6),
1418: nexthop->rifindex);
1419: }
1420: #endif /* HAVE_IPV6 */
1421: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1422: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1423: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1424: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1425: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1426: {
1427: addattr32 (&req.n, sizeof req, RTA_OIF,
1428: nexthop->rifindex);
1429: if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1430: || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1431: && nexthop->src.ipv4.s_addr)
1432: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1433: &nexthop->src.ipv4, bytelen);
1434:
1435: if (IS_ZEBRA_DEBUG_KERNEL)
1436: zlog_debug("netlink_route_multipath() (recursive, "
1437: "1 hop): nexthop via if %u",
1438: nexthop->rifindex);
1439: }
1440: }
1441: else
1442: {
1443: if (IS_ZEBRA_DEBUG_KERNEL)
1444: {
1445: zlog_debug
1446: ("netlink_route_multipath() (single hop): "
1447: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1448: #ifdef HAVE_IPV6
1449: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1450: inet6_ntoa (p->u.prefix6),
1451: #else
1452: inet_ntoa (p->u.prefix4),
1453: #endif /* HAVE_IPV6 */
1454: p->prefixlen, nexthop_types_desc[nexthop->type]);
1455: }
1456:
1457: if (nexthop->type == NEXTHOP_TYPE_IPV4
1458: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1459: {
1460: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1461: &nexthop->gate.ipv4, bytelen);
1462: if (nexthop->src.ipv4.s_addr)
1463: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1464: &nexthop->src.ipv4, bytelen);
1465:
1466: if (IS_ZEBRA_DEBUG_KERNEL)
1467: zlog_debug("netlink_route_multipath() (single hop): "
1468: "nexthop via %s if %u",
1469: inet_ntoa (nexthop->gate.ipv4),
1470: nexthop->ifindex);
1471: }
1472: #ifdef HAVE_IPV6
1473: if (nexthop->type == NEXTHOP_TYPE_IPV6
1474: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1475: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1476: {
1477: addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1478: &nexthop->gate.ipv6, bytelen);
1479:
1480: if (IS_ZEBRA_DEBUG_KERNEL)
1481: zlog_debug("netlink_route_multipath() (single hop): "
1482: "nexthop via %s if %u",
1483: inet6_ntoa (nexthop->gate.ipv6),
1484: nexthop->ifindex);
1485: }
1486: #endif /* HAVE_IPV6 */
1487: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1488: || nexthop->type == NEXTHOP_TYPE_IFNAME
1489: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1490: {
1491: addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1492:
1493: if (nexthop->src.ipv4.s_addr)
1494: addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1495: &nexthop->src.ipv4, bytelen);
1496:
1497: if (IS_ZEBRA_DEBUG_KERNEL)
1498: zlog_debug("netlink_route_multipath() (single hop): "
1499: "nexthop via if %u", nexthop->ifindex);
1500: }
1501: else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1502: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1503: {
1504: addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1505:
1506: if (IS_ZEBRA_DEBUG_KERNEL)
1507: zlog_debug("netlink_route_multipath() (single hop): "
1508: "nexthop via if %u", nexthop->ifindex);
1509: }
1510: }
1511:
1512: if (cmd == RTM_NEWROUTE)
1513: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1514:
1515: nexthop_num++;
1516: break;
1517: }
1518: }
1519: }
1520: else
1521: {
1522: char buf[1024];
1523: struct rtattr *rta = (void *) buf;
1524: struct rtnexthop *rtnh;
1525: union g_addr *src = NULL;
1526:
1527: rta->rta_type = RTA_MULTIPATH;
1528: rta->rta_len = RTA_LENGTH (0);
1529: rtnh = RTA_DATA (rta);
1530:
1531: nexthop_num = 0;
1532: for (nexthop = rib->nexthop;
1533: nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1534: nexthop = nexthop->next)
1535: {
1536: if ((cmd == RTM_NEWROUTE
1537: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1538: || (cmd == RTM_DELROUTE
1539: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1540: {
1541: nexthop_num++;
1542:
1543: rtnh->rtnh_len = sizeof (*rtnh);
1544: rtnh->rtnh_flags = 0;
1545: rtnh->rtnh_hops = 0;
1546: rta->rta_len += rtnh->rtnh_len;
1547:
1548: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1549: {
1550: if (IS_ZEBRA_DEBUG_KERNEL)
1551: {
1552: zlog_debug ("netlink_route_multipath() "
1553: "(recursive, multihop): %s %s/%d type %s",
1554: lookup (nlmsg_str, cmd),
1555: #ifdef HAVE_IPV6
1556: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1557: inet6_ntoa (p->u.prefix6),
1558: #else
1559: inet_ntoa (p->u.prefix4),
1560: #endif /* HAVE_IPV6 */
1561: p->prefixlen, nexthop_types_desc[nexthop->rtype]);
1562: }
1563: if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1564: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1565: {
1566: rta_addattr_l (rta, 4096, RTA_GATEWAY,
1567: &nexthop->rgate.ipv4, bytelen);
1568: rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1569:
1570: if (nexthop->src.ipv4.s_addr)
1571: src = &nexthop->src;
1572:
1573: if (IS_ZEBRA_DEBUG_KERNEL)
1574: zlog_debug("netlink_route_multipath() (recursive, "
1575: "multihop): nexthop via %s if %u",
1576: inet_ntoa (nexthop->rgate.ipv4),
1577: nexthop->rifindex);
1578: }
1579: #ifdef HAVE_IPV6
1580: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1581: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1582: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1583: {
1584: rta_addattr_l (rta, 4096, RTA_GATEWAY,
1585: &nexthop->rgate.ipv6, bytelen);
1586:
1587: if (IS_ZEBRA_DEBUG_KERNEL)
1588: zlog_debug("netlink_route_multipath() (recursive, "
1589: "multihop): nexthop via %s if %u",
1590: inet6_ntoa (nexthop->rgate.ipv6),
1591: nexthop->rifindex);
1592: }
1593: #endif /* HAVE_IPV6 */
1594: /* ifindex */
1595: if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1596: || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1597: || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1598: {
1599: rtnh->rtnh_ifindex = nexthop->rifindex;
1600: if (nexthop->src.ipv4.s_addr)
1601: src = &nexthop->src;
1602:
1603: if (IS_ZEBRA_DEBUG_KERNEL)
1604: zlog_debug("netlink_route_multipath() (recursive, "
1605: "multihop): nexthop via if %u",
1606: nexthop->rifindex);
1607: }
1608: else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1609: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1610: {
1611: rtnh->rtnh_ifindex = nexthop->rifindex;
1612:
1613: if (IS_ZEBRA_DEBUG_KERNEL)
1614: zlog_debug("netlink_route_multipath() (recursive, "
1615: "multihop): nexthop via if %u",
1616: nexthop->rifindex);
1617: }
1618: else
1619: {
1620: rtnh->rtnh_ifindex = 0;
1621: }
1622: }
1623: else
1624: {
1625: if (IS_ZEBRA_DEBUG_KERNEL)
1626: {
1627: zlog_debug ("netlink_route_multipath() (multihop): "
1628: "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1629: #ifdef HAVE_IPV6
1630: (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1631: inet6_ntoa (p->u.prefix6),
1632: #else
1633: inet_ntoa (p->u.prefix4),
1634: #endif /* HAVE_IPV6 */
1635: p->prefixlen, nexthop_types_desc[nexthop->type]);
1636: }
1637: if (nexthop->type == NEXTHOP_TYPE_IPV4
1638: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1639: {
1640: rta_addattr_l (rta, 4096, RTA_GATEWAY,
1641: &nexthop->gate.ipv4, bytelen);
1642: rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1643:
1644: if (nexthop->src.ipv4.s_addr)
1645: src = &nexthop->src;
1646:
1647: if (IS_ZEBRA_DEBUG_KERNEL)
1648: zlog_debug("netlink_route_multipath() (multihop): "
1649: "nexthop via %s if %u",
1650: inet_ntoa (nexthop->gate.ipv4),
1651: nexthop->ifindex);
1652: }
1653: #ifdef HAVE_IPV6
1654: if (nexthop->type == NEXTHOP_TYPE_IPV6
1655: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1656: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1657: {
1658: rta_addattr_l (rta, 4096, RTA_GATEWAY,
1659: &nexthop->gate.ipv6, bytelen);
1660:
1661: if (IS_ZEBRA_DEBUG_KERNEL)
1662: zlog_debug("netlink_route_multipath() (multihop): "
1663: "nexthop via %s if %u",
1664: inet6_ntoa (nexthop->gate.ipv6),
1665: nexthop->ifindex);
1666: }
1667: #endif /* HAVE_IPV6 */
1668: /* ifindex */
1669: if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1670: || nexthop->type == NEXTHOP_TYPE_IFINDEX
1671: || nexthop->type == NEXTHOP_TYPE_IFNAME)
1672: {
1673: rtnh->rtnh_ifindex = nexthop->ifindex;
1674: if (nexthop->src.ipv4.s_addr)
1675: src = &nexthop->src;
1676: if (IS_ZEBRA_DEBUG_KERNEL)
1677: zlog_debug("netlink_route_multipath() (multihop): "
1678: "nexthop via if %u", nexthop->ifindex);
1679: }
1680: else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1681: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1682: {
1683: rtnh->rtnh_ifindex = nexthop->ifindex;
1684:
1685: if (IS_ZEBRA_DEBUG_KERNEL)
1686: zlog_debug("netlink_route_multipath() (multihop): "
1687: "nexthop via if %u", nexthop->ifindex);
1688: }
1689: else
1690: {
1691: rtnh->rtnh_ifindex = 0;
1692: }
1693: }
1694: rtnh = RTNH_NEXT (rtnh);
1695:
1696: if (cmd == RTM_NEWROUTE)
1697: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1698: }
1699: }
1700: if (src)
1701: addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
1702:
1703: if (rta->rta_len > RTA_LENGTH (0))
1704: addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1705: RTA_PAYLOAD (rta));
1706: }
1707:
1708: /* If there is no useful nexthop then return. */
1709: if (nexthop_num == 0)
1710: {
1711: if (IS_ZEBRA_DEBUG_KERNEL)
1712: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
1713: return 0;
1714: }
1715:
1716: skip:
1717:
1718: /* Destination netlink address. */
1719: memset (&snl, 0, sizeof snl);
1720: snl.nl_family = AF_NETLINK;
1721:
1722: /* Talk to netlink socket. */
1723: return netlink_talk (&req.n, &netlink_cmd);
1724: }
1725:
1726: int
1727: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1728: {
1729: return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1730: }
1731:
1732: int
1733: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1734: {
1735: return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1736: }
1737:
1738: #ifdef HAVE_IPV6
1739: int
1740: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1741: {
1742: return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1743: }
1744:
1745: int
1746: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1747: {
1748: return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1749: }
1750:
1751: /* Delete IPv6 route from the kernel. */
1752: int
1753: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
1754: unsigned int index, int flags, int table)
1755: {
1756: return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1757: dest->prefixlen, gate, index, flags, table);
1758: }
1759: #endif /* HAVE_IPV6 */
1760:
1761: /* Interface address modification. */
1762: static int
1763: netlink_address (int cmd, int family, struct interface *ifp,
1764: struct connected *ifc)
1765: {
1766: int bytelen;
1767: struct prefix *p;
1768:
1769: struct
1770: {
1771: struct nlmsghdr n;
1772: struct ifaddrmsg ifa;
1773: char buf[1024];
1774: } req;
1775:
1776: p = ifc->address;
1777: memset (&req, 0, sizeof req);
1778:
1779: bytelen = (family == AF_INET ? 4 : 16);
1780:
1781: req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
1782: req.n.nlmsg_flags = NLM_F_REQUEST;
1783: req.n.nlmsg_type = cmd;
1784: req.ifa.ifa_family = family;
1785:
1786: req.ifa.ifa_index = ifp->ifindex;
1787: req.ifa.ifa_prefixlen = p->prefixlen;
1788:
1789: addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1790:
1791: if (family == AF_INET && cmd == RTM_NEWADDR)
1792: {
1793: if (!CONNECTED_PEER(ifc) && ifc->destination)
1794: {
1795: p = ifc->destination;
1796: addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1797: bytelen);
1798: }
1799: }
1800:
1801: if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1802: SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
1803:
1804: if (ifc->label)
1805: addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
1806: strlen (ifc->label) + 1);
1807:
1808: return netlink_talk (&req.n, &netlink_cmd);
1809: }
1810:
1811: int
1812: kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1813: {
1814: return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1815: }
1816:
1817: int
1818: kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1819: {
1820: return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1821: }
1822:
1823:
1824: extern struct thread_master *master;
1825:
1826: /* Kernel route reflection. */
1827: static int
1828: kernel_read (struct thread *thread)
1829: {
1830: int ret;
1831: int sock;
1832:
1833: sock = THREAD_FD (thread);
1834: ret = netlink_parse_info (netlink_information_fetch, &netlink);
1835: thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1836:
1837: return 0;
1838: }
1839:
1840: /* Filter out messages from self that occur on listener socket,
1841: caused by our actions on the command socket
1842: */
1843: static void netlink_install_filter (int sock, __u32 pid)
1844: {
1845: struct sock_filter filter[] = {
1846: /* 0: ldh [4] */
1847: BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1848: /* 1: jeq 0x18 jt 3 jf 6 */
1849: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1850: /* 2: jeq 0x19 jt 3 jf 6 */
1851: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1852: /* 3: ldw [12] */
1853: BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1854: /* 4: jeq XX jt 5 jf 6 */
1855: BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1856: /* 5: ret 0 (skip) */
1857: BPF_STMT(BPF_RET|BPF_K, 0),
1858: /* 6: ret 0xffff (keep) */
1859: BPF_STMT(BPF_RET|BPF_K, 0xffff),
1860: };
1861:
1862: struct sock_fprog prog = {
1863: .len = sizeof(filter) / sizeof(filter[0]),
1864: .filter = filter,
1865: };
1866:
1867: if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1868: zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1869: }
1870:
1871: /* Exported interface function. This function simply calls
1872: netlink_socket (). */
1873: void
1874: kernel_init (void)
1875: {
1876: unsigned long groups;
1877:
1878: groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
1879: #ifdef HAVE_IPV6
1880: groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
1881: #endif /* HAVE_IPV6 */
1882: netlink_socket (&netlink, groups);
1883: netlink_socket (&netlink_cmd, 0);
1884:
1885: /* Register kernel socket. */
1886: if (netlink.sock > 0)
1887: {
1888: /* Only want non-blocking on the netlink event socket */
1889: if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1890: zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1891: safe_strerror (errno));
1892:
1893: /* Set receive buffer size if it's set from command line */
1894: if (nl_rcvbufsize)
1895: netlink_recvbuf (&netlink, nl_rcvbufsize);
1896:
1897: netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
1898: thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1899: }
1900: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>