blob: f5903a63fe9e9861bafd6b641f7704e95297da5b [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,
ajs6099b3b2004-11-20 02:06:59 +0000102 safe_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,
ajs6099b3b2004-11-20 02:06:59 +0000110 safe_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,
ajs6099b3b2004-11-20 02:06:59 +0000128 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000129 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,
ajs6099b3b2004-11-20 02:06:59 +0000138 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000139 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,
ajs6099b3b2004-11-20 02:06:59 +0000147 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000148 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",
ajs6099b3b2004-11-20 02:06:59 +0000175 nl->name, snl.nl_groups, safe_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,
ajs6099b3b2004-11-20 02:06:59 +0000186 safe_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",
ajs6099b3b2004-11-20 02:06:59 +0000204 __FUNCTION__, __LINE__, safe_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",
ajs6099b3b2004-11-20 02:06:59 +0000211 __FUNCTION__, __LINE__, safe_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",
ajs6099b3b2004-11-20 02:06:59 +0000225 __FUNCTION__, __LINE__, safe_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,
ajs6099b3b2004-11-20 02:06:59 +0000280 safe_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 {
ajsb6178002004-12-07 21:12:56 +0000360 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000361 __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",
ajs6099b3b2004-11-20 02:06:59 +0000395 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000396 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)
ajsb6178002004-12-07 21:12:56 +0000408 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000409 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)
ajsb6178002004-12-07 21:12:56 +0000417 zlog_debug ("netlink_parse_info: %s packet comes from %s",
paul7021c422003-07-15 12:52:22 +0000418 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);
paulc15cb242005-01-24 09:05:27 +0000483
484 /* check for wireless messages to ignore */
485 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
486 {
487 if (IS_ZEBRA_DEBUG_KERNEL)
488 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
489 return 0;
490 }
491
paul718e3742002-12-13 20:15:29 +0000492 if (tb[IFLA_IFNAME] == NULL)
493 return -1;
paul7021c422003-07-15 12:52:22 +0000494 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000495
496 /* Add interface. */
497 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000498
paul718e3742002-12-13 20:15:29 +0000499 ifp->ifindex = ifi->ifi_index;
500 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000501 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000502 ifp->metric = 1;
503
504 /* Hardware type and address. */
505 ifp->hw_type = ifi->ifi_type;
506
507 if (tb[IFLA_ADDRESS])
508 {
509 int hw_addr_len;
510
paul7021c422003-07-15 12:52:22 +0000511 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000512
513 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000514 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000515 else
paul7021c422003-07-15 12:52:22 +0000516 {
517 ifp->hw_addr_len = hw_addr_len;
518 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000519
paul7021c422003-07-15 12:52:22 +0000520 for (i = 0; i < hw_addr_len; i++)
521 if (ifp->hw_addr[i] != 0)
522 break;
paul718e3742002-12-13 20:15:29 +0000523
paul7021c422003-07-15 12:52:22 +0000524 if (i == hw_addr_len)
525 ifp->hw_addr_len = 0;
526 else
527 ifp->hw_addr_len = hw_addr_len;
528 }
paul718e3742002-12-13 20:15:29 +0000529 }
530
531 if_add_update (ifp);
532
533 return 0;
534}
535
536/* Lookup interface IPv4/IPv6 address. */
537int
538netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
539{
540 int len;
541 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000542 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000543 struct interface *ifp;
544 void *addr = NULL;
545 void *broad = NULL;
546 u_char flags = 0;
547 char *label = NULL;
548
549 ifa = NLMSG_DATA (h);
550
paul7021c422003-07-15 12:52:22 +0000551 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000552#ifdef HAVE_IPV6
553 && ifa->ifa_family != AF_INET6
554#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000555 )
paul718e3742002-12-13 20:15:29 +0000556 return 0;
557
558 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
559 return 0;
560
paul7021c422003-07-15 12:52:22 +0000561 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000562 if (len < 0)
563 return -1;
564
565 memset (tb, 0, sizeof tb);
566 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
567
568 ifp = if_lookup_by_index (ifa->ifa_index);
569 if (ifp == NULL)
570 {
571 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000572 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000573 return -1;
574 }
575
paul7021c422003-07-15 12:52:22 +0000576 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000577 {
paul00df0c12002-12-13 21:07:36 +0000578 char buf[BUFSIZ];
ajsb6178002004-12-07 21:12:56 +0000579 zlog_debug ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000580 lookup (nlmsg_str, h->nlmsg_type),
581 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000582 if (tb[IFA_LOCAL])
ajsb6178002004-12-07 21:12:56 +0000583 zlog_debug (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000584 RTA_DATA (tb[IFA_LOCAL]),
585 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000586 if (tb[IFA_ADDRESS])
ajsb6178002004-12-07 21:12:56 +0000587 zlog_debug (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000588 RTA_DATA (tb
589 [IFA_ADDRESS]),
590 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000591 if (tb[IFA_BROADCAST])
ajsb6178002004-12-07 21:12:56 +0000592 zlog_debug (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000593 RTA_DATA (tb
594 [IFA_BROADCAST]),
595 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000596 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000597 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000598 }
paul31a476c2003-09-29 19:54:53 +0000599
600 if (tb[IFA_ADDRESS] == NULL)
601 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
602
603 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000604 {
paul31a476c2003-09-29 19:54:53 +0000605 if (tb[IFA_LOCAL])
606 {
607 addr = RTA_DATA (tb[IFA_LOCAL]);
hasso3fb9cd62004-10-19 19:44:43 +0000608 if (tb[IFA_ADDRESS] &&
609 memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4))
610 /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */
paul31a476c2003-09-29 19:54:53 +0000611 broad = RTA_DATA (tb[IFA_ADDRESS]);
612 else
613 broad = NULL;
614 }
615 else
616 {
617 if (tb[IFA_ADDRESS])
618 addr = RTA_DATA (tb[IFA_ADDRESS]);
619 else
620 addr = NULL;
621 }
paul7021c422003-07-15 12:52:22 +0000622 }
paul31a476c2003-09-29 19:54:53 +0000623 else
paul7021c422003-07-15 12:52:22 +0000624 {
paul31a476c2003-09-29 19:54:53 +0000625 if (tb[IFA_ADDRESS])
626 addr = RTA_DATA (tb[IFA_ADDRESS]);
627 else
628 addr = NULL;
629
630 if (tb[IFA_BROADCAST])
631 broad = RTA_DATA(tb[IFA_BROADCAST]);
632 else
633 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000634 }
paul00df0c12002-12-13 21:07:36 +0000635
paul718e3742002-12-13 20:15:29 +0000636 /* Flags. */
637 if (ifa->ifa_flags & IFA_F_SECONDARY)
638 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
639
640 /* Label */
641 if (tb[IFA_LABEL])
642 label = (char *) RTA_DATA (tb[IFA_LABEL]);
643
644 if (ifp && label && strcmp (ifp->name, label) == 0)
645 label = NULL;
646
647 /* Register interface address to the interface. */
648 if (ifa->ifa_family == AF_INET)
649 {
paul7021c422003-07-15 12:52:22 +0000650 if (h->nlmsg_type == RTM_NEWADDR)
651 connected_add_ipv4 (ifp, flags,
652 (struct in_addr *) addr, ifa->ifa_prefixlen,
653 (struct in_addr *) broad, label);
654 else
655 connected_delete_ipv4 (ifp, flags,
656 (struct in_addr *) addr, ifa->ifa_prefixlen,
657 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000658 }
659#ifdef HAVE_IPV6
660 if (ifa->ifa_family == AF_INET6)
661 {
662 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000663 connected_add_ipv6 (ifp,
664 (struct in6_addr *) addr, ifa->ifa_prefixlen,
665 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000666 else
paul7021c422003-07-15 12:52:22 +0000667 connected_delete_ipv6 (ifp,
668 (struct in6_addr *) addr, ifa->ifa_prefixlen,
669 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000670 }
paul7021c422003-07-15 12:52:22 +0000671#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000672
673 return 0;
674}
675
676/* Looking up routing table by netlink interface. */
677int
678netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
679{
680 int len;
681 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000682 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000683 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000684
685 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000686
687 int index;
688 int table;
hasso34195bf2004-04-06 12:07:06 +0000689 int metric;
690
paul718e3742002-12-13 20:15:29 +0000691 void *dest;
692 void *gate;
693
694 rtm = NLMSG_DATA (h);
695
696 if (h->nlmsg_type != RTM_NEWROUTE)
697 return 0;
698 if (rtm->rtm_type != RTN_UNICAST)
699 return 0;
700
701 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000702#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000703 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000704 return 0;
705#endif
706
paul7021c422003-07-15 12:52:22 +0000707 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000708 if (len < 0)
709 return -1;
710
711 memset (tb, 0, sizeof tb);
712 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
713
714 if (rtm->rtm_flags & RTM_F_CLONED)
715 return 0;
716 if (rtm->rtm_protocol == RTPROT_REDIRECT)
717 return 0;
718 if (rtm->rtm_protocol == RTPROT_KERNEL)
719 return 0;
720
721 if (rtm->rtm_src_len != 0)
722 return 0;
723
724 /* Route which inserted by Zebra. */
725 if (rtm->rtm_protocol == RTPROT_ZEBRA)
726 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000727
paul718e3742002-12-13 20:15:29 +0000728 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000729 metric = 0;
paul718e3742002-12-13 20:15:29 +0000730 dest = NULL;
731 gate = NULL;
732
733 if (tb[RTA_OIF])
734 index = *(int *) RTA_DATA (tb[RTA_OIF]);
735
736 if (tb[RTA_DST])
737 dest = RTA_DATA (tb[RTA_DST]);
738 else
739 dest = anyaddr;
740
741 /* Multipath treatment is needed. */
742 if (tb[RTA_GATEWAY])
743 gate = RTA_DATA (tb[RTA_GATEWAY]);
744
hasso34195bf2004-04-06 12:07:06 +0000745 if (tb[RTA_PRIORITY])
746 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
747
paul718e3742002-12-13 20:15:29 +0000748 if (rtm->rtm_family == AF_INET)
749 {
750 struct prefix_ipv4 p;
751 p.family = AF_INET;
752 memcpy (&p.prefix, dest, 4);
753 p.prefixlen = rtm->rtm_dst_len;
754
hasso34195bf2004-04-06 12:07:06 +0000755 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000756 }
757#ifdef HAVE_IPV6
758 if (rtm->rtm_family == AF_INET6)
759 {
760 struct prefix_ipv6 p;
761 p.family = AF_INET6;
762 memcpy (&p.prefix, dest, 16);
763 p.prefixlen = rtm->rtm_dst_len;
764
765 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
766 }
767#endif /* HAVE_IPV6 */
768
769 return 0;
770}
771
paul7021c422003-07-15 12:52:22 +0000772struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000773 {RTPROT_REDIRECT, "redirect"},
774 {RTPROT_KERNEL, "kernel"},
775 {RTPROT_BOOT, "boot"},
776 {RTPROT_STATIC, "static"},
777 {RTPROT_GATED, "GateD"},
778 {RTPROT_RA, "router advertisement"},
779 {RTPROT_MRT, "MRT"},
780 {RTPROT_ZEBRA, "Zebra"},
781#ifdef RTPROT_BIRD
782 {RTPROT_BIRD, "BIRD"},
783#endif /* RTPROT_BIRD */
784 {0, NULL}
785};
786
787/* Routing information change from the kernel. */
788int
789netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
790{
791 int len;
792 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000793 struct rtattr *tb[RTA_MAX + 1];
794
795 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000796
797 int index;
798 int table;
799 void *dest;
800 void *gate;
801
802 rtm = NLMSG_DATA (h);
803
paul7021c422003-07-15 12:52:22 +0000804 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000805 {
806 /* If this is not route add/delete message print warning. */
807 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
808 return 0;
809 }
810
811 /* Connected route. */
812 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000813 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000814 h->nlmsg_type ==
815 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
816 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
817 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
818 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000819
820 if (rtm->rtm_type != RTN_UNICAST)
821 {
822 return 0;
823 }
824
825 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000826 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000827 {
828 return 0;
829 }
830
paul7021c422003-07-15 12:52:22 +0000831 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000832 if (len < 0)
833 return -1;
834
835 memset (tb, 0, sizeof tb);
836 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
837
838 if (rtm->rtm_flags & RTM_F_CLONED)
839 return 0;
840 if (rtm->rtm_protocol == RTPROT_REDIRECT)
841 return 0;
842 if (rtm->rtm_protocol == RTPROT_KERNEL)
843 return 0;
844
845 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
846 return 0;
847
848 if (rtm->rtm_src_len != 0)
849 {
850 zlog_warn ("netlink_route_change(): no src len");
851 return 0;
852 }
paul7021c422003-07-15 12:52:22 +0000853
paul718e3742002-12-13 20:15:29 +0000854 index = 0;
855 dest = NULL;
856 gate = NULL;
857
858 if (tb[RTA_OIF])
859 index = *(int *) RTA_DATA (tb[RTA_OIF]);
860
861 if (tb[RTA_DST])
862 dest = RTA_DATA (tb[RTA_DST]);
863 else
864 dest = anyaddr;
865
866 if (tb[RTA_GATEWAY])
867 gate = RTA_DATA (tb[RTA_GATEWAY]);
868
869 if (rtm->rtm_family == AF_INET)
870 {
871 struct prefix_ipv4 p;
872 p.family = AF_INET;
873 memcpy (&p.prefix, dest, 4);
874 p.prefixlen = rtm->rtm_dst_len;
875
876 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000877 {
878 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000879 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000880 inet_ntoa (p.prefix), p.prefixlen);
881 else
ajsb6178002004-12-07 21:12:56 +0000882 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000883 inet_ntoa (p.prefix), p.prefixlen);
884 }
paul718e3742002-12-13 20:15:29 +0000885
886 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000887 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000888 else
paul7021c422003-07-15 12:52:22 +0000889 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000890 }
891
892#ifdef HAVE_IPV6
893 if (rtm->rtm_family == AF_INET6)
894 {
895 struct prefix_ipv6 p;
896 char buf[BUFSIZ];
897
898 p.family = AF_INET6;
899 memcpy (&p.prefix, dest, 16);
900 p.prefixlen = rtm->rtm_dst_len;
901
902 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000903 {
904 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000905 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000906 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
907 p.prefixlen);
908 else
ajsb6178002004-12-07 21:12:56 +0000909 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000910 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
911 p.prefixlen);
912 }
paul718e3742002-12-13 20:15:29 +0000913
914 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000915 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000916 else
paul7021c422003-07-15 12:52:22 +0000917 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000918 }
919#endif /* HAVE_IPV6 */
920
921 return 0;
922}
923
924int
925netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
926{
927 int len;
928 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000929 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000930 struct interface *ifp;
931 char *name;
932
933 ifi = NLMSG_DATA (h);
934
paul7021c422003-07-15 12:52:22 +0000935 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000936 {
937 /* If this is not link add/delete message so print warning. */
938 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000939 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000940 return 0;
941 }
942
943 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
944 if (len < 0)
945 return -1;
946
947 /* Looking up interface name. */
948 memset (tb, 0, sizeof tb);
949 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000950
951 /* check for wireless messages to ignore */
952 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
953 {
954 if (IS_ZEBRA_DEBUG_KERNEL)
955 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
956 return 0;
957 }
958
paul718e3742002-12-13 20:15:29 +0000959 if (tb[IFLA_IFNAME] == NULL)
960 return -1;
paul7021c422003-07-15 12:52:22 +0000961 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000962
963 /* Add interface. */
964 if (h->nlmsg_type == RTM_NEWLINK)
965 {
966 ifp = if_lookup_by_name (name);
967
paul7021c422003-07-15 12:52:22 +0000968 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
969 {
970 if (ifp == NULL)
971 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000972
paul7021c422003-07-15 12:52:22 +0000973 ifp->ifindex = ifi->ifi_index;
974 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000975 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000976 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000977
paul7021c422003-07-15 12:52:22 +0000978 /* If new link is added. */
979 if_add_update (ifp);
980 }
paul718e3742002-12-13 20:15:29 +0000981 else
paul7021c422003-07-15 12:52:22 +0000982 {
983 /* Interface status change. */
984 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000985 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000986 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000987
paul7021c422003-07-15 12:52:22 +0000988 if (if_is_operative (ifp))
989 {
990 ifp->flags = ifi->ifi_flags & 0x0000fffff;
991 if (!if_is_operative (ifp))
992 if_down (ifp);
993 }
994 else
995 {
996 ifp->flags = ifi->ifi_flags & 0x0000fffff;
997 if (if_is_operative (ifp))
998 if_up (ifp);
999 }
1000 }
paul718e3742002-12-13 20:15:29 +00001001 }
1002 else
1003 {
1004 /* RTM_DELLINK. */
1005 ifp = if_lookup_by_name (name);
1006
1007 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001008 {
1009 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001010 name);
paul7021c422003-07-15 12:52:22 +00001011 return 0;
1012 }
1013
paul718e3742002-12-13 20:15:29 +00001014 if_delete_update (ifp);
1015 }
1016
1017 return 0;
1018}
1019
1020int
1021netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1022{
1023 switch (h->nlmsg_type)
1024 {
1025 case RTM_NEWROUTE:
1026 return netlink_route_change (snl, h);
1027 break;
1028 case RTM_DELROUTE:
1029 return netlink_route_change (snl, h);
1030 break;
1031 case RTM_NEWLINK:
1032 return netlink_link_change (snl, h);
1033 break;
1034 case RTM_DELLINK:
1035 return netlink_link_change (snl, h);
1036 break;
1037 case RTM_NEWADDR:
1038 return netlink_interface_addr (snl, h);
1039 break;
1040 case RTM_DELADDR:
1041 return netlink_interface_addr (snl, h);
1042 break;
1043 default:
1044 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1045 break;
1046 }
1047 return 0;
1048}
1049
1050/* Interface lookup by netlink socket. */
1051int
1052interface_lookup_netlink ()
1053{
1054 int ret;
paul5f37d862003-04-19 00:11:28 +00001055 int flags;
1056 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001057
paul5f37d862003-04-19 00:11:28 +00001058 /*
1059 * Change netlink socket flags to blocking to ensure we get
1060 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001061 */
1062 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1063 if (snb_ret < 0)
1064 zlog (NULL, LOG_WARNING,
1065 "%s:%i Warning: Could not set netlink socket to blocking.",
1066 __FUNCTION__, __LINE__);
1067
paul718e3742002-12-13 20:15:29 +00001068 /* Get interface information. */
1069 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1070 if (ret < 0)
1071 return ret;
1072 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1073 if (ret < 0)
1074 return ret;
1075
1076 /* Get IPv4 address of the interfaces. */
1077 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1078 if (ret < 0)
1079 return ret;
1080 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1081 if (ret < 0)
1082 return ret;
1083
1084#ifdef HAVE_IPV6
1085 /* Get IPv6 address of the interfaces. */
1086 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1087 if (ret < 0)
1088 return ret;
1089 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1090 if (ret < 0)
1091 return ret;
1092#endif /* HAVE_IPV6 */
1093
paul7021c422003-07-15 12:52:22 +00001094 /* restore socket flags */
1095 if (snb_ret == 0)
1096 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001097 return 0;
1098}
1099
1100/* Routing table read function using netlink interface. Only called
1101 bootstrap time. */
1102int
1103netlink_route_read ()
1104{
1105 int ret;
paul5f37d862003-04-19 00:11:28 +00001106 int flags;
1107 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001108
paul5f37d862003-04-19 00:11:28 +00001109 /*
1110 * Change netlink socket flags to blocking to ensure we get
1111 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001112 */
1113 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1114 if (snb_ret < 0)
1115 zlog (NULL, LOG_WARNING,
1116 "%s:%i Warning: Could not set netlink socket to blocking.",
1117 __FUNCTION__, __LINE__);
1118
paul718e3742002-12-13 20:15:29 +00001119 /* Get IPv4 routing table. */
1120 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1121 if (ret < 0)
1122 return ret;
1123 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1124 if (ret < 0)
1125 return ret;
1126
1127#ifdef HAVE_IPV6
1128 /* Get IPv6 routing table. */
1129 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1130 if (ret < 0)
1131 return ret;
1132 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1133 if (ret < 0)
1134 return ret;
1135#endif /* HAVE_IPV6 */
1136
paul5f37d862003-04-19 00:11:28 +00001137 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001138 if (snb_ret == 0)
1139 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001140 return 0;
1141}
1142
1143/* Utility function comes from iproute2.
1144 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1145int
1146addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1147{
1148 int len;
1149 struct rtattr *rta;
1150
paul7021c422003-07-15 12:52:22 +00001151 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001152
paul7021c422003-07-15 12:52:22 +00001153 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001154 return -1;
1155
paul7021c422003-07-15 12:52:22 +00001156 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001157 rta->rta_type = type;
1158 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001159 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001160 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1161
1162 return 0;
1163}
1164
1165int
1166rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1167{
1168 int len;
1169 struct rtattr *subrta;
1170
paul7021c422003-07-15 12:52:22 +00001171 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001172
paul7021c422003-07-15 12:52:22 +00001173 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001174 return -1;
1175
paul7021c422003-07-15 12:52:22 +00001176 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001177 subrta->rta_type = type;
1178 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001179 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001180 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1181
1182 return 0;
1183}
1184
1185/* Utility function comes from iproute2.
1186 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1187int
1188addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1189{
1190 int len;
1191 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001192
1193 len = RTA_LENGTH (4);
1194
paul718e3742002-12-13 20:15:29 +00001195 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1196 return -1;
1197
paul7021c422003-07-15 12:52:22 +00001198 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001199 rta->rta_type = type;
1200 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001201 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001202 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1203
1204 return 0;
1205}
1206
1207static int
1208netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1209{
1210 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1211 return 0;
1212}
1213
1214/* sendmsg() to netlink socket then recvmsg(). */
1215int
1216netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1217{
1218 int status;
1219 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001220 struct iovec iov = { (void *) n, n->nlmsg_len };
1221 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001222 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001223 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001224
paul718e3742002-12-13 20:15:29 +00001225 memset (&snl, 0, sizeof snl);
1226 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001227
paul718e3742002-12-13 20:15:29 +00001228 n->nlmsg_seq = ++netlink_cmd.seq;
1229
1230 /* Request an acknowledgement by setting NLM_F_ACK */
1231 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001232
1233 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001234 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001235 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1236 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001237
1238 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001239 if (zserv_privs.change (ZPRIVS_RAISE))
1240 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001241 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001242 if (zserv_privs.change (ZPRIVS_LOWER))
1243 zlog (NULL, LOG_ERR, "Can't lower privileges");
1244
paul718e3742002-12-13 20:15:29 +00001245 if (status < 0)
1246 {
1247 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs6099b3b2004-11-20 02:06:59 +00001248 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001249 return -1;
1250 }
paul7021c422003-07-15 12:52:22 +00001251
paul718e3742002-12-13 20:15:29 +00001252 /*
1253 * Change socket flags for blocking I/O.
1254 * This ensures we wait for a reply in netlink_parse_info().
1255 */
paul7021c422003-07-15 12:52:22 +00001256 snb_ret = set_netlink_blocking (nl, &flags);
1257 if (snb_ret < 0)
1258 zlog (NULL, LOG_WARNING,
1259 "%s:%i Warning: Could not set netlink socket to blocking.",
1260 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001261
1262 /*
1263 * Get reply from netlink socket.
1264 * The reply should either be an acknowlegement or an error.
1265 */
1266 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001267
paul718e3742002-12-13 20:15:29 +00001268 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001269 if (snb_ret == 0)
1270 set_netlink_nonblocking (nl, &flags);
1271
paul718e3742002-12-13 20:15:29 +00001272 return status;
1273}
1274
1275/* Routing table change via netlink interface. */
1276int
1277netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001278 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001279{
1280 int ret;
1281 int bytelen;
1282 struct sockaddr_nl snl;
1283 int discard;
1284
paul7021c422003-07-15 12:52:22 +00001285 struct
paul718e3742002-12-13 20:15:29 +00001286 {
1287 struct nlmsghdr n;
1288 struct rtmsg r;
1289 char buf[1024];
1290 } req;
1291
1292 memset (&req, 0, sizeof req);
1293
1294 bytelen = (family == AF_INET ? 4 : 16);
1295
1296 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1297 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1298 req.n.nlmsg_type = cmd;
1299 req.r.rtm_family = family;
1300 req.r.rtm_table = table;
1301 req.r.rtm_dst_len = length;
1302
hasso81dfcaa2003-05-25 19:21:25 +00001303 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1304 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001305 discard = 1;
1306 else
1307 discard = 0;
1308
paul7021c422003-07-15 12:52:22 +00001309 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001310 {
1311 req.r.rtm_protocol = RTPROT_ZEBRA;
1312 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1313
paul7021c422003-07-15 12:52:22 +00001314 if (discard)
paul595db7f2003-05-25 21:35:06 +00001315 {
1316 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1317 req.r.rtm_type = RTN_BLACKHOLE;
1318 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1319 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001320 else
1321 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1322 }
paul595db7f2003-05-25 21:35:06 +00001323 else
paul7021c422003-07-15 12:52:22 +00001324 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001325 }
1326
1327 if (dest)
1328 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1329
paul7021c422003-07-15 12:52:22 +00001330 if (!discard)
paul718e3742002-12-13 20:15:29 +00001331 {
1332 if (gate)
paul7021c422003-07-15 12:52:22 +00001333 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001334 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001335 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001336 }
1337
1338 /* Destination netlink address. */
1339 memset (&snl, 0, sizeof snl);
1340 snl.nl_family = AF_NETLINK;
1341
1342 /* Talk to netlink socket. */
1343 ret = netlink_talk (&req.n, &netlink);
1344 if (ret < 0)
1345 return -1;
1346
1347 return 0;
1348}
1349
1350/* Routing table change via netlink interface. */
1351int
1352netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001353 int family)
paul718e3742002-12-13 20:15:29 +00001354{
1355 int bytelen;
1356 struct sockaddr_nl snl;
1357 struct nexthop *nexthop = NULL;
1358 int nexthop_num = 0;
1359 struct nlsock *nl;
1360 int discard;
1361
paul7021c422003-07-15 12:52:22 +00001362 struct
paul718e3742002-12-13 20:15:29 +00001363 {
1364 struct nlmsghdr n;
1365 struct rtmsg r;
1366 char buf[1024];
1367 } req;
1368
1369 memset (&req, 0, sizeof req);
1370
1371 bytelen = (family == AF_INET ? 4 : 16);
1372
1373 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1374 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1375 req.n.nlmsg_type = cmd;
1376 req.r.rtm_family = family;
1377 req.r.rtm_table = rib->table;
1378 req.r.rtm_dst_len = p->prefixlen;
1379
paul13766da2003-02-07 14:46:23 +00001380#ifdef RTM_F_EQUALIZE
1381 req.r.rtm_flags |= RTM_F_EQUALIZE;
1382#endif /* RTM_F_EQUALIZE */
1383
paul7021c422003-07-15 12:52:22 +00001384 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001385 discard = 1;
1386 else
1387 discard = 0;
1388
paul7021c422003-07-15 12:52:22 +00001389 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001390 {
1391 req.r.rtm_protocol = RTPROT_ZEBRA;
1392 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1393
paul7021c422003-07-15 12:52:22 +00001394 if (discard)
paul595db7f2003-05-25 21:35:06 +00001395 {
1396 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1397 req.r.rtm_type = RTN_BLACKHOLE;
1398 else if (rib->flags & ZEBRA_FLAG_REJECT)
1399 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001400 else
1401 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1402 }
paul595db7f2003-05-25 21:35:06 +00001403 else
paul7021c422003-07-15 12:52:22 +00001404 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001405 }
1406
1407 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1408
1409 /* Metric. */
1410 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1411
1412 if (discard)
1413 {
1414 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001415 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1416 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001417 goto skip;
1418 }
1419
1420 /* Multipath case. */
1421 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1422 {
1423 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001424 {
paul5ec90d22003-06-19 01:41:37 +00001425
paul7021c422003-07-15 12:52:22 +00001426 if ((cmd == RTM_NEWROUTE
1427 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1428 || (cmd == RTM_DELROUTE
1429 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1430 {
paul5ec90d22003-06-19 01:41:37 +00001431
paul7021c422003-07-15 12:52:22 +00001432 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1433 {
1434 if (IS_ZEBRA_DEBUG_KERNEL)
1435 {
ajsb6178002004-12-07 21:12:56 +00001436 zlog_debug
paul7021c422003-07-15 12:52:22 +00001437 ("netlink_route_multipath() (recursive, 1 hop): "
1438 "%s %s/%d via %s if %u, type %s",
1439 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1440 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1441 nexthop->rifindex,
1442 nexthop_types_desc[nexthop->rtype]);
1443 }
paul5ec90d22003-06-19 01:41:37 +00001444
paul7021c422003-07-15 12:52:22 +00001445 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1446 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1447 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1448 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001449#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001450 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1451 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1452 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1453 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1454 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001455#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001456 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1457 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1458 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1459 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1460 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1461 addattr32 (&req.n, sizeof req, RTA_OIF,
1462 nexthop->rifindex);
1463 }
1464 else
1465 {
1466 if (IS_ZEBRA_DEBUG_KERNEL)
1467 {
ajsb6178002004-12-07 21:12:56 +00001468 zlog_debug
paul7021c422003-07-15 12:52:22 +00001469 ("netlink_route_multipath(): (single hop)"
1470 "%s %s/%d via %s if %u, type %s",
1471 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1472 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1473 nexthop->ifindex,
1474 nexthop_types_desc[nexthop->type]);
1475 }
paul5ec90d22003-06-19 01:41:37 +00001476
paul7021c422003-07-15 12:52:22 +00001477 if (nexthop->type == NEXTHOP_TYPE_IPV4
1478 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1479 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1480 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001481#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001482 if (nexthop->type == NEXTHOP_TYPE_IPV6
1483 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1484 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1485 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1486 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001487#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001488 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1489 || nexthop->type == NEXTHOP_TYPE_IFNAME
1490 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1491 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1492 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1493 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1494 }
paul718e3742002-12-13 20:15:29 +00001495
paul7021c422003-07-15 12:52:22 +00001496 if (cmd == RTM_NEWROUTE)
1497 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001498
paul7021c422003-07-15 12:52:22 +00001499 nexthop_num++;
1500 break;
1501 }
1502 }
paul718e3742002-12-13 20:15:29 +00001503 }
1504 else
1505 {
1506 char buf[1024];
1507 struct rtattr *rta = (void *) buf;
1508 struct rtnexthop *rtnh;
1509
1510 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001511 rta->rta_len = RTA_LENGTH (0);
1512 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001513
1514 nexthop_num = 0;
1515 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001516 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1517 nexthop = nexthop->next)
1518 {
1519 if ((cmd == RTM_NEWROUTE
1520 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1521 || (cmd == RTM_DELROUTE
1522 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1523 {
1524 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001525
paul7021c422003-07-15 12:52:22 +00001526 rtnh->rtnh_len = sizeof (*rtnh);
1527 rtnh->rtnh_flags = 0;
1528 rtnh->rtnh_hops = 0;
1529 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001530
paul7021c422003-07-15 12:52:22 +00001531 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1532 {
1533 if (IS_ZEBRA_DEBUG_KERNEL)
1534 {
ajsb6178002004-12-07 21:12:56 +00001535 zlog_debug ("netlink_route_multipath() "
paul7021c422003-07-15 12:52:22 +00001536 "(recursive, multihop): "
1537 "%s %s/%d via %s if %u, type %s",
1538 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1539 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1540 nexthop->rifindex,
1541 nexthop_types_desc[nexthop->type]);
1542 }
1543 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1544 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1545 {
1546 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1547 &nexthop->rgate.ipv4, bytelen);
1548 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1549 }
paul718e3742002-12-13 20:15:29 +00001550#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001551 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1552 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1553 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1554 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1555 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001556#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001557 /* ifindex */
1558 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1559 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1560 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1561 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1562 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1563 rtnh->rtnh_ifindex = nexthop->rifindex;
1564 else
1565 rtnh->rtnh_ifindex = 0;
1566 }
1567 else
1568 {
1569 if (IS_ZEBRA_DEBUG_KERNEL)
1570 {
ajsb6178002004-12-07 21:12:56 +00001571 zlog_debug ("netlink_route_multipath() "
paul7021c422003-07-15 12:52:22 +00001572 "(multihop): "
1573 "%s %s/%d via %s if %u, type %s",
1574 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1575 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1576 nexthop->rifindex,
1577 nexthop_types_desc[nexthop->type]);
1578 }
1579 if (nexthop->type == NEXTHOP_TYPE_IPV4
1580 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1581 {
1582 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1583 &nexthop->gate.ipv4, bytelen);
1584 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1585 }
paul718e3742002-12-13 20:15:29 +00001586#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001587 if (nexthop->type == NEXTHOP_TYPE_IPV6
1588 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1589 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1590 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1591 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001592#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001593 /* ifindex */
1594 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1595 || nexthop->type == NEXTHOP_TYPE_IFNAME
1596 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1597 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1598 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1599 rtnh->rtnh_ifindex = nexthop->ifindex;
1600 else
1601 rtnh->rtnh_ifindex = 0;
1602 }
1603 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001604
paul7021c422003-07-15 12:52:22 +00001605 if (cmd == RTM_NEWROUTE)
1606 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1607 }
1608 }
paul718e3742002-12-13 20:15:29 +00001609
1610 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001611 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1612 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001613 }
1614
1615 /* If there is no useful nexthop then return. */
1616 if (nexthop_num == 0)
1617 {
1618 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001619 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001620 return 0;
1621 }
1622
paul7021c422003-07-15 12:52:22 +00001623skip:
paul718e3742002-12-13 20:15:29 +00001624
1625 /* Destination netlink address. */
1626 memset (&snl, 0, sizeof snl);
1627 snl.nl_family = AF_NETLINK;
1628
1629 if (family == AF_INET)
1630 nl = &netlink_cmd;
1631 else
1632 nl = &netlink;
1633
1634 /* Talk to netlink socket. */
1635 return netlink_talk (&req.n, nl);
1636}
1637
1638int
1639kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1640{
1641 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1642}
1643
1644int
1645kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1646{
1647 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1648}
1649
1650#ifdef HAVE_IPV6
1651int
1652kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1653{
1654 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1655}
1656
1657int
1658kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1659{
1660 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1661}
1662
1663/* Delete IPv6 route from the kernel. */
1664int
1665kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001666 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001667{
paul7021c422003-07-15 12:52:22 +00001668 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1669 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001670}
1671#endif /* HAVE_IPV6 */
1672
1673/* Interface address modification. */
1674int
1675netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001676 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001677{
1678 int bytelen;
1679 struct prefix *p;
1680
paul7021c422003-07-15 12:52:22 +00001681 struct
paul718e3742002-12-13 20:15:29 +00001682 {
1683 struct nlmsghdr n;
1684 struct ifaddrmsg ifa;
1685 char buf[1024];
1686 } req;
1687
1688 p = ifc->address;
1689 memset (&req, 0, sizeof req);
1690
1691 bytelen = (family == AF_INET ? 4 : 16);
1692
paul7021c422003-07-15 12:52:22 +00001693 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001694 req.n.nlmsg_flags = NLM_F_REQUEST;
1695 req.n.nlmsg_type = cmd;
1696 req.ifa.ifa_family = family;
1697
1698 req.ifa.ifa_index = ifp->ifindex;
1699 req.ifa.ifa_prefixlen = p->prefixlen;
1700
1701 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1702
1703 if (family == AF_INET && cmd == RTM_NEWADDR)
1704 {
1705 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001706 {
1707 p = ifc->destination;
1708 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1709 bytelen);
1710 }
paul718e3742002-12-13 20:15:29 +00001711 }
1712
1713 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1714 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001715
paul718e3742002-12-13 20:15:29 +00001716 if (ifc->label)
1717 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001718 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001719
1720 return netlink_talk (&req.n, &netlink_cmd);
1721}
1722
1723int
1724kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1725{
1726 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1727}
1728
1729int
1730kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1731{
1732 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1733}
1734
paul718e3742002-12-13 20:15:29 +00001735
1736extern struct thread_master *master;
1737
1738/* Kernel route reflection. */
1739int
1740kernel_read (struct thread *thread)
1741{
1742 int ret;
1743 int sock;
1744
1745 sock = THREAD_FD (thread);
1746 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001747 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001748
1749 return 0;
1750}
1751
1752/* Exported interface function. This function simply calls
1753 netlink_socket (). */
1754void
1755kernel_init ()
1756{
1757 unsigned long groups;
1758
paul7021c422003-07-15 12:52:22 +00001759 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001760#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001761 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001762#endif /* HAVE_IPV6 */
1763 netlink_socket (&netlink, groups);
1764 netlink_socket (&netlink_cmd, 0);
1765
1766 /* Register kernel socket. */
1767 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001768 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001769}