blob: 6db8496de6ae29f318c16527de72964d3ec3258c [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 */
hasso1ada8192005-06-12 11:28:18 +000052 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
paul718e3742002-12-13 20:15:29 +000053
paul7021c422003-07-15 12:52:22 +000054struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000055 {RTM_NEWROUTE, "RTM_NEWROUTE"},
56 {RTM_DELROUTE, "RTM_DELROUTE"},
57 {RTM_GETROUTE, "RTM_GETROUTE"},
58 {RTM_NEWLINK, "RTM_NEWLINK"},
59 {RTM_DELLINK, "RTM_DELLINK"},
60 {RTM_GETLINK, "RTM_GETLINK"},
61 {RTM_NEWADDR, "RTM_NEWADDR"},
62 {RTM_DELADDR, "RTM_DELADDR"},
63 {RTM_GETADDR, "RTM_GETADDR"},
paul7021c422003-07-15 12:52:22 +000064 {0, NULL}
paul718e3742002-12-13 20:15:29 +000065};
66
hassofce954f2004-10-07 20:29:24 +000067const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000068{
69 "none",
70 "Directly connected",
71 "Interface route",
72 "IPv4 nexthop",
73 "IPv4 nexthop with ifindex",
74 "IPv4 nexthop with ifname",
hassofa599802005-04-09 16:59:28 +000075 "IPv6 nexthop",
paul7021c422003-07-15 12:52:22 +000076 "IPv6 nexthop with ifindex",
77 "IPv6 nexthop with ifname",
78 "Null0 nexthop",
79};
80
81
paulb21b19c2003-06-15 01:28:29 +000082extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000083
pauledd7c242003-06-04 13:59:38 +000084extern struct zebra_privs_t zserv_privs;
85
hassoc34b6b52004-08-31 13:41:49 +000086extern u_int32_t nl_rcvbufsize;
87
ajsd2fc8892005-04-02 18:38:43 +000088/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
89 names and ifindex values. */
90static void
91set_ifindex(struct interface *ifp, unsigned int ifi_index)
92{
93 struct interface *oifp;
94
95 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
96 {
97 if (ifi_index == IFINDEX_INTERNAL)
98 zlog_err("Netlink is setting interface %s ifindex to reserved "
99 "internal value %u", ifp->name, ifi_index);
100 else
101 {
102 if (IS_ZEBRA_DEBUG_KERNEL)
103 zlog_debug("interface index %d was renamed from %s to %s",
104 ifi_index, oifp->name, ifp->name);
105 if (if_is_up(oifp))
106 zlog_err("interface rename detected on up interface: index %d "
107 "was renamed from %s to %s, results are uncertain!",
108 ifi_index, oifp->name, ifp->name);
109 if_delete_update(oifp);
110 }
111 }
112 ifp->ifindex = ifi_index;
113}
114
paul718e3742002-12-13 20:15:29 +0000115/* Make socket for Linux netlink interface. */
116static int
117netlink_socket (struct nlsock *nl, unsigned long groups)
118{
119 int ret;
120 struct sockaddr_nl snl;
121 int sock;
122 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000123 int save_errno;
paul718e3742002-12-13 20:15:29 +0000124
125 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
126 if (sock < 0)
127 {
128 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000129 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000130 return -1;
131 }
132
133 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
134 if (ret < 0)
135 {
136 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000137 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000138 close (sock);
139 return -1;
140 }
paul7021c422003-07-15 12:52:22 +0000141
hassoc34b6b52004-08-31 13:41:49 +0000142 /* Set receive buffer size if it's set from command line */
143 if (nl_rcvbufsize)
144 {
145 u_int32_t oldsize, oldlen;
146 u_int32_t newsize, newlen;
147
148 oldlen = sizeof(oldsize);
149 newlen = sizeof(newsize);
150
151 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
152 if (ret < 0)
153 {
154 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000155 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000156 close (sock);
157 return -1;
158 }
159
160 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
161 sizeof(nl_rcvbufsize));
162 if (ret < 0)
163 {
164 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000165 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000166 close (sock);
167 return -1;
168 }
169
170 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
171 if (ret < 0)
172 {
173 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000174 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000175 close (sock);
176 return -1;
177 }
178
179 zlog (NULL, LOG_INFO,
180 "Setting netlink socket receive buffer size: %u -> %u",
181 oldsize, newsize);
182 }
183
paul718e3742002-12-13 20:15:29 +0000184 memset (&snl, 0, sizeof snl);
185 snl.nl_family = AF_NETLINK;
186 snl.nl_groups = groups;
187
188 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000189 if (zserv_privs.change (ZPRIVS_RAISE))
190 {
191 zlog (NULL, LOG_ERR, "Can't raise privileges");
192 return -1;
193 }
pauledd7c242003-06-04 13:59:38 +0000194
paul718e3742002-12-13 20:15:29 +0000195 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000196 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000197 if (zserv_privs.change (ZPRIVS_LOWER))
198 zlog (NULL, LOG_ERR, "Can't lower privileges");
199
paul718e3742002-12-13 20:15:29 +0000200 if (ret < 0)
201 {
paul7021c422003-07-15 12:52:22 +0000202 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000203 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000204 close (sock);
205 return -1;
206 }
paul7021c422003-07-15 12:52:22 +0000207
paul718e3742002-12-13 20:15:29 +0000208 /* multiple netlink sockets will have different nl_pid */
209 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000210 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000211 if (ret < 0 || namelen != sizeof snl)
212 {
213 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000214 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000215 close (sock);
216 return -1;
217 }
218
219 nl->snl = snl;
220 nl->sock = sock;
221 return ret;
222}
223
paul7021c422003-07-15 12:52:22 +0000224int
225set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000226{
227
228 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000229 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000230 {
paul7021c422003-07-15 12:52:22 +0000231 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000232 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000233 return -1;
234 }
235 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000236 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000237 {
paul7021c422003-07-15 12:52:22 +0000238 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000239 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000240 return -1;
241 }
242 return 0;
243}
244
paul7021c422003-07-15 12:52:22 +0000245int
246set_netlink_nonblocking (struct nlsock *nl, int *flags)
247{
paul5f37d862003-04-19 00:11:28 +0000248 /* Restore socket flags for nonblocking I/O */
249 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000250 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000251 {
paul7021c422003-07-15 12:52:22 +0000252 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000253 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000254 return -1;
255 }
256 return 0;
257}
258
paul718e3742002-12-13 20:15:29 +0000259/* Get type specified information from netlink. */
260static int
261netlink_request (int family, int type, struct nlsock *nl)
262{
263 int ret;
264 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000265 int save_errno;
paul718e3742002-12-13 20:15:29 +0000266
267 struct
268 {
269 struct nlmsghdr nlh;
270 struct rtgenmsg g;
271 } req;
272
273
274 /* Check netlink socket. */
275 if (nl->sock < 0)
276 {
277 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
278 return -1;
279 }
280
281 memset (&snl, 0, sizeof snl);
282 snl.nl_family = AF_NETLINK;
283
ajsc05612b2005-10-01 16:36:54 +0000284 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000285 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 {
hasso1ada8192005-06-12 11:28:18 +0000394 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
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), "
hasso1ada8192005-06-12 11:28:18 +0000428 "seq=%u, pid=%u",
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)
hasso1ada8192005-06-12 11:28:18 +0000442 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
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",
hasso1ada8192005-06-12 11:28:18 +0000452 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000453 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,
paul0752ef02005-11-03 12:35:21 +0000689 (struct in_addr *) broad);
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,
paul0752ef02005-11-03 12:35:21 +0000697 (struct in6_addr *) broad, label);
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
hassobe61c4e2005-08-27 06:05:47 +0000797 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
798 metric, 0);
paul718e3742002-12-13 20:15:29 +0000799 }
800#endif /* HAVE_IPV6 */
801
802 return 0;
803}
804
paul7021c422003-07-15 12:52:22 +0000805struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000806 {RTPROT_REDIRECT, "redirect"},
807 {RTPROT_KERNEL, "kernel"},
808 {RTPROT_BOOT, "boot"},
809 {RTPROT_STATIC, "static"},
810 {RTPROT_GATED, "GateD"},
811 {RTPROT_RA, "router advertisement"},
812 {RTPROT_MRT, "MRT"},
813 {RTPROT_ZEBRA, "Zebra"},
814#ifdef RTPROT_BIRD
815 {RTPROT_BIRD, "BIRD"},
816#endif /* RTPROT_BIRD */
817 {0, NULL}
818};
819
820/* Routing information change from the kernel. */
821int
822netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
823{
824 int len;
825 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000826 struct rtattr *tb[RTA_MAX + 1];
827
828 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000829
830 int index;
831 int table;
832 void *dest;
833 void *gate;
834
835 rtm = NLMSG_DATA (h);
836
paul7021c422003-07-15 12:52:22 +0000837 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000838 {
839 /* If this is not route add/delete message print warning. */
840 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
841 return 0;
842 }
843
844 /* Connected route. */
845 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000846 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000847 h->nlmsg_type ==
848 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
849 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
850 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
851 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000852
853 if (rtm->rtm_type != RTN_UNICAST)
854 {
855 return 0;
856 }
857
858 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000859 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000860 {
861 return 0;
862 }
863
paul7021c422003-07-15 12:52:22 +0000864 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000865 if (len < 0)
866 return -1;
867
868 memset (tb, 0, sizeof tb);
869 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
870
871 if (rtm->rtm_flags & RTM_F_CLONED)
872 return 0;
873 if (rtm->rtm_protocol == RTPROT_REDIRECT)
874 return 0;
875 if (rtm->rtm_protocol == RTPROT_KERNEL)
876 return 0;
877
878 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
879 return 0;
880
881 if (rtm->rtm_src_len != 0)
882 {
883 zlog_warn ("netlink_route_change(): no src len");
884 return 0;
885 }
paul7021c422003-07-15 12:52:22 +0000886
paul718e3742002-12-13 20:15:29 +0000887 index = 0;
888 dest = NULL;
889 gate = NULL;
890
891 if (tb[RTA_OIF])
892 index = *(int *) RTA_DATA (tb[RTA_OIF]);
893
894 if (tb[RTA_DST])
895 dest = RTA_DATA (tb[RTA_DST]);
896 else
897 dest = anyaddr;
898
899 if (tb[RTA_GATEWAY])
900 gate = RTA_DATA (tb[RTA_GATEWAY]);
901
902 if (rtm->rtm_family == AF_INET)
903 {
904 struct prefix_ipv4 p;
905 p.family = AF_INET;
906 memcpy (&p.prefix, dest, 4);
907 p.prefixlen = rtm->rtm_dst_len;
908
909 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000910 {
911 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000912 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000913 inet_ntoa (p.prefix), p.prefixlen);
914 else
ajsb6178002004-12-07 21:12:56 +0000915 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000916 inet_ntoa (p.prefix), p.prefixlen);
917 }
paul718e3742002-12-13 20:15:29 +0000918
919 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000920 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000921 else
paul7021c422003-07-15 12:52:22 +0000922 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000923 }
924
925#ifdef HAVE_IPV6
926 if (rtm->rtm_family == AF_INET6)
927 {
928 struct prefix_ipv6 p;
929 char buf[BUFSIZ];
930
931 p.family = AF_INET6;
932 memcpy (&p.prefix, dest, 16);
933 p.prefixlen = rtm->rtm_dst_len;
934
935 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000936 {
937 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000938 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000939 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
940 p.prefixlen);
941 else
ajsb6178002004-12-07 21:12:56 +0000942 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000943 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
944 p.prefixlen);
945 }
paul718e3742002-12-13 20:15:29 +0000946
947 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000948 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000949 else
paul7021c422003-07-15 12:52:22 +0000950 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000951 }
952#endif /* HAVE_IPV6 */
953
954 return 0;
955}
956
957int
958netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
959{
960 int len;
961 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000962 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000963 struct interface *ifp;
964 char *name;
965
966 ifi = NLMSG_DATA (h);
967
paul7021c422003-07-15 12:52:22 +0000968 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000969 {
970 /* If this is not link add/delete message so print warning. */
971 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000972 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000973 return 0;
974 }
975
976 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
977 if (len < 0)
978 return -1;
979
980 /* Looking up interface name. */
981 memset (tb, 0, sizeof tb);
982 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000983
paul1e193152005-02-14 23:53:05 +0000984#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000985 /* check for wireless messages to ignore */
986 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
987 {
988 if (IS_ZEBRA_DEBUG_KERNEL)
989 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
990 return 0;
991 }
paul1e193152005-02-14 23:53:05 +0000992#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000993
paul718e3742002-12-13 20:15:29 +0000994 if (tb[IFLA_IFNAME] == NULL)
995 return -1;
paul7021c422003-07-15 12:52:22 +0000996 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000997
998 /* Add interface. */
999 if (h->nlmsg_type == RTM_NEWLINK)
1000 {
1001 ifp = if_lookup_by_name (name);
1002
paul7021c422003-07-15 12:52:22 +00001003 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1004 {
1005 if (ifp == NULL)
1006 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001007
ajsd2fc8892005-04-02 18:38:43 +00001008 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001009 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001010 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001011 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001012
paul7021c422003-07-15 12:52:22 +00001013 /* If new link is added. */
1014 if_add_update (ifp);
1015 }
paul718e3742002-12-13 20:15:29 +00001016 else
paul7021c422003-07-15 12:52:22 +00001017 {
1018 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001019 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001020 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001021 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001022
paul7021c422003-07-15 12:52:22 +00001023 if (if_is_operative (ifp))
1024 {
1025 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1026 if (!if_is_operative (ifp))
1027 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001028 else
1029 /* Must notify client daemons of new interface status. */
1030 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001031 }
1032 else
1033 {
1034 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1035 if (if_is_operative (ifp))
1036 if_up (ifp);
1037 }
1038 }
paul718e3742002-12-13 20:15:29 +00001039 }
1040 else
1041 {
1042 /* RTM_DELLINK. */
1043 ifp = if_lookup_by_name (name);
1044
1045 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001046 {
1047 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001048 name);
paul7021c422003-07-15 12:52:22 +00001049 return 0;
1050 }
1051
paul718e3742002-12-13 20:15:29 +00001052 if_delete_update (ifp);
1053 }
1054
1055 return 0;
1056}
1057
1058int
1059netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1060{
1061 switch (h->nlmsg_type)
1062 {
1063 case RTM_NEWROUTE:
1064 return netlink_route_change (snl, h);
1065 break;
1066 case RTM_DELROUTE:
1067 return netlink_route_change (snl, h);
1068 break;
1069 case RTM_NEWLINK:
1070 return netlink_link_change (snl, h);
1071 break;
1072 case RTM_DELLINK:
1073 return netlink_link_change (snl, h);
1074 break;
1075 case RTM_NEWADDR:
1076 return netlink_interface_addr (snl, h);
1077 break;
1078 case RTM_DELADDR:
1079 return netlink_interface_addr (snl, h);
1080 break;
1081 default:
1082 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1083 break;
1084 }
1085 return 0;
1086}
1087
1088/* Interface lookup by netlink socket. */
1089int
1090interface_lookup_netlink ()
1091{
1092 int ret;
paul5f37d862003-04-19 00:11:28 +00001093 int flags;
1094 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001095
paul5f37d862003-04-19 00:11:28 +00001096 /*
1097 * Change netlink socket flags to blocking to ensure we get
1098 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001099 */
1100 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1101 if (snb_ret < 0)
1102 zlog (NULL, LOG_WARNING,
1103 "%s:%i Warning: Could not set netlink socket to blocking.",
1104 __FUNCTION__, __LINE__);
1105
paul718e3742002-12-13 20:15:29 +00001106 /* Get interface information. */
1107 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1108 if (ret < 0)
1109 return ret;
1110 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1111 if (ret < 0)
1112 return ret;
1113
1114 /* Get IPv4 address of the interfaces. */
1115 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1116 if (ret < 0)
1117 return ret;
1118 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1119 if (ret < 0)
1120 return ret;
1121
1122#ifdef HAVE_IPV6
1123 /* Get IPv6 address of the interfaces. */
1124 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1125 if (ret < 0)
1126 return ret;
1127 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1128 if (ret < 0)
1129 return ret;
1130#endif /* HAVE_IPV6 */
1131
paul7021c422003-07-15 12:52:22 +00001132 /* restore socket flags */
1133 if (snb_ret == 0)
1134 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001135 return 0;
1136}
1137
1138/* Routing table read function using netlink interface. Only called
1139 bootstrap time. */
1140int
1141netlink_route_read ()
1142{
1143 int ret;
paul5f37d862003-04-19 00:11:28 +00001144 int flags;
1145 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001146
paul5f37d862003-04-19 00:11:28 +00001147 /*
1148 * Change netlink socket flags to blocking to ensure we get
1149 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001150 */
1151 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1152 if (snb_ret < 0)
1153 zlog (NULL, LOG_WARNING,
1154 "%s:%i Warning: Could not set netlink socket to blocking.",
1155 __FUNCTION__, __LINE__);
1156
paul718e3742002-12-13 20:15:29 +00001157 /* Get IPv4 routing table. */
1158 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1159 if (ret < 0)
1160 return ret;
1161 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1162 if (ret < 0)
1163 return ret;
1164
1165#ifdef HAVE_IPV6
1166 /* Get IPv6 routing table. */
1167 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1168 if (ret < 0)
1169 return ret;
1170 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1171 if (ret < 0)
1172 return ret;
1173#endif /* HAVE_IPV6 */
1174
paul5f37d862003-04-19 00:11:28 +00001175 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001176 if (snb_ret == 0)
1177 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001178 return 0;
1179}
1180
1181/* Utility function comes from iproute2.
1182 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1183int
1184addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1185{
1186 int len;
1187 struct rtattr *rta;
1188
paul7021c422003-07-15 12:52:22 +00001189 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001190
paul7021c422003-07-15 12:52:22 +00001191 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001192 return -1;
1193
paul7021c422003-07-15 12:52:22 +00001194 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001195 rta->rta_type = type;
1196 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001197 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001198 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1199
1200 return 0;
1201}
1202
1203int
1204rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1205{
1206 int len;
1207 struct rtattr *subrta;
1208
paul7021c422003-07-15 12:52:22 +00001209 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001210
paul7021c422003-07-15 12:52:22 +00001211 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001212 return -1;
1213
paul7021c422003-07-15 12:52:22 +00001214 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001215 subrta->rta_type = type;
1216 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001217 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001218 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1219
1220 return 0;
1221}
1222
1223/* Utility function comes from iproute2.
1224 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1225int
1226addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1227{
1228 int len;
1229 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001230
1231 len = RTA_LENGTH (4);
1232
paul718e3742002-12-13 20:15:29 +00001233 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1234 return -1;
1235
paul7021c422003-07-15 12:52:22 +00001236 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001237 rta->rta_type = type;
1238 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001239 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001240 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1241
1242 return 0;
1243}
1244
1245static int
1246netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1247{
hassob7ed1ec2005-03-31 20:13:49 +00001248 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001249 return 0;
1250}
1251
1252/* sendmsg() to netlink socket then recvmsg(). */
1253int
1254netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1255{
1256 int status;
1257 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001258 struct iovec iov = { (void *) n, n->nlmsg_len };
1259 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001260 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001261 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001262 int save_errno;
paul7021c422003-07-15 12:52:22 +00001263
paul718e3742002-12-13 20:15:29 +00001264 memset (&snl, 0, sizeof snl);
1265 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001266
hassob7ed1ec2005-03-31 20:13:49 +00001267 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001268
1269 /* Request an acknowledgement by setting NLM_F_ACK */
1270 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001271
1272 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001273 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001274 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1275 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001276
1277 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001278 if (zserv_privs.change (ZPRIVS_RAISE))
1279 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001280 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001281 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001282 if (zserv_privs.change (ZPRIVS_LOWER))
1283 zlog (NULL, LOG_ERR, "Can't lower privileges");
1284
paul718e3742002-12-13 20:15:29 +00001285 if (status < 0)
1286 {
1287 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001288 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001289 return -1;
1290 }
paul7021c422003-07-15 12:52:22 +00001291
paul718e3742002-12-13 20:15:29 +00001292 /*
1293 * Change socket flags for blocking I/O.
1294 * This ensures we wait for a reply in netlink_parse_info().
1295 */
paul7021c422003-07-15 12:52:22 +00001296 snb_ret = set_netlink_blocking (nl, &flags);
1297 if (snb_ret < 0)
1298 zlog (NULL, LOG_WARNING,
1299 "%s:%i Warning: Could not set netlink socket to blocking.",
1300 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001301
1302 /*
1303 * Get reply from netlink socket.
1304 * The reply should either be an acknowlegement or an error.
1305 */
1306 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001307
paul718e3742002-12-13 20:15:29 +00001308 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001309 if (snb_ret == 0)
1310 set_netlink_nonblocking (nl, &flags);
1311
paul718e3742002-12-13 20:15:29 +00001312 return status;
1313}
1314
1315/* Routing table change via netlink interface. */
1316int
1317netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001318 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001319{
1320 int ret;
1321 int bytelen;
1322 struct sockaddr_nl snl;
1323 int discard;
1324
paul7021c422003-07-15 12:52:22 +00001325 struct
paul718e3742002-12-13 20:15:29 +00001326 {
1327 struct nlmsghdr n;
1328 struct rtmsg r;
1329 char buf[1024];
1330 } req;
1331
1332 memset (&req, 0, sizeof req);
1333
1334 bytelen = (family == AF_INET ? 4 : 16);
1335
1336 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1337 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1338 req.n.nlmsg_type = cmd;
1339 req.r.rtm_family = family;
1340 req.r.rtm_table = table;
1341 req.r.rtm_dst_len = length;
1342
hasso81dfcaa2003-05-25 19:21:25 +00001343 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1344 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001345 discard = 1;
1346 else
1347 discard = 0;
1348
paul7021c422003-07-15 12:52:22 +00001349 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001350 {
1351 req.r.rtm_protocol = RTPROT_ZEBRA;
1352 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1353
paul7021c422003-07-15 12:52:22 +00001354 if (discard)
paul595db7f2003-05-25 21:35:06 +00001355 {
1356 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1357 req.r.rtm_type = RTN_BLACKHOLE;
1358 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1359 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001360 else
1361 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1362 }
paul595db7f2003-05-25 21:35:06 +00001363 else
paul7021c422003-07-15 12:52:22 +00001364 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001365 }
1366
1367 if (dest)
1368 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1369
paul7021c422003-07-15 12:52:22 +00001370 if (!discard)
paul718e3742002-12-13 20:15:29 +00001371 {
1372 if (gate)
paul7021c422003-07-15 12:52:22 +00001373 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001374 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001375 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001376 }
1377
1378 /* Destination netlink address. */
1379 memset (&snl, 0, sizeof snl);
1380 snl.nl_family = AF_NETLINK;
1381
1382 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001383 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001384 if (ret < 0)
1385 return -1;
1386
1387 return 0;
1388}
1389
1390/* Routing table change via netlink interface. */
1391int
1392netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001393 int family)
paul718e3742002-12-13 20:15:29 +00001394{
1395 int bytelen;
1396 struct sockaddr_nl snl;
1397 struct nexthop *nexthop = NULL;
1398 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001399 int discard;
1400
paul7021c422003-07-15 12:52:22 +00001401 struct
paul718e3742002-12-13 20:15:29 +00001402 {
1403 struct nlmsghdr n;
1404 struct rtmsg r;
1405 char buf[1024];
1406 } req;
1407
1408 memset (&req, 0, sizeof req);
1409
1410 bytelen = (family == AF_INET ? 4 : 16);
1411
1412 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1413 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1414 req.n.nlmsg_type = cmd;
1415 req.r.rtm_family = family;
1416 req.r.rtm_table = rib->table;
1417 req.r.rtm_dst_len = p->prefixlen;
1418
paul7021c422003-07-15 12:52:22 +00001419 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001420 discard = 1;
1421 else
1422 discard = 0;
1423
paul7021c422003-07-15 12:52:22 +00001424 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001425 {
1426 req.r.rtm_protocol = RTPROT_ZEBRA;
1427 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1428
paul7021c422003-07-15 12:52:22 +00001429 if (discard)
paul595db7f2003-05-25 21:35:06 +00001430 {
1431 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1432 req.r.rtm_type = RTN_BLACKHOLE;
1433 else if (rib->flags & ZEBRA_FLAG_REJECT)
1434 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001435 else
1436 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1437 }
paul595db7f2003-05-25 21:35:06 +00001438 else
paul7021c422003-07-15 12:52:22 +00001439 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001440 }
1441
1442 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1443
1444 /* Metric. */
1445 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1446
1447 if (discard)
1448 {
1449 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001450 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1451 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001452 goto skip;
1453 }
1454
1455 /* Multipath case. */
1456 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1457 {
1458 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001459 {
paul5ec90d22003-06-19 01:41:37 +00001460
paul7021c422003-07-15 12:52:22 +00001461 if ((cmd == RTM_NEWROUTE
1462 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1463 || (cmd == RTM_DELROUTE
1464 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1465 {
paul5ec90d22003-06-19 01:41:37 +00001466
paul7021c422003-07-15 12:52:22 +00001467 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1468 {
1469 if (IS_ZEBRA_DEBUG_KERNEL)
1470 {
ajsb6178002004-12-07 21:12:56 +00001471 zlog_debug
paul7021c422003-07-15 12:52:22 +00001472 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001473 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001474#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001475 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001476 inet6_ntoa (p->u.prefix6),
1477#else
1478 inet_ntoa (p->u.prefix4),
1479#endif /* HAVE_IPV6 */
1480
1481 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001482 }
paul5ec90d22003-06-19 01:41:37 +00001483
paul7021c422003-07-15 12:52:22 +00001484 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1485 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001486 {
1487 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1488 &nexthop->rgate.ipv4, bytelen);
1489
1490 if (IS_ZEBRA_DEBUG_KERNEL)
1491 zlog_debug("netlink_route_multipath() (recursive, "
1492 "1 hop): nexthop via %s if %u",
1493 inet_ntoa (nexthop->rgate.ipv4),
1494 nexthop->rifindex);
1495 }
paul718e3742002-12-13 20:15:29 +00001496#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001497 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1498 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1499 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001500 {
1501 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1502 &nexthop->rgate.ipv6, bytelen);
1503
1504 if (IS_ZEBRA_DEBUG_KERNEL)
1505 zlog_debug("netlink_route_multipath() (recursive, "
1506 "1 hop): nexthop via %s if %u",
1507 inet6_ntoa (nexthop->rgate.ipv6),
1508 nexthop->rifindex);
1509 }
paul718e3742002-12-13 20:15:29 +00001510#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001511 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1512 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1513 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1514 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1515 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001516 {
1517 addattr32 (&req.n, sizeof req, RTA_OIF,
1518 nexthop->rifindex);
1519
1520 if (IS_ZEBRA_DEBUG_KERNEL)
1521 zlog_debug("netlink_route_multipath() (recursive, "
1522 "1 hop): nexthop via if %u",
1523 nexthop->rifindex);
1524 }
paul7021c422003-07-15 12:52:22 +00001525 }
1526 else
1527 {
1528 if (IS_ZEBRA_DEBUG_KERNEL)
1529 {
ajsb6178002004-12-07 21:12:56 +00001530 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001531 ("netlink_route_multipath() (single hop): "
1532 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001533#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001534 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001535 inet6_ntoa (p->u.prefix6),
1536#else
1537 inet_ntoa (p->u.prefix4),
1538#endif /* HAVE_IPV6 */
1539 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001540 }
paul5ec90d22003-06-19 01:41:37 +00001541
paul7021c422003-07-15 12:52:22 +00001542 if (nexthop->type == NEXTHOP_TYPE_IPV4
1543 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001544 {
1545 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1546 &nexthop->gate.ipv4, bytelen);
1547
1548 if (IS_ZEBRA_DEBUG_KERNEL)
1549 zlog_debug("netlink_route_multipath() (single hop): "
1550 "nexthop via %s if %u",
1551 inet_ntoa (nexthop->gate.ipv4),
1552 nexthop->ifindex);
1553 }
paul718e3742002-12-13 20:15:29 +00001554#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001555 if (nexthop->type == NEXTHOP_TYPE_IPV6
1556 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1557 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001558 {
1559 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1560 &nexthop->gate.ipv6, bytelen);
1561
1562 if (IS_ZEBRA_DEBUG_KERNEL)
1563 zlog_debug("netlink_route_multipath() (single hop): "
1564 "nexthop via %s if %u",
1565 inet6_ntoa (nexthop->gate.ipv6),
1566 nexthop->ifindex);
1567 }
paul718e3742002-12-13 20:15:29 +00001568#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001569 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1570 || nexthop->type == NEXTHOP_TYPE_IFNAME
1571 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1572 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1573 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001574 {
1575 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1576
1577 if (IS_ZEBRA_DEBUG_KERNEL)
1578 zlog_debug("netlink_route_multipath() (single hop): "
1579 "nexthop via if %u", nexthop->ifindex);
1580 }
paul7021c422003-07-15 12:52:22 +00001581 }
paul718e3742002-12-13 20:15:29 +00001582
paul7021c422003-07-15 12:52:22 +00001583 if (cmd == RTM_NEWROUTE)
1584 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001585
paul7021c422003-07-15 12:52:22 +00001586 nexthop_num++;
1587 break;
1588 }
1589 }
paul718e3742002-12-13 20:15:29 +00001590 }
1591 else
1592 {
1593 char buf[1024];
1594 struct rtattr *rta = (void *) buf;
1595 struct rtnexthop *rtnh;
1596
1597 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001598 rta->rta_len = RTA_LENGTH (0);
1599 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001600
1601 nexthop_num = 0;
1602 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001603 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1604 nexthop = nexthop->next)
1605 {
1606 if ((cmd == RTM_NEWROUTE
1607 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1608 || (cmd == RTM_DELROUTE
1609 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1610 {
1611 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001612
paul7021c422003-07-15 12:52:22 +00001613 rtnh->rtnh_len = sizeof (*rtnh);
1614 rtnh->rtnh_flags = 0;
1615 rtnh->rtnh_hops = 0;
1616 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001617
paul7021c422003-07-15 12:52:22 +00001618 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1619 {
1620 if (IS_ZEBRA_DEBUG_KERNEL)
1621 {
ajsb6178002004-12-07 21:12:56 +00001622 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001623 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001624 lookup (nlmsg_str, cmd),
1625#ifdef HAVE_IPV6
1626 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1627 inet6_ntoa (p->u.prefix6),
1628#else
1629 inet_ntoa (p->u.prefix4),
1630#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001631 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001632 }
1633 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1634 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1635 {
1636 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1637 &nexthop->rgate.ipv4, bytelen);
1638 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001639
1640 if (IS_ZEBRA_DEBUG_KERNEL)
1641 zlog_debug("netlink_route_multipath() (recursive, "
1642 "multihop): nexthop via %s if %u",
1643 inet_ntoa (nexthop->rgate.ipv4),
1644 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001645 }
paul718e3742002-12-13 20:15:29 +00001646#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001647 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1648 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1649 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001650 {
1651 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1652 &nexthop->rgate.ipv6, bytelen);
1653
1654 if (IS_ZEBRA_DEBUG_KERNEL)
1655 zlog_debug("netlink_route_multipath() (recursive, "
1656 "multihop): nexthop via %s if %u",
1657 inet6_ntoa (nexthop->rgate.ipv6),
1658 nexthop->rifindex);
1659 }
paul718e3742002-12-13 20:15:29 +00001660#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001661 /* ifindex */
1662 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1663 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1664 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1665 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1666 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001667 {
1668 rtnh->rtnh_ifindex = nexthop->rifindex;
1669
1670 if (IS_ZEBRA_DEBUG_KERNEL)
1671 zlog_debug("netlink_route_multipath() (recursive, "
1672 "multihop): nexthop via if %u",
1673 nexthop->rifindex);
1674 }
paul7021c422003-07-15 12:52:22 +00001675 else
hasso206d8052005-04-09 16:38:51 +00001676 {
1677 rtnh->rtnh_ifindex = 0;
1678 }
paul7021c422003-07-15 12:52:22 +00001679 }
1680 else
1681 {
1682 if (IS_ZEBRA_DEBUG_KERNEL)
1683 {
hasso206d8052005-04-09 16:38:51 +00001684 zlog_debug ("netlink_route_multipath() (multihop): "
1685 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001686#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001687 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001688 inet6_ntoa (p->u.prefix6),
1689#else
1690 inet_ntoa (p->u.prefix4),
1691#endif /* HAVE_IPV6 */
1692 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001693 }
1694 if (nexthop->type == NEXTHOP_TYPE_IPV4
1695 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1696 {
hasso206d8052005-04-09 16:38:51 +00001697 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1698 &nexthop->gate.ipv4, bytelen);
1699 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1700
1701 if (IS_ZEBRA_DEBUG_KERNEL)
1702 zlog_debug("netlink_route_multipath() (multihop): "
1703 "nexthop via %s if %u",
1704 inet_ntoa (nexthop->gate.ipv4),
1705 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001706 }
paul718e3742002-12-13 20:15:29 +00001707#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001708 if (nexthop->type == NEXTHOP_TYPE_IPV6
1709 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1710 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001711 {
1712 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1713 &nexthop->gate.ipv6, bytelen);
1714
1715 if (IS_ZEBRA_DEBUG_KERNEL)
1716 zlog_debug("netlink_route_multipath() (multihop): "
1717 "nexthop via %s if %u",
1718 inet6_ntoa (nexthop->gate.ipv6),
1719 nexthop->ifindex);
1720 }
paul718e3742002-12-13 20:15:29 +00001721#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001722 /* ifindex */
1723 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1724 || nexthop->type == NEXTHOP_TYPE_IFNAME
1725 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1726 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1727 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001728 {
1729 rtnh->rtnh_ifindex = nexthop->ifindex;
1730
1731 if (IS_ZEBRA_DEBUG_KERNEL)
1732 zlog_debug("netlink_route_multipath() (multihop): "
1733 "nexthop via if %u", nexthop->ifindex);
1734 }
paul7021c422003-07-15 12:52:22 +00001735 else
hasso206d8052005-04-09 16:38:51 +00001736 {
1737 rtnh->rtnh_ifindex = 0;
1738 }
paul7021c422003-07-15 12:52:22 +00001739 }
1740 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001741
paul7021c422003-07-15 12:52:22 +00001742 if (cmd == RTM_NEWROUTE)
1743 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1744 }
1745 }
paul718e3742002-12-13 20:15:29 +00001746
1747 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001748 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1749 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001750 }
1751
1752 /* If there is no useful nexthop then return. */
1753 if (nexthop_num == 0)
1754 {
1755 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001756 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001757 return 0;
1758 }
1759
paul7021c422003-07-15 12:52:22 +00001760skip:
paul718e3742002-12-13 20:15:29 +00001761
1762 /* Destination netlink address. */
1763 memset (&snl, 0, sizeof snl);
1764 snl.nl_family = AF_NETLINK;
1765
paul718e3742002-12-13 20:15:29 +00001766 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001767 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001768}
1769
1770int
1771kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1772{
1773 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1774}
1775
1776int
1777kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1778{
1779 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1780}
1781
1782#ifdef HAVE_IPV6
1783int
1784kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1785{
1786 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1787}
1788
1789int
1790kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1791{
1792 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1793}
1794
1795/* Delete IPv6 route from the kernel. */
1796int
1797kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001798 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001799{
paul7021c422003-07-15 12:52:22 +00001800 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1801 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001802}
1803#endif /* HAVE_IPV6 */
1804
1805/* Interface address modification. */
1806int
1807netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001808 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001809{
1810 int bytelen;
1811 struct prefix *p;
1812
paul7021c422003-07-15 12:52:22 +00001813 struct
paul718e3742002-12-13 20:15:29 +00001814 {
1815 struct nlmsghdr n;
1816 struct ifaddrmsg ifa;
1817 char buf[1024];
1818 } req;
1819
1820 p = ifc->address;
1821 memset (&req, 0, sizeof req);
1822
1823 bytelen = (family == AF_INET ? 4 : 16);
1824
paul7021c422003-07-15 12:52:22 +00001825 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001826 req.n.nlmsg_flags = NLM_F_REQUEST;
1827 req.n.nlmsg_type = cmd;
1828 req.ifa.ifa_family = family;
1829
1830 req.ifa.ifa_index = ifp->ifindex;
1831 req.ifa.ifa_prefixlen = p->prefixlen;
1832
1833 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1834
1835 if (family == AF_INET && cmd == RTM_NEWADDR)
1836 {
1837 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001838 {
1839 p = ifc->destination;
1840 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1841 bytelen);
1842 }
paul718e3742002-12-13 20:15:29 +00001843 }
1844
1845 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1846 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001847
paul718e3742002-12-13 20:15:29 +00001848 if (ifc->label)
1849 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001850 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001851
1852 return netlink_talk (&req.n, &netlink_cmd);
1853}
1854
1855int
1856kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1857{
1858 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1859}
1860
1861int
1862kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1863{
1864 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1865}
1866
paul718e3742002-12-13 20:15:29 +00001867
1868extern struct thread_master *master;
1869
1870/* Kernel route reflection. */
1871int
1872kernel_read (struct thread *thread)
1873{
1874 int ret;
1875 int sock;
1876
1877 sock = THREAD_FD (thread);
1878 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001879 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001880
1881 return 0;
1882}
1883
1884/* Exported interface function. This function simply calls
1885 netlink_socket (). */
1886void
1887kernel_init ()
1888{
1889 unsigned long groups;
1890
paul7021c422003-07-15 12:52:22 +00001891 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001892#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001893 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001894#endif /* HAVE_IPV6 */
1895 netlink_socket (&netlink, groups);
1896 netlink_socket (&netlink_cmd, 0);
1897
1898 /* Register kernel socket. */
1899 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001900 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001901}