blob: 50e83b77c110cfed9c04e674aedc02d68ffe61d5 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
paule04ab742003-01-17 23:47:00 +000036#include "thread.h"
pauledd7c242003-06-04 13:59:38 +000037#include "privs.h"
paul718e3742002-12-13 20:15:29 +000038
39#include "zebra/zserv.h"
40#include "zebra/redistribute.h"
41#include "zebra/interface.h"
42#include "zebra/debug.h"
43
44/* Socket interface to kernel */
45struct nlsock
46{
47 int sock;
48 int seq;
49 struct sockaddr_nl snl;
hassofce954f2004-10-07 20:29:24 +000050 const char *name;
paul7021c422003-07-15 12:52:22 +000051} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
52 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}, /* command channel */
53 netlink_addr = { -1, 0, {0}, "netlink-addr"}; /* address channel */
paul718e3742002-12-13 20:15:29 +000054
paul7021c422003-07-15 12:52:22 +000055struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000056 {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"},
paul7021c422003-07-15 12:52:22 +000065 {0, NULL}
paul718e3742002-12-13 20:15:29 +000066};
67
hassofce954f2004-10-07 20:29:24 +000068const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000069{
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
paulb21b19c2003-06-15 01:28:29 +000083extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000084
pauledd7c242003-06-04 13:59:38 +000085extern struct zebra_privs_t zserv_privs;
86
hassoc34b6b52004-08-31 13:41:49 +000087extern u_int32_t nl_rcvbufsize;
88
paul718e3742002-12-13 20:15:29 +000089/* Make socket for Linux netlink interface. */
90static int
91netlink_socket (struct nlsock *nl, unsigned long groups)
92{
93 int ret;
94 struct sockaddr_nl snl;
95 int sock;
96 int namelen;
97
98 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
99 if (sock < 0)
100 {
101 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000102 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000103 return -1;
104 }
105
106 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
107 if (ret < 0)
108 {
109 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000110 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000111 close (sock);
112 return -1;
113 }
paul7021c422003-07-15 12:52:22 +0000114
hassoc34b6b52004-08-31 13:41:49 +0000115 /* Set receive buffer size if it's set from command line */
116 if (nl_rcvbufsize)
117 {
118 u_int32_t oldsize, oldlen;
119 u_int32_t newsize, newlen;
120
121 oldlen = sizeof(oldsize);
122 newlen = sizeof(newsize);
123
124 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
125 if (ret < 0)
126 {
127 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
128 strerror (errno));
129 close (sock);
130 return -1;
131 }
132
133 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
134 sizeof(nl_rcvbufsize));
135 if (ret < 0)
136 {
137 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
138 strerror (errno));
139 close (sock);
140 return -1;
141 }
142
143 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
144 if (ret < 0)
145 {
146 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
147 strerror (errno));
148 close (sock);
149 return -1;
150 }
151
152 zlog (NULL, LOG_INFO,
153 "Setting netlink socket receive buffer size: %u -> %u",
154 oldsize, newsize);
155 }
156
paul718e3742002-12-13 20:15:29 +0000157 memset (&snl, 0, sizeof snl);
158 snl.nl_family = AF_NETLINK;
159 snl.nl_groups = groups;
160
161 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000162 if (zserv_privs.change (ZPRIVS_RAISE))
163 {
164 zlog (NULL, LOG_ERR, "Can't raise privileges");
165 return -1;
166 }
pauledd7c242003-06-04 13:59:38 +0000167
paul718e3742002-12-13 20:15:29 +0000168 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
hasso55e7ecd2004-08-06 08:41:56 +0000169 if (zserv_privs.change (ZPRIVS_LOWER))
170 zlog (NULL, LOG_ERR, "Can't lower privileges");
171
paul718e3742002-12-13 20:15:29 +0000172 if (ret < 0)
173 {
paul7021c422003-07-15 12:52:22 +0000174 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
175 nl->name, snl.nl_groups, strerror (errno));
paul718e3742002-12-13 20:15:29 +0000176 close (sock);
177 return -1;
178 }
paul7021c422003-07-15 12:52:22 +0000179
paul718e3742002-12-13 20:15:29 +0000180 /* multiple netlink sockets will have different nl_pid */
181 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000182 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000183 if (ret < 0 || namelen != sizeof snl)
184 {
185 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000186 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000187 close (sock);
188 return -1;
189 }
190
191 nl->snl = snl;
192 nl->sock = sock;
193 return ret;
194}
195
paul7021c422003-07-15 12:52:22 +0000196int
197set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000198{
199
200 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000201 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000202 {
paul7021c422003-07-15 12:52:22 +0000203 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
204 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000205 return -1;
206 }
207 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000208 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000209 {
paul7021c422003-07-15 12:52:22 +0000210 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
211 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000212 return -1;
213 }
214 return 0;
215}
216
paul7021c422003-07-15 12:52:22 +0000217int
218set_netlink_nonblocking (struct nlsock *nl, int *flags)
219{
paul5f37d862003-04-19 00:11:28 +0000220 /* Restore socket flags for nonblocking I/O */
221 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000222 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000223 {
paul7021c422003-07-15 12:52:22 +0000224 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
225 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000226 return -1;
227 }
228 return 0;
229}
230
paul718e3742002-12-13 20:15:29 +0000231/* Get type specified information from netlink. */
232static int
233netlink_request (int family, int type, struct nlsock *nl)
234{
235 int ret;
236 struct sockaddr_nl snl;
237
238 struct
239 {
240 struct nlmsghdr nlh;
241 struct rtgenmsg g;
242 } req;
243
244
245 /* Check netlink socket. */
246 if (nl->sock < 0)
247 {
248 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
249 return -1;
250 }
251
252 memset (&snl, 0, sizeof snl);
253 snl.nl_family = AF_NETLINK;
254
255 req.nlh.nlmsg_len = sizeof req;
256 req.nlh.nlmsg_type = type;
257 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
258 req.nlh.nlmsg_pid = 0;
259 req.nlh.nlmsg_seq = ++nl->seq;
260 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000261
262 /* linux appears to check capabilities on every message
263 * have to raise caps for every message sent
264 */
paul7021c422003-07-15 12:52:22 +0000265 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000266 {
267 zlog (NULL, LOG_ERR, "Can't raise privileges");
268 return -1;
269 }
paul7021c422003-07-15 12:52:22 +0000270
271 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
272 (struct sockaddr *) &snl, sizeof snl);
273
274 if (zserv_privs.change (ZPRIVS_LOWER))
275 zlog (NULL, LOG_ERR, "Can't lower privileges");
276
paul718e3742002-12-13 20:15:29 +0000277 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000278 {
279 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
280 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000281 return -1;
282 }
pauledd7c242003-06-04 13:59:38 +0000283
paul718e3742002-12-13 20:15:29 +0000284 return 0;
285}
286
287/* Receive message from netlink interface and pass those information
288 to the given function. */
289static int
290netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000291 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000292{
293 int status;
294 int ret = 0;
295 int error;
296
297 while (1)
298 {
299 char buf[4096];
300 struct iovec iov = { buf, sizeof buf };
301 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000302 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000303 struct nlmsghdr *h;
304
paul7021c422003-07-15 12:52:22 +0000305 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000306 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000307
paul718e3742002-12-13 20:15:29 +0000308 status = recvmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +0000309
310 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000311 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000312
313 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000314 {
315 if (errno == EINTR)
316 continue;
317 if (errno == EWOULDBLOCK || errno == EAGAIN)
318 break;
319 zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
320 continue;
321 }
paul718e3742002-12-13 20:15:29 +0000322
323 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000324 {
325 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
326 return -1;
327 }
paul718e3742002-12-13 20:15:29 +0000328
329 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000330 {
331 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
332 nl->name, msg.msg_namelen);
333 return -1;
334 }
paulb84d3a12003-11-17 10:31:01 +0000335
336 /* JF: Ignore messages that aren't from the kernel */
337 if ( snl.nl_pid != 0 )
338 {
339 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
340 continue;
341 }
paul718e3742002-12-13 20:15:29 +0000342
paul7021c422003-07-15 12:52:22 +0000343 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
344 h = NLMSG_NEXT (h, status))
345 {
346 /* Finish of reading. */
347 if (h->nlmsg_type == NLMSG_DONE)
348 return ret;
paul718e3742002-12-13 20:15:29 +0000349
paul7021c422003-07-15 12:52:22 +0000350 /* Error handling. */
351 if (h->nlmsg_type == NLMSG_ERROR)
352 {
353 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
354
paul718e3742002-12-13 20:15:29 +0000355 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000356 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000357 {
paul7021c422003-07-15 12:52:22 +0000358 if (IS_ZEBRA_DEBUG_KERNEL)
359 {
360 zlog_info ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
361 __FUNCTION__, nl->name,
362 lookup (nlmsg_str, err->msg.nlmsg_type),
363 err->msg.nlmsg_type, err->msg.nlmsg_seq,
364 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000365 }
paul7021c422003-07-15 12:52:22 +0000366
367 /* return if not a multipart message, otherwise continue */
368 if (!(h->nlmsg_flags & NLM_F_MULTI))
369 {
370 return 0;
paul718e3742002-12-13 20:15:29 +0000371 }
paul7021c422003-07-15 12:52:22 +0000372 continue;
paul718e3742002-12-13 20:15:29 +0000373 }
paul7021c422003-07-15 12:52:22 +0000374
paul718e3742002-12-13 20:15:29 +0000375 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000376 {
377 zlog (NULL, LOG_ERR, "%s error: message truncated",
378 nl->name);
379 return -1;
380 }
pauld753e9e2003-01-22 19:45:50 +0000381
paul7021c422003-07-15 12:52:22 +0000382 /* Deal with Error Noise - MAG */
383 {
384 int loglvl = LOG_ERR;
385 int errnum = err->error;
386 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000387
paul7021c422003-07-15 12:52:22 +0000388 if (nl == &netlink_cmd
389 && (-errnum == ENODEV || -errnum == ESRCH)
390 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
391 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000392
paul7021c422003-07-15 12:52:22 +0000393 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
394 "seq=%u, pid=%d",
395 nl->name, strerror (-errnum),
396 lookup (nlmsg_str, msg_type),
397 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
398 }
399 /*
400 ret = -1;
401 continue;
402 */
403 return -1;
404 }
paul718e3742002-12-13 20:15:29 +0000405
paul7021c422003-07-15 12:52:22 +0000406 /* OK we got netlink message. */
407 if (IS_ZEBRA_DEBUG_KERNEL)
408 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
409 nl->name,
410 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
411 h->nlmsg_seq, h->nlmsg_pid);
412
413 /* skip unsolicited messages originating from command socket */
414 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
415 {
416 if (IS_ZEBRA_DEBUG_KERNEL)
417 zlog_info ("netlink_parse_info: %s packet comes from %s",
418 nl->name, netlink_cmd.name);
419 continue;
420 }
421
422 error = (*filter) (&snl, h);
423 if (error < 0)
424 {
425 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
426 ret = error;
427 }
428 }
paul718e3742002-12-13 20:15:29 +0000429
430 /* After error care. */
431 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000432 {
433 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
434 continue;
435 }
paul718e3742002-12-13 20:15:29 +0000436 if (status)
paul7021c422003-07-15 12:52:22 +0000437 {
438 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
439 status);
440 return -1;
441 }
paul718e3742002-12-13 20:15:29 +0000442 }
443 return ret;
444}
445
446/* Utility function for parse rtattr. */
447static void
paul7021c422003-07-15 12:52:22 +0000448netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
449 int len)
paul718e3742002-12-13 20:15:29 +0000450{
paul7021c422003-07-15 12:52:22 +0000451 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000452 {
453 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000454 tb[rta->rta_type] = rta;
455 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000456 }
457}
458
459/* Called from interface_lookup_netlink(). This function is only used
460 during bootstrap. */
461int
462netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
463{
464 int len;
465 struct ifinfomsg *ifi;
466 struct rtattr *tb[IFLA_MAX + 1];
467 struct interface *ifp;
468 char *name;
469 int i;
470
471 ifi = NLMSG_DATA (h);
472
473 if (h->nlmsg_type != RTM_NEWLINK)
474 return 0;
475
476 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
477 if (len < 0)
478 return -1;
479
480 /* Looking up interface name. */
481 memset (tb, 0, sizeof tb);
482 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
483 if (tb[IFLA_IFNAME] == NULL)
484 return -1;
paul7021c422003-07-15 12:52:22 +0000485 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000486
487 /* Add interface. */
488 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000489
paul718e3742002-12-13 20:15:29 +0000490 ifp->ifindex = ifi->ifi_index;
491 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000492 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000493 ifp->metric = 1;
494
495 /* Hardware type and address. */
496 ifp->hw_type = ifi->ifi_type;
497
498 if (tb[IFLA_ADDRESS])
499 {
500 int hw_addr_len;
501
paul7021c422003-07-15 12:52:22 +0000502 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000503
504 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000505 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000506 else
paul7021c422003-07-15 12:52:22 +0000507 {
508 ifp->hw_addr_len = hw_addr_len;
509 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000510
paul7021c422003-07-15 12:52:22 +0000511 for (i = 0; i < hw_addr_len; i++)
512 if (ifp->hw_addr[i] != 0)
513 break;
paul718e3742002-12-13 20:15:29 +0000514
paul7021c422003-07-15 12:52:22 +0000515 if (i == hw_addr_len)
516 ifp->hw_addr_len = 0;
517 else
518 ifp->hw_addr_len = hw_addr_len;
519 }
paul718e3742002-12-13 20:15:29 +0000520 }
521
522 if_add_update (ifp);
523
524 return 0;
525}
526
527/* Lookup interface IPv4/IPv6 address. */
528int
529netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
530{
531 int len;
532 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000533 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000534 struct interface *ifp;
535 void *addr = NULL;
536 void *broad = NULL;
537 u_char flags = 0;
538 char *label = NULL;
539
540 ifa = NLMSG_DATA (h);
541
paul7021c422003-07-15 12:52:22 +0000542 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000543#ifdef HAVE_IPV6
544 && ifa->ifa_family != AF_INET6
545#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000546 )
paul718e3742002-12-13 20:15:29 +0000547 return 0;
548
549 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
550 return 0;
551
paul7021c422003-07-15 12:52:22 +0000552 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000553 if (len < 0)
554 return -1;
555
556 memset (tb, 0, sizeof tb);
557 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
558
559 ifp = if_lookup_by_index (ifa->ifa_index);
560 if (ifp == NULL)
561 {
562 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000563 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000564 return -1;
565 }
566
paul7021c422003-07-15 12:52:22 +0000567 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000568 {
paul00df0c12002-12-13 21:07:36 +0000569 char buf[BUFSIZ];
570 zlog_info ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000571 lookup (nlmsg_str, h->nlmsg_type),
572 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000573 if (tb[IFA_LOCAL])
paul7021c422003-07-15 12:52:22 +0000574 zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
575 RTA_DATA (tb[IFA_LOCAL]),
576 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000577 if (tb[IFA_ADDRESS])
paul7021c422003-07-15 12:52:22 +0000578 zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
579 RTA_DATA (tb
580 [IFA_ADDRESS]),
581 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000582 if (tb[IFA_BROADCAST])
paul7021c422003-07-15 12:52:22 +0000583 zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
584 RTA_DATA (tb
585 [IFA_BROADCAST]),
586 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000587 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
hasso5707cce2004-03-04 19:20:44 +0000588 zlog_info (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000589 }
paul31a476c2003-09-29 19:54:53 +0000590
591 if (tb[IFA_ADDRESS] == NULL)
592 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
593
594 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000595 {
paul31a476c2003-09-29 19:54:53 +0000596 if (tb[IFA_LOCAL])
597 {
598 addr = RTA_DATA (tb[IFA_LOCAL]);
hasso3fb9cd62004-10-19 19:44:43 +0000599 if (tb[IFA_ADDRESS] &&
600 memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4))
601 /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */
paul31a476c2003-09-29 19:54:53 +0000602 broad = RTA_DATA (tb[IFA_ADDRESS]);
603 else
604 broad = NULL;
605 }
606 else
607 {
608 if (tb[IFA_ADDRESS])
609 addr = RTA_DATA (tb[IFA_ADDRESS]);
610 else
611 addr = NULL;
612 }
paul7021c422003-07-15 12:52:22 +0000613 }
paul31a476c2003-09-29 19:54:53 +0000614 else
paul7021c422003-07-15 12:52:22 +0000615 {
paul31a476c2003-09-29 19:54:53 +0000616 if (tb[IFA_ADDRESS])
617 addr = RTA_DATA (tb[IFA_ADDRESS]);
618 else
619 addr = NULL;
620
621 if (tb[IFA_BROADCAST])
622 broad = RTA_DATA(tb[IFA_BROADCAST]);
623 else
624 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000625 }
paul00df0c12002-12-13 21:07:36 +0000626
paul718e3742002-12-13 20:15:29 +0000627 /* Flags. */
628 if (ifa->ifa_flags & IFA_F_SECONDARY)
629 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
630
631 /* Label */
632 if (tb[IFA_LABEL])
633 label = (char *) RTA_DATA (tb[IFA_LABEL]);
634
635 if (ifp && label && strcmp (ifp->name, label) == 0)
636 label = NULL;
637
638 /* Register interface address to the interface. */
639 if (ifa->ifa_family == AF_INET)
640 {
paul7021c422003-07-15 12:52:22 +0000641 if (h->nlmsg_type == RTM_NEWADDR)
642 connected_add_ipv4 (ifp, flags,
643 (struct in_addr *) addr, ifa->ifa_prefixlen,
644 (struct in_addr *) broad, label);
645 else
646 connected_delete_ipv4 (ifp, flags,
647 (struct in_addr *) addr, ifa->ifa_prefixlen,
648 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000649 }
650#ifdef HAVE_IPV6
651 if (ifa->ifa_family == AF_INET6)
652 {
653 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000654 connected_add_ipv6 (ifp,
655 (struct in6_addr *) addr, ifa->ifa_prefixlen,
656 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000657 else
paul7021c422003-07-15 12:52:22 +0000658 connected_delete_ipv6 (ifp,
659 (struct in6_addr *) addr, ifa->ifa_prefixlen,
660 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000661 }
paul7021c422003-07-15 12:52:22 +0000662#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000663
664 return 0;
665}
666
667/* Looking up routing table by netlink interface. */
668int
669netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
670{
671 int len;
672 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000673 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000674 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000675
676 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000677
678 int index;
679 int table;
hasso34195bf2004-04-06 12:07:06 +0000680 int metric;
681
paul718e3742002-12-13 20:15:29 +0000682 void *dest;
683 void *gate;
684
685 rtm = NLMSG_DATA (h);
686
687 if (h->nlmsg_type != RTM_NEWROUTE)
688 return 0;
689 if (rtm->rtm_type != RTN_UNICAST)
690 return 0;
691
692 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000693#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000694 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000695 return 0;
696#endif
697
paul7021c422003-07-15 12:52:22 +0000698 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000699 if (len < 0)
700 return -1;
701
702 memset (tb, 0, sizeof tb);
703 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
704
705 if (rtm->rtm_flags & RTM_F_CLONED)
706 return 0;
707 if (rtm->rtm_protocol == RTPROT_REDIRECT)
708 return 0;
709 if (rtm->rtm_protocol == RTPROT_KERNEL)
710 return 0;
711
712 if (rtm->rtm_src_len != 0)
713 return 0;
714
715 /* Route which inserted by Zebra. */
716 if (rtm->rtm_protocol == RTPROT_ZEBRA)
717 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000718
paul718e3742002-12-13 20:15:29 +0000719 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000720 metric = 0;
paul718e3742002-12-13 20:15:29 +0000721 dest = NULL;
722 gate = NULL;
723
724 if (tb[RTA_OIF])
725 index = *(int *) RTA_DATA (tb[RTA_OIF]);
726
727 if (tb[RTA_DST])
728 dest = RTA_DATA (tb[RTA_DST]);
729 else
730 dest = anyaddr;
731
732 /* Multipath treatment is needed. */
733 if (tb[RTA_GATEWAY])
734 gate = RTA_DATA (tb[RTA_GATEWAY]);
735
hasso34195bf2004-04-06 12:07:06 +0000736 if (tb[RTA_PRIORITY])
737 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
738
paul718e3742002-12-13 20:15:29 +0000739 if (rtm->rtm_family == AF_INET)
740 {
741 struct prefix_ipv4 p;
742 p.family = AF_INET;
743 memcpy (&p.prefix, dest, 4);
744 p.prefixlen = rtm->rtm_dst_len;
745
hasso34195bf2004-04-06 12:07:06 +0000746 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000747 }
748#ifdef HAVE_IPV6
749 if (rtm->rtm_family == AF_INET6)
750 {
751 struct prefix_ipv6 p;
752 p.family = AF_INET6;
753 memcpy (&p.prefix, dest, 16);
754 p.prefixlen = rtm->rtm_dst_len;
755
756 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
757 }
758#endif /* HAVE_IPV6 */
759
760 return 0;
761}
762
paul7021c422003-07-15 12:52:22 +0000763struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000764 {RTPROT_REDIRECT, "redirect"},
765 {RTPROT_KERNEL, "kernel"},
766 {RTPROT_BOOT, "boot"},
767 {RTPROT_STATIC, "static"},
768 {RTPROT_GATED, "GateD"},
769 {RTPROT_RA, "router advertisement"},
770 {RTPROT_MRT, "MRT"},
771 {RTPROT_ZEBRA, "Zebra"},
772#ifdef RTPROT_BIRD
773 {RTPROT_BIRD, "BIRD"},
774#endif /* RTPROT_BIRD */
775 {0, NULL}
776};
777
778/* Routing information change from the kernel. */
779int
780netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
781{
782 int len;
783 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000784 struct rtattr *tb[RTA_MAX + 1];
785
786 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000787
788 int index;
789 int table;
790 void *dest;
791 void *gate;
792
793 rtm = NLMSG_DATA (h);
794
paul7021c422003-07-15 12:52:22 +0000795 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000796 {
797 /* If this is not route add/delete message print warning. */
798 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
799 return 0;
800 }
801
802 /* Connected route. */
803 if (IS_ZEBRA_DEBUG_KERNEL)
804 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000805 h->nlmsg_type ==
806 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
807 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
808 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
809 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000810
811 if (rtm->rtm_type != RTN_UNICAST)
812 {
813 return 0;
814 }
815
816 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000817 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000818 {
819 return 0;
820 }
821
paul7021c422003-07-15 12:52:22 +0000822 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000823 if (len < 0)
824 return -1;
825
826 memset (tb, 0, sizeof tb);
827 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
828
829 if (rtm->rtm_flags & RTM_F_CLONED)
830 return 0;
831 if (rtm->rtm_protocol == RTPROT_REDIRECT)
832 return 0;
833 if (rtm->rtm_protocol == RTPROT_KERNEL)
834 return 0;
835
836 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
837 return 0;
838
839 if (rtm->rtm_src_len != 0)
840 {
841 zlog_warn ("netlink_route_change(): no src len");
842 return 0;
843 }
paul7021c422003-07-15 12:52:22 +0000844
paul718e3742002-12-13 20:15:29 +0000845 index = 0;
846 dest = NULL;
847 gate = NULL;
848
849 if (tb[RTA_OIF])
850 index = *(int *) RTA_DATA (tb[RTA_OIF]);
851
852 if (tb[RTA_DST])
853 dest = RTA_DATA (tb[RTA_DST]);
854 else
855 dest = anyaddr;
856
857 if (tb[RTA_GATEWAY])
858 gate = RTA_DATA (tb[RTA_GATEWAY]);
859
860 if (rtm->rtm_family == AF_INET)
861 {
862 struct prefix_ipv4 p;
863 p.family = AF_INET;
864 memcpy (&p.prefix, dest, 4);
865 p.prefixlen = rtm->rtm_dst_len;
866
867 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000868 {
869 if (h->nlmsg_type == RTM_NEWROUTE)
870 zlog_info ("RTM_NEWROUTE %s/%d",
871 inet_ntoa (p.prefix), p.prefixlen);
872 else
873 zlog_info ("RTM_DELROUTE %s/%d",
874 inet_ntoa (p.prefix), p.prefixlen);
875 }
paul718e3742002-12-13 20:15:29 +0000876
877 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000878 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000879 else
paul7021c422003-07-15 12:52:22 +0000880 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000881 }
882
883#ifdef HAVE_IPV6
884 if (rtm->rtm_family == AF_INET6)
885 {
886 struct prefix_ipv6 p;
887 char buf[BUFSIZ];
888
889 p.family = AF_INET6;
890 memcpy (&p.prefix, dest, 16);
891 p.prefixlen = rtm->rtm_dst_len;
892
893 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000894 {
895 if (h->nlmsg_type == RTM_NEWROUTE)
896 zlog_info ("RTM_NEWROUTE %s/%d",
897 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
898 p.prefixlen);
899 else
900 zlog_info ("RTM_DELROUTE %s/%d",
901 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
902 p.prefixlen);
903 }
paul718e3742002-12-13 20:15:29 +0000904
905 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000906 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000907 else
paul7021c422003-07-15 12:52:22 +0000908 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000909 }
910#endif /* HAVE_IPV6 */
911
912 return 0;
913}
914
915int
916netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
917{
918 int len;
919 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000920 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000921 struct interface *ifp;
922 char *name;
923
924 ifi = NLMSG_DATA (h);
925
paul7021c422003-07-15 12:52:22 +0000926 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000927 {
928 /* If this is not link add/delete message so print warning. */
929 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000930 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000931 return 0;
932 }
933
934 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
935 if (len < 0)
936 return -1;
937
938 /* Looking up interface name. */
939 memset (tb, 0, sizeof tb);
940 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
941 if (tb[IFLA_IFNAME] == NULL)
942 return -1;
paul7021c422003-07-15 12:52:22 +0000943 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000944
945 /* Add interface. */
946 if (h->nlmsg_type == RTM_NEWLINK)
947 {
948 ifp = if_lookup_by_name (name);
949
paul7021c422003-07-15 12:52:22 +0000950 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
951 {
952 if (ifp == NULL)
953 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000954
paul7021c422003-07-15 12:52:22 +0000955 ifp->ifindex = ifi->ifi_index;
956 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000957 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000958 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000959
paul7021c422003-07-15 12:52:22 +0000960 /* If new link is added. */
961 if_add_update (ifp);
962 }
paul718e3742002-12-13 20:15:29 +0000963 else
paul7021c422003-07-15 12:52:22 +0000964 {
965 /* Interface status change. */
966 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000967 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000968 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000969
paul7021c422003-07-15 12:52:22 +0000970 if (if_is_operative (ifp))
971 {
972 ifp->flags = ifi->ifi_flags & 0x0000fffff;
973 if (!if_is_operative (ifp))
974 if_down (ifp);
975 }
976 else
977 {
978 ifp->flags = ifi->ifi_flags & 0x0000fffff;
979 if (if_is_operative (ifp))
980 if_up (ifp);
981 }
982 }
paul718e3742002-12-13 20:15:29 +0000983 }
984 else
985 {
986 /* RTM_DELLINK. */
987 ifp = if_lookup_by_name (name);
988
989 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000990 {
991 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000992 name);
paul7021c422003-07-15 12:52:22 +0000993 return 0;
994 }
995
paul718e3742002-12-13 20:15:29 +0000996 if_delete_update (ifp);
997 }
998
999 return 0;
1000}
1001
1002int
1003netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1004{
1005 switch (h->nlmsg_type)
1006 {
1007 case RTM_NEWROUTE:
1008 return netlink_route_change (snl, h);
1009 break;
1010 case RTM_DELROUTE:
1011 return netlink_route_change (snl, h);
1012 break;
1013 case RTM_NEWLINK:
1014 return netlink_link_change (snl, h);
1015 break;
1016 case RTM_DELLINK:
1017 return netlink_link_change (snl, h);
1018 break;
1019 case RTM_NEWADDR:
1020 return netlink_interface_addr (snl, h);
1021 break;
1022 case RTM_DELADDR:
1023 return netlink_interface_addr (snl, h);
1024 break;
1025 default:
1026 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1027 break;
1028 }
1029 return 0;
1030}
1031
1032/* Interface lookup by netlink socket. */
1033int
1034interface_lookup_netlink ()
1035{
1036 int ret;
paul5f37d862003-04-19 00:11:28 +00001037 int flags;
1038 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001039
paul5f37d862003-04-19 00:11:28 +00001040 /*
1041 * Change netlink socket flags to blocking to ensure we get
1042 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001043 */
1044 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1045 if (snb_ret < 0)
1046 zlog (NULL, LOG_WARNING,
1047 "%s:%i Warning: Could not set netlink socket to blocking.",
1048 __FUNCTION__, __LINE__);
1049
paul718e3742002-12-13 20:15:29 +00001050 /* Get interface information. */
1051 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1052 if (ret < 0)
1053 return ret;
1054 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1055 if (ret < 0)
1056 return ret;
1057
1058 /* Get IPv4 address of the interfaces. */
1059 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1060 if (ret < 0)
1061 return ret;
1062 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1063 if (ret < 0)
1064 return ret;
1065
1066#ifdef HAVE_IPV6
1067 /* Get IPv6 address of the interfaces. */
1068 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1069 if (ret < 0)
1070 return ret;
1071 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1072 if (ret < 0)
1073 return ret;
1074#endif /* HAVE_IPV6 */
1075
paul7021c422003-07-15 12:52:22 +00001076 /* restore socket flags */
1077 if (snb_ret == 0)
1078 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001079 return 0;
1080}
1081
1082/* Routing table read function using netlink interface. Only called
1083 bootstrap time. */
1084int
1085netlink_route_read ()
1086{
1087 int ret;
paul5f37d862003-04-19 00:11:28 +00001088 int flags;
1089 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001090
paul5f37d862003-04-19 00:11:28 +00001091 /*
1092 * Change netlink socket flags to blocking to ensure we get
1093 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001094 */
1095 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1096 if (snb_ret < 0)
1097 zlog (NULL, LOG_WARNING,
1098 "%s:%i Warning: Could not set netlink socket to blocking.",
1099 __FUNCTION__, __LINE__);
1100
paul718e3742002-12-13 20:15:29 +00001101 /* Get IPv4 routing table. */
1102 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1103 if (ret < 0)
1104 return ret;
1105 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1106 if (ret < 0)
1107 return ret;
1108
1109#ifdef HAVE_IPV6
1110 /* Get IPv6 routing table. */
1111 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1112 if (ret < 0)
1113 return ret;
1114 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1115 if (ret < 0)
1116 return ret;
1117#endif /* HAVE_IPV6 */
1118
paul5f37d862003-04-19 00:11:28 +00001119 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001120 if (snb_ret == 0)
1121 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001122 return 0;
1123}
1124
1125/* Utility function comes from iproute2.
1126 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1127int
1128addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1129{
1130 int len;
1131 struct rtattr *rta;
1132
paul7021c422003-07-15 12:52:22 +00001133 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001134
paul7021c422003-07-15 12:52:22 +00001135 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001136 return -1;
1137
paul7021c422003-07-15 12:52:22 +00001138 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001139 rta->rta_type = type;
1140 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001141 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001142 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1143
1144 return 0;
1145}
1146
1147int
1148rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1149{
1150 int len;
1151 struct rtattr *subrta;
1152
paul7021c422003-07-15 12:52:22 +00001153 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001154
paul7021c422003-07-15 12:52:22 +00001155 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001156 return -1;
1157
paul7021c422003-07-15 12:52:22 +00001158 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001159 subrta->rta_type = type;
1160 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001161 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001162 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1163
1164 return 0;
1165}
1166
1167/* Utility function comes from iproute2.
1168 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1169int
1170addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1171{
1172 int len;
1173 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001174
1175 len = RTA_LENGTH (4);
1176
paul718e3742002-12-13 20:15:29 +00001177 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1178 return -1;
1179
paul7021c422003-07-15 12:52:22 +00001180 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001181 rta->rta_type = type;
1182 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001183 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001184 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1185
1186 return 0;
1187}
1188
1189static int
1190netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1191{
1192 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1193 return 0;
1194}
1195
1196/* sendmsg() to netlink socket then recvmsg(). */
1197int
1198netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1199{
1200 int status;
1201 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001202 struct iovec iov = { (void *) n, n->nlmsg_len };
1203 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001204 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001205 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001206
paul718e3742002-12-13 20:15:29 +00001207 memset (&snl, 0, sizeof snl);
1208 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001209
paul718e3742002-12-13 20:15:29 +00001210 n->nlmsg_seq = ++netlink_cmd.seq;
1211
1212 /* Request an acknowledgement by setting NLM_F_ACK */
1213 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001214
1215 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001216 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001217 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1218 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001219
1220 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001221 if (zserv_privs.change (ZPRIVS_RAISE))
1222 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001223 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001224 if (zserv_privs.change (ZPRIVS_LOWER))
1225 zlog (NULL, LOG_ERR, "Can't lower privileges");
1226
paul718e3742002-12-13 20:15:29 +00001227 if (status < 0)
1228 {
1229 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001230 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001231 return -1;
1232 }
paul7021c422003-07-15 12:52:22 +00001233
paul718e3742002-12-13 20:15:29 +00001234 /*
1235 * Change socket flags for blocking I/O.
1236 * This ensures we wait for a reply in netlink_parse_info().
1237 */
paul7021c422003-07-15 12:52:22 +00001238 snb_ret = set_netlink_blocking (nl, &flags);
1239 if (snb_ret < 0)
1240 zlog (NULL, LOG_WARNING,
1241 "%s:%i Warning: Could not set netlink socket to blocking.",
1242 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001243
1244 /*
1245 * Get reply from netlink socket.
1246 * The reply should either be an acknowlegement or an error.
1247 */
1248 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001249
paul718e3742002-12-13 20:15:29 +00001250 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001251 if (snb_ret == 0)
1252 set_netlink_nonblocking (nl, &flags);
1253
paul718e3742002-12-13 20:15:29 +00001254 return status;
1255}
1256
1257/* Routing table change via netlink interface. */
1258int
1259netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001260 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001261{
1262 int ret;
1263 int bytelen;
1264 struct sockaddr_nl snl;
1265 int discard;
1266
paul7021c422003-07-15 12:52:22 +00001267 struct
paul718e3742002-12-13 20:15:29 +00001268 {
1269 struct nlmsghdr n;
1270 struct rtmsg r;
1271 char buf[1024];
1272 } req;
1273
1274 memset (&req, 0, sizeof req);
1275
1276 bytelen = (family == AF_INET ? 4 : 16);
1277
1278 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1279 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1280 req.n.nlmsg_type = cmd;
1281 req.r.rtm_family = family;
1282 req.r.rtm_table = table;
1283 req.r.rtm_dst_len = length;
1284
hasso81dfcaa2003-05-25 19:21:25 +00001285 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1286 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001287 discard = 1;
1288 else
1289 discard = 0;
1290
paul7021c422003-07-15 12:52:22 +00001291 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001292 {
1293 req.r.rtm_protocol = RTPROT_ZEBRA;
1294 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1295
paul7021c422003-07-15 12:52:22 +00001296 if (discard)
paul595db7f2003-05-25 21:35:06 +00001297 {
1298 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1299 req.r.rtm_type = RTN_BLACKHOLE;
1300 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1301 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001302 else
1303 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1304 }
paul595db7f2003-05-25 21:35:06 +00001305 else
paul7021c422003-07-15 12:52:22 +00001306 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001307 }
1308
1309 if (dest)
1310 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1311
paul7021c422003-07-15 12:52:22 +00001312 if (!discard)
paul718e3742002-12-13 20:15:29 +00001313 {
1314 if (gate)
paul7021c422003-07-15 12:52:22 +00001315 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001316 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001317 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001318 }
1319
1320 /* Destination netlink address. */
1321 memset (&snl, 0, sizeof snl);
1322 snl.nl_family = AF_NETLINK;
1323
1324 /* Talk to netlink socket. */
1325 ret = netlink_talk (&req.n, &netlink);
1326 if (ret < 0)
1327 return -1;
1328
1329 return 0;
1330}
1331
1332/* Routing table change via netlink interface. */
1333int
1334netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001335 int family)
paul718e3742002-12-13 20:15:29 +00001336{
1337 int bytelen;
1338 struct sockaddr_nl snl;
1339 struct nexthop *nexthop = NULL;
1340 int nexthop_num = 0;
1341 struct nlsock *nl;
1342 int discard;
1343
paul7021c422003-07-15 12:52:22 +00001344 struct
paul718e3742002-12-13 20:15:29 +00001345 {
1346 struct nlmsghdr n;
1347 struct rtmsg r;
1348 char buf[1024];
1349 } req;
1350
1351 memset (&req, 0, sizeof req);
1352
1353 bytelen = (family == AF_INET ? 4 : 16);
1354
1355 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1356 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1357 req.n.nlmsg_type = cmd;
1358 req.r.rtm_family = family;
1359 req.r.rtm_table = rib->table;
1360 req.r.rtm_dst_len = p->prefixlen;
1361
paul13766da2003-02-07 14:46:23 +00001362#ifdef RTM_F_EQUALIZE
1363 req.r.rtm_flags |= RTM_F_EQUALIZE;
1364#endif /* RTM_F_EQUALIZE */
1365
paul7021c422003-07-15 12:52:22 +00001366 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001367 discard = 1;
1368 else
1369 discard = 0;
1370
paul7021c422003-07-15 12:52:22 +00001371 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001372 {
1373 req.r.rtm_protocol = RTPROT_ZEBRA;
1374 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1375
paul7021c422003-07-15 12:52:22 +00001376 if (discard)
paul595db7f2003-05-25 21:35:06 +00001377 {
1378 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1379 req.r.rtm_type = RTN_BLACKHOLE;
1380 else if (rib->flags & ZEBRA_FLAG_REJECT)
1381 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001382 else
1383 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1384 }
paul595db7f2003-05-25 21:35:06 +00001385 else
paul7021c422003-07-15 12:52:22 +00001386 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001387 }
1388
1389 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1390
1391 /* Metric. */
1392 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1393
1394 if (discard)
1395 {
1396 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001397 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1398 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001399 goto skip;
1400 }
1401
1402 /* Multipath case. */
1403 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1404 {
1405 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001406 {
paul5ec90d22003-06-19 01:41:37 +00001407
paul7021c422003-07-15 12:52:22 +00001408 if ((cmd == RTM_NEWROUTE
1409 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1410 || (cmd == RTM_DELROUTE
1411 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1412 {
paul5ec90d22003-06-19 01:41:37 +00001413
paul7021c422003-07-15 12:52:22 +00001414 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1415 {
1416 if (IS_ZEBRA_DEBUG_KERNEL)
1417 {
1418 zlog_info
1419 ("netlink_route_multipath() (recursive, 1 hop): "
1420 "%s %s/%d via %s if %u, type %s",
1421 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1422 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1423 nexthop->rifindex,
1424 nexthop_types_desc[nexthop->rtype]);
1425 }
paul5ec90d22003-06-19 01:41:37 +00001426
paul7021c422003-07-15 12:52:22 +00001427 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1428 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1429 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1430 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001431#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001432 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1433 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1434 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1435 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1436 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001437#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001438 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1439 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1440 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1441 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1442 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1443 addattr32 (&req.n, sizeof req, RTA_OIF,
1444 nexthop->rifindex);
1445 }
1446 else
1447 {
1448 if (IS_ZEBRA_DEBUG_KERNEL)
1449 {
1450 zlog_info
1451 ("netlink_route_multipath(): (single hop)"
1452 "%s %s/%d via %s if %u, type %s",
1453 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1454 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1455 nexthop->ifindex,
1456 nexthop_types_desc[nexthop->type]);
1457 }
paul5ec90d22003-06-19 01:41:37 +00001458
paul7021c422003-07-15 12:52:22 +00001459 if (nexthop->type == NEXTHOP_TYPE_IPV4
1460 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1461 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1462 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001463#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001464 if (nexthop->type == NEXTHOP_TYPE_IPV6
1465 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1466 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1467 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1468 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001469#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001470 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1471 || nexthop->type == NEXTHOP_TYPE_IFNAME
1472 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1473 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1474 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1475 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1476 }
paul718e3742002-12-13 20:15:29 +00001477
paul7021c422003-07-15 12:52:22 +00001478 if (cmd == RTM_NEWROUTE)
1479 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001480
paul7021c422003-07-15 12:52:22 +00001481 nexthop_num++;
1482 break;
1483 }
1484 }
paul718e3742002-12-13 20:15:29 +00001485 }
1486 else
1487 {
1488 char buf[1024];
1489 struct rtattr *rta = (void *) buf;
1490 struct rtnexthop *rtnh;
1491
1492 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001493 rta->rta_len = RTA_LENGTH (0);
1494 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001495
1496 nexthop_num = 0;
1497 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001498 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1499 nexthop = nexthop->next)
1500 {
1501 if ((cmd == RTM_NEWROUTE
1502 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1503 || (cmd == RTM_DELROUTE
1504 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1505 {
1506 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001507
paul7021c422003-07-15 12:52:22 +00001508 rtnh->rtnh_len = sizeof (*rtnh);
1509 rtnh->rtnh_flags = 0;
1510 rtnh->rtnh_hops = 0;
1511 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001512
paul7021c422003-07-15 12:52:22 +00001513 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1514 {
1515 if (IS_ZEBRA_DEBUG_KERNEL)
1516 {
1517 zlog_info ("netlink_route_multipath() "
1518 "(recursive, multihop): "
1519 "%s %s/%d via %s if %u, type %s",
1520 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1521 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1522 nexthop->rifindex,
1523 nexthop_types_desc[nexthop->type]);
1524 }
1525 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1526 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1527 {
1528 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1529 &nexthop->rgate.ipv4, bytelen);
1530 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1531 }
paul718e3742002-12-13 20:15:29 +00001532#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001533 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1534 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1535 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1536 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1537 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001538#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001539 /* ifindex */
1540 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1541 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1542 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1543 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1544 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1545 rtnh->rtnh_ifindex = nexthop->rifindex;
1546 else
1547 rtnh->rtnh_ifindex = 0;
1548 }
1549 else
1550 {
1551 if (IS_ZEBRA_DEBUG_KERNEL)
1552 {
1553 zlog_info ("netlink_route_multipath() "
1554 "(multihop): "
1555 "%s %s/%d via %s if %u, type %s",
1556 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1557 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1558 nexthop->rifindex,
1559 nexthop_types_desc[nexthop->type]);
1560 }
1561 if (nexthop->type == NEXTHOP_TYPE_IPV4
1562 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1563 {
1564 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1565 &nexthop->gate.ipv4, bytelen);
1566 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1567 }
paul718e3742002-12-13 20:15:29 +00001568#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001569 if (nexthop->type == NEXTHOP_TYPE_IPV6
1570 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1571 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1572 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1573 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001574#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001575 /* ifindex */
1576 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1577 || nexthop->type == NEXTHOP_TYPE_IFNAME
1578 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1579 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1580 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1581 rtnh->rtnh_ifindex = nexthop->ifindex;
1582 else
1583 rtnh->rtnh_ifindex = 0;
1584 }
1585 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001586
paul7021c422003-07-15 12:52:22 +00001587 if (cmd == RTM_NEWROUTE)
1588 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1589 }
1590 }
paul718e3742002-12-13 20:15:29 +00001591
1592 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001593 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1594 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001595 }
1596
1597 /* If there is no useful nexthop then return. */
1598 if (nexthop_num == 0)
1599 {
1600 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001601 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001602 return 0;
1603 }
1604
paul7021c422003-07-15 12:52:22 +00001605skip:
paul718e3742002-12-13 20:15:29 +00001606
1607 /* Destination netlink address. */
1608 memset (&snl, 0, sizeof snl);
1609 snl.nl_family = AF_NETLINK;
1610
1611 if (family == AF_INET)
1612 nl = &netlink_cmd;
1613 else
1614 nl = &netlink;
1615
1616 /* Talk to netlink socket. */
1617 return netlink_talk (&req.n, nl);
1618}
1619
1620int
1621kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1622{
1623 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1624}
1625
1626int
1627kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1628{
1629 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1630}
1631
1632#ifdef HAVE_IPV6
1633int
1634kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1635{
1636 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1637}
1638
1639int
1640kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1641{
1642 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1643}
1644
1645/* Delete IPv6 route from the kernel. */
1646int
1647kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001648 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001649{
paul7021c422003-07-15 12:52:22 +00001650 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1651 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001652}
1653#endif /* HAVE_IPV6 */
1654
1655/* Interface address modification. */
1656int
1657netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001658 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001659{
1660 int bytelen;
1661 struct prefix *p;
1662
paul7021c422003-07-15 12:52:22 +00001663 struct
paul718e3742002-12-13 20:15:29 +00001664 {
1665 struct nlmsghdr n;
1666 struct ifaddrmsg ifa;
1667 char buf[1024];
1668 } req;
1669
1670 p = ifc->address;
1671 memset (&req, 0, sizeof req);
1672
1673 bytelen = (family == AF_INET ? 4 : 16);
1674
paul7021c422003-07-15 12:52:22 +00001675 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001676 req.n.nlmsg_flags = NLM_F_REQUEST;
1677 req.n.nlmsg_type = cmd;
1678 req.ifa.ifa_family = family;
1679
1680 req.ifa.ifa_index = ifp->ifindex;
1681 req.ifa.ifa_prefixlen = p->prefixlen;
1682
1683 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1684
1685 if (family == AF_INET && cmd == RTM_NEWADDR)
1686 {
1687 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001688 {
1689 p = ifc->destination;
1690 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1691 bytelen);
1692 }
paul718e3742002-12-13 20:15:29 +00001693 }
1694
1695 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1696 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001697
paul718e3742002-12-13 20:15:29 +00001698 if (ifc->label)
1699 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001700 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001701
1702 return netlink_talk (&req.n, &netlink_cmd);
1703}
1704
1705int
1706kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1707{
1708 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1709}
1710
1711int
1712kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1713{
1714 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1715}
1716
paul718e3742002-12-13 20:15:29 +00001717
1718extern struct thread_master *master;
1719
1720/* Kernel route reflection. */
1721int
1722kernel_read (struct thread *thread)
1723{
1724 int ret;
1725 int sock;
1726
1727 sock = THREAD_FD (thread);
1728 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001729 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001730
1731 return 0;
1732}
1733
1734/* Exported interface function. This function simply calls
1735 netlink_socket (). */
1736void
1737kernel_init ()
1738{
1739 unsigned long groups;
1740
paul7021c422003-07-15 12:52:22 +00001741 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001742#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001743 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001744#endif /* HAVE_IPV6 */
1745 netlink_socket (&netlink, groups);
1746 netlink_socket (&netlink_cmd, 0);
1747
1748 /* Register kernel socket. */
1749 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001750 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001751}