blob: 830eb430523f9b90be3e5ddcc2ebf2fca15a441a [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
ajsd2fc8892005-04-02 18:38:43 +000089/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
90 names and ifindex values. */
91static void
92set_ifindex(struct interface *ifp, unsigned int ifi_index)
93{
94 struct interface *oifp;
95
96 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
97 {
98 if (ifi_index == IFINDEX_INTERNAL)
99 zlog_err("Netlink is setting interface %s ifindex to reserved "
100 "internal value %u", ifp->name, ifi_index);
101 else
102 {
103 if (IS_ZEBRA_DEBUG_KERNEL)
104 zlog_debug("interface index %d was renamed from %s to %s",
105 ifi_index, oifp->name, ifp->name);
106 if (if_is_up(oifp))
107 zlog_err("interface rename detected on up interface: index %d "
108 "was renamed from %s to %s, results are uncertain!",
109 ifi_index, oifp->name, ifp->name);
110 if_delete_update(oifp);
111 }
112 }
113 ifp->ifindex = ifi_index;
114}
115
paul718e3742002-12-13 20:15:29 +0000116/* Make socket for Linux netlink interface. */
117static int
118netlink_socket (struct nlsock *nl, unsigned long groups)
119{
120 int ret;
121 struct sockaddr_nl snl;
122 int sock;
123 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000124 int save_errno;
paul718e3742002-12-13 20:15:29 +0000125
126 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
127 if (sock < 0)
128 {
129 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000130 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000131 return -1;
132 }
133
134 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
135 if (ret < 0)
136 {
137 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000138 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000139 close (sock);
140 return -1;
141 }
paul7021c422003-07-15 12:52:22 +0000142
hassoc34b6b52004-08-31 13:41:49 +0000143 /* Set receive buffer size if it's set from command line */
144 if (nl_rcvbufsize)
145 {
146 u_int32_t oldsize, oldlen;
147 u_int32_t newsize, newlen;
148
149 oldlen = sizeof(oldsize);
150 newlen = sizeof(newsize);
151
152 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
153 if (ret < 0)
154 {
155 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000156 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000157 close (sock);
158 return -1;
159 }
160
161 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
162 sizeof(nl_rcvbufsize));
163 if (ret < 0)
164 {
165 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000166 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000167 close (sock);
168 return -1;
169 }
170
171 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
172 if (ret < 0)
173 {
174 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000175 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000176 close (sock);
177 return -1;
178 }
179
180 zlog (NULL, LOG_INFO,
181 "Setting netlink socket receive buffer size: %u -> %u",
182 oldsize, newsize);
183 }
184
paul718e3742002-12-13 20:15:29 +0000185 memset (&snl, 0, sizeof snl);
186 snl.nl_family = AF_NETLINK;
187 snl.nl_groups = groups;
188
189 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000190 if (zserv_privs.change (ZPRIVS_RAISE))
191 {
192 zlog (NULL, LOG_ERR, "Can't raise privileges");
193 return -1;
194 }
pauledd7c242003-06-04 13:59:38 +0000195
paul718e3742002-12-13 20:15:29 +0000196 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000197 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000198 if (zserv_privs.change (ZPRIVS_LOWER))
199 zlog (NULL, LOG_ERR, "Can't lower privileges");
200
paul718e3742002-12-13 20:15:29 +0000201 if (ret < 0)
202 {
paul7021c422003-07-15 12:52:22 +0000203 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000204 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000205 close (sock);
206 return -1;
207 }
paul7021c422003-07-15 12:52:22 +0000208
paul718e3742002-12-13 20:15:29 +0000209 /* multiple netlink sockets will have different nl_pid */
210 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000211 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000212 if (ret < 0 || namelen != sizeof snl)
213 {
214 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000215 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000216 close (sock);
217 return -1;
218 }
219
220 nl->snl = snl;
221 nl->sock = sock;
222 return ret;
223}
224
paul7021c422003-07-15 12:52:22 +0000225int
226set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000227{
228
229 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000230 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000231 {
paul7021c422003-07-15 12:52:22 +0000232 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000233 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000234 return -1;
235 }
236 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000237 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000238 {
paul7021c422003-07-15 12:52:22 +0000239 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000240 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000241 return -1;
242 }
243 return 0;
244}
245
paul7021c422003-07-15 12:52:22 +0000246int
247set_netlink_nonblocking (struct nlsock *nl, int *flags)
248{
paul5f37d862003-04-19 00:11:28 +0000249 /* Restore socket flags for nonblocking I/O */
250 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000251 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000252 {
paul7021c422003-07-15 12:52:22 +0000253 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000254 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000255 return -1;
256 }
257 return 0;
258}
259
paul718e3742002-12-13 20:15:29 +0000260/* Get type specified information from netlink. */
261static int
262netlink_request (int family, int type, struct nlsock *nl)
263{
264 int ret;
265 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000266 int save_errno;
paul718e3742002-12-13 20:15:29 +0000267
268 struct
269 {
270 struct nlmsghdr nlh;
271 struct rtgenmsg g;
272 } req;
273
274
275 /* Check netlink socket. */
276 if (nl->sock < 0)
277 {
278 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
279 return -1;
280 }
281
282 memset (&snl, 0, sizeof snl);
283 snl.nl_family = AF_NETLINK;
284
285 req.nlh.nlmsg_len = sizeof req;
286 req.nlh.nlmsg_type = type;
287 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
288 req.nlh.nlmsg_pid = 0;
289 req.nlh.nlmsg_seq = ++nl->seq;
290 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000291
292 /* linux appears to check capabilities on every message
293 * have to raise caps for every message sent
294 */
paul7021c422003-07-15 12:52:22 +0000295 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000296 {
297 zlog (NULL, LOG_ERR, "Can't raise privileges");
298 return -1;
299 }
paul7021c422003-07-15 12:52:22 +0000300
301 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
302 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000303 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000304
305 if (zserv_privs.change (ZPRIVS_LOWER))
306 zlog (NULL, LOG_ERR, "Can't lower privileges");
307
paul718e3742002-12-13 20:15:29 +0000308 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000309 {
310 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000311 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000312 return -1;
313 }
pauledd7c242003-06-04 13:59:38 +0000314
paul718e3742002-12-13 20:15:29 +0000315 return 0;
316}
317
318/* Receive message from netlink interface and pass those information
319 to the given function. */
320static int
321netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000322 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000323{
324 int status;
325 int ret = 0;
326 int error;
327
328 while (1)
329 {
330 char buf[4096];
331 struct iovec iov = { buf, sizeof buf };
332 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000333 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000334 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000335 int save_errno;
paul718e3742002-12-13 20:15:29 +0000336
paul7021c422003-07-15 12:52:22 +0000337 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000338 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000339
paul718e3742002-12-13 20:15:29 +0000340 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000341 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000342
343 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000344 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000345
346 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000347 {
ajs4be019d2005-01-29 16:12:41 +0000348 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000349 continue;
ajs4be019d2005-01-29 16:12:41 +0000350 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000351 break;
ajs4be019d2005-01-29 16:12:41 +0000352 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
353 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000354 continue;
355 }
paul718e3742002-12-13 20:15:29 +0000356
357 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000358 {
359 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
360 return -1;
361 }
paul718e3742002-12-13 20:15:29 +0000362
363 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000364 {
365 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
366 nl->name, msg.msg_namelen);
367 return -1;
368 }
paulb84d3a12003-11-17 10:31:01 +0000369
370 /* JF: Ignore messages that aren't from the kernel */
371 if ( snl.nl_pid != 0 )
372 {
373 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
374 continue;
375 }
paul718e3742002-12-13 20:15:29 +0000376
hasso206d8052005-04-09 16:38:51 +0000377 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000378 h = NLMSG_NEXT (h, status))
379 {
380 /* Finish of reading. */
381 if (h->nlmsg_type == NLMSG_DONE)
382 return ret;
paul718e3742002-12-13 20:15:29 +0000383
paul7021c422003-07-15 12:52:22 +0000384 /* Error handling. */
385 if (h->nlmsg_type == NLMSG_ERROR)
386 {
387 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
388
paul718e3742002-12-13 20:15:29 +0000389 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000390 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000391 {
paul7021c422003-07-15 12:52:22 +0000392 if (IS_ZEBRA_DEBUG_KERNEL)
393 {
ajsb6178002004-12-07 21:12:56 +0000394 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000395 __FUNCTION__, nl->name,
396 lookup (nlmsg_str, err->msg.nlmsg_type),
397 err->msg.nlmsg_type, err->msg.nlmsg_seq,
398 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000399 }
paul7021c422003-07-15 12:52:22 +0000400
401 /* return if not a multipart message, otherwise continue */
402 if (!(h->nlmsg_flags & NLM_F_MULTI))
403 {
404 return 0;
paul718e3742002-12-13 20:15:29 +0000405 }
paul7021c422003-07-15 12:52:22 +0000406 continue;
paul718e3742002-12-13 20:15:29 +0000407 }
paul7021c422003-07-15 12:52:22 +0000408
paul718e3742002-12-13 20:15:29 +0000409 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000410 {
411 zlog (NULL, LOG_ERR, "%s error: message truncated",
412 nl->name);
413 return -1;
414 }
pauld753e9e2003-01-22 19:45:50 +0000415
paul7021c422003-07-15 12:52:22 +0000416 /* Deal with Error Noise - MAG */
417 {
418 int loglvl = LOG_ERR;
419 int errnum = err->error;
420 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000421
paul7021c422003-07-15 12:52:22 +0000422 if (nl == &netlink_cmd
423 && (-errnum == ENODEV || -errnum == ESRCH)
424 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
425 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000426
paul7021c422003-07-15 12:52:22 +0000427 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
428 "seq=%u, pid=%d",
ajs6099b3b2004-11-20 02:06:59 +0000429 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000430 lookup (nlmsg_str, msg_type),
431 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
432 }
433 /*
434 ret = -1;
435 continue;
436 */
437 return -1;
438 }
paul718e3742002-12-13 20:15:29 +0000439
paul7021c422003-07-15 12:52:22 +0000440 /* OK we got netlink message. */
441 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000442 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
paul7021c422003-07-15 12:52:22 +0000443 nl->name,
444 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
445 h->nlmsg_seq, h->nlmsg_pid);
446
447 /* skip unsolicited messages originating from command socket */
448 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
449 {
450 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000451 zlog_debug ("netlink_parse_info: %s packet comes from %s",
paul7021c422003-07-15 12:52:22 +0000452 nl->name, netlink_cmd.name);
453 continue;
454 }
455
456 error = (*filter) (&snl, h);
457 if (error < 0)
458 {
459 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
460 ret = error;
461 }
462 }
paul718e3742002-12-13 20:15:29 +0000463
464 /* After error care. */
465 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000466 {
467 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
468 continue;
469 }
paul718e3742002-12-13 20:15:29 +0000470 if (status)
paul7021c422003-07-15 12:52:22 +0000471 {
472 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
473 status);
474 return -1;
475 }
paul718e3742002-12-13 20:15:29 +0000476 }
477 return ret;
478}
479
480/* Utility function for parse rtattr. */
481static void
paul7021c422003-07-15 12:52:22 +0000482netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
483 int len)
paul718e3742002-12-13 20:15:29 +0000484{
paul7021c422003-07-15 12:52:22 +0000485 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000486 {
487 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000488 tb[rta->rta_type] = rta;
489 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000490 }
491}
492
493/* Called from interface_lookup_netlink(). This function is only used
494 during bootstrap. */
495int
496netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
497{
498 int len;
499 struct ifinfomsg *ifi;
500 struct rtattr *tb[IFLA_MAX + 1];
501 struct interface *ifp;
502 char *name;
503 int i;
504
505 ifi = NLMSG_DATA (h);
506
507 if (h->nlmsg_type != RTM_NEWLINK)
508 return 0;
509
510 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
511 if (len < 0)
512 return -1;
513
514 /* Looking up interface name. */
515 memset (tb, 0, sizeof tb);
516 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000517
paul1e193152005-02-14 23:53:05 +0000518#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000519 /* check for wireless messages to ignore */
520 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
521 {
522 if (IS_ZEBRA_DEBUG_KERNEL)
523 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
524 return 0;
525 }
paul1e193152005-02-14 23:53:05 +0000526#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000527
paul718e3742002-12-13 20:15:29 +0000528 if (tb[IFLA_IFNAME] == NULL)
529 return -1;
paul7021c422003-07-15 12:52:22 +0000530 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000531
532 /* Add interface. */
533 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000534 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000535 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000536 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000537 ifp->metric = 1;
538
539 /* Hardware type and address. */
540 ifp->hw_type = ifi->ifi_type;
541
542 if (tb[IFLA_ADDRESS])
543 {
544 int hw_addr_len;
545
paul7021c422003-07-15 12:52:22 +0000546 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000547
548 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000549 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000550 else
paul7021c422003-07-15 12:52:22 +0000551 {
552 ifp->hw_addr_len = hw_addr_len;
553 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000554
paul7021c422003-07-15 12:52:22 +0000555 for (i = 0; i < hw_addr_len; i++)
556 if (ifp->hw_addr[i] != 0)
557 break;
paul718e3742002-12-13 20:15:29 +0000558
paul7021c422003-07-15 12:52:22 +0000559 if (i == hw_addr_len)
560 ifp->hw_addr_len = 0;
561 else
562 ifp->hw_addr_len = hw_addr_len;
563 }
paul718e3742002-12-13 20:15:29 +0000564 }
565
566 if_add_update (ifp);
567
568 return 0;
569}
570
571/* Lookup interface IPv4/IPv6 address. */
572int
573netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
574{
575 int len;
576 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000577 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000578 struct interface *ifp;
579 void *addr = NULL;
580 void *broad = NULL;
581 u_char flags = 0;
582 char *label = NULL;
583
584 ifa = NLMSG_DATA (h);
585
paul7021c422003-07-15 12:52:22 +0000586 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000587#ifdef HAVE_IPV6
588 && ifa->ifa_family != AF_INET6
589#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000590 )
paul718e3742002-12-13 20:15:29 +0000591 return 0;
592
593 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
594 return 0;
595
paul7021c422003-07-15 12:52:22 +0000596 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000597 if (len < 0)
598 return -1;
599
600 memset (tb, 0, sizeof tb);
601 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
602
603 ifp = if_lookup_by_index (ifa->ifa_index);
604 if (ifp == NULL)
605 {
606 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000607 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000608 return -1;
609 }
610
paul7021c422003-07-15 12:52:22 +0000611 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000612 {
paul00df0c12002-12-13 21:07:36 +0000613 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000614 zlog_debug ("netlink_interface_addr %s %s:",
615 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000616 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000617 zlog_debug (" IFA_LOCAL %s/%d",
618 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
619 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000620 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000621 zlog_debug (" IFA_ADDRESS %s/%d",
622 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
623 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000624 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000625 zlog_debug (" IFA_BROADCAST %s/%d",
626 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
627 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000628 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000629 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000630 }
paul31a476c2003-09-29 19:54:53 +0000631
632 if (tb[IFA_ADDRESS] == NULL)
633 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
634
635 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000636 {
paul31a476c2003-09-29 19:54:53 +0000637 if (tb[IFA_LOCAL])
638 {
639 addr = RTA_DATA (tb[IFA_LOCAL]);
hasso3fb9cd62004-10-19 19:44:43 +0000640 if (tb[IFA_ADDRESS] &&
641 memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4))
642 /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */
paul31a476c2003-09-29 19:54:53 +0000643 broad = RTA_DATA (tb[IFA_ADDRESS]);
644 else
645 broad = NULL;
646 }
647 else
648 {
649 if (tb[IFA_ADDRESS])
650 addr = RTA_DATA (tb[IFA_ADDRESS]);
651 else
652 addr = NULL;
653 }
paul7021c422003-07-15 12:52:22 +0000654 }
paul31a476c2003-09-29 19:54:53 +0000655 else
paul7021c422003-07-15 12:52:22 +0000656 {
paul31a476c2003-09-29 19:54:53 +0000657 if (tb[IFA_ADDRESS])
658 addr = RTA_DATA (tb[IFA_ADDRESS]);
659 else
660 addr = NULL;
661
662 if (tb[IFA_BROADCAST])
663 broad = RTA_DATA(tb[IFA_BROADCAST]);
664 else
665 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000666 }
paul00df0c12002-12-13 21:07:36 +0000667
paul718e3742002-12-13 20:15:29 +0000668 /* Flags. */
669 if (ifa->ifa_flags & IFA_F_SECONDARY)
670 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
671
672 /* Label */
673 if (tb[IFA_LABEL])
674 label = (char *) RTA_DATA (tb[IFA_LABEL]);
675
676 if (ifp && label && strcmp (ifp->name, label) == 0)
677 label = NULL;
678
679 /* Register interface address to the interface. */
680 if (ifa->ifa_family == AF_INET)
681 {
paul7021c422003-07-15 12:52:22 +0000682 if (h->nlmsg_type == RTM_NEWADDR)
683 connected_add_ipv4 (ifp, flags,
684 (struct in_addr *) addr, ifa->ifa_prefixlen,
685 (struct in_addr *) broad, label);
686 else
687 connected_delete_ipv4 (ifp, flags,
688 (struct in_addr *) addr, ifa->ifa_prefixlen,
689 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000690 }
691#ifdef HAVE_IPV6
692 if (ifa->ifa_family == AF_INET6)
693 {
694 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000695 connected_add_ipv6 (ifp,
696 (struct in6_addr *) addr, ifa->ifa_prefixlen,
697 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000698 else
paul7021c422003-07-15 12:52:22 +0000699 connected_delete_ipv6 (ifp,
700 (struct in6_addr *) addr, ifa->ifa_prefixlen,
701 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000702 }
paul7021c422003-07-15 12:52:22 +0000703#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000704
705 return 0;
706}
707
708/* Looking up routing table by netlink interface. */
709int
710netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
711{
712 int len;
713 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000714 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000715 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000716
717 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000718
719 int index;
720 int table;
hasso34195bf2004-04-06 12:07:06 +0000721 int metric;
722
paul718e3742002-12-13 20:15:29 +0000723 void *dest;
724 void *gate;
725
726 rtm = NLMSG_DATA (h);
727
728 if (h->nlmsg_type != RTM_NEWROUTE)
729 return 0;
730 if (rtm->rtm_type != RTN_UNICAST)
731 return 0;
732
733 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000734#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000735 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000736 return 0;
737#endif
738
paul7021c422003-07-15 12:52:22 +0000739 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000740 if (len < 0)
741 return -1;
742
743 memset (tb, 0, sizeof tb);
744 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
745
746 if (rtm->rtm_flags & RTM_F_CLONED)
747 return 0;
748 if (rtm->rtm_protocol == RTPROT_REDIRECT)
749 return 0;
750 if (rtm->rtm_protocol == RTPROT_KERNEL)
751 return 0;
752
753 if (rtm->rtm_src_len != 0)
754 return 0;
755
756 /* Route which inserted by Zebra. */
757 if (rtm->rtm_protocol == RTPROT_ZEBRA)
758 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000759
paul718e3742002-12-13 20:15:29 +0000760 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000761 metric = 0;
paul718e3742002-12-13 20:15:29 +0000762 dest = NULL;
763 gate = NULL;
764
765 if (tb[RTA_OIF])
766 index = *(int *) RTA_DATA (tb[RTA_OIF]);
767
768 if (tb[RTA_DST])
769 dest = RTA_DATA (tb[RTA_DST]);
770 else
771 dest = anyaddr;
772
773 /* Multipath treatment is needed. */
774 if (tb[RTA_GATEWAY])
775 gate = RTA_DATA (tb[RTA_GATEWAY]);
776
hasso34195bf2004-04-06 12:07:06 +0000777 if (tb[RTA_PRIORITY])
778 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
779
paul718e3742002-12-13 20:15:29 +0000780 if (rtm->rtm_family == AF_INET)
781 {
782 struct prefix_ipv4 p;
783 p.family = AF_INET;
784 memcpy (&p.prefix, dest, 4);
785 p.prefixlen = rtm->rtm_dst_len;
786
hasso34195bf2004-04-06 12:07:06 +0000787 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000788 }
789#ifdef HAVE_IPV6
790 if (rtm->rtm_family == AF_INET6)
791 {
792 struct prefix_ipv6 p;
793 p.family = AF_INET6;
794 memcpy (&p.prefix, dest, 16);
795 p.prefixlen = rtm->rtm_dst_len;
796
797 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
798 }
799#endif /* HAVE_IPV6 */
800
801 return 0;
802}
803
paul7021c422003-07-15 12:52:22 +0000804struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000805 {RTPROT_REDIRECT, "redirect"},
806 {RTPROT_KERNEL, "kernel"},
807 {RTPROT_BOOT, "boot"},
808 {RTPROT_STATIC, "static"},
809 {RTPROT_GATED, "GateD"},
810 {RTPROT_RA, "router advertisement"},
811 {RTPROT_MRT, "MRT"},
812 {RTPROT_ZEBRA, "Zebra"},
813#ifdef RTPROT_BIRD
814 {RTPROT_BIRD, "BIRD"},
815#endif /* RTPROT_BIRD */
816 {0, NULL}
817};
818
819/* Routing information change from the kernel. */
820int
821netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
822{
823 int len;
824 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000825 struct rtattr *tb[RTA_MAX + 1];
826
827 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000828
829 int index;
830 int table;
831 void *dest;
832 void *gate;
833
834 rtm = NLMSG_DATA (h);
835
paul7021c422003-07-15 12:52:22 +0000836 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000837 {
838 /* If this is not route add/delete message print warning. */
839 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
840 return 0;
841 }
842
843 /* Connected route. */
844 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000845 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000846 h->nlmsg_type ==
847 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
848 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
849 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
850 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000851
852 if (rtm->rtm_type != RTN_UNICAST)
853 {
854 return 0;
855 }
856
857 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000858 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000859 {
860 return 0;
861 }
862
paul7021c422003-07-15 12:52:22 +0000863 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000864 if (len < 0)
865 return -1;
866
867 memset (tb, 0, sizeof tb);
868 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
869
870 if (rtm->rtm_flags & RTM_F_CLONED)
871 return 0;
872 if (rtm->rtm_protocol == RTPROT_REDIRECT)
873 return 0;
874 if (rtm->rtm_protocol == RTPROT_KERNEL)
875 return 0;
876
877 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
878 return 0;
879
880 if (rtm->rtm_src_len != 0)
881 {
882 zlog_warn ("netlink_route_change(): no src len");
883 return 0;
884 }
paul7021c422003-07-15 12:52:22 +0000885
paul718e3742002-12-13 20:15:29 +0000886 index = 0;
887 dest = NULL;
888 gate = NULL;
889
890 if (tb[RTA_OIF])
891 index = *(int *) RTA_DATA (tb[RTA_OIF]);
892
893 if (tb[RTA_DST])
894 dest = RTA_DATA (tb[RTA_DST]);
895 else
896 dest = anyaddr;
897
898 if (tb[RTA_GATEWAY])
899 gate = RTA_DATA (tb[RTA_GATEWAY]);
900
901 if (rtm->rtm_family == AF_INET)
902 {
903 struct prefix_ipv4 p;
904 p.family = AF_INET;
905 memcpy (&p.prefix, dest, 4);
906 p.prefixlen = rtm->rtm_dst_len;
907
908 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000909 {
910 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000911 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000912 inet_ntoa (p.prefix), p.prefixlen);
913 else
ajsb6178002004-12-07 21:12:56 +0000914 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000915 inet_ntoa (p.prefix), p.prefixlen);
916 }
paul718e3742002-12-13 20:15:29 +0000917
918 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000919 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000920 else
paul7021c422003-07-15 12:52:22 +0000921 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000922 }
923
924#ifdef HAVE_IPV6
925 if (rtm->rtm_family == AF_INET6)
926 {
927 struct prefix_ipv6 p;
928 char buf[BUFSIZ];
929
930 p.family = AF_INET6;
931 memcpy (&p.prefix, dest, 16);
932 p.prefixlen = rtm->rtm_dst_len;
933
934 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000935 {
936 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000937 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000938 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
939 p.prefixlen);
940 else
ajsb6178002004-12-07 21:12:56 +0000941 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000942 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
943 p.prefixlen);
944 }
paul718e3742002-12-13 20:15:29 +0000945
946 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000947 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000948 else
paul7021c422003-07-15 12:52:22 +0000949 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000950 }
951#endif /* HAVE_IPV6 */
952
953 return 0;
954}
955
956int
957netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
958{
959 int len;
960 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000961 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000962 struct interface *ifp;
963 char *name;
964
965 ifi = NLMSG_DATA (h);
966
paul7021c422003-07-15 12:52:22 +0000967 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000968 {
969 /* If this is not link add/delete message so print warning. */
970 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000971 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000972 return 0;
973 }
974
975 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
976 if (len < 0)
977 return -1;
978
979 /* Looking up interface name. */
980 memset (tb, 0, sizeof tb);
981 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000982
paul1e193152005-02-14 23:53:05 +0000983#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000984 /* check for wireless messages to ignore */
985 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
986 {
987 if (IS_ZEBRA_DEBUG_KERNEL)
988 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
989 return 0;
990 }
paul1e193152005-02-14 23:53:05 +0000991#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000992
paul718e3742002-12-13 20:15:29 +0000993 if (tb[IFLA_IFNAME] == NULL)
994 return -1;
paul7021c422003-07-15 12:52:22 +0000995 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000996
997 /* Add interface. */
998 if (h->nlmsg_type == RTM_NEWLINK)
999 {
1000 ifp = if_lookup_by_name (name);
1001
paul7021c422003-07-15 12:52:22 +00001002 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1003 {
1004 if (ifp == NULL)
1005 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001006
ajsd2fc8892005-04-02 18:38:43 +00001007 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001008 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001009 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001010 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001011
paul7021c422003-07-15 12:52:22 +00001012 /* If new link is added. */
1013 if_add_update (ifp);
1014 }
paul718e3742002-12-13 20:15:29 +00001015 else
paul7021c422003-07-15 12:52:22 +00001016 {
1017 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001018 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001019 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001020 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001021
paul7021c422003-07-15 12:52:22 +00001022 if (if_is_operative (ifp))
1023 {
1024 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1025 if (!if_is_operative (ifp))
1026 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001027 else
1028 /* Must notify client daemons of new interface status. */
1029 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001030 }
1031 else
1032 {
1033 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1034 if (if_is_operative (ifp))
1035 if_up (ifp);
1036 }
1037 }
paul718e3742002-12-13 20:15:29 +00001038 }
1039 else
1040 {
1041 /* RTM_DELLINK. */
1042 ifp = if_lookup_by_name (name);
1043
1044 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001045 {
1046 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001047 name);
paul7021c422003-07-15 12:52:22 +00001048 return 0;
1049 }
1050
paul718e3742002-12-13 20:15:29 +00001051 if_delete_update (ifp);
1052 }
1053
1054 return 0;
1055}
1056
1057int
1058netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1059{
1060 switch (h->nlmsg_type)
1061 {
1062 case RTM_NEWROUTE:
1063 return netlink_route_change (snl, h);
1064 break;
1065 case RTM_DELROUTE:
1066 return netlink_route_change (snl, h);
1067 break;
1068 case RTM_NEWLINK:
1069 return netlink_link_change (snl, h);
1070 break;
1071 case RTM_DELLINK:
1072 return netlink_link_change (snl, h);
1073 break;
1074 case RTM_NEWADDR:
1075 return netlink_interface_addr (snl, h);
1076 break;
1077 case RTM_DELADDR:
1078 return netlink_interface_addr (snl, h);
1079 break;
1080 default:
1081 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1082 break;
1083 }
1084 return 0;
1085}
1086
1087/* Interface lookup by netlink socket. */
1088int
1089interface_lookup_netlink ()
1090{
1091 int ret;
paul5f37d862003-04-19 00:11:28 +00001092 int flags;
1093 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001094
paul5f37d862003-04-19 00:11:28 +00001095 /*
1096 * Change netlink socket flags to blocking to ensure we get
1097 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001098 */
1099 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1100 if (snb_ret < 0)
1101 zlog (NULL, LOG_WARNING,
1102 "%s:%i Warning: Could not set netlink socket to blocking.",
1103 __FUNCTION__, __LINE__);
1104
paul718e3742002-12-13 20:15:29 +00001105 /* Get interface information. */
1106 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1107 if (ret < 0)
1108 return ret;
1109 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1110 if (ret < 0)
1111 return ret;
1112
1113 /* Get IPv4 address of the interfaces. */
1114 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1115 if (ret < 0)
1116 return ret;
1117 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1118 if (ret < 0)
1119 return ret;
1120
1121#ifdef HAVE_IPV6
1122 /* Get IPv6 address of the interfaces. */
1123 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1124 if (ret < 0)
1125 return ret;
1126 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1127 if (ret < 0)
1128 return ret;
1129#endif /* HAVE_IPV6 */
1130
paul7021c422003-07-15 12:52:22 +00001131 /* restore socket flags */
1132 if (snb_ret == 0)
1133 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001134 return 0;
1135}
1136
1137/* Routing table read function using netlink interface. Only called
1138 bootstrap time. */
1139int
1140netlink_route_read ()
1141{
1142 int ret;
paul5f37d862003-04-19 00:11:28 +00001143 int flags;
1144 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001145
paul5f37d862003-04-19 00:11:28 +00001146 /*
1147 * Change netlink socket flags to blocking to ensure we get
1148 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001149 */
1150 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1151 if (snb_ret < 0)
1152 zlog (NULL, LOG_WARNING,
1153 "%s:%i Warning: Could not set netlink socket to blocking.",
1154 __FUNCTION__, __LINE__);
1155
paul718e3742002-12-13 20:15:29 +00001156 /* Get IPv4 routing table. */
1157 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1158 if (ret < 0)
1159 return ret;
1160 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1161 if (ret < 0)
1162 return ret;
1163
1164#ifdef HAVE_IPV6
1165 /* Get IPv6 routing table. */
1166 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1167 if (ret < 0)
1168 return ret;
1169 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1170 if (ret < 0)
1171 return ret;
1172#endif /* HAVE_IPV6 */
1173
paul5f37d862003-04-19 00:11:28 +00001174 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001175 if (snb_ret == 0)
1176 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001177 return 0;
1178}
1179
1180/* Utility function comes from iproute2.
1181 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1182int
1183addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1184{
1185 int len;
1186 struct rtattr *rta;
1187
paul7021c422003-07-15 12:52:22 +00001188 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001189
paul7021c422003-07-15 12:52:22 +00001190 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001191 return -1;
1192
paul7021c422003-07-15 12:52:22 +00001193 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001194 rta->rta_type = type;
1195 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001196 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001197 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1198
1199 return 0;
1200}
1201
1202int
1203rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1204{
1205 int len;
1206 struct rtattr *subrta;
1207
paul7021c422003-07-15 12:52:22 +00001208 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001209
paul7021c422003-07-15 12:52:22 +00001210 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001211 return -1;
1212
paul7021c422003-07-15 12:52:22 +00001213 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001214 subrta->rta_type = type;
1215 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001216 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001217 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1218
1219 return 0;
1220}
1221
1222/* Utility function comes from iproute2.
1223 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1224int
1225addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1226{
1227 int len;
1228 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001229
1230 len = RTA_LENGTH (4);
1231
paul718e3742002-12-13 20:15:29 +00001232 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1233 return -1;
1234
paul7021c422003-07-15 12:52:22 +00001235 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001236 rta->rta_type = type;
1237 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001238 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001239 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1240
1241 return 0;
1242}
1243
1244static int
1245netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1246{
hassob7ed1ec2005-03-31 20:13:49 +00001247 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001248 return 0;
1249}
1250
1251/* sendmsg() to netlink socket then recvmsg(). */
1252int
1253netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1254{
1255 int status;
1256 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001257 struct iovec iov = { (void *) n, n->nlmsg_len };
1258 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001259 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001260 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001261 int save_errno;
paul7021c422003-07-15 12:52:22 +00001262
paul718e3742002-12-13 20:15:29 +00001263 memset (&snl, 0, sizeof snl);
1264 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001265
hassob7ed1ec2005-03-31 20:13:49 +00001266 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001267
1268 /* Request an acknowledgement by setting NLM_F_ACK */
1269 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001270
1271 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001272 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001273 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1274 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001275
1276 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001277 if (zserv_privs.change (ZPRIVS_RAISE))
1278 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001279 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001280 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001281 if (zserv_privs.change (ZPRIVS_LOWER))
1282 zlog (NULL, LOG_ERR, "Can't lower privileges");
1283
paul718e3742002-12-13 20:15:29 +00001284 if (status < 0)
1285 {
1286 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001287 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001288 return -1;
1289 }
paul7021c422003-07-15 12:52:22 +00001290
paul718e3742002-12-13 20:15:29 +00001291 /*
1292 * Change socket flags for blocking I/O.
1293 * This ensures we wait for a reply in netlink_parse_info().
1294 */
paul7021c422003-07-15 12:52:22 +00001295 snb_ret = set_netlink_blocking (nl, &flags);
1296 if (snb_ret < 0)
1297 zlog (NULL, LOG_WARNING,
1298 "%s:%i Warning: Could not set netlink socket to blocking.",
1299 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001300
1301 /*
1302 * Get reply from netlink socket.
1303 * The reply should either be an acknowlegement or an error.
1304 */
1305 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001306
paul718e3742002-12-13 20:15:29 +00001307 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001308 if (snb_ret == 0)
1309 set_netlink_nonblocking (nl, &flags);
1310
paul718e3742002-12-13 20:15:29 +00001311 return status;
1312}
1313
1314/* Routing table change via netlink interface. */
1315int
1316netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001317 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001318{
1319 int ret;
1320 int bytelen;
1321 struct sockaddr_nl snl;
1322 int discard;
1323
paul7021c422003-07-15 12:52:22 +00001324 struct
paul718e3742002-12-13 20:15:29 +00001325 {
1326 struct nlmsghdr n;
1327 struct rtmsg r;
1328 char buf[1024];
1329 } req;
1330
1331 memset (&req, 0, sizeof req);
1332
1333 bytelen = (family == AF_INET ? 4 : 16);
1334
1335 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1336 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1337 req.n.nlmsg_type = cmd;
1338 req.r.rtm_family = family;
1339 req.r.rtm_table = table;
1340 req.r.rtm_dst_len = length;
1341
hasso81dfcaa2003-05-25 19:21:25 +00001342 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1343 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001344 discard = 1;
1345 else
1346 discard = 0;
1347
paul7021c422003-07-15 12:52:22 +00001348 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001349 {
1350 req.r.rtm_protocol = RTPROT_ZEBRA;
1351 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1352
paul7021c422003-07-15 12:52:22 +00001353 if (discard)
paul595db7f2003-05-25 21:35:06 +00001354 {
1355 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1356 req.r.rtm_type = RTN_BLACKHOLE;
1357 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1358 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001359 else
1360 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1361 }
paul595db7f2003-05-25 21:35:06 +00001362 else
paul7021c422003-07-15 12:52:22 +00001363 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001364 }
1365
1366 if (dest)
1367 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1368
paul7021c422003-07-15 12:52:22 +00001369 if (!discard)
paul718e3742002-12-13 20:15:29 +00001370 {
1371 if (gate)
paul7021c422003-07-15 12:52:22 +00001372 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001373 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001374 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001375 }
1376
1377 /* Destination netlink address. */
1378 memset (&snl, 0, sizeof snl);
1379 snl.nl_family = AF_NETLINK;
1380
1381 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001382 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001383 if (ret < 0)
1384 return -1;
1385
1386 return 0;
1387}
1388
1389/* Routing table change via netlink interface. */
1390int
1391netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001392 int family)
paul718e3742002-12-13 20:15:29 +00001393{
1394 int bytelen;
1395 struct sockaddr_nl snl;
1396 struct nexthop *nexthop = NULL;
1397 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001398 int discard;
1399
paul7021c422003-07-15 12:52:22 +00001400 struct
paul718e3742002-12-13 20:15:29 +00001401 {
1402 struct nlmsghdr n;
1403 struct rtmsg r;
1404 char buf[1024];
1405 } req;
1406
1407 memset (&req, 0, sizeof req);
1408
1409 bytelen = (family == AF_INET ? 4 : 16);
1410
1411 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1412 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1413 req.n.nlmsg_type = cmd;
1414 req.r.rtm_family = family;
1415 req.r.rtm_table = rib->table;
1416 req.r.rtm_dst_len = p->prefixlen;
1417
paul7021c422003-07-15 12:52:22 +00001418 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001419 discard = 1;
1420 else
1421 discard = 0;
1422
paul7021c422003-07-15 12:52:22 +00001423 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001424 {
1425 req.r.rtm_protocol = RTPROT_ZEBRA;
1426 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1427
paul7021c422003-07-15 12:52:22 +00001428 if (discard)
paul595db7f2003-05-25 21:35:06 +00001429 {
1430 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1431 req.r.rtm_type = RTN_BLACKHOLE;
1432 else if (rib->flags & ZEBRA_FLAG_REJECT)
1433 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001434 else
1435 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1436 }
paul595db7f2003-05-25 21:35:06 +00001437 else
paul7021c422003-07-15 12:52:22 +00001438 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001439 }
1440
1441 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1442
1443 /* Metric. */
1444 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1445
1446 if (discard)
1447 {
1448 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001449 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1450 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001451 goto skip;
1452 }
1453
1454 /* Multipath case. */
1455 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1456 {
1457 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001458 {
paul5ec90d22003-06-19 01:41:37 +00001459
paul7021c422003-07-15 12:52:22 +00001460 if ((cmd == RTM_NEWROUTE
1461 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1462 || (cmd == RTM_DELROUTE
1463 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1464 {
paul5ec90d22003-06-19 01:41:37 +00001465
paul7021c422003-07-15 12:52:22 +00001466 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1467 {
1468 if (IS_ZEBRA_DEBUG_KERNEL)
1469 {
ajsb6178002004-12-07 21:12:56 +00001470 zlog_debug
paul7021c422003-07-15 12:52:22 +00001471 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001472 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1473 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1474 inet6_ntoa (p->u.prefix6), p->prefixlen,
paul7021c422003-07-15 12:52:22 +00001475 nexthop_types_desc[nexthop->rtype]);
1476 }
paul5ec90d22003-06-19 01:41:37 +00001477
paul7021c422003-07-15 12:52:22 +00001478 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1479 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001480 {
1481 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1482 &nexthop->rgate.ipv4, bytelen);
1483
1484 if (IS_ZEBRA_DEBUG_KERNEL)
1485 zlog_debug("netlink_route_multipath() (recursive, "
1486 "1 hop): nexthop via %s if %u",
1487 inet_ntoa (nexthop->rgate.ipv4),
1488 nexthop->rifindex);
1489 }
paul718e3742002-12-13 20:15:29 +00001490#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001491 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1492 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1493 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001494 {
1495 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1496 &nexthop->rgate.ipv6, bytelen);
1497
1498 if (IS_ZEBRA_DEBUG_KERNEL)
1499 zlog_debug("netlink_route_multipath() (recursive, "
1500 "1 hop): nexthop via %s if %u",
1501 inet6_ntoa (nexthop->rgate.ipv6),
1502 nexthop->rifindex);
1503 }
paul718e3742002-12-13 20:15:29 +00001504#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001505 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1506 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1507 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1508 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1509 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001510 {
1511 addattr32 (&req.n, sizeof req, RTA_OIF,
1512 nexthop->rifindex);
1513
1514 if (IS_ZEBRA_DEBUG_KERNEL)
1515 zlog_debug("netlink_route_multipath() (recursive, "
1516 "1 hop): nexthop via if %u",
1517 nexthop->rifindex);
1518 }
paul7021c422003-07-15 12:52:22 +00001519 }
1520 else
1521 {
1522 if (IS_ZEBRA_DEBUG_KERNEL)
1523 {
ajsb6178002004-12-07 21:12:56 +00001524 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001525 ("netlink_route_multipath() (single hop): "
1526 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1527 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1528 inet6_ntoa (p->u.prefix6), p->prefixlen,
1529 nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001530 }
paul5ec90d22003-06-19 01:41:37 +00001531
paul7021c422003-07-15 12:52:22 +00001532 if (nexthop->type == NEXTHOP_TYPE_IPV4
1533 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001534 {
1535 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1536 &nexthop->gate.ipv4, bytelen);
1537
1538 if (IS_ZEBRA_DEBUG_KERNEL)
1539 zlog_debug("netlink_route_multipath() (single hop): "
1540 "nexthop via %s if %u",
1541 inet_ntoa (nexthop->gate.ipv4),
1542 nexthop->ifindex);
1543 }
paul718e3742002-12-13 20:15:29 +00001544#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001545 if (nexthop->type == NEXTHOP_TYPE_IPV6
1546 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1547 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001548 {
1549 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1550 &nexthop->gate.ipv6, bytelen);
1551
1552 if (IS_ZEBRA_DEBUG_KERNEL)
1553 zlog_debug("netlink_route_multipath() (single hop): "
1554 "nexthop via %s if %u",
1555 inet6_ntoa (nexthop->gate.ipv6),
1556 nexthop->ifindex);
1557 }
paul718e3742002-12-13 20:15:29 +00001558#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001559 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1560 || nexthop->type == NEXTHOP_TYPE_IFNAME
1561 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1562 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1563 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001564 {
1565 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1566
1567 if (IS_ZEBRA_DEBUG_KERNEL)
1568 zlog_debug("netlink_route_multipath() (single hop): "
1569 "nexthop via if %u", nexthop->ifindex);
1570 }
paul7021c422003-07-15 12:52:22 +00001571 }
paul718e3742002-12-13 20:15:29 +00001572
paul7021c422003-07-15 12:52:22 +00001573 if (cmd == RTM_NEWROUTE)
1574 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001575
paul7021c422003-07-15 12:52:22 +00001576 nexthop_num++;
1577 break;
1578 }
1579 }
paul718e3742002-12-13 20:15:29 +00001580 }
1581 else
1582 {
1583 char buf[1024];
1584 struct rtattr *rta = (void *) buf;
1585 struct rtnexthop *rtnh;
1586
1587 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001588 rta->rta_len = RTA_LENGTH (0);
1589 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001590
1591 nexthop_num = 0;
1592 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001593 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1594 nexthop = nexthop->next)
1595 {
1596 if ((cmd == RTM_NEWROUTE
1597 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1598 || (cmd == RTM_DELROUTE
1599 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1600 {
1601 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001602
paul7021c422003-07-15 12:52:22 +00001603 rtnh->rtnh_len = sizeof (*rtnh);
1604 rtnh->rtnh_flags = 0;
1605 rtnh->rtnh_hops = 0;
1606 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001607
paul7021c422003-07-15 12:52:22 +00001608 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1609 {
1610 if (IS_ZEBRA_DEBUG_KERNEL)
1611 {
ajsb6178002004-12-07 21:12:56 +00001612 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001613 "(recursive, multihop): %s %s/%d type %s",
1614 lookup (nlmsg_str, cmd), (family == AF_INET) ?
1615 inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6),
1616 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001617 }
1618 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1619 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1620 {
1621 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1622 &nexthop->rgate.ipv4, bytelen);
1623 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001624
1625 if (IS_ZEBRA_DEBUG_KERNEL)
1626 zlog_debug("netlink_route_multipath() (recursive, "
1627 "multihop): nexthop via %s if %u",
1628 inet_ntoa (nexthop->rgate.ipv4),
1629 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001630 }
paul718e3742002-12-13 20:15:29 +00001631#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001632 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1633 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1634 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001635 {
1636 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1637 &nexthop->rgate.ipv6, bytelen);
1638
1639 if (IS_ZEBRA_DEBUG_KERNEL)
1640 zlog_debug("netlink_route_multipath() (recursive, "
1641 "multihop): nexthop via %s if %u",
1642 inet6_ntoa (nexthop->rgate.ipv6),
1643 nexthop->rifindex);
1644 }
paul718e3742002-12-13 20:15:29 +00001645#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001646 /* ifindex */
1647 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1648 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1649 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1650 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1651 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001652 {
1653 rtnh->rtnh_ifindex = nexthop->rifindex;
1654
1655 if (IS_ZEBRA_DEBUG_KERNEL)
1656 zlog_debug("netlink_route_multipath() (recursive, "
1657 "multihop): nexthop via if %u",
1658 nexthop->rifindex);
1659 }
paul7021c422003-07-15 12:52:22 +00001660 else
hasso206d8052005-04-09 16:38:51 +00001661 {
1662 rtnh->rtnh_ifindex = 0;
1663 }
paul7021c422003-07-15 12:52:22 +00001664 }
1665 else
1666 {
1667 if (IS_ZEBRA_DEBUG_KERNEL)
1668 {
hasso206d8052005-04-09 16:38:51 +00001669 zlog_debug ("netlink_route_multipath() (multihop): "
1670 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
1671 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1672 inet6_ntoa (p->u.prefix6), p->prefixlen,
paul7021c422003-07-15 12:52:22 +00001673 nexthop_types_desc[nexthop->type]);
1674 }
1675 if (nexthop->type == NEXTHOP_TYPE_IPV4
1676 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1677 {
hasso206d8052005-04-09 16:38:51 +00001678 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1679 &nexthop->gate.ipv4, bytelen);
1680 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1681
1682 if (IS_ZEBRA_DEBUG_KERNEL)
1683 zlog_debug("netlink_route_multipath() (multihop): "
1684 "nexthop via %s if %u",
1685 inet_ntoa (nexthop->gate.ipv4),
1686 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001687 }
paul718e3742002-12-13 20:15:29 +00001688#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001689 if (nexthop->type == NEXTHOP_TYPE_IPV6
1690 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1691 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001692 {
1693 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1694 &nexthop->gate.ipv6, bytelen);
1695
1696 if (IS_ZEBRA_DEBUG_KERNEL)
1697 zlog_debug("netlink_route_multipath() (multihop): "
1698 "nexthop via %s if %u",
1699 inet6_ntoa (nexthop->gate.ipv6),
1700 nexthop->ifindex);
1701 }
paul718e3742002-12-13 20:15:29 +00001702#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001703 /* ifindex */
1704 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1705 || nexthop->type == NEXTHOP_TYPE_IFNAME
1706 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1707 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1708 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001709 {
1710 rtnh->rtnh_ifindex = nexthop->ifindex;
1711
1712 if (IS_ZEBRA_DEBUG_KERNEL)
1713 zlog_debug("netlink_route_multipath() (multihop): "
1714 "nexthop via if %u", nexthop->ifindex);
1715 }
paul7021c422003-07-15 12:52:22 +00001716 else
hasso206d8052005-04-09 16:38:51 +00001717 {
1718 rtnh->rtnh_ifindex = 0;
1719 }
paul7021c422003-07-15 12:52:22 +00001720 }
1721 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001722
paul7021c422003-07-15 12:52:22 +00001723 if (cmd == RTM_NEWROUTE)
1724 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1725 }
1726 }
paul718e3742002-12-13 20:15:29 +00001727
1728 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001729 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1730 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001731 }
1732
1733 /* If there is no useful nexthop then return. */
1734 if (nexthop_num == 0)
1735 {
1736 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001737 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001738 return 0;
1739 }
1740
paul7021c422003-07-15 12:52:22 +00001741skip:
paul718e3742002-12-13 20:15:29 +00001742
1743 /* Destination netlink address. */
1744 memset (&snl, 0, sizeof snl);
1745 snl.nl_family = AF_NETLINK;
1746
paul718e3742002-12-13 20:15:29 +00001747 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001748 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001749}
1750
1751int
1752kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1753{
1754 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1755}
1756
1757int
1758kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1759{
1760 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1761}
1762
1763#ifdef HAVE_IPV6
1764int
1765kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1766{
1767 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1768}
1769
1770int
1771kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1772{
1773 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1774}
1775
1776/* Delete IPv6 route from the kernel. */
1777int
1778kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001779 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001780{
paul7021c422003-07-15 12:52:22 +00001781 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1782 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001783}
1784#endif /* HAVE_IPV6 */
1785
1786/* Interface address modification. */
1787int
1788netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001789 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001790{
1791 int bytelen;
1792 struct prefix *p;
1793
paul7021c422003-07-15 12:52:22 +00001794 struct
paul718e3742002-12-13 20:15:29 +00001795 {
1796 struct nlmsghdr n;
1797 struct ifaddrmsg ifa;
1798 char buf[1024];
1799 } req;
1800
1801 p = ifc->address;
1802 memset (&req, 0, sizeof req);
1803
1804 bytelen = (family == AF_INET ? 4 : 16);
1805
paul7021c422003-07-15 12:52:22 +00001806 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001807 req.n.nlmsg_flags = NLM_F_REQUEST;
1808 req.n.nlmsg_type = cmd;
1809 req.ifa.ifa_family = family;
1810
1811 req.ifa.ifa_index = ifp->ifindex;
1812 req.ifa.ifa_prefixlen = p->prefixlen;
1813
1814 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1815
1816 if (family == AF_INET && cmd == RTM_NEWADDR)
1817 {
1818 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001819 {
1820 p = ifc->destination;
1821 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1822 bytelen);
1823 }
paul718e3742002-12-13 20:15:29 +00001824 }
1825
1826 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1827 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001828
paul718e3742002-12-13 20:15:29 +00001829 if (ifc->label)
1830 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001831 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001832
1833 return netlink_talk (&req.n, &netlink_cmd);
1834}
1835
1836int
1837kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1838{
1839 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1840}
1841
1842int
1843kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1844{
1845 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1846}
1847
paul718e3742002-12-13 20:15:29 +00001848
1849extern struct thread_master *master;
1850
1851/* Kernel route reflection. */
1852int
1853kernel_read (struct thread *thread)
1854{
1855 int ret;
1856 int sock;
1857
1858 sock = THREAD_FD (thread);
1859 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001860 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001861
1862 return 0;
1863}
1864
1865/* Exported interface function. This function simply calls
1866 netlink_socket (). */
1867void
1868kernel_init ()
1869{
1870 unsigned long groups;
1871
paul7021c422003-07-15 12:52:22 +00001872 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001873#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001874 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001875#endif /* HAVE_IPV6 */
1876 netlink_socket (&netlink, groups);
1877 netlink_socket (&netlink_cmd, 0);
1878
1879 /* Register kernel socket. */
1880 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001881 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001882}