blob: 7a78602e7436671c4db7119b8b65c7b478f3a27e [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;
ajs4be019d2005-01-29 16:12:41 +000097 int save_errno;
paul718e3742002-12-13 20:15:29 +000098
99 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
100 if (sock < 0)
101 {
102 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000103 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000104 return -1;
105 }
106
107 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
108 if (ret < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000111 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000112 close (sock);
113 return -1;
114 }
paul7021c422003-07-15 12:52:22 +0000115
hassoc34b6b52004-08-31 13:41:49 +0000116 /* Set receive buffer size if it's set from command line */
117 if (nl_rcvbufsize)
118 {
119 u_int32_t oldsize, oldlen;
120 u_int32_t newsize, newlen;
121
122 oldlen = sizeof(oldsize);
123 newlen = sizeof(newsize);
124
125 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
126 if (ret < 0)
127 {
128 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000129 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000130 close (sock);
131 return -1;
132 }
133
134 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
135 sizeof(nl_rcvbufsize));
136 if (ret < 0)
137 {
138 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000139 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000140 close (sock);
141 return -1;
142 }
143
144 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
145 if (ret < 0)
146 {
147 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000148 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000149 close (sock);
150 return -1;
151 }
152
153 zlog (NULL, LOG_INFO,
154 "Setting netlink socket receive buffer size: %u -> %u",
155 oldsize, newsize);
156 }
157
paul718e3742002-12-13 20:15:29 +0000158 memset (&snl, 0, sizeof snl);
159 snl.nl_family = AF_NETLINK;
160 snl.nl_groups = groups;
161
162 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000163 if (zserv_privs.change (ZPRIVS_RAISE))
164 {
165 zlog (NULL, LOG_ERR, "Can't raise privileges");
166 return -1;
167 }
pauledd7c242003-06-04 13:59:38 +0000168
paul718e3742002-12-13 20:15:29 +0000169 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000170 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000171 if (zserv_privs.change (ZPRIVS_LOWER))
172 zlog (NULL, LOG_ERR, "Can't lower privileges");
173
paul718e3742002-12-13 20:15:29 +0000174 if (ret < 0)
175 {
paul7021c422003-07-15 12:52:22 +0000176 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000177 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000178 close (sock);
179 return -1;
180 }
paul7021c422003-07-15 12:52:22 +0000181
paul718e3742002-12-13 20:15:29 +0000182 /* multiple netlink sockets will have different nl_pid */
183 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000184 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000185 if (ret < 0 || namelen != sizeof snl)
186 {
187 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000188 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000189 close (sock);
190 return -1;
191 }
192
193 nl->snl = snl;
194 nl->sock = sock;
195 return ret;
196}
197
paul7021c422003-07-15 12:52:22 +0000198int
199set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000200{
201
202 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000203 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000204 {
paul7021c422003-07-15 12:52:22 +0000205 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000206 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000207 return -1;
208 }
209 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000210 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000211 {
paul7021c422003-07-15 12:52:22 +0000212 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000213 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000214 return -1;
215 }
216 return 0;
217}
218
paul7021c422003-07-15 12:52:22 +0000219int
220set_netlink_nonblocking (struct nlsock *nl, int *flags)
221{
paul5f37d862003-04-19 00:11:28 +0000222 /* Restore socket flags for nonblocking I/O */
223 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000224 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000225 {
paul7021c422003-07-15 12:52:22 +0000226 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000227 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000228 return -1;
229 }
230 return 0;
231}
232
paul718e3742002-12-13 20:15:29 +0000233/* Get type specified information from netlink. */
234static int
235netlink_request (int family, int type, struct nlsock *nl)
236{
237 int ret;
238 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000239 int save_errno;
paul718e3742002-12-13 20:15:29 +0000240
241 struct
242 {
243 struct nlmsghdr nlh;
244 struct rtgenmsg g;
245 } req;
246
247
248 /* Check netlink socket. */
249 if (nl->sock < 0)
250 {
251 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
252 return -1;
253 }
254
255 memset (&snl, 0, sizeof snl);
256 snl.nl_family = AF_NETLINK;
257
258 req.nlh.nlmsg_len = sizeof req;
259 req.nlh.nlmsg_type = type;
260 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
261 req.nlh.nlmsg_pid = 0;
262 req.nlh.nlmsg_seq = ++nl->seq;
263 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000264
265 /* linux appears to check capabilities on every message
266 * have to raise caps for every message sent
267 */
paul7021c422003-07-15 12:52:22 +0000268 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000269 {
270 zlog (NULL, LOG_ERR, "Can't raise privileges");
271 return -1;
272 }
paul7021c422003-07-15 12:52:22 +0000273
274 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
275 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000276 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000277
278 if (zserv_privs.change (ZPRIVS_LOWER))
279 zlog (NULL, LOG_ERR, "Can't lower privileges");
280
paul718e3742002-12-13 20:15:29 +0000281 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000282 {
283 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000284 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000285 return -1;
286 }
pauledd7c242003-06-04 13:59:38 +0000287
paul718e3742002-12-13 20:15:29 +0000288 return 0;
289}
290
291/* Receive message from netlink interface and pass those information
292 to the given function. */
293static int
294netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000295 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000296{
297 int status;
298 int ret = 0;
299 int error;
300
301 while (1)
302 {
303 char buf[4096];
304 struct iovec iov = { buf, sizeof buf };
305 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000306 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000307 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000308 int save_errno;
paul718e3742002-12-13 20:15:29 +0000309
paul7021c422003-07-15 12:52:22 +0000310 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000311 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000312
paul718e3742002-12-13 20:15:29 +0000313 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000314 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000315
316 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000317 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000318
319 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000320 {
ajs4be019d2005-01-29 16:12:41 +0000321 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000322 continue;
ajs4be019d2005-01-29 16:12:41 +0000323 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000324 break;
ajs4be019d2005-01-29 16:12:41 +0000325 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
326 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000327 continue;
328 }
paul718e3742002-12-13 20:15:29 +0000329
330 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000331 {
332 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
333 return -1;
334 }
paul718e3742002-12-13 20:15:29 +0000335
336 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000337 {
338 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
339 nl->name, msg.msg_namelen);
340 return -1;
341 }
paulb84d3a12003-11-17 10:31:01 +0000342
343 /* JF: Ignore messages that aren't from the kernel */
344 if ( snl.nl_pid != 0 )
345 {
346 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
347 continue;
348 }
paul718e3742002-12-13 20:15:29 +0000349
paul7021c422003-07-15 12:52:22 +0000350 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
351 h = NLMSG_NEXT (h, status))
352 {
353 /* Finish of reading. */
354 if (h->nlmsg_type == NLMSG_DONE)
355 return ret;
paul718e3742002-12-13 20:15:29 +0000356
paul7021c422003-07-15 12:52:22 +0000357 /* Error handling. */
358 if (h->nlmsg_type == NLMSG_ERROR)
359 {
360 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
361
paul718e3742002-12-13 20:15:29 +0000362 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000363 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000364 {
paul7021c422003-07-15 12:52:22 +0000365 if (IS_ZEBRA_DEBUG_KERNEL)
366 {
ajsb6178002004-12-07 21:12:56 +0000367 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000368 __FUNCTION__, nl->name,
369 lookup (nlmsg_str, err->msg.nlmsg_type),
370 err->msg.nlmsg_type, err->msg.nlmsg_seq,
371 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000372 }
paul7021c422003-07-15 12:52:22 +0000373
374 /* return if not a multipart message, otherwise continue */
375 if (!(h->nlmsg_flags & NLM_F_MULTI))
376 {
377 return 0;
paul718e3742002-12-13 20:15:29 +0000378 }
paul7021c422003-07-15 12:52:22 +0000379 continue;
paul718e3742002-12-13 20:15:29 +0000380 }
paul7021c422003-07-15 12:52:22 +0000381
paul718e3742002-12-13 20:15:29 +0000382 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000383 {
384 zlog (NULL, LOG_ERR, "%s error: message truncated",
385 nl->name);
386 return -1;
387 }
pauld753e9e2003-01-22 19:45:50 +0000388
paul7021c422003-07-15 12:52:22 +0000389 /* Deal with Error Noise - MAG */
390 {
391 int loglvl = LOG_ERR;
392 int errnum = err->error;
393 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000394
paul7021c422003-07-15 12:52:22 +0000395 if (nl == &netlink_cmd
396 && (-errnum == ENODEV || -errnum == ESRCH)
397 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
398 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000399
paul7021c422003-07-15 12:52:22 +0000400 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
401 "seq=%u, pid=%d",
ajs6099b3b2004-11-20 02:06:59 +0000402 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000403 lookup (nlmsg_str, msg_type),
404 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
405 }
406 /*
407 ret = -1;
408 continue;
409 */
410 return -1;
411 }
paul718e3742002-12-13 20:15:29 +0000412
paul7021c422003-07-15 12:52:22 +0000413 /* OK we got netlink message. */
414 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000415 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000416 nl->name,
417 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
418 h->nlmsg_seq, h->nlmsg_pid);
419
420 /* skip unsolicited messages originating from command socket */
421 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
422 {
423 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000424 zlog_debug ("netlink_parse_info: %s packet comes from %s",
paul7021c422003-07-15 12:52:22 +0000425 nl->name, netlink_cmd.name);
426 continue;
427 }
428
429 error = (*filter) (&snl, h);
430 if (error < 0)
431 {
432 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
433 ret = error;
434 }
435 }
paul718e3742002-12-13 20:15:29 +0000436
437 /* After error care. */
438 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000439 {
440 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
441 continue;
442 }
paul718e3742002-12-13 20:15:29 +0000443 if (status)
paul7021c422003-07-15 12:52:22 +0000444 {
445 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
446 status);
447 return -1;
448 }
paul718e3742002-12-13 20:15:29 +0000449 }
450 return ret;
451}
452
453/* Utility function for parse rtattr. */
454static void
paul7021c422003-07-15 12:52:22 +0000455netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
456 int len)
paul718e3742002-12-13 20:15:29 +0000457{
paul7021c422003-07-15 12:52:22 +0000458 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000459 {
460 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000461 tb[rta->rta_type] = rta;
462 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000463 }
464}
465
466/* Called from interface_lookup_netlink(). This function is only used
467 during bootstrap. */
468int
469netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
470{
471 int len;
472 struct ifinfomsg *ifi;
473 struct rtattr *tb[IFLA_MAX + 1];
474 struct interface *ifp;
475 char *name;
476 int i;
477
478 ifi = NLMSG_DATA (h);
479
480 if (h->nlmsg_type != RTM_NEWLINK)
481 return 0;
482
483 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
484 if (len < 0)
485 return -1;
486
487 /* Looking up interface name. */
488 memset (tb, 0, sizeof tb);
489 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000490
paul1e193152005-02-14 23:53:05 +0000491#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000492 /* check for wireless messages to ignore */
493 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
494 {
495 if (IS_ZEBRA_DEBUG_KERNEL)
496 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
497 return 0;
498 }
paul1e193152005-02-14 23:53:05 +0000499#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000500
paul718e3742002-12-13 20:15:29 +0000501 if (tb[IFLA_IFNAME] == NULL)
502 return -1;
paul7021c422003-07-15 12:52:22 +0000503 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000504
505 /* Add interface. */
506 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000507
paul718e3742002-12-13 20:15:29 +0000508 ifp->ifindex = ifi->ifi_index;
509 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000510 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000511 ifp->metric = 1;
512
513 /* Hardware type and address. */
514 ifp->hw_type = ifi->ifi_type;
515
516 if (tb[IFLA_ADDRESS])
517 {
518 int hw_addr_len;
519
paul7021c422003-07-15 12:52:22 +0000520 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000521
522 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000523 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000524 else
paul7021c422003-07-15 12:52:22 +0000525 {
526 ifp->hw_addr_len = hw_addr_len;
527 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000528
paul7021c422003-07-15 12:52:22 +0000529 for (i = 0; i < hw_addr_len; i++)
530 if (ifp->hw_addr[i] != 0)
531 break;
paul718e3742002-12-13 20:15:29 +0000532
paul7021c422003-07-15 12:52:22 +0000533 if (i == hw_addr_len)
534 ifp->hw_addr_len = 0;
535 else
536 ifp->hw_addr_len = hw_addr_len;
537 }
paul718e3742002-12-13 20:15:29 +0000538 }
539
540 if_add_update (ifp);
541
542 return 0;
543}
544
545/* Lookup interface IPv4/IPv6 address. */
546int
547netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
548{
549 int len;
550 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000551 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000552 struct interface *ifp;
553 void *addr = NULL;
554 void *broad = NULL;
555 u_char flags = 0;
556 char *label = NULL;
557
558 ifa = NLMSG_DATA (h);
559
paul7021c422003-07-15 12:52:22 +0000560 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000561#ifdef HAVE_IPV6
562 && ifa->ifa_family != AF_INET6
563#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000564 )
paul718e3742002-12-13 20:15:29 +0000565 return 0;
566
567 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
568 return 0;
569
paul7021c422003-07-15 12:52:22 +0000570 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000571 if (len < 0)
572 return -1;
573
574 memset (tb, 0, sizeof tb);
575 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
576
577 ifp = if_lookup_by_index (ifa->ifa_index);
578 if (ifp == NULL)
579 {
580 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000581 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000582 return -1;
583 }
584
paul7021c422003-07-15 12:52:22 +0000585 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000586 {
paul00df0c12002-12-13 21:07:36 +0000587 char buf[BUFSIZ];
ajsb6178002004-12-07 21:12:56 +0000588 zlog_debug ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000589 lookup (nlmsg_str, h->nlmsg_type),
590 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000591 if (tb[IFA_LOCAL])
ajsb6178002004-12-07 21:12:56 +0000592 zlog_debug (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000593 RTA_DATA (tb[IFA_LOCAL]),
594 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000595 if (tb[IFA_ADDRESS])
ajsb6178002004-12-07 21:12:56 +0000596 zlog_debug (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000597 RTA_DATA (tb
598 [IFA_ADDRESS]),
599 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000600 if (tb[IFA_BROADCAST])
ajsb6178002004-12-07 21:12:56 +0000601 zlog_debug (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
paul7021c422003-07-15 12:52:22 +0000602 RTA_DATA (tb
603 [IFA_BROADCAST]),
604 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000605 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000606 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000607 }
paul31a476c2003-09-29 19:54:53 +0000608
609 if (tb[IFA_ADDRESS] == NULL)
610 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
611
612 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000613 {
paul31a476c2003-09-29 19:54:53 +0000614 if (tb[IFA_LOCAL])
615 {
616 addr = RTA_DATA (tb[IFA_LOCAL]);
hasso3fb9cd62004-10-19 19:44:43 +0000617 if (tb[IFA_ADDRESS] &&
618 memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4))
619 /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */
paul31a476c2003-09-29 19:54:53 +0000620 broad = RTA_DATA (tb[IFA_ADDRESS]);
621 else
622 broad = NULL;
623 }
624 else
625 {
626 if (tb[IFA_ADDRESS])
627 addr = RTA_DATA (tb[IFA_ADDRESS]);
628 else
629 addr = NULL;
630 }
paul7021c422003-07-15 12:52:22 +0000631 }
paul31a476c2003-09-29 19:54:53 +0000632 else
paul7021c422003-07-15 12:52:22 +0000633 {
paul31a476c2003-09-29 19:54:53 +0000634 if (tb[IFA_ADDRESS])
635 addr = RTA_DATA (tb[IFA_ADDRESS]);
636 else
637 addr = NULL;
638
639 if (tb[IFA_BROADCAST])
640 broad = RTA_DATA(tb[IFA_BROADCAST]);
641 else
642 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000643 }
paul00df0c12002-12-13 21:07:36 +0000644
paul718e3742002-12-13 20:15:29 +0000645 /* Flags. */
646 if (ifa->ifa_flags & IFA_F_SECONDARY)
647 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
648
649 /* Label */
650 if (tb[IFA_LABEL])
651 label = (char *) RTA_DATA (tb[IFA_LABEL]);
652
653 if (ifp && label && strcmp (ifp->name, label) == 0)
654 label = NULL;
655
656 /* Register interface address to the interface. */
657 if (ifa->ifa_family == AF_INET)
658 {
paul7021c422003-07-15 12:52:22 +0000659 if (h->nlmsg_type == RTM_NEWADDR)
660 connected_add_ipv4 (ifp, flags,
661 (struct in_addr *) addr, ifa->ifa_prefixlen,
662 (struct in_addr *) broad, label);
663 else
664 connected_delete_ipv4 (ifp, flags,
665 (struct in_addr *) addr, ifa->ifa_prefixlen,
666 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000667 }
668#ifdef HAVE_IPV6
669 if (ifa->ifa_family == AF_INET6)
670 {
671 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000672 connected_add_ipv6 (ifp,
673 (struct in6_addr *) addr, ifa->ifa_prefixlen,
674 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000675 else
paul7021c422003-07-15 12:52:22 +0000676 connected_delete_ipv6 (ifp,
677 (struct in6_addr *) addr, ifa->ifa_prefixlen,
678 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000679 }
paul7021c422003-07-15 12:52:22 +0000680#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000681
682 return 0;
683}
684
685/* Looking up routing table by netlink interface. */
686int
687netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
688{
689 int len;
690 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000691 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000692 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000693
694 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000695
696 int index;
697 int table;
hasso34195bf2004-04-06 12:07:06 +0000698 int metric;
699
paul718e3742002-12-13 20:15:29 +0000700 void *dest;
701 void *gate;
702
703 rtm = NLMSG_DATA (h);
704
705 if (h->nlmsg_type != RTM_NEWROUTE)
706 return 0;
707 if (rtm->rtm_type != RTN_UNICAST)
708 return 0;
709
710 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000711#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000712 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000713 return 0;
714#endif
715
paul7021c422003-07-15 12:52:22 +0000716 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000717 if (len < 0)
718 return -1;
719
720 memset (tb, 0, sizeof tb);
721 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
722
723 if (rtm->rtm_flags & RTM_F_CLONED)
724 return 0;
725 if (rtm->rtm_protocol == RTPROT_REDIRECT)
726 return 0;
727 if (rtm->rtm_protocol == RTPROT_KERNEL)
728 return 0;
729
730 if (rtm->rtm_src_len != 0)
731 return 0;
732
733 /* Route which inserted by Zebra. */
734 if (rtm->rtm_protocol == RTPROT_ZEBRA)
735 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000736
paul718e3742002-12-13 20:15:29 +0000737 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000738 metric = 0;
paul718e3742002-12-13 20:15:29 +0000739 dest = NULL;
740 gate = NULL;
741
742 if (tb[RTA_OIF])
743 index = *(int *) RTA_DATA (tb[RTA_OIF]);
744
745 if (tb[RTA_DST])
746 dest = RTA_DATA (tb[RTA_DST]);
747 else
748 dest = anyaddr;
749
750 /* Multipath treatment is needed. */
751 if (tb[RTA_GATEWAY])
752 gate = RTA_DATA (tb[RTA_GATEWAY]);
753
hasso34195bf2004-04-06 12:07:06 +0000754 if (tb[RTA_PRIORITY])
755 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
756
paul718e3742002-12-13 20:15:29 +0000757 if (rtm->rtm_family == AF_INET)
758 {
759 struct prefix_ipv4 p;
760 p.family = AF_INET;
761 memcpy (&p.prefix, dest, 4);
762 p.prefixlen = rtm->rtm_dst_len;
763
hasso34195bf2004-04-06 12:07:06 +0000764 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000765 }
766#ifdef HAVE_IPV6
767 if (rtm->rtm_family == AF_INET6)
768 {
769 struct prefix_ipv6 p;
770 p.family = AF_INET6;
771 memcpy (&p.prefix, dest, 16);
772 p.prefixlen = rtm->rtm_dst_len;
773
774 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
775 }
776#endif /* HAVE_IPV6 */
777
778 return 0;
779}
780
paul7021c422003-07-15 12:52:22 +0000781struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000782 {RTPROT_REDIRECT, "redirect"},
783 {RTPROT_KERNEL, "kernel"},
784 {RTPROT_BOOT, "boot"},
785 {RTPROT_STATIC, "static"},
786 {RTPROT_GATED, "GateD"},
787 {RTPROT_RA, "router advertisement"},
788 {RTPROT_MRT, "MRT"},
789 {RTPROT_ZEBRA, "Zebra"},
790#ifdef RTPROT_BIRD
791 {RTPROT_BIRD, "BIRD"},
792#endif /* RTPROT_BIRD */
793 {0, NULL}
794};
795
796/* Routing information change from the kernel. */
797int
798netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
799{
800 int len;
801 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000802 struct rtattr *tb[RTA_MAX + 1];
803
804 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000805
806 int index;
807 int table;
808 void *dest;
809 void *gate;
810
811 rtm = NLMSG_DATA (h);
812
paul7021c422003-07-15 12:52:22 +0000813 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000814 {
815 /* If this is not route add/delete message print warning. */
816 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
817 return 0;
818 }
819
820 /* Connected route. */
821 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000822 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000823 h->nlmsg_type ==
824 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
825 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
826 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
827 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000828
829 if (rtm->rtm_type != RTN_UNICAST)
830 {
831 return 0;
832 }
833
834 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000835 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000836 {
837 return 0;
838 }
839
paul7021c422003-07-15 12:52:22 +0000840 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000841 if (len < 0)
842 return -1;
843
844 memset (tb, 0, sizeof tb);
845 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
846
847 if (rtm->rtm_flags & RTM_F_CLONED)
848 return 0;
849 if (rtm->rtm_protocol == RTPROT_REDIRECT)
850 return 0;
851 if (rtm->rtm_protocol == RTPROT_KERNEL)
852 return 0;
853
854 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
855 return 0;
856
857 if (rtm->rtm_src_len != 0)
858 {
859 zlog_warn ("netlink_route_change(): no src len");
860 return 0;
861 }
paul7021c422003-07-15 12:52:22 +0000862
paul718e3742002-12-13 20:15:29 +0000863 index = 0;
864 dest = NULL;
865 gate = NULL;
866
867 if (tb[RTA_OIF])
868 index = *(int *) RTA_DATA (tb[RTA_OIF]);
869
870 if (tb[RTA_DST])
871 dest = RTA_DATA (tb[RTA_DST]);
872 else
873 dest = anyaddr;
874
875 if (tb[RTA_GATEWAY])
876 gate = RTA_DATA (tb[RTA_GATEWAY]);
877
878 if (rtm->rtm_family == AF_INET)
879 {
880 struct prefix_ipv4 p;
881 p.family = AF_INET;
882 memcpy (&p.prefix, dest, 4);
883 p.prefixlen = rtm->rtm_dst_len;
884
885 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000886 {
887 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000888 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000889 inet_ntoa (p.prefix), p.prefixlen);
890 else
ajsb6178002004-12-07 21:12:56 +0000891 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000892 inet_ntoa (p.prefix), p.prefixlen);
893 }
paul718e3742002-12-13 20:15:29 +0000894
895 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000896 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000897 else
paul7021c422003-07-15 12:52:22 +0000898 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000899 }
900
901#ifdef HAVE_IPV6
902 if (rtm->rtm_family == AF_INET6)
903 {
904 struct prefix_ipv6 p;
905 char buf[BUFSIZ];
906
907 p.family = AF_INET6;
908 memcpy (&p.prefix, dest, 16);
909 p.prefixlen = rtm->rtm_dst_len;
910
911 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000912 {
913 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000914 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000915 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
916 p.prefixlen);
917 else
ajsb6178002004-12-07 21:12:56 +0000918 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000919 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
920 p.prefixlen);
921 }
paul718e3742002-12-13 20:15:29 +0000922
923 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000924 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000925 else
paul7021c422003-07-15 12:52:22 +0000926 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000927 }
928#endif /* HAVE_IPV6 */
929
930 return 0;
931}
932
933int
934netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
935{
936 int len;
937 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000938 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000939 struct interface *ifp;
940 char *name;
941
942 ifi = NLMSG_DATA (h);
943
paul7021c422003-07-15 12:52:22 +0000944 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000945 {
946 /* If this is not link add/delete message so print warning. */
947 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000948 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000949 return 0;
950 }
951
952 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
953 if (len < 0)
954 return -1;
955
956 /* Looking up interface name. */
957 memset (tb, 0, sizeof tb);
958 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000959
paul1e193152005-02-14 23:53:05 +0000960#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000961 /* check for wireless messages to ignore */
962 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
963 {
964 if (IS_ZEBRA_DEBUG_KERNEL)
965 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
966 return 0;
967 }
paul1e193152005-02-14 23:53:05 +0000968#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000969
paul718e3742002-12-13 20:15:29 +0000970 if (tb[IFLA_IFNAME] == NULL)
971 return -1;
paul7021c422003-07-15 12:52:22 +0000972 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000973
974 /* Add interface. */
975 if (h->nlmsg_type == RTM_NEWLINK)
976 {
977 ifp = if_lookup_by_name (name);
978
paul7021c422003-07-15 12:52:22 +0000979 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
980 {
981 if (ifp == NULL)
982 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000983
paul7021c422003-07-15 12:52:22 +0000984 ifp->ifindex = ifi->ifi_index;
985 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000986 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000987 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000988
paul7021c422003-07-15 12:52:22 +0000989 /* If new link is added. */
990 if_add_update (ifp);
991 }
paul718e3742002-12-13 20:15:29 +0000992 else
paul7021c422003-07-15 12:52:22 +0000993 {
994 /* Interface status change. */
995 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000996 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000997 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000998
paul7021c422003-07-15 12:52:22 +0000999 if (if_is_operative (ifp))
1000 {
1001 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1002 if (!if_is_operative (ifp))
1003 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001004 else
1005 /* Must notify client daemons of new interface status. */
1006 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001007 }
1008 else
1009 {
1010 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1011 if (if_is_operative (ifp))
1012 if_up (ifp);
1013 }
1014 }
paul718e3742002-12-13 20:15:29 +00001015 }
1016 else
1017 {
1018 /* RTM_DELLINK. */
1019 ifp = if_lookup_by_name (name);
1020
1021 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001022 {
1023 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001024 name);
paul7021c422003-07-15 12:52:22 +00001025 return 0;
1026 }
1027
paul718e3742002-12-13 20:15:29 +00001028 if_delete_update (ifp);
1029 }
1030
1031 return 0;
1032}
1033
1034int
1035netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1036{
1037 switch (h->nlmsg_type)
1038 {
1039 case RTM_NEWROUTE:
1040 return netlink_route_change (snl, h);
1041 break;
1042 case RTM_DELROUTE:
1043 return netlink_route_change (snl, h);
1044 break;
1045 case RTM_NEWLINK:
1046 return netlink_link_change (snl, h);
1047 break;
1048 case RTM_DELLINK:
1049 return netlink_link_change (snl, h);
1050 break;
1051 case RTM_NEWADDR:
1052 return netlink_interface_addr (snl, h);
1053 break;
1054 case RTM_DELADDR:
1055 return netlink_interface_addr (snl, h);
1056 break;
1057 default:
1058 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1059 break;
1060 }
1061 return 0;
1062}
1063
1064/* Interface lookup by netlink socket. */
1065int
1066interface_lookup_netlink ()
1067{
1068 int ret;
paul5f37d862003-04-19 00:11:28 +00001069 int flags;
1070 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001071
paul5f37d862003-04-19 00:11:28 +00001072 /*
1073 * Change netlink socket flags to blocking to ensure we get
1074 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001075 */
1076 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1077 if (snb_ret < 0)
1078 zlog (NULL, LOG_WARNING,
1079 "%s:%i Warning: Could not set netlink socket to blocking.",
1080 __FUNCTION__, __LINE__);
1081
paul718e3742002-12-13 20:15:29 +00001082 /* Get interface information. */
1083 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1084 if (ret < 0)
1085 return ret;
1086 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1087 if (ret < 0)
1088 return ret;
1089
1090 /* Get IPv4 address of the interfaces. */
1091 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1092 if (ret < 0)
1093 return ret;
1094 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1095 if (ret < 0)
1096 return ret;
1097
1098#ifdef HAVE_IPV6
1099 /* Get IPv6 address of the interfaces. */
1100 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1101 if (ret < 0)
1102 return ret;
1103 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1104 if (ret < 0)
1105 return ret;
1106#endif /* HAVE_IPV6 */
1107
paul7021c422003-07-15 12:52:22 +00001108 /* restore socket flags */
1109 if (snb_ret == 0)
1110 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001111 return 0;
1112}
1113
1114/* Routing table read function using netlink interface. Only called
1115 bootstrap time. */
1116int
1117netlink_route_read ()
1118{
1119 int ret;
paul5f37d862003-04-19 00:11:28 +00001120 int flags;
1121 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001122
paul5f37d862003-04-19 00:11:28 +00001123 /*
1124 * Change netlink socket flags to blocking to ensure we get
1125 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001126 */
1127 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1128 if (snb_ret < 0)
1129 zlog (NULL, LOG_WARNING,
1130 "%s:%i Warning: Could not set netlink socket to blocking.",
1131 __FUNCTION__, __LINE__);
1132
paul718e3742002-12-13 20:15:29 +00001133 /* Get IPv4 routing table. */
1134 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1135 if (ret < 0)
1136 return ret;
1137 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1138 if (ret < 0)
1139 return ret;
1140
1141#ifdef HAVE_IPV6
1142 /* Get IPv6 routing table. */
1143 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1144 if (ret < 0)
1145 return ret;
1146 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1147 if (ret < 0)
1148 return ret;
1149#endif /* HAVE_IPV6 */
1150
paul5f37d862003-04-19 00:11:28 +00001151 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001152 if (snb_ret == 0)
1153 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001154 return 0;
1155}
1156
1157/* Utility function comes from iproute2.
1158 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1159int
1160addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1161{
1162 int len;
1163 struct rtattr *rta;
1164
paul7021c422003-07-15 12:52:22 +00001165 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001166
paul7021c422003-07-15 12:52:22 +00001167 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001168 return -1;
1169
paul7021c422003-07-15 12:52:22 +00001170 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001171 rta->rta_type = type;
1172 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001173 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001174 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1175
1176 return 0;
1177}
1178
1179int
1180rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1181{
1182 int len;
1183 struct rtattr *subrta;
1184
paul7021c422003-07-15 12:52:22 +00001185 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001186
paul7021c422003-07-15 12:52:22 +00001187 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001188 return -1;
1189
paul7021c422003-07-15 12:52:22 +00001190 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001191 subrta->rta_type = type;
1192 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001193 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001194 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1195
1196 return 0;
1197}
1198
1199/* Utility function comes from iproute2.
1200 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1201int
1202addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1203{
1204 int len;
1205 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001206
1207 len = RTA_LENGTH (4);
1208
paul718e3742002-12-13 20:15:29 +00001209 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1210 return -1;
1211
paul7021c422003-07-15 12:52:22 +00001212 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001213 rta->rta_type = type;
1214 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001215 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001216 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1217
1218 return 0;
1219}
1220
1221static int
1222netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1223{
hassoe8274dc2005-02-20 19:09:23 +00001224 if (IS_ZEBRA_DEBUG_KERNEL)
1225 zlog_debug ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001226 return 0;
1227}
1228
1229/* sendmsg() to netlink socket then recvmsg(). */
1230int
1231netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1232{
1233 int status;
1234 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001235 struct iovec iov = { (void *) n, n->nlmsg_len };
1236 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001237 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001238 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001239 int save_errno;
paul7021c422003-07-15 12:52:22 +00001240
paul718e3742002-12-13 20:15:29 +00001241 memset (&snl, 0, sizeof snl);
1242 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001243
paul718e3742002-12-13 20:15:29 +00001244 n->nlmsg_seq = ++netlink_cmd.seq;
1245
1246 /* Request an acknowledgement by setting NLM_F_ACK */
1247 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001248
1249 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001250 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001251 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1252 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001253
1254 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001255 if (zserv_privs.change (ZPRIVS_RAISE))
1256 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001257 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001258 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001259 if (zserv_privs.change (ZPRIVS_LOWER))
1260 zlog (NULL, LOG_ERR, "Can't lower privileges");
1261
paul718e3742002-12-13 20:15:29 +00001262 if (status < 0)
1263 {
1264 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001265 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001266 return -1;
1267 }
paul7021c422003-07-15 12:52:22 +00001268
paul718e3742002-12-13 20:15:29 +00001269 /*
1270 * Change socket flags for blocking I/O.
1271 * This ensures we wait for a reply in netlink_parse_info().
1272 */
paul7021c422003-07-15 12:52:22 +00001273 snb_ret = set_netlink_blocking (nl, &flags);
1274 if (snb_ret < 0)
1275 zlog (NULL, LOG_WARNING,
1276 "%s:%i Warning: Could not set netlink socket to blocking.",
1277 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001278
1279 /*
1280 * Get reply from netlink socket.
1281 * The reply should either be an acknowlegement or an error.
1282 */
1283 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001284
paul718e3742002-12-13 20:15:29 +00001285 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001286 if (snb_ret == 0)
1287 set_netlink_nonblocking (nl, &flags);
1288
paul718e3742002-12-13 20:15:29 +00001289 return status;
1290}
1291
1292/* Routing table change via netlink interface. */
1293int
1294netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001295 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001296{
1297 int ret;
1298 int bytelen;
1299 struct sockaddr_nl snl;
1300 int discard;
1301
paul7021c422003-07-15 12:52:22 +00001302 struct
paul718e3742002-12-13 20:15:29 +00001303 {
1304 struct nlmsghdr n;
1305 struct rtmsg r;
1306 char buf[1024];
1307 } req;
1308
1309 memset (&req, 0, sizeof req);
1310
1311 bytelen = (family == AF_INET ? 4 : 16);
1312
1313 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1314 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1315 req.n.nlmsg_type = cmd;
1316 req.r.rtm_family = family;
1317 req.r.rtm_table = table;
1318 req.r.rtm_dst_len = length;
1319
hasso81dfcaa2003-05-25 19:21:25 +00001320 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1321 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001322 discard = 1;
1323 else
1324 discard = 0;
1325
paul7021c422003-07-15 12:52:22 +00001326 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001327 {
1328 req.r.rtm_protocol = RTPROT_ZEBRA;
1329 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1330
paul7021c422003-07-15 12:52:22 +00001331 if (discard)
paul595db7f2003-05-25 21:35:06 +00001332 {
1333 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1334 req.r.rtm_type = RTN_BLACKHOLE;
1335 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1336 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001337 else
1338 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1339 }
paul595db7f2003-05-25 21:35:06 +00001340 else
paul7021c422003-07-15 12:52:22 +00001341 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001342 }
1343
1344 if (dest)
1345 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1346
paul7021c422003-07-15 12:52:22 +00001347 if (!discard)
paul718e3742002-12-13 20:15:29 +00001348 {
1349 if (gate)
paul7021c422003-07-15 12:52:22 +00001350 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001351 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001352 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001353 }
1354
1355 /* Destination netlink address. */
1356 memset (&snl, 0, sizeof snl);
1357 snl.nl_family = AF_NETLINK;
1358
1359 /* Talk to netlink socket. */
1360 ret = netlink_talk (&req.n, &netlink);
1361 if (ret < 0)
1362 return -1;
1363
1364 return 0;
1365}
1366
1367/* Routing table change via netlink interface. */
1368int
1369netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001370 int family)
paul718e3742002-12-13 20:15:29 +00001371{
1372 int bytelen;
1373 struct sockaddr_nl snl;
1374 struct nexthop *nexthop = NULL;
1375 int nexthop_num = 0;
1376 struct nlsock *nl;
1377 int discard;
1378
paul7021c422003-07-15 12:52:22 +00001379 struct
paul718e3742002-12-13 20:15:29 +00001380 {
1381 struct nlmsghdr n;
1382 struct rtmsg r;
1383 char buf[1024];
1384 } req;
1385
1386 memset (&req, 0, sizeof req);
1387
1388 bytelen = (family == AF_INET ? 4 : 16);
1389
1390 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1391 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1392 req.n.nlmsg_type = cmd;
1393 req.r.rtm_family = family;
1394 req.r.rtm_table = rib->table;
1395 req.r.rtm_dst_len = p->prefixlen;
1396
paul7021c422003-07-15 12:52:22 +00001397 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001398 discard = 1;
1399 else
1400 discard = 0;
1401
paul7021c422003-07-15 12:52:22 +00001402 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001403 {
1404 req.r.rtm_protocol = RTPROT_ZEBRA;
1405 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1406
paul7021c422003-07-15 12:52:22 +00001407 if (discard)
paul595db7f2003-05-25 21:35:06 +00001408 {
1409 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1410 req.r.rtm_type = RTN_BLACKHOLE;
1411 else if (rib->flags & ZEBRA_FLAG_REJECT)
1412 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001413 else
1414 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1415 }
paul595db7f2003-05-25 21:35:06 +00001416 else
paul7021c422003-07-15 12:52:22 +00001417 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001418 }
1419
1420 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1421
1422 /* Metric. */
1423 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1424
1425 if (discard)
1426 {
1427 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001428 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1429 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001430 goto skip;
1431 }
1432
1433 /* Multipath case. */
1434 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1435 {
1436 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001437 {
paul5ec90d22003-06-19 01:41:37 +00001438
paul7021c422003-07-15 12:52:22 +00001439 if ((cmd == RTM_NEWROUTE
1440 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1441 || (cmd == RTM_DELROUTE
1442 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1443 {
paul5ec90d22003-06-19 01:41:37 +00001444
paul7021c422003-07-15 12:52:22 +00001445 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1446 {
1447 if (IS_ZEBRA_DEBUG_KERNEL)
1448 {
ajsb6178002004-12-07 21:12:56 +00001449 zlog_debug
paul7021c422003-07-15 12:52:22 +00001450 ("netlink_route_multipath() (recursive, 1 hop): "
1451 "%s %s/%d via %s if %u, type %s",
1452 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1453 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1454 nexthop->rifindex,
1455 nexthop_types_desc[nexthop->rtype]);
1456 }
paul5ec90d22003-06-19 01:41:37 +00001457
paul7021c422003-07-15 12:52:22 +00001458 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1459 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1460 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1461 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001462#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001463 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1464 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1465 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1466 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1467 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001468#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001469 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1470 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1471 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1472 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1473 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1474 addattr32 (&req.n, sizeof req, RTA_OIF,
1475 nexthop->rifindex);
1476 }
1477 else
1478 {
1479 if (IS_ZEBRA_DEBUG_KERNEL)
1480 {
ajsb6178002004-12-07 21:12:56 +00001481 zlog_debug
paul7021c422003-07-15 12:52:22 +00001482 ("netlink_route_multipath(): (single hop)"
1483 "%s %s/%d via %s if %u, type %s",
1484 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1485 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1486 nexthop->ifindex,
1487 nexthop_types_desc[nexthop->type]);
1488 }
paul5ec90d22003-06-19 01:41:37 +00001489
paul7021c422003-07-15 12:52:22 +00001490 if (nexthop->type == NEXTHOP_TYPE_IPV4
1491 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1492 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1493 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001494#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001495 if (nexthop->type == NEXTHOP_TYPE_IPV6
1496 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1497 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1498 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1499 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001500#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001501 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1502 || nexthop->type == NEXTHOP_TYPE_IFNAME
1503 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1504 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1505 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1506 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1507 }
paul718e3742002-12-13 20:15:29 +00001508
paul7021c422003-07-15 12:52:22 +00001509 if (cmd == RTM_NEWROUTE)
1510 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001511
paul7021c422003-07-15 12:52:22 +00001512 nexthop_num++;
1513 break;
1514 }
1515 }
paul718e3742002-12-13 20:15:29 +00001516 }
1517 else
1518 {
1519 char buf[1024];
1520 struct rtattr *rta = (void *) buf;
1521 struct rtnexthop *rtnh;
1522
1523 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001524 rta->rta_len = RTA_LENGTH (0);
1525 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001526
1527 nexthop_num = 0;
1528 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001529 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1530 nexthop = nexthop->next)
1531 {
1532 if ((cmd == RTM_NEWROUTE
1533 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1534 || (cmd == RTM_DELROUTE
1535 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1536 {
1537 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001538
paul7021c422003-07-15 12:52:22 +00001539 rtnh->rtnh_len = sizeof (*rtnh);
1540 rtnh->rtnh_flags = 0;
1541 rtnh->rtnh_hops = 0;
1542 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001543
paul7021c422003-07-15 12:52:22 +00001544 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1545 {
1546 if (IS_ZEBRA_DEBUG_KERNEL)
1547 {
ajsb6178002004-12-07 21:12:56 +00001548 zlog_debug ("netlink_route_multipath() "
paul7021c422003-07-15 12:52:22 +00001549 "(recursive, multihop): "
1550 "%s %s/%d via %s if %u, type %s",
1551 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1552 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1553 nexthop->rifindex,
1554 nexthop_types_desc[nexthop->type]);
1555 }
1556 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1557 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1558 {
1559 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1560 &nexthop->rgate.ipv4, bytelen);
1561 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1562 }
paul718e3742002-12-13 20:15:29 +00001563#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001564 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1565 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1566 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1567 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1568 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001569#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001570 /* ifindex */
1571 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1572 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1573 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1574 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1575 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1576 rtnh->rtnh_ifindex = nexthop->rifindex;
1577 else
1578 rtnh->rtnh_ifindex = 0;
1579 }
1580 else
1581 {
1582 if (IS_ZEBRA_DEBUG_KERNEL)
1583 {
ajsb6178002004-12-07 21:12:56 +00001584 zlog_debug ("netlink_route_multipath() "
paul7021c422003-07-15 12:52:22 +00001585 "(multihop): "
1586 "%s %s/%d via %s if %u, type %s",
1587 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1588 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1589 nexthop->rifindex,
1590 nexthop_types_desc[nexthop->type]);
1591 }
1592 if (nexthop->type == NEXTHOP_TYPE_IPV4
1593 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1594 {
1595 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1596 &nexthop->gate.ipv4, bytelen);
1597 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1598 }
paul718e3742002-12-13 20:15:29 +00001599#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001600 if (nexthop->type == NEXTHOP_TYPE_IPV6
1601 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1602 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1603 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1604 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001605#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001606 /* ifindex */
1607 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1608 || nexthop->type == NEXTHOP_TYPE_IFNAME
1609 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1610 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1611 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1612 rtnh->rtnh_ifindex = nexthop->ifindex;
1613 else
1614 rtnh->rtnh_ifindex = 0;
1615 }
1616 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001617
paul7021c422003-07-15 12:52:22 +00001618 if (cmd == RTM_NEWROUTE)
1619 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1620 }
1621 }
paul718e3742002-12-13 20:15:29 +00001622
1623 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001624 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1625 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001626 }
1627
1628 /* If there is no useful nexthop then return. */
1629 if (nexthop_num == 0)
1630 {
1631 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001632 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001633 return 0;
1634 }
1635
paul7021c422003-07-15 12:52:22 +00001636skip:
paul718e3742002-12-13 20:15:29 +00001637
1638 /* Destination netlink address. */
1639 memset (&snl, 0, sizeof snl);
1640 snl.nl_family = AF_NETLINK;
1641
1642 if (family == AF_INET)
1643 nl = &netlink_cmd;
1644 else
1645 nl = &netlink;
1646
1647 /* Talk to netlink socket. */
1648 return netlink_talk (&req.n, nl);
1649}
1650
1651int
1652kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1653{
1654 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1655}
1656
1657int
1658kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1659{
1660 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1661}
1662
1663#ifdef HAVE_IPV6
1664int
1665kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1666{
1667 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1668}
1669
1670int
1671kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1672{
1673 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1674}
1675
1676/* Delete IPv6 route from the kernel. */
1677int
1678kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001679 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001680{
paul7021c422003-07-15 12:52:22 +00001681 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1682 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001683}
1684#endif /* HAVE_IPV6 */
1685
1686/* Interface address modification. */
1687int
1688netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001689 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001690{
1691 int bytelen;
1692 struct prefix *p;
1693
paul7021c422003-07-15 12:52:22 +00001694 struct
paul718e3742002-12-13 20:15:29 +00001695 {
1696 struct nlmsghdr n;
1697 struct ifaddrmsg ifa;
1698 char buf[1024];
1699 } req;
1700
1701 p = ifc->address;
1702 memset (&req, 0, sizeof req);
1703
1704 bytelen = (family == AF_INET ? 4 : 16);
1705
paul7021c422003-07-15 12:52:22 +00001706 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001707 req.n.nlmsg_flags = NLM_F_REQUEST;
1708 req.n.nlmsg_type = cmd;
1709 req.ifa.ifa_family = family;
1710
1711 req.ifa.ifa_index = ifp->ifindex;
1712 req.ifa.ifa_prefixlen = p->prefixlen;
1713
1714 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1715
1716 if (family == AF_INET && cmd == RTM_NEWADDR)
1717 {
1718 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001719 {
1720 p = ifc->destination;
1721 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1722 bytelen);
1723 }
paul718e3742002-12-13 20:15:29 +00001724 }
1725
1726 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1727 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001728
paul718e3742002-12-13 20:15:29 +00001729 if (ifc->label)
1730 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001731 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001732
1733 return netlink_talk (&req.n, &netlink_cmd);
1734}
1735
1736int
1737kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1738{
1739 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1740}
1741
1742int
1743kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1744{
1745 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1746}
1747
paul718e3742002-12-13 20:15:29 +00001748
1749extern struct thread_master *master;
1750
1751/* Kernel route reflection. */
1752int
1753kernel_read (struct thread *thread)
1754{
1755 int ret;
1756 int sock;
1757
1758 sock = THREAD_FD (thread);
1759 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001760 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001761
1762 return 0;
1763}
1764
1765/* Exported interface function. This function simply calls
1766 netlink_socket (). */
1767void
1768kernel_init ()
1769{
1770 unsigned long groups;
1771
paul7021c422003-07-15 12:52:22 +00001772 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001773#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001774 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001775#endif /* HAVE_IPV6 */
1776 netlink_socket (&netlink, groups);
1777 netlink_socket (&netlink_cmd, 0);
1778
1779 /* Register kernel socket. */
1780 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001781 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001782}