]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rt_netlink.c
Initial revision
[mirror_frr.git] / zebra / rt_netlink.c
CommitLineData
718e3744 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
37#include "zebra/zserv.h"
38#include "zebra/redistribute.h"
39#include "zebra/interface.h"
40#include "zebra/debug.h"
41
42/* Socket interface to kernel */
43struct nlsock
44{
45 int sock;
46 int seq;
47 struct sockaddr_nl snl;
48 char *name;
49} netlink = { -1, 0, {0}, "netlink-listen" }, /* kernel messages */
50 netlink_cmd = { -1, 0, {0}, "netlink-cmd" }, /* command channel */
51 netlink_addr = {-1, 0, {0}, "netlink-addr" }; /* address channel */
52
53struct message nlmsg_str[] =
54{
55 {RTM_NEWROUTE, "RTM_NEWROUTE"},
56 {RTM_DELROUTE, "RTM_DELROUTE"},
57 {RTM_GETROUTE, "RTM_GETROUTE"},
58 {RTM_NEWLINK, "RTM_NEWLINK"},
59 {RTM_DELLINK, "RTM_DELLINK"},
60 {RTM_GETLINK, "RTM_GETLINK"},
61 {RTM_NEWADDR, "RTM_NEWADDR"},
62 {RTM_DELADDR, "RTM_DELADDR"},
63 {RTM_GETADDR, "RTM_GETADDR"},
64 {0, NULL}
65};
66
67extern int rtm_table_default;
68
69/* Make socket for Linux netlink interface. */
70static int
71netlink_socket (struct nlsock *nl, unsigned long groups)
72{
73 int ret;
74 struct sockaddr_nl snl;
75 int sock;
76 int namelen;
77
78 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
79 if (sock < 0)
80 {
81 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
82 strerror (errno));
83 return -1;
84 }
85
86 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
87 if (ret < 0)
88 {
89 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
90 strerror (errno));
91 close (sock);
92 return -1;
93 }
94
95 memset (&snl, 0, sizeof snl);
96 snl.nl_family = AF_NETLINK;
97 snl.nl_groups = groups;
98
99 /* Bind the socket to the netlink structure for anything. */
100 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
101 if (ret < 0)
102 {
103 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
104 nl->name, snl.nl_groups, strerror (errno));
105 close (sock);
106 return -1;
107 }
108
109 /* multiple netlink sockets will have different nl_pid */
110 namelen = sizeof snl;
111 ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
112 if (ret < 0 || namelen != sizeof snl)
113 {
114 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
115 strerror (errno));
116 close (sock);
117 return -1;
118 }
119
120 nl->snl = snl;
121 nl->sock = sock;
122 return ret;
123}
124
125/* Get type specified information from netlink. */
126static int
127netlink_request (int family, int type, struct nlsock *nl)
128{
129 int ret;
130 struct sockaddr_nl snl;
131
132 struct
133 {
134 struct nlmsghdr nlh;
135 struct rtgenmsg g;
136 } req;
137
138
139 /* Check netlink socket. */
140 if (nl->sock < 0)
141 {
142 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
143 return -1;
144 }
145
146 memset (&snl, 0, sizeof snl);
147 snl.nl_family = AF_NETLINK;
148
149 req.nlh.nlmsg_len = sizeof req;
150 req.nlh.nlmsg_type = type;
151 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
152 req.nlh.nlmsg_pid = 0;
153 req.nlh.nlmsg_seq = ++nl->seq;
154 req.g.rtgen_family = family;
155
156 ret = sendto (nl->sock, (void*) &req, sizeof req, 0,
157 (struct sockaddr*) &snl, sizeof snl);
158 if (ret < 0)
159 {
160 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno));
161 return -1;
162 }
163 return 0;
164}
165
166/* Receive message from netlink interface and pass those information
167 to the given function. */
168static int
169netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
170 struct nlsock *nl)
171{
172 int status;
173 int ret = 0;
174 int error;
175
176 while (1)
177 {
178 char buf[4096];
179 struct iovec iov = { buf, sizeof buf };
180 struct sockaddr_nl snl;
181 struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0};
182 struct nlmsghdr *h;
183
184 status = recvmsg (nl->sock, &msg, 0);
185
186 if (status < 0)
187 {
188 if (errno == EINTR)
189 continue;
190 if (errno == EWOULDBLOCK || errno == EAGAIN)
191 break;
192 zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
193 continue;
194 }
195
196 if (status == 0)
197 {
198 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
199 return -1;
200 }
201
202 if (msg.msg_namelen != sizeof snl)
203 {
204 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
205 nl->name, msg.msg_namelen);
206 return -1;
207 }
208
209 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
210 h = NLMSG_NEXT (h, status))
211 {
212 /* Finish of reading. */
213 if (h->nlmsg_type == NLMSG_DONE)
214 return ret;
215
216 /* Error handling. */
217 if (h->nlmsg_type == NLMSG_ERROR)
218 {
219 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
220
221 /* If the error field is zero, then this is an ACK */
222 if (err->error == 0)
223 {
224 if (IS_ZEBRA_DEBUG_KERNEL)
225 {
226 zlog_info("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
227 __FUNCTION__, nl->name,
228 lookup (nlmsg_str, err->msg.nlmsg_type),
229 err->msg.nlmsg_type, err->msg.nlmsg_seq,
230 err->msg.nlmsg_pid);
231 }
232
233 /* return if not a multipart message, otherwise continue */
234 if(!(h->nlmsg_flags & NLM_F_MULTI))
235 {
236 return 0;
237 }
238 continue;
239 }
240
241 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
242 {
243 zlog (NULL, LOG_ERR, "%s error: message truncated",
244 nl->name);
245 return -1;
246 }
247 zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d",
248 nl->name, strerror (-err->error),
249 lookup (nlmsg_str, err->msg.nlmsg_type),
250 err->msg.nlmsg_type, err->msg.nlmsg_seq,
251 err->msg.nlmsg_pid);
252 /*
253 ret = -1;
254 continue;
255 */
256 return -1;
257 }
258
259 /* OK we got netlink message. */
260 if (IS_ZEBRA_DEBUG_KERNEL)
261 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
262 nl->name,
263 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
264 h->nlmsg_seq, h->nlmsg_pid);
265
266 /* skip unsolicited messages originating from command socket */
267 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
268 {
269 if (IS_ZEBRA_DEBUG_KERNEL)
270 zlog_info ("netlink_parse_info: %s packet comes from %s",
271 nl->name, netlink_cmd.name);
272 continue;
273 }
274
275 error = (*filter) (&snl, h);
276 if (error < 0)
277 {
278 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
279 ret = error;
280 }
281 }
282
283 /* After error care. */
284 if (msg.msg_flags & MSG_TRUNC)
285 {
286 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
287 continue;
288 }
289 if (status)
290 {
291 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
292 status);
293 return -1;
294 }
295 }
296 return ret;
297}
298
299/* Utility function for parse rtattr. */
300static void
301netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len)
302{
303 while (RTA_OK(rta, len))
304 {
305 if (rta->rta_type <= max)
306 tb[rta->rta_type] = rta;
307 rta = RTA_NEXT(rta,len);
308 }
309}
310
311/* Called from interface_lookup_netlink(). This function is only used
312 during bootstrap. */
313int
314netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
315{
316 int len;
317 struct ifinfomsg *ifi;
318 struct rtattr *tb[IFLA_MAX + 1];
319 struct interface *ifp;
320 char *name;
321 int i;
322
323 ifi = NLMSG_DATA (h);
324
325 if (h->nlmsg_type != RTM_NEWLINK)
326 return 0;
327
328 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
329 if (len < 0)
330 return -1;
331
332 /* Looking up interface name. */
333 memset (tb, 0, sizeof tb);
334 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
335 if (tb[IFLA_IFNAME] == NULL)
336 return -1;
337 name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
338
339 /* Add interface. */
340 ifp = if_get_by_name (name);
341
342 ifp->ifindex = ifi->ifi_index;
343 ifp->flags = ifi->ifi_flags & 0x0000fffff;
344 ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
345 ifp->metric = 1;
346
347 /* Hardware type and address. */
348 ifp->hw_type = ifi->ifi_type;
349
350 if (tb[IFLA_ADDRESS])
351 {
352 int hw_addr_len;
353
354 hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
355
356 if (hw_addr_len > INTERFACE_HWADDR_MAX)
357 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
358 else
359 {
360 ifp->hw_addr_len = hw_addr_len;
361 memcpy (ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), hw_addr_len);
362
363 for (i = 0; i < hw_addr_len; i++)
364 if (ifp->hw_addr[i] != 0)
365 break;
366
367 if (i == hw_addr_len)
368 ifp->hw_addr_len = 0;
369 else
370 ifp->hw_addr_len = hw_addr_len;
371 }
372 }
373
374 if_add_update (ifp);
375
376 return 0;
377}
378
379/* Lookup interface IPv4/IPv6 address. */
380int
381netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
382{
383 int len;
384 struct ifaddrmsg *ifa;
385 struct rtattr *tb [IFA_MAX + 1];
386 struct interface *ifp;
387 void *addr = NULL;
388 void *broad = NULL;
389 u_char flags = 0;
390 char *label = NULL;
391
392 ifa = NLMSG_DATA (h);
393
394 if (ifa->ifa_family != AF_INET
395#ifdef HAVE_IPV6
396 && ifa->ifa_family != AF_INET6
397#endif /* HAVE_IPV6 */
398 )
399 return 0;
400
401 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
402 return 0;
403
404 len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg));
405 if (len < 0)
406 return -1;
407
408 memset (tb, 0, sizeof tb);
409 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
410
411 ifp = if_lookup_by_index (ifa->ifa_index);
412 if (ifp == NULL)
413 {
414 zlog_err ("netlink_interface_addr can't find interface by index %d",
415 ifa->ifa_index);
416 return -1;
417 }
418
419 if (tb[IFA_ADDRESS] == NULL)
420 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
421
422 if (ifp->flags & IFF_POINTOPOINT)
423 {
424 if (tb[IFA_LOCAL])
425 {
426 addr = RTA_DATA (tb[IFA_LOCAL]);
427 if (tb[IFA_ADDRESS])
428 broad = RTA_DATA (tb[IFA_ADDRESS]);
429 else
430 broad = NULL;
431 }
432 else
433 {
434 if (tb[IFA_ADDRESS])
435 addr = RTA_DATA (tb[IFA_ADDRESS]);
436 else
437 addr = NULL;
438 }
439 }
440 else
441 {
442 if (tb[IFA_ADDRESS])
443 addr = RTA_DATA (tb[IFA_ADDRESS]);
444 else
445 addr = NULL;
446
447 if (tb[IFA_BROADCAST])
448 broad = RTA_DATA(tb[IFA_BROADCAST]);
449 else
450 broad = NULL;
451 }
452
453 /* Flags. */
454 if (ifa->ifa_flags & IFA_F_SECONDARY)
455 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
456
457 /* Label */
458 if (tb[IFA_LABEL])
459 label = (char *) RTA_DATA (tb[IFA_LABEL]);
460
461 if (ifp && label && strcmp (ifp->name, label) == 0)
462 label = NULL;
463
464 /* Register interface address to the interface. */
465 if (ifa->ifa_family == AF_INET)
466 {
467 if (h->nlmsg_type == RTM_NEWADDR)
468 connected_add_ipv4 (ifp, flags,
469 (struct in_addr *) addr, ifa->ifa_prefixlen,
470 (struct in_addr *) broad, label);
471 else
472 connected_delete_ipv4 (ifp, flags,
473 (struct in_addr *) addr, ifa->ifa_prefixlen,
474 (struct in_addr *) broad, label);
475 }
476#ifdef HAVE_IPV6
477 if (ifa->ifa_family == AF_INET6)
478 {
479 if (h->nlmsg_type == RTM_NEWADDR)
480 connected_add_ipv6 (ifp,
481 (struct in6_addr *) addr, ifa->ifa_prefixlen,
482 (struct in6_addr *) broad);
483 else
484 connected_delete_ipv6 (ifp,
485 (struct in6_addr *) addr, ifa->ifa_prefixlen,
486 (struct in6_addr *) broad);
487 }
488#endif /* HAVE_IPV6*/
489
490 return 0;
491}
492
493/* Looking up routing table by netlink interface. */
494int
495netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
496{
497 int len;
498 struct rtmsg *rtm;
499 struct rtattr *tb [RTA_MAX + 1];
500 u_char flags = 0;
501
502 char anyaddr[16] = {0};
503
504 int index;
505 int table;
506 void *dest;
507 void *gate;
508
509 rtm = NLMSG_DATA (h);
510
511 if (h->nlmsg_type != RTM_NEWROUTE)
512 return 0;
513 if (rtm->rtm_type != RTN_UNICAST)
514 return 0;
515
516 table = rtm->rtm_table;
517#if 0 /* we weed them out later in rib_weed_tables () */
518 if (table != RT_TABLE_MAIN && table != rtm_table_default)
519 return 0;
520#endif
521
522 len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
523 if (len < 0)
524 return -1;
525
526 memset (tb, 0, sizeof tb);
527 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
528
529 if (rtm->rtm_flags & RTM_F_CLONED)
530 return 0;
531 if (rtm->rtm_protocol == RTPROT_REDIRECT)
532 return 0;
533 if (rtm->rtm_protocol == RTPROT_KERNEL)
534 return 0;
535
536 if (rtm->rtm_src_len != 0)
537 return 0;
538
539 /* Route which inserted by Zebra. */
540 if (rtm->rtm_protocol == RTPROT_ZEBRA)
541 flags |= ZEBRA_FLAG_SELFROUTE;
542
543 index = 0;
544 dest = NULL;
545 gate = NULL;
546
547 if (tb[RTA_OIF])
548 index = *(int *) RTA_DATA (tb[RTA_OIF]);
549
550 if (tb[RTA_DST])
551 dest = RTA_DATA (tb[RTA_DST]);
552 else
553 dest = anyaddr;
554
555 /* Multipath treatment is needed. */
556 if (tb[RTA_GATEWAY])
557 gate = RTA_DATA (tb[RTA_GATEWAY]);
558
559 if (rtm->rtm_family == AF_INET)
560 {
561 struct prefix_ipv4 p;
562 p.family = AF_INET;
563 memcpy (&p.prefix, dest, 4);
564 p.prefixlen = rtm->rtm_dst_len;
565
566 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
567 }
568#ifdef HAVE_IPV6
569 if (rtm->rtm_family == AF_INET6)
570 {
571 struct prefix_ipv6 p;
572 p.family = AF_INET6;
573 memcpy (&p.prefix, dest, 16);
574 p.prefixlen = rtm->rtm_dst_len;
575
576 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
577 }
578#endif /* HAVE_IPV6 */
579
580 return 0;
581}
582
583struct message rtproto_str [] =
584{
585 {RTPROT_REDIRECT, "redirect"},
586 {RTPROT_KERNEL, "kernel"},
587 {RTPROT_BOOT, "boot"},
588 {RTPROT_STATIC, "static"},
589 {RTPROT_GATED, "GateD"},
590 {RTPROT_RA, "router advertisement"},
591 {RTPROT_MRT, "MRT"},
592 {RTPROT_ZEBRA, "Zebra"},
593#ifdef RTPROT_BIRD
594 {RTPROT_BIRD, "BIRD"},
595#endif /* RTPROT_BIRD */
596 {0, NULL}
597};
598
599/* Routing information change from the kernel. */
600int
601netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
602{
603 int len;
604 struct rtmsg *rtm;
605 struct rtattr *tb [RTA_MAX + 1];
606
607 char anyaddr[16] = {0};
608
609 int index;
610 int table;
611 void *dest;
612 void *gate;
613
614 rtm = NLMSG_DATA (h);
615
616 if (! (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
617 {
618 /* If this is not route add/delete message print warning. */
619 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
620 return 0;
621 }
622
623 /* Connected route. */
624 if (IS_ZEBRA_DEBUG_KERNEL)
625 zlog_info ("%s %s %s proto %s",
626 h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
627 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
628 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
629 lookup (rtproto_str, rtm->rtm_protocol));
630
631 if (rtm->rtm_type != RTN_UNICAST)
632 {
633 return 0;
634 }
635
636 table = rtm->rtm_table;
637 if (table != RT_TABLE_MAIN && table != rtm_table_default)
638 {
639 return 0;
640 }
641
642 len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct rtmsg));
643 if (len < 0)
644 return -1;
645
646 memset (tb, 0, sizeof tb);
647 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
648
649 if (rtm->rtm_flags & RTM_F_CLONED)
650 return 0;
651 if (rtm->rtm_protocol == RTPROT_REDIRECT)
652 return 0;
653 if (rtm->rtm_protocol == RTPROT_KERNEL)
654 return 0;
655
656 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
657 return 0;
658
659 if (rtm->rtm_src_len != 0)
660 {
661 zlog_warn ("netlink_route_change(): no src len");
662 return 0;
663 }
664
665 index = 0;
666 dest = NULL;
667 gate = NULL;
668
669 if (tb[RTA_OIF])
670 index = *(int *) RTA_DATA (tb[RTA_OIF]);
671
672 if (tb[RTA_DST])
673 dest = RTA_DATA (tb[RTA_DST]);
674 else
675 dest = anyaddr;
676
677 if (tb[RTA_GATEWAY])
678 gate = RTA_DATA (tb[RTA_GATEWAY]);
679
680 if (rtm->rtm_family == AF_INET)
681 {
682 struct prefix_ipv4 p;
683 p.family = AF_INET;
684 memcpy (&p.prefix, dest, 4);
685 p.prefixlen = rtm->rtm_dst_len;
686
687 if (IS_ZEBRA_DEBUG_KERNEL)
688 {
689 if (h->nlmsg_type == RTM_NEWROUTE)
690 zlog_info ("RTM_NEWROUTE %s/%d",
691 inet_ntoa (p.prefix), p.prefixlen);
692 else
693 zlog_info ("RTM_DELROUTE %s/%d",
694 inet_ntoa (p.prefix), p.prefixlen);
695 }
696
697 if (h->nlmsg_type == RTM_NEWROUTE)
698 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
699 else
700 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
701 }
702
703#ifdef HAVE_IPV6
704 if (rtm->rtm_family == AF_INET6)
705 {
706 struct prefix_ipv6 p;
707 char buf[BUFSIZ];
708
709 p.family = AF_INET6;
710 memcpy (&p.prefix, dest, 16);
711 p.prefixlen = rtm->rtm_dst_len;
712
713 if (IS_ZEBRA_DEBUG_KERNEL)
714 {
715 if (h->nlmsg_type == RTM_NEWROUTE)
716 zlog_info ("RTM_NEWROUTE %s/%d",
717 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
718 p.prefixlen);
719 else
720 zlog_info ("RTM_DELROUTE %s/%d",
721 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
722 p.prefixlen);
723 }
724
725 if (h->nlmsg_type == RTM_NEWROUTE)
726 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
727 else
728 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
729 }
730#endif /* HAVE_IPV6 */
731
732 return 0;
733}
734
735int
736netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
737{
738 int len;
739 struct ifinfomsg *ifi;
740 struct rtattr *tb [IFLA_MAX + 1];
741 struct interface *ifp;
742 char *name;
743
744 ifi = NLMSG_DATA (h);
745
746 if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
747 {
748 /* If this is not link add/delete message so print warning. */
749 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
750 h->nlmsg_type);
751 return 0;
752 }
753
754 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
755 if (len < 0)
756 return -1;
757
758 /* Looking up interface name. */
759 memset (tb, 0, sizeof tb);
760 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
761 if (tb[IFLA_IFNAME] == NULL)
762 return -1;
763 name = (char *)RTA_DATA(tb[IFLA_IFNAME]);
764
765 /* Add interface. */
766 if (h->nlmsg_type == RTM_NEWLINK)
767 {
768 ifp = if_lookup_by_name (name);
769
770 if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
771 {
772 if (ifp == NULL)
773 ifp = if_get_by_name (name);
774
775 ifp->ifindex = ifi->ifi_index;
776 ifp->flags = ifi->ifi_flags & 0x0000fffff;
777 ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
778 ifp->metric = 1;
779
780 /* If new link is added. */
781 if_add_update(ifp);
782 }
783 else
784 {
785 /* Interface status change. */
786 ifp->ifindex = ifi->ifi_index;
787 ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]);
788 ifp->metric = 1;
789
790 if (if_is_up (ifp))
791 {
792 ifp->flags = ifi->ifi_flags & 0x0000fffff;
793 if (! if_is_up (ifp))
794 if_down (ifp);
795 }
796 else
797 {
798 ifp->flags = ifi->ifi_flags & 0x0000fffff;
799 if (if_is_up (ifp))
800 if_up (ifp);
801 }
802 }
803 }
804 else
805 {
806 /* RTM_DELLINK. */
807 ifp = if_lookup_by_name (name);
808
809 if (ifp == NULL)
810 {
811 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
812 name);
813 return 0;
814 }
815
816 if_delete_update (ifp);
817 }
818
819 return 0;
820}
821
822int
823netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
824{
825 switch (h->nlmsg_type)
826 {
827 case RTM_NEWROUTE:
828 return netlink_route_change (snl, h);
829 break;
830 case RTM_DELROUTE:
831 return netlink_route_change (snl, h);
832 break;
833 case RTM_NEWLINK:
834 return netlink_link_change (snl, h);
835 break;
836 case RTM_DELLINK:
837 return netlink_link_change (snl, h);
838 break;
839 case RTM_NEWADDR:
840 return netlink_interface_addr (snl, h);
841 break;
842 case RTM_DELADDR:
843 return netlink_interface_addr (snl, h);
844 break;
845 default:
846 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
847 break;
848 }
849 return 0;
850}
851
852/* Interface lookup by netlink socket. */
853int
854interface_lookup_netlink ()
855{
856 int ret;
857
858 /* Get interface information. */
859 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
860 if (ret < 0)
861 return ret;
862 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
863 if (ret < 0)
864 return ret;
865
866 /* Get IPv4 address of the interfaces. */
867 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
868 if (ret < 0)
869 return ret;
870 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
871 if (ret < 0)
872 return ret;
873
874#ifdef HAVE_IPV6
875 /* Get IPv6 address of the interfaces. */
876 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
877 if (ret < 0)
878 return ret;
879 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
880 if (ret < 0)
881 return ret;
882#endif /* HAVE_IPV6 */
883
884 return 0;
885}
886
887/* Routing table read function using netlink interface. Only called
888 bootstrap time. */
889int
890netlink_route_read ()
891{
892 int ret;
893
894 /* Get IPv4 routing table. */
895 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
896 if (ret < 0)
897 return ret;
898 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
899 if (ret < 0)
900 return ret;
901
902#ifdef HAVE_IPV6
903 /* Get IPv6 routing table. */
904 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
905 if (ret < 0)
906 return ret;
907 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
908 if (ret < 0)
909 return ret;
910#endif /* HAVE_IPV6 */
911
912 return 0;
913}
914
915/* Utility function comes from iproute2.
916 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
917int
918addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
919{
920 int len;
921 struct rtattr *rta;
922
923 len = RTA_LENGTH(alen);
924
925 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
926 return -1;
927
928 rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
929 rta->rta_type = type;
930 rta->rta_len = len;
931 memcpy (RTA_DATA(rta), data, alen);
932 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
933
934 return 0;
935}
936
937int
938rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
939{
940 int len;
941 struct rtattr *subrta;
942
943 len = RTA_LENGTH(alen);
944
945 if (RTA_ALIGN(rta->rta_len) + len > maxlen)
946 return -1;
947
948 subrta = (struct rtattr*) (((char*)rta) + RTA_ALIGN (rta->rta_len));
949 subrta->rta_type = type;
950 subrta->rta_len = len;
951 memcpy (RTA_DATA(subrta), data, alen);
952 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
953
954 return 0;
955}
956
957/* Utility function comes from iproute2.
958 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
959int
960addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
961{
962 int len;
963 struct rtattr *rta;
964
965 len = RTA_LENGTH(4);
966
967 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
968 return -1;
969
970 rta = (struct rtattr*) (((char*)n) + NLMSG_ALIGN (n->nlmsg_len));
971 rta->rta_type = type;
972 rta->rta_len = len;
973 memcpy (RTA_DATA(rta), &data, 4);
974 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
975
976 return 0;
977}
978
979static int
980netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
981{
982 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
983 return 0;
984}
985
986/* sendmsg() to netlink socket then recvmsg(). */
987int
988netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
989{
990 int status;
991 struct sockaddr_nl snl;
992 struct iovec iov = { (void*) n, n->nlmsg_len };
993 struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
994 int flags = 0;
995
996 memset (&snl, 0, sizeof snl);
997 snl.nl_family = AF_NETLINK;
998
999 n->nlmsg_seq = ++netlink_cmd.seq;
1000
1001 /* Request an acknowledgement by setting NLM_F_ACK */
1002 n->nlmsg_flags |= NLM_F_ACK;
1003
1004 if (IS_ZEBRA_DEBUG_KERNEL)
1005 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
1006 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1007 n->nlmsg_seq);
1008
1009 /* Send message to netlink interface. */
1010 status = sendmsg (nl->sock, &msg, 0);
1011 if (status < 0)
1012 {
1013 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
1014 strerror (errno));
1015 return -1;
1016 }
1017
1018 /*
1019 * Change socket flags for blocking I/O.
1020 * This ensures we wait for a reply in netlink_parse_info().
1021 */
1022 if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0)
1023 {
1024 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
1025 __FUNCTION__, __LINE__, strerror (errno));
1026 }
1027 flags &= ~O_NONBLOCK;
1028 if(fcntl(nl->sock, F_SETFL, flags) < 0)
1029 {
1030 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
1031 __FUNCTION__, __LINE__, strerror (errno));
1032 }
1033
1034 /*
1035 * Get reply from netlink socket.
1036 * The reply should either be an acknowlegement or an error.
1037 */
1038 status = netlink_parse_info (netlink_talk_filter, nl);
1039
1040 /* Restore socket flags for nonblocking I/O */
1041 flags |= O_NONBLOCK;
1042 if(fcntl(nl->sock, F_SETFL, flags) < 0)
1043 {
1044 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
1045 __FUNCTION__, __LINE__, strerror (errno));
1046 }
1047
1048 return status;
1049}
1050
1051/* Routing table change via netlink interface. */
1052int
1053netlink_route (int cmd, int family, void *dest, int length, void *gate,
1054 int index, int zebra_flags, int table)
1055{
1056 int ret;
1057 int bytelen;
1058 struct sockaddr_nl snl;
1059 int discard;
1060
1061 struct
1062 {
1063 struct nlmsghdr n;
1064 struct rtmsg r;
1065 char buf[1024];
1066 } req;
1067
1068 memset (&req, 0, sizeof req);
1069
1070 bytelen = (family == AF_INET ? 4 : 16);
1071
1072 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1073 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1074 req.n.nlmsg_type = cmd;
1075 req.r.rtm_family = family;
1076 req.r.rtm_table = table;
1077 req.r.rtm_dst_len = length;
1078
1079 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1080 discard = 1;
1081 else
1082 discard = 0;
1083
1084 if (cmd == RTM_NEWROUTE)
1085 {
1086 req.r.rtm_protocol = RTPROT_ZEBRA;
1087 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1088
1089 if (discard)
1090 req.r.rtm_type = RTN_BLACKHOLE;
1091 else
1092 req.r.rtm_type = RTN_UNICAST;
1093 }
1094
1095 if (dest)
1096 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1097
1098 if (! discard)
1099 {
1100 if (gate)
1101 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
1102 if (index > 0)
1103 addattr32 (&req.n, sizeof req, RTA_OIF, index);
1104 }
1105
1106 /* Destination netlink address. */
1107 memset (&snl, 0, sizeof snl);
1108 snl.nl_family = AF_NETLINK;
1109
1110 /* Talk to netlink socket. */
1111 ret = netlink_talk (&req.n, &netlink);
1112 if (ret < 0)
1113 return -1;
1114
1115 return 0;
1116}
1117
1118/* Routing table change via netlink interface. */
1119int
1120netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
1121 int family)
1122{
1123 int bytelen;
1124 struct sockaddr_nl snl;
1125 struct nexthop *nexthop = NULL;
1126 int nexthop_num = 0;
1127 struct nlsock *nl;
1128 int discard;
1129
1130 struct
1131 {
1132 struct nlmsghdr n;
1133 struct rtmsg r;
1134 char buf[1024];
1135 } req;
1136
1137 memset (&req, 0, sizeof req);
1138
1139 bytelen = (family == AF_INET ? 4 : 16);
1140
1141 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1142 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1143 req.n.nlmsg_type = cmd;
1144 req.r.rtm_family = family;
1145 req.r.rtm_table = rib->table;
1146 req.r.rtm_dst_len = p->prefixlen;
1147
1148 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1149 discard = 1;
1150 else
1151 discard = 0;
1152
1153 if (cmd == RTM_NEWROUTE)
1154 {
1155 req.r.rtm_protocol = RTPROT_ZEBRA;
1156 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1157
1158 if (discard)
1159 req.r.rtm_type = RTN_BLACKHOLE;
1160 else
1161 req.r.rtm_type = RTN_UNICAST;
1162 }
1163
1164 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1165
1166 /* Metric. */
1167 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1168
1169 if (discard)
1170 {
1171 if (cmd == RTM_NEWROUTE)
1172 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1173 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1174 goto skip;
1175 }
1176
1177 /* Multipath case. */
1178 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1179 {
1180 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1181 {
1182 if ((cmd == RTM_NEWROUTE
1183 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1184 || (cmd == RTM_DELROUTE
1185 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1186 {
1187 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1188 {
1189 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1190 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1191 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1192 &nexthop->rgate.ipv4, bytelen);
1193#ifdef HAVE_IPV6
1194 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1195 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1196 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1197 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1198 &nexthop->rgate.ipv6, bytelen);
1199#endif /* HAVE_IPV6 */
1200 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1201 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1202 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1203 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1204 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1205 addattr32 (&req.n, sizeof req, RTA_OIF,
1206 nexthop->rifindex);
1207 }
1208 else
1209 {
1210 if (nexthop->type == NEXTHOP_TYPE_IPV4
1211 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1212 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1213 &nexthop->gate.ipv4, bytelen);
1214#ifdef HAVE_IPV6
1215 if (nexthop->type == NEXTHOP_TYPE_IPV6
1216 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1217 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1218 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1219 &nexthop->gate.ipv6, bytelen);
1220#endif /* HAVE_IPV6 */
1221 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1222 || nexthop->type == NEXTHOP_TYPE_IFNAME
1223 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1224 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1225 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1226 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1227 }
1228
1229 if (cmd == RTM_NEWROUTE)
1230 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1231
1232 nexthop_num++;
1233 break;
1234 }
1235 }
1236 }
1237 else
1238 {
1239 char buf[1024];
1240 struct rtattr *rta = (void *) buf;
1241 struct rtnexthop *rtnh;
1242
1243 rta->rta_type = RTA_MULTIPATH;
1244 rta->rta_len = RTA_LENGTH(0);
1245 rtnh = RTA_DATA(rta);
1246
1247 nexthop_num = 0;
1248 for (nexthop = rib->nexthop;
1249 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1250 nexthop = nexthop->next)
1251 {
1252 if ((cmd == RTM_NEWROUTE
1253 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1254 || (cmd == RTM_DELROUTE
1255 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1256 {
1257 nexthop_num++;
1258
1259 rtnh->rtnh_len = sizeof (*rtnh);
1260 rtnh->rtnh_flags = 0;
1261 rtnh->rtnh_hops = 0;
1262 rta->rta_len += rtnh->rtnh_len;
1263
1264 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1265 {
1266 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1267 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1268 {
1269 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1270 &nexthop->rgate.ipv4, bytelen);
1271 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1272 }
1273#ifdef HAVE_IPV6
1274 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1275 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1276 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1277 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1278 &nexthop->rgate.ipv6, bytelen);
1279#endif /* HAVE_IPV6 */
1280 /* ifindex */
1281 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1282 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1283 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1284 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1285 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1286 rtnh->rtnh_ifindex = nexthop->rifindex;
1287 else
1288 rtnh->rtnh_ifindex = 0;
1289 }
1290 else
1291 {
1292 if (nexthop->type == NEXTHOP_TYPE_IPV4
1293 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1294 {
1295 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1296 &nexthop->gate.ipv4, bytelen);
1297 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1298 }
1299#ifdef HAVE_IPV6
1300 if (nexthop->type == NEXTHOP_TYPE_IPV6
1301 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1302 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1303 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1304 &nexthop->gate.ipv6, bytelen);
1305#endif /* HAVE_IPV6 */
1306 /* ifindex */
1307 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1308 || nexthop->type == NEXTHOP_TYPE_IFNAME
1309 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1310 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1311 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1312 rtnh->rtnh_ifindex = nexthop->ifindex;
1313 else
1314 rtnh->rtnh_ifindex = 0;
1315 }
1316 rtnh = RTNH_NEXT(rtnh);
1317
1318 if (cmd == RTM_NEWROUTE)
1319 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1320 }
1321 }
1322
1323 if (rta->rta_len > RTA_LENGTH (0))
1324 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA(rta),
1325 RTA_PAYLOAD(rta));
1326 }
1327
1328 /* If there is no useful nexthop then return. */
1329 if (nexthop_num == 0)
1330 {
1331 if (IS_ZEBRA_DEBUG_KERNEL)
1332 zlog_info ("netlink_route_multipath(): No useful nexthop.");
1333 return 0;
1334 }
1335
1336 skip:
1337
1338 /* Destination netlink address. */
1339 memset (&snl, 0, sizeof snl);
1340 snl.nl_family = AF_NETLINK;
1341
1342 if (family == AF_INET)
1343 nl = &netlink_cmd;
1344 else
1345 nl = &netlink;
1346
1347 /* Talk to netlink socket. */
1348 return netlink_talk (&req.n, nl);
1349}
1350
1351int
1352kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1353{
1354 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1355}
1356
1357int
1358kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1359{
1360 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1361}
1362
1363#ifdef HAVE_IPV6
1364int
1365kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1366{
1367 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1368}
1369
1370int
1371kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1372{
1373 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1374}
1375
1376/* Delete IPv6 route from the kernel. */
1377int
1378kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
1379 int index, int flags, int table)
1380{
1381 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen,
1382 gate, index, flags, table);
1383}
1384#endif /* HAVE_IPV6 */
1385\f
1386/* Interface address modification. */
1387int
1388netlink_address (int cmd, int family, struct interface *ifp,
1389 struct connected *ifc)
1390{
1391 int bytelen;
1392 struct prefix *p;
1393
1394 struct
1395 {
1396 struct nlmsghdr n;
1397 struct ifaddrmsg ifa;
1398 char buf[1024];
1399 } req;
1400
1401 p = ifc->address;
1402 memset (&req, 0, sizeof req);
1403
1404 bytelen = (family == AF_INET ? 4 : 16);
1405
1406 req.n.nlmsg_len = NLMSG_LENGTH (sizeof(struct ifaddrmsg));
1407 req.n.nlmsg_flags = NLM_F_REQUEST;
1408 req.n.nlmsg_type = cmd;
1409 req.ifa.ifa_family = family;
1410
1411 req.ifa.ifa_index = ifp->ifindex;
1412 req.ifa.ifa_prefixlen = p->prefixlen;
1413
1414 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1415
1416 if (family == AF_INET && cmd == RTM_NEWADDR)
1417 {
1418 if (if_is_broadcast (ifp) && ifc->destination)
1419 {
1420 p = ifc->destination;
1421 addattr_l(&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen);
1422 }
1423 }
1424
1425 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1426 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
1427
1428 if (ifc->label)
1429 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
1430 strlen (ifc->label) + 1);
1431
1432 return netlink_talk (&req.n, &netlink_cmd);
1433}
1434
1435int
1436kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1437{
1438 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1439}
1440
1441int
1442kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1443{
1444 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1445}
1446
1447#include "thread.h"
1448
1449extern struct thread_master *master;
1450
1451/* Kernel route reflection. */
1452int
1453kernel_read (struct thread *thread)
1454{
1455 int ret;
1456 int sock;
1457
1458 sock = THREAD_FD (thread);
1459 ret = netlink_parse_info (netlink_information_fetch, &netlink);
1460 thread_add_read (master, kernel_read, NULL, netlink.sock);
1461
1462 return 0;
1463}
1464
1465/* Exported interface function. This function simply calls
1466 netlink_socket (). */
1467void
1468kernel_init ()
1469{
1470 unsigned long groups;
1471
1472 groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR;
1473#ifdef HAVE_IPV6
1474 groups |= RTMGRP_IPV6_ROUTE|RTMGRP_IPV6_IFADDR;
1475#endif /* HAVE_IPV6 */
1476 netlink_socket (&netlink, groups);
1477 netlink_socket (&netlink_cmd, 0);
1478
1479 /* Register kernel socket. */
1480 if (netlink.sock > 0)
1481 thread_add_read (master, kernel_read, NULL, netlink.sock);
1482}