blob: 3f22a6cc03e33ac7dda439becf2940fdcf08096e [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
284 req.nlh.nlmsg_len = sizeof req;
285 req.nlh.nlmsg_type = type;
286 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
287 req.nlh.nlmsg_pid = 0;
288 req.nlh.nlmsg_seq = ++nl->seq;
289 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000290
291 /* linux appears to check capabilities on every message
292 * have to raise caps for every message sent
293 */
paul7021c422003-07-15 12:52:22 +0000294 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000295 {
296 zlog (NULL, LOG_ERR, "Can't raise privileges");
297 return -1;
298 }
paul7021c422003-07-15 12:52:22 +0000299
300 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
301 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000302 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000303
304 if (zserv_privs.change (ZPRIVS_LOWER))
305 zlog (NULL, LOG_ERR, "Can't lower privileges");
306
paul718e3742002-12-13 20:15:29 +0000307 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000308 {
309 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000310 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000311 return -1;
312 }
pauledd7c242003-06-04 13:59:38 +0000313
paul718e3742002-12-13 20:15:29 +0000314 return 0;
315}
316
317/* Receive message from netlink interface and pass those information
318 to the given function. */
319static int
320netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000321 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000322{
323 int status;
324 int ret = 0;
325 int error;
326
327 while (1)
328 {
329 char buf[4096];
330 struct iovec iov = { buf, sizeof buf };
331 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000332 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000333 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000334 int save_errno;
paul718e3742002-12-13 20:15:29 +0000335
paul7021c422003-07-15 12:52:22 +0000336 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000337 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000338
paul718e3742002-12-13 20:15:29 +0000339 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000340 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000341
342 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000343 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000344
345 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000346 {
ajs4be019d2005-01-29 16:12:41 +0000347 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000348 continue;
ajs4be019d2005-01-29 16:12:41 +0000349 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000350 break;
ajs4be019d2005-01-29 16:12:41 +0000351 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
352 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000353 continue;
354 }
paul718e3742002-12-13 20:15:29 +0000355
356 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000357 {
358 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
359 return -1;
360 }
paul718e3742002-12-13 20:15:29 +0000361
362 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000363 {
364 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
365 nl->name, msg.msg_namelen);
366 return -1;
367 }
paulb84d3a12003-11-17 10:31:01 +0000368
369 /* JF: Ignore messages that aren't from the kernel */
370 if ( snl.nl_pid != 0 )
371 {
372 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
373 continue;
374 }
paul718e3742002-12-13 20:15:29 +0000375
hasso206d8052005-04-09 16:38:51 +0000376 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000377 h = NLMSG_NEXT (h, status))
378 {
379 /* Finish of reading. */
380 if (h->nlmsg_type == NLMSG_DONE)
381 return ret;
paul718e3742002-12-13 20:15:29 +0000382
paul7021c422003-07-15 12:52:22 +0000383 /* Error handling. */
384 if (h->nlmsg_type == NLMSG_ERROR)
385 {
386 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
387
paul718e3742002-12-13 20:15:29 +0000388 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000389 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000390 {
paul7021c422003-07-15 12:52:22 +0000391 if (IS_ZEBRA_DEBUG_KERNEL)
392 {
hasso1ada8192005-06-12 11:28:18 +0000393 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000394 __FUNCTION__, nl->name,
395 lookup (nlmsg_str, err->msg.nlmsg_type),
396 err->msg.nlmsg_type, err->msg.nlmsg_seq,
397 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000398 }
paul7021c422003-07-15 12:52:22 +0000399
400 /* return if not a multipart message, otherwise continue */
401 if (!(h->nlmsg_flags & NLM_F_MULTI))
402 {
403 return 0;
paul718e3742002-12-13 20:15:29 +0000404 }
paul7021c422003-07-15 12:52:22 +0000405 continue;
paul718e3742002-12-13 20:15:29 +0000406 }
paul7021c422003-07-15 12:52:22 +0000407
paul718e3742002-12-13 20:15:29 +0000408 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000409 {
410 zlog (NULL, LOG_ERR, "%s error: message truncated",
411 nl->name);
412 return -1;
413 }
pauld753e9e2003-01-22 19:45:50 +0000414
paul7021c422003-07-15 12:52:22 +0000415 /* Deal with Error Noise - MAG */
416 {
417 int loglvl = LOG_ERR;
418 int errnum = err->error;
419 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000420
paul7021c422003-07-15 12:52:22 +0000421 if (nl == &netlink_cmd
422 && (-errnum == ENODEV || -errnum == ESRCH)
423 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
424 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000425
paul7021c422003-07-15 12:52:22 +0000426 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
hasso1ada8192005-06-12 11:28:18 +0000427 "seq=%u, pid=%u",
ajs6099b3b2004-11-20 02:06:59 +0000428 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000429 lookup (nlmsg_str, msg_type),
430 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
431 }
432 /*
433 ret = -1;
434 continue;
435 */
436 return -1;
437 }
paul718e3742002-12-13 20:15:29 +0000438
paul7021c422003-07-15 12:52:22 +0000439 /* OK we got netlink message. */
440 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000441 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000442 nl->name,
443 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
444 h->nlmsg_seq, h->nlmsg_pid);
445
446 /* skip unsolicited messages originating from command socket */
447 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
448 {
449 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000450 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000451 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000452 continue;
453 }
454
455 error = (*filter) (&snl, h);
456 if (error < 0)
457 {
458 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
459 ret = error;
460 }
461 }
paul718e3742002-12-13 20:15:29 +0000462
463 /* After error care. */
464 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000465 {
466 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
467 continue;
468 }
paul718e3742002-12-13 20:15:29 +0000469 if (status)
paul7021c422003-07-15 12:52:22 +0000470 {
471 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
472 status);
473 return -1;
474 }
paul718e3742002-12-13 20:15:29 +0000475 }
476 return ret;
477}
478
479/* Utility function for parse rtattr. */
480static void
paul7021c422003-07-15 12:52:22 +0000481netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
482 int len)
paul718e3742002-12-13 20:15:29 +0000483{
paul7021c422003-07-15 12:52:22 +0000484 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000485 {
486 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000487 tb[rta->rta_type] = rta;
488 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000489 }
490}
491
492/* Called from interface_lookup_netlink(). This function is only used
493 during bootstrap. */
494int
495netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
496{
497 int len;
498 struct ifinfomsg *ifi;
499 struct rtattr *tb[IFLA_MAX + 1];
500 struct interface *ifp;
501 char *name;
502 int i;
503
504 ifi = NLMSG_DATA (h);
505
506 if (h->nlmsg_type != RTM_NEWLINK)
507 return 0;
508
509 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
510 if (len < 0)
511 return -1;
512
513 /* Looking up interface name. */
514 memset (tb, 0, sizeof tb);
515 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000516
paul1e193152005-02-14 23:53:05 +0000517#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000518 /* check for wireless messages to ignore */
519 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
520 {
521 if (IS_ZEBRA_DEBUG_KERNEL)
522 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
523 return 0;
524 }
paul1e193152005-02-14 23:53:05 +0000525#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000526
paul718e3742002-12-13 20:15:29 +0000527 if (tb[IFLA_IFNAME] == NULL)
528 return -1;
paul7021c422003-07-15 12:52:22 +0000529 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000530
531 /* Add interface. */
532 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000533 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000534 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000535 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000536 ifp->metric = 1;
537
538 /* Hardware type and address. */
539 ifp->hw_type = ifi->ifi_type;
540
541 if (tb[IFLA_ADDRESS])
542 {
543 int hw_addr_len;
544
paul7021c422003-07-15 12:52:22 +0000545 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000546
547 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000548 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000549 else
paul7021c422003-07-15 12:52:22 +0000550 {
551 ifp->hw_addr_len = hw_addr_len;
552 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000553
paul7021c422003-07-15 12:52:22 +0000554 for (i = 0; i < hw_addr_len; i++)
555 if (ifp->hw_addr[i] != 0)
556 break;
paul718e3742002-12-13 20:15:29 +0000557
paul7021c422003-07-15 12:52:22 +0000558 if (i == hw_addr_len)
559 ifp->hw_addr_len = 0;
560 else
561 ifp->hw_addr_len = hw_addr_len;
562 }
paul718e3742002-12-13 20:15:29 +0000563 }
564
565 if_add_update (ifp);
566
567 return 0;
568}
569
570/* Lookup interface IPv4/IPv6 address. */
571int
572netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
573{
574 int len;
575 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000576 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000577 struct interface *ifp;
578 void *addr = NULL;
579 void *broad = NULL;
580 u_char flags = 0;
581 char *label = NULL;
582
583 ifa = NLMSG_DATA (h);
584
paul7021c422003-07-15 12:52:22 +0000585 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000586#ifdef HAVE_IPV6
587 && ifa->ifa_family != AF_INET6
588#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000589 )
paul718e3742002-12-13 20:15:29 +0000590 return 0;
591
592 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
593 return 0;
594
paul7021c422003-07-15 12:52:22 +0000595 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000596 if (len < 0)
597 return -1;
598
599 memset (tb, 0, sizeof tb);
600 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
601
602 ifp = if_lookup_by_index (ifa->ifa_index);
603 if (ifp == NULL)
604 {
605 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000606 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000607 return -1;
608 }
609
paul7021c422003-07-15 12:52:22 +0000610 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000611 {
paul00df0c12002-12-13 21:07:36 +0000612 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000613 zlog_debug ("netlink_interface_addr %s %s:",
614 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000615 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000616 zlog_debug (" IFA_LOCAL %s/%d",
617 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
618 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000619 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000620 zlog_debug (" IFA_ADDRESS %s/%d",
621 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
622 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000623 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000624 zlog_debug (" IFA_BROADCAST %s/%d",
625 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
626 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000627 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000628 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000629 }
paul31a476c2003-09-29 19:54:53 +0000630
631 if (tb[IFA_ADDRESS] == NULL)
632 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
633
634 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000635 {
paul31a476c2003-09-29 19:54:53 +0000636 if (tb[IFA_LOCAL])
637 {
638 addr = RTA_DATA (tb[IFA_LOCAL]);
hasso3fb9cd62004-10-19 19:44:43 +0000639 if (tb[IFA_ADDRESS] &&
640 memcmp(RTA_DATA(tb[IFA_ADDRESS]),RTA_DATA(tb[IFA_LOCAL]),4))
641 /* if IFA_ADDRESS != IFA_LOCAL, then it's the peer address */
paul31a476c2003-09-29 19:54:53 +0000642 broad = RTA_DATA (tb[IFA_ADDRESS]);
643 else
644 broad = NULL;
645 }
646 else
647 {
648 if (tb[IFA_ADDRESS])
649 addr = RTA_DATA (tb[IFA_ADDRESS]);
650 else
651 addr = NULL;
652 }
paul7021c422003-07-15 12:52:22 +0000653 }
paul31a476c2003-09-29 19:54:53 +0000654 else
paul7021c422003-07-15 12:52:22 +0000655 {
paul31a476c2003-09-29 19:54:53 +0000656 if (tb[IFA_ADDRESS])
657 addr = RTA_DATA (tb[IFA_ADDRESS]);
658 else
659 addr = NULL;
660
661 if (tb[IFA_BROADCAST])
662 broad = RTA_DATA(tb[IFA_BROADCAST]);
663 else
664 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000665 }
paul00df0c12002-12-13 21:07:36 +0000666
paul718e3742002-12-13 20:15:29 +0000667 /* Flags. */
668 if (ifa->ifa_flags & IFA_F_SECONDARY)
669 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
670
671 /* Label */
672 if (tb[IFA_LABEL])
673 label = (char *) RTA_DATA (tb[IFA_LABEL]);
674
675 if (ifp && label && strcmp (ifp->name, label) == 0)
676 label = NULL;
677
678 /* Register interface address to the interface. */
679 if (ifa->ifa_family == AF_INET)
680 {
paul7021c422003-07-15 12:52:22 +0000681 if (h->nlmsg_type == RTM_NEWADDR)
682 connected_add_ipv4 (ifp, flags,
683 (struct in_addr *) addr, ifa->ifa_prefixlen,
684 (struct in_addr *) broad, label);
685 else
686 connected_delete_ipv4 (ifp, flags,
687 (struct in_addr *) addr, ifa->ifa_prefixlen,
688 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000689 }
690#ifdef HAVE_IPV6
691 if (ifa->ifa_family == AF_INET6)
692 {
693 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000694 connected_add_ipv6 (ifp,
695 (struct in6_addr *) addr, ifa->ifa_prefixlen,
696 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000697 else
paul7021c422003-07-15 12:52:22 +0000698 connected_delete_ipv6 (ifp,
699 (struct in6_addr *) addr, ifa->ifa_prefixlen,
700 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000701 }
paul7021c422003-07-15 12:52:22 +0000702#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000703
704 return 0;
705}
706
707/* Looking up routing table by netlink interface. */
708int
709netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
710{
711 int len;
712 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000713 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000714 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000715
716 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000717
718 int index;
719 int table;
hasso34195bf2004-04-06 12:07:06 +0000720 int metric;
721
paul718e3742002-12-13 20:15:29 +0000722 void *dest;
723 void *gate;
724
725 rtm = NLMSG_DATA (h);
726
727 if (h->nlmsg_type != RTM_NEWROUTE)
728 return 0;
729 if (rtm->rtm_type != RTN_UNICAST)
730 return 0;
731
732 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000733#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000734 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000735 return 0;
736#endif
737
paul7021c422003-07-15 12:52:22 +0000738 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000739 if (len < 0)
740 return -1;
741
742 memset (tb, 0, sizeof tb);
743 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
744
745 if (rtm->rtm_flags & RTM_F_CLONED)
746 return 0;
747 if (rtm->rtm_protocol == RTPROT_REDIRECT)
748 return 0;
749 if (rtm->rtm_protocol == RTPROT_KERNEL)
750 return 0;
751
752 if (rtm->rtm_src_len != 0)
753 return 0;
754
755 /* Route which inserted by Zebra. */
756 if (rtm->rtm_protocol == RTPROT_ZEBRA)
757 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000758
paul718e3742002-12-13 20:15:29 +0000759 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000760 metric = 0;
paul718e3742002-12-13 20:15:29 +0000761 dest = NULL;
762 gate = NULL;
763
764 if (tb[RTA_OIF])
765 index = *(int *) RTA_DATA (tb[RTA_OIF]);
766
767 if (tb[RTA_DST])
768 dest = RTA_DATA (tb[RTA_DST]);
769 else
770 dest = anyaddr;
771
772 /* Multipath treatment is needed. */
773 if (tb[RTA_GATEWAY])
774 gate = RTA_DATA (tb[RTA_GATEWAY]);
775
hasso34195bf2004-04-06 12:07:06 +0000776 if (tb[RTA_PRIORITY])
777 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
778
paul718e3742002-12-13 20:15:29 +0000779 if (rtm->rtm_family == AF_INET)
780 {
781 struct prefix_ipv4 p;
782 p.family = AF_INET;
783 memcpy (&p.prefix, dest, 4);
784 p.prefixlen = rtm->rtm_dst_len;
785
hasso34195bf2004-04-06 12:07:06 +0000786 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000787 }
788#ifdef HAVE_IPV6
789 if (rtm->rtm_family == AF_INET6)
790 {
791 struct prefix_ipv6 p;
792 p.family = AF_INET6;
793 memcpy (&p.prefix, dest, 16);
794 p.prefixlen = rtm->rtm_dst_len;
795
796 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
797 }
798#endif /* HAVE_IPV6 */
799
800 return 0;
801}
802
paul7021c422003-07-15 12:52:22 +0000803struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000804 {RTPROT_REDIRECT, "redirect"},
805 {RTPROT_KERNEL, "kernel"},
806 {RTPROT_BOOT, "boot"},
807 {RTPROT_STATIC, "static"},
808 {RTPROT_GATED, "GateD"},
809 {RTPROT_RA, "router advertisement"},
810 {RTPROT_MRT, "MRT"},
811 {RTPROT_ZEBRA, "Zebra"},
812#ifdef RTPROT_BIRD
813 {RTPROT_BIRD, "BIRD"},
814#endif /* RTPROT_BIRD */
815 {0, NULL}
816};
817
818/* Routing information change from the kernel. */
819int
820netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
821{
822 int len;
823 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000824 struct rtattr *tb[RTA_MAX + 1];
825
826 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000827
828 int index;
829 int table;
830 void *dest;
831 void *gate;
832
833 rtm = NLMSG_DATA (h);
834
paul7021c422003-07-15 12:52:22 +0000835 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000836 {
837 /* If this is not route add/delete message print warning. */
838 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
839 return 0;
840 }
841
842 /* Connected route. */
843 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000844 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000845 h->nlmsg_type ==
846 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
847 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
848 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
849 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000850
851 if (rtm->rtm_type != RTN_UNICAST)
852 {
853 return 0;
854 }
855
856 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000857 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000858 {
859 return 0;
860 }
861
paul7021c422003-07-15 12:52:22 +0000862 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000863 if (len < 0)
864 return -1;
865
866 memset (tb, 0, sizeof tb);
867 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
868
869 if (rtm->rtm_flags & RTM_F_CLONED)
870 return 0;
871 if (rtm->rtm_protocol == RTPROT_REDIRECT)
872 return 0;
873 if (rtm->rtm_protocol == RTPROT_KERNEL)
874 return 0;
875
876 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
877 return 0;
878
879 if (rtm->rtm_src_len != 0)
880 {
881 zlog_warn ("netlink_route_change(): no src len");
882 return 0;
883 }
paul7021c422003-07-15 12:52:22 +0000884
paul718e3742002-12-13 20:15:29 +0000885 index = 0;
886 dest = NULL;
887 gate = NULL;
888
889 if (tb[RTA_OIF])
890 index = *(int *) RTA_DATA (tb[RTA_OIF]);
891
892 if (tb[RTA_DST])
893 dest = RTA_DATA (tb[RTA_DST]);
894 else
895 dest = anyaddr;
896
897 if (tb[RTA_GATEWAY])
898 gate = RTA_DATA (tb[RTA_GATEWAY]);
899
900 if (rtm->rtm_family == AF_INET)
901 {
902 struct prefix_ipv4 p;
903 p.family = AF_INET;
904 memcpy (&p.prefix, dest, 4);
905 p.prefixlen = rtm->rtm_dst_len;
906
907 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000908 {
909 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000910 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000911 inet_ntoa (p.prefix), p.prefixlen);
912 else
ajsb6178002004-12-07 21:12:56 +0000913 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000914 inet_ntoa (p.prefix), p.prefixlen);
915 }
paul718e3742002-12-13 20:15:29 +0000916
917 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000918 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000919 else
paul7021c422003-07-15 12:52:22 +0000920 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000921 }
922
923#ifdef HAVE_IPV6
924 if (rtm->rtm_family == AF_INET6)
925 {
926 struct prefix_ipv6 p;
927 char buf[BUFSIZ];
928
929 p.family = AF_INET6;
930 memcpy (&p.prefix, dest, 16);
931 p.prefixlen = rtm->rtm_dst_len;
932
933 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000934 {
935 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000936 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000937 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
938 p.prefixlen);
939 else
ajsb6178002004-12-07 21:12:56 +0000940 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000941 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
942 p.prefixlen);
943 }
paul718e3742002-12-13 20:15:29 +0000944
945 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000946 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000947 else
paul7021c422003-07-15 12:52:22 +0000948 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000949 }
950#endif /* HAVE_IPV6 */
951
952 return 0;
953}
954
955int
956netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
957{
958 int len;
959 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000960 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000961 struct interface *ifp;
962 char *name;
963
964 ifi = NLMSG_DATA (h);
965
paul7021c422003-07-15 12:52:22 +0000966 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000967 {
968 /* If this is not link add/delete message so print warning. */
969 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000970 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000971 return 0;
972 }
973
974 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
975 if (len < 0)
976 return -1;
977
978 /* Looking up interface name. */
979 memset (tb, 0, sizeof tb);
980 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000981
paul1e193152005-02-14 23:53:05 +0000982#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000983 /* check for wireless messages to ignore */
984 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
985 {
986 if (IS_ZEBRA_DEBUG_KERNEL)
987 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
988 return 0;
989 }
paul1e193152005-02-14 23:53:05 +0000990#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000991
paul718e3742002-12-13 20:15:29 +0000992 if (tb[IFLA_IFNAME] == NULL)
993 return -1;
paul7021c422003-07-15 12:52:22 +0000994 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000995
996 /* Add interface. */
997 if (h->nlmsg_type == RTM_NEWLINK)
998 {
999 ifp = if_lookup_by_name (name);
1000
paul7021c422003-07-15 12:52:22 +00001001 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1002 {
1003 if (ifp == NULL)
1004 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001005
ajsd2fc8892005-04-02 18:38:43 +00001006 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001007 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001008 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001009 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001010
paul7021c422003-07-15 12:52:22 +00001011 /* If new link is added. */
1012 if_add_update (ifp);
1013 }
paul718e3742002-12-13 20:15:29 +00001014 else
paul7021c422003-07-15 12:52:22 +00001015 {
1016 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001017 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001018 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001019 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001020
paul7021c422003-07-15 12:52:22 +00001021 if (if_is_operative (ifp))
1022 {
1023 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1024 if (!if_is_operative (ifp))
1025 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001026 else
1027 /* Must notify client daemons of new interface status. */
1028 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001029 }
1030 else
1031 {
1032 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1033 if (if_is_operative (ifp))
1034 if_up (ifp);
1035 }
1036 }
paul718e3742002-12-13 20:15:29 +00001037 }
1038 else
1039 {
1040 /* RTM_DELLINK. */
1041 ifp = if_lookup_by_name (name);
1042
1043 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001044 {
1045 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001046 name);
paul7021c422003-07-15 12:52:22 +00001047 return 0;
1048 }
1049
paul718e3742002-12-13 20:15:29 +00001050 if_delete_update (ifp);
1051 }
1052
1053 return 0;
1054}
1055
1056int
1057netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1058{
1059 switch (h->nlmsg_type)
1060 {
1061 case RTM_NEWROUTE:
1062 return netlink_route_change (snl, h);
1063 break;
1064 case RTM_DELROUTE:
1065 return netlink_route_change (snl, h);
1066 break;
1067 case RTM_NEWLINK:
1068 return netlink_link_change (snl, h);
1069 break;
1070 case RTM_DELLINK:
1071 return netlink_link_change (snl, h);
1072 break;
1073 case RTM_NEWADDR:
1074 return netlink_interface_addr (snl, h);
1075 break;
1076 case RTM_DELADDR:
1077 return netlink_interface_addr (snl, h);
1078 break;
1079 default:
1080 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1081 break;
1082 }
1083 return 0;
1084}
1085
1086/* Interface lookup by netlink socket. */
1087int
1088interface_lookup_netlink ()
1089{
1090 int ret;
paul5f37d862003-04-19 00:11:28 +00001091 int flags;
1092 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001093
paul5f37d862003-04-19 00:11:28 +00001094 /*
1095 * Change netlink socket flags to blocking to ensure we get
1096 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001097 */
1098 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1099 if (snb_ret < 0)
1100 zlog (NULL, LOG_WARNING,
1101 "%s:%i Warning: Could not set netlink socket to blocking.",
1102 __FUNCTION__, __LINE__);
1103
paul718e3742002-12-13 20:15:29 +00001104 /* Get interface information. */
1105 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1106 if (ret < 0)
1107 return ret;
1108 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1109 if (ret < 0)
1110 return ret;
1111
1112 /* Get IPv4 address of the interfaces. */
1113 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1114 if (ret < 0)
1115 return ret;
1116 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1117 if (ret < 0)
1118 return ret;
1119
1120#ifdef HAVE_IPV6
1121 /* Get IPv6 address of the interfaces. */
1122 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1123 if (ret < 0)
1124 return ret;
1125 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1126 if (ret < 0)
1127 return ret;
1128#endif /* HAVE_IPV6 */
1129
paul7021c422003-07-15 12:52:22 +00001130 /* restore socket flags */
1131 if (snb_ret == 0)
1132 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001133 return 0;
1134}
1135
1136/* Routing table read function using netlink interface. Only called
1137 bootstrap time. */
1138int
1139netlink_route_read ()
1140{
1141 int ret;
paul5f37d862003-04-19 00:11:28 +00001142 int flags;
1143 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001144
paul5f37d862003-04-19 00:11:28 +00001145 /*
1146 * Change netlink socket flags to blocking to ensure we get
1147 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001148 */
1149 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1150 if (snb_ret < 0)
1151 zlog (NULL, LOG_WARNING,
1152 "%s:%i Warning: Could not set netlink socket to blocking.",
1153 __FUNCTION__, __LINE__);
1154
paul718e3742002-12-13 20:15:29 +00001155 /* Get IPv4 routing table. */
1156 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1157 if (ret < 0)
1158 return ret;
1159 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1160 if (ret < 0)
1161 return ret;
1162
1163#ifdef HAVE_IPV6
1164 /* Get IPv6 routing table. */
1165 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1166 if (ret < 0)
1167 return ret;
1168 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1169 if (ret < 0)
1170 return ret;
1171#endif /* HAVE_IPV6 */
1172
paul5f37d862003-04-19 00:11:28 +00001173 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001174 if (snb_ret == 0)
1175 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001176 return 0;
1177}
1178
1179/* Utility function comes from iproute2.
1180 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1181int
1182addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1183{
1184 int len;
1185 struct rtattr *rta;
1186
paul7021c422003-07-15 12:52:22 +00001187 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001188
paul7021c422003-07-15 12:52:22 +00001189 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001190 return -1;
1191
paul7021c422003-07-15 12:52:22 +00001192 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001193 rta->rta_type = type;
1194 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001195 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001196 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1197
1198 return 0;
1199}
1200
1201int
1202rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1203{
1204 int len;
1205 struct rtattr *subrta;
1206
paul7021c422003-07-15 12:52:22 +00001207 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001208
paul7021c422003-07-15 12:52:22 +00001209 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001210 return -1;
1211
paul7021c422003-07-15 12:52:22 +00001212 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001213 subrta->rta_type = type;
1214 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001215 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001216 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1217
1218 return 0;
1219}
1220
1221/* Utility function comes from iproute2.
1222 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1223int
1224addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1225{
1226 int len;
1227 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001228
1229 len = RTA_LENGTH (4);
1230
paul718e3742002-12-13 20:15:29 +00001231 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1232 return -1;
1233
paul7021c422003-07-15 12:52:22 +00001234 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001235 rta->rta_type = type;
1236 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001237 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001238 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1239
1240 return 0;
1241}
1242
1243static int
1244netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1245{
hassob7ed1ec2005-03-31 20:13:49 +00001246 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001247 return 0;
1248}
1249
1250/* sendmsg() to netlink socket then recvmsg(). */
1251int
1252netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1253{
1254 int status;
1255 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001256 struct iovec iov = { (void *) n, n->nlmsg_len };
1257 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001258 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001259 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001260 int save_errno;
paul7021c422003-07-15 12:52:22 +00001261
paul718e3742002-12-13 20:15:29 +00001262 memset (&snl, 0, sizeof snl);
1263 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001264
hassob7ed1ec2005-03-31 20:13:49 +00001265 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001266
1267 /* Request an acknowledgement by setting NLM_F_ACK */
1268 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001269
1270 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001271 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001272 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1273 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001274
1275 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001276 if (zserv_privs.change (ZPRIVS_RAISE))
1277 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001278 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001279 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001280 if (zserv_privs.change (ZPRIVS_LOWER))
1281 zlog (NULL, LOG_ERR, "Can't lower privileges");
1282
paul718e3742002-12-13 20:15:29 +00001283 if (status < 0)
1284 {
1285 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001286 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001287 return -1;
1288 }
paul7021c422003-07-15 12:52:22 +00001289
paul718e3742002-12-13 20:15:29 +00001290 /*
1291 * Change socket flags for blocking I/O.
1292 * This ensures we wait for a reply in netlink_parse_info().
1293 */
paul7021c422003-07-15 12:52:22 +00001294 snb_ret = set_netlink_blocking (nl, &flags);
1295 if (snb_ret < 0)
1296 zlog (NULL, LOG_WARNING,
1297 "%s:%i Warning: Could not set netlink socket to blocking.",
1298 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001299
1300 /*
1301 * Get reply from netlink socket.
1302 * The reply should either be an acknowlegement or an error.
1303 */
1304 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001305
paul718e3742002-12-13 20:15:29 +00001306 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001307 if (snb_ret == 0)
1308 set_netlink_nonblocking (nl, &flags);
1309
paul718e3742002-12-13 20:15:29 +00001310 return status;
1311}
1312
1313/* Routing table change via netlink interface. */
1314int
1315netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001316 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001317{
1318 int ret;
1319 int bytelen;
1320 struct sockaddr_nl snl;
1321 int discard;
1322
paul7021c422003-07-15 12:52:22 +00001323 struct
paul718e3742002-12-13 20:15:29 +00001324 {
1325 struct nlmsghdr n;
1326 struct rtmsg r;
1327 char buf[1024];
1328 } req;
1329
1330 memset (&req, 0, sizeof req);
1331
1332 bytelen = (family == AF_INET ? 4 : 16);
1333
1334 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1335 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1336 req.n.nlmsg_type = cmd;
1337 req.r.rtm_family = family;
1338 req.r.rtm_table = table;
1339 req.r.rtm_dst_len = length;
1340
hasso81dfcaa2003-05-25 19:21:25 +00001341 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1342 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001343 discard = 1;
1344 else
1345 discard = 0;
1346
paul7021c422003-07-15 12:52:22 +00001347 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001348 {
1349 req.r.rtm_protocol = RTPROT_ZEBRA;
1350 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1351
paul7021c422003-07-15 12:52:22 +00001352 if (discard)
paul595db7f2003-05-25 21:35:06 +00001353 {
1354 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1355 req.r.rtm_type = RTN_BLACKHOLE;
1356 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1357 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001358 else
1359 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1360 }
paul595db7f2003-05-25 21:35:06 +00001361 else
paul7021c422003-07-15 12:52:22 +00001362 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001363 }
1364
1365 if (dest)
1366 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1367
paul7021c422003-07-15 12:52:22 +00001368 if (!discard)
paul718e3742002-12-13 20:15:29 +00001369 {
1370 if (gate)
paul7021c422003-07-15 12:52:22 +00001371 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001372 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001373 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001374 }
1375
1376 /* Destination netlink address. */
1377 memset (&snl, 0, sizeof snl);
1378 snl.nl_family = AF_NETLINK;
1379
1380 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001381 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001382 if (ret < 0)
1383 return -1;
1384
1385 return 0;
1386}
1387
1388/* Routing table change via netlink interface. */
1389int
1390netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001391 int family)
paul718e3742002-12-13 20:15:29 +00001392{
1393 int bytelen;
1394 struct sockaddr_nl snl;
1395 struct nexthop *nexthop = NULL;
1396 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001397 int discard;
1398
paul7021c422003-07-15 12:52:22 +00001399 struct
paul718e3742002-12-13 20:15:29 +00001400 {
1401 struct nlmsghdr n;
1402 struct rtmsg r;
1403 char buf[1024];
1404 } req;
1405
1406 memset (&req, 0, sizeof req);
1407
1408 bytelen = (family == AF_INET ? 4 : 16);
1409
1410 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1411 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1412 req.n.nlmsg_type = cmd;
1413 req.r.rtm_family = family;
1414 req.r.rtm_table = rib->table;
1415 req.r.rtm_dst_len = p->prefixlen;
1416
paul7021c422003-07-15 12:52:22 +00001417 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001418 discard = 1;
1419 else
1420 discard = 0;
1421
paul7021c422003-07-15 12:52:22 +00001422 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001423 {
1424 req.r.rtm_protocol = RTPROT_ZEBRA;
1425 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1426
paul7021c422003-07-15 12:52:22 +00001427 if (discard)
paul595db7f2003-05-25 21:35:06 +00001428 {
1429 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1430 req.r.rtm_type = RTN_BLACKHOLE;
1431 else if (rib->flags & ZEBRA_FLAG_REJECT)
1432 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001433 else
1434 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1435 }
paul595db7f2003-05-25 21:35:06 +00001436 else
paul7021c422003-07-15 12:52:22 +00001437 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001438 }
1439
1440 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1441
1442 /* Metric. */
1443 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1444
1445 if (discard)
1446 {
1447 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001448 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1449 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001450 goto skip;
1451 }
1452
1453 /* Multipath case. */
1454 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1455 {
1456 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001457 {
paul5ec90d22003-06-19 01:41:37 +00001458
paul7021c422003-07-15 12:52:22 +00001459 if ((cmd == RTM_NEWROUTE
1460 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1461 || (cmd == RTM_DELROUTE
1462 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1463 {
paul5ec90d22003-06-19 01:41:37 +00001464
paul7021c422003-07-15 12:52:22 +00001465 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1466 {
1467 if (IS_ZEBRA_DEBUG_KERNEL)
1468 {
ajsb6178002004-12-07 21:12:56 +00001469 zlog_debug
paul7021c422003-07-15 12:52:22 +00001470 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001471 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001472#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001473 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001474 inet6_ntoa (p->u.prefix6),
1475#else
1476 inet_ntoa (p->u.prefix4),
1477#endif /* HAVE_IPV6 */
1478
1479 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001480 }
paul5ec90d22003-06-19 01:41:37 +00001481
paul7021c422003-07-15 12:52:22 +00001482 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1483 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001484 {
1485 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1486 &nexthop->rgate.ipv4, bytelen);
1487
1488 if (IS_ZEBRA_DEBUG_KERNEL)
1489 zlog_debug("netlink_route_multipath() (recursive, "
1490 "1 hop): nexthop via %s if %u",
1491 inet_ntoa (nexthop->rgate.ipv4),
1492 nexthop->rifindex);
1493 }
paul718e3742002-12-13 20:15:29 +00001494#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001495 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1496 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1497 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001498 {
1499 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1500 &nexthop->rgate.ipv6, bytelen);
1501
1502 if (IS_ZEBRA_DEBUG_KERNEL)
1503 zlog_debug("netlink_route_multipath() (recursive, "
1504 "1 hop): nexthop via %s if %u",
1505 inet6_ntoa (nexthop->rgate.ipv6),
1506 nexthop->rifindex);
1507 }
paul718e3742002-12-13 20:15:29 +00001508#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001509 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1510 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1511 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1512 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1513 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001514 {
1515 addattr32 (&req.n, sizeof req, RTA_OIF,
1516 nexthop->rifindex);
1517
1518 if (IS_ZEBRA_DEBUG_KERNEL)
1519 zlog_debug("netlink_route_multipath() (recursive, "
1520 "1 hop): nexthop via if %u",
1521 nexthop->rifindex);
1522 }
paul7021c422003-07-15 12:52:22 +00001523 }
1524 else
1525 {
1526 if (IS_ZEBRA_DEBUG_KERNEL)
1527 {
ajsb6178002004-12-07 21:12:56 +00001528 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001529 ("netlink_route_multipath() (single hop): "
1530 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001531#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001532 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001533 inet6_ntoa (p->u.prefix6),
1534#else
1535 inet_ntoa (p->u.prefix4),
1536#endif /* HAVE_IPV6 */
1537 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001538 }
paul5ec90d22003-06-19 01:41:37 +00001539
paul7021c422003-07-15 12:52:22 +00001540 if (nexthop->type == NEXTHOP_TYPE_IPV4
1541 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001542 {
1543 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1544 &nexthop->gate.ipv4, bytelen);
1545
1546 if (IS_ZEBRA_DEBUG_KERNEL)
1547 zlog_debug("netlink_route_multipath() (single hop): "
1548 "nexthop via %s if %u",
1549 inet_ntoa (nexthop->gate.ipv4),
1550 nexthop->ifindex);
1551 }
paul718e3742002-12-13 20:15:29 +00001552#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001553 if (nexthop->type == NEXTHOP_TYPE_IPV6
1554 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1555 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001556 {
1557 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1558 &nexthop->gate.ipv6, bytelen);
1559
1560 if (IS_ZEBRA_DEBUG_KERNEL)
1561 zlog_debug("netlink_route_multipath() (single hop): "
1562 "nexthop via %s if %u",
1563 inet6_ntoa (nexthop->gate.ipv6),
1564 nexthop->ifindex);
1565 }
paul718e3742002-12-13 20:15:29 +00001566#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001567 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1568 || nexthop->type == NEXTHOP_TYPE_IFNAME
1569 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1570 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1571 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001572 {
1573 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1574
1575 if (IS_ZEBRA_DEBUG_KERNEL)
1576 zlog_debug("netlink_route_multipath() (single hop): "
1577 "nexthop via if %u", nexthop->ifindex);
1578 }
paul7021c422003-07-15 12:52:22 +00001579 }
paul718e3742002-12-13 20:15:29 +00001580
paul7021c422003-07-15 12:52:22 +00001581 if (cmd == RTM_NEWROUTE)
1582 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001583
paul7021c422003-07-15 12:52:22 +00001584 nexthop_num++;
1585 break;
1586 }
1587 }
paul718e3742002-12-13 20:15:29 +00001588 }
1589 else
1590 {
1591 char buf[1024];
1592 struct rtattr *rta = (void *) buf;
1593 struct rtnexthop *rtnh;
1594
1595 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001596 rta->rta_len = RTA_LENGTH (0);
1597 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001598
1599 nexthop_num = 0;
1600 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001601 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1602 nexthop = nexthop->next)
1603 {
1604 if ((cmd == RTM_NEWROUTE
1605 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1606 || (cmd == RTM_DELROUTE
1607 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1608 {
1609 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001610
paul7021c422003-07-15 12:52:22 +00001611 rtnh->rtnh_len = sizeof (*rtnh);
1612 rtnh->rtnh_flags = 0;
1613 rtnh->rtnh_hops = 0;
1614 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001615
paul7021c422003-07-15 12:52:22 +00001616 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1617 {
1618 if (IS_ZEBRA_DEBUG_KERNEL)
1619 {
ajsb6178002004-12-07 21:12:56 +00001620 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001621 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001622 lookup (nlmsg_str, cmd),
1623#ifdef HAVE_IPV6
1624 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1625 inet6_ntoa (p->u.prefix6),
1626#else
1627 inet_ntoa (p->u.prefix4),
1628#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001629 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001630 }
1631 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1632 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1633 {
1634 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1635 &nexthop->rgate.ipv4, bytelen);
1636 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001637
1638 if (IS_ZEBRA_DEBUG_KERNEL)
1639 zlog_debug("netlink_route_multipath() (recursive, "
1640 "multihop): nexthop via %s if %u",
1641 inet_ntoa (nexthop->rgate.ipv4),
1642 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001643 }
paul718e3742002-12-13 20:15:29 +00001644#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001645 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1646 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1647 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001648 {
1649 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1650 &nexthop->rgate.ipv6, bytelen);
1651
1652 if (IS_ZEBRA_DEBUG_KERNEL)
1653 zlog_debug("netlink_route_multipath() (recursive, "
1654 "multihop): nexthop via %s if %u",
1655 inet6_ntoa (nexthop->rgate.ipv6),
1656 nexthop->rifindex);
1657 }
paul718e3742002-12-13 20:15:29 +00001658#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001659 /* ifindex */
1660 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1661 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1662 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1663 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1664 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001665 {
1666 rtnh->rtnh_ifindex = nexthop->rifindex;
1667
1668 if (IS_ZEBRA_DEBUG_KERNEL)
1669 zlog_debug("netlink_route_multipath() (recursive, "
1670 "multihop): nexthop via if %u",
1671 nexthop->rifindex);
1672 }
paul7021c422003-07-15 12:52:22 +00001673 else
hasso206d8052005-04-09 16:38:51 +00001674 {
1675 rtnh->rtnh_ifindex = 0;
1676 }
paul7021c422003-07-15 12:52:22 +00001677 }
1678 else
1679 {
1680 if (IS_ZEBRA_DEBUG_KERNEL)
1681 {
hasso206d8052005-04-09 16:38:51 +00001682 zlog_debug ("netlink_route_multipath() (multihop): "
1683 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001684#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001685 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001686 inet6_ntoa (p->u.prefix6),
1687#else
1688 inet_ntoa (p->u.prefix4),
1689#endif /* HAVE_IPV6 */
1690 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001691 }
1692 if (nexthop->type == NEXTHOP_TYPE_IPV4
1693 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1694 {
hasso206d8052005-04-09 16:38:51 +00001695 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1696 &nexthop->gate.ipv4, bytelen);
1697 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1698
1699 if (IS_ZEBRA_DEBUG_KERNEL)
1700 zlog_debug("netlink_route_multipath() (multihop): "
1701 "nexthop via %s if %u",
1702 inet_ntoa (nexthop->gate.ipv4),
1703 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001704 }
paul718e3742002-12-13 20:15:29 +00001705#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001706 if (nexthop->type == NEXTHOP_TYPE_IPV6
1707 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1708 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001709 {
1710 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1711 &nexthop->gate.ipv6, bytelen);
1712
1713 if (IS_ZEBRA_DEBUG_KERNEL)
1714 zlog_debug("netlink_route_multipath() (multihop): "
1715 "nexthop via %s if %u",
1716 inet6_ntoa (nexthop->gate.ipv6),
1717 nexthop->ifindex);
1718 }
paul718e3742002-12-13 20:15:29 +00001719#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001720 /* ifindex */
1721 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1722 || nexthop->type == NEXTHOP_TYPE_IFNAME
1723 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1724 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1725 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001726 {
1727 rtnh->rtnh_ifindex = nexthop->ifindex;
1728
1729 if (IS_ZEBRA_DEBUG_KERNEL)
1730 zlog_debug("netlink_route_multipath() (multihop): "
1731 "nexthop via if %u", nexthop->ifindex);
1732 }
paul7021c422003-07-15 12:52:22 +00001733 else
hasso206d8052005-04-09 16:38:51 +00001734 {
1735 rtnh->rtnh_ifindex = 0;
1736 }
paul7021c422003-07-15 12:52:22 +00001737 }
1738 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001739
paul7021c422003-07-15 12:52:22 +00001740 if (cmd == RTM_NEWROUTE)
1741 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1742 }
1743 }
paul718e3742002-12-13 20:15:29 +00001744
1745 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001746 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1747 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001748 }
1749
1750 /* If there is no useful nexthop then return. */
1751 if (nexthop_num == 0)
1752 {
1753 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001754 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001755 return 0;
1756 }
1757
paul7021c422003-07-15 12:52:22 +00001758skip:
paul718e3742002-12-13 20:15:29 +00001759
1760 /* Destination netlink address. */
1761 memset (&snl, 0, sizeof snl);
1762 snl.nl_family = AF_NETLINK;
1763
paul718e3742002-12-13 20:15:29 +00001764 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001765 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001766}
1767
1768int
1769kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1770{
1771 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1772}
1773
1774int
1775kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1776{
1777 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1778}
1779
1780#ifdef HAVE_IPV6
1781int
1782kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1783{
1784 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1785}
1786
1787int
1788kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1789{
1790 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1791}
1792
1793/* Delete IPv6 route from the kernel. */
1794int
1795kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001796 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001797{
paul7021c422003-07-15 12:52:22 +00001798 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1799 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001800}
1801#endif /* HAVE_IPV6 */
1802
1803/* Interface address modification. */
1804int
1805netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001806 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001807{
1808 int bytelen;
1809 struct prefix *p;
1810
paul7021c422003-07-15 12:52:22 +00001811 struct
paul718e3742002-12-13 20:15:29 +00001812 {
1813 struct nlmsghdr n;
1814 struct ifaddrmsg ifa;
1815 char buf[1024];
1816 } req;
1817
1818 p = ifc->address;
1819 memset (&req, 0, sizeof req);
1820
1821 bytelen = (family == AF_INET ? 4 : 16);
1822
paul7021c422003-07-15 12:52:22 +00001823 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001824 req.n.nlmsg_flags = NLM_F_REQUEST;
1825 req.n.nlmsg_type = cmd;
1826 req.ifa.ifa_family = family;
1827
1828 req.ifa.ifa_index = ifp->ifindex;
1829 req.ifa.ifa_prefixlen = p->prefixlen;
1830
1831 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1832
1833 if (family == AF_INET && cmd == RTM_NEWADDR)
1834 {
1835 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001836 {
1837 p = ifc->destination;
1838 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1839 bytelen);
1840 }
paul718e3742002-12-13 20:15:29 +00001841 }
1842
1843 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1844 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001845
paul718e3742002-12-13 20:15:29 +00001846 if (ifc->label)
1847 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001848 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001849
1850 return netlink_talk (&req.n, &netlink_cmd);
1851}
1852
1853int
1854kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1855{
1856 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1857}
1858
1859int
1860kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1861{
1862 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1863}
1864
paul718e3742002-12-13 20:15:29 +00001865
1866extern struct thread_master *master;
1867
1868/* Kernel route reflection. */
1869int
1870kernel_read (struct thread *thread)
1871{
1872 int ret;
1873 int sock;
1874
1875 sock = THREAD_FD (thread);
1876 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001877 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001878
1879 return 0;
1880}
1881
1882/* Exported interface function. This function simply calls
1883 netlink_socket (). */
1884void
1885kernel_init ()
1886{
1887 unsigned long groups;
1888
paul7021c422003-07-15 12:52:22 +00001889 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001890#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001891 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001892#endif /* HAVE_IPV6 */
1893 netlink_socket (&netlink, groups);
1894 netlink_socket (&netlink_cmd, 0);
1895
1896 /* Register kernel socket. */
1897 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001898 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001899}