blob: 62d166b29dd993ab14cd49e8608812bf4ec97eb8 [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
hassobe61c4e2005-08-27 06:05:47 +0000796 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
797 metric, 0);
paul718e3742002-12-13 20:15:29 +0000798 }
799#endif /* HAVE_IPV6 */
800
801 return 0;
802}
803
paul7021c422003-07-15 12:52:22 +0000804struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000805 {RTPROT_REDIRECT, "redirect"},
806 {RTPROT_KERNEL, "kernel"},
807 {RTPROT_BOOT, "boot"},
808 {RTPROT_STATIC, "static"},
809 {RTPROT_GATED, "GateD"},
810 {RTPROT_RA, "router advertisement"},
811 {RTPROT_MRT, "MRT"},
812 {RTPROT_ZEBRA, "Zebra"},
813#ifdef RTPROT_BIRD
814 {RTPROT_BIRD, "BIRD"},
815#endif /* RTPROT_BIRD */
816 {0, NULL}
817};
818
819/* Routing information change from the kernel. */
820int
821netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
822{
823 int len;
824 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000825 struct rtattr *tb[RTA_MAX + 1];
826
827 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000828
829 int index;
830 int table;
831 void *dest;
832 void *gate;
833
834 rtm = NLMSG_DATA (h);
835
paul7021c422003-07-15 12:52:22 +0000836 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000837 {
838 /* If this is not route add/delete message print warning. */
839 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
840 return 0;
841 }
842
843 /* Connected route. */
844 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000845 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000846 h->nlmsg_type ==
847 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
848 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
849 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
850 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000851
852 if (rtm->rtm_type != RTN_UNICAST)
853 {
854 return 0;
855 }
856
857 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000858 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000859 {
860 return 0;
861 }
862
paul7021c422003-07-15 12:52:22 +0000863 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000864 if (len < 0)
865 return -1;
866
867 memset (tb, 0, sizeof tb);
868 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
869
870 if (rtm->rtm_flags & RTM_F_CLONED)
871 return 0;
872 if (rtm->rtm_protocol == RTPROT_REDIRECT)
873 return 0;
874 if (rtm->rtm_protocol == RTPROT_KERNEL)
875 return 0;
876
877 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
878 return 0;
879
880 if (rtm->rtm_src_len != 0)
881 {
882 zlog_warn ("netlink_route_change(): no src len");
883 return 0;
884 }
paul7021c422003-07-15 12:52:22 +0000885
paul718e3742002-12-13 20:15:29 +0000886 index = 0;
887 dest = NULL;
888 gate = NULL;
889
890 if (tb[RTA_OIF])
891 index = *(int *) RTA_DATA (tb[RTA_OIF]);
892
893 if (tb[RTA_DST])
894 dest = RTA_DATA (tb[RTA_DST]);
895 else
896 dest = anyaddr;
897
898 if (tb[RTA_GATEWAY])
899 gate = RTA_DATA (tb[RTA_GATEWAY]);
900
901 if (rtm->rtm_family == AF_INET)
902 {
903 struct prefix_ipv4 p;
904 p.family = AF_INET;
905 memcpy (&p.prefix, dest, 4);
906 p.prefixlen = rtm->rtm_dst_len;
907
908 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000909 {
910 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000911 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000912 inet_ntoa (p.prefix), p.prefixlen);
913 else
ajsb6178002004-12-07 21:12:56 +0000914 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000915 inet_ntoa (p.prefix), p.prefixlen);
916 }
paul718e3742002-12-13 20:15:29 +0000917
918 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000919 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000920 else
paul7021c422003-07-15 12:52:22 +0000921 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000922 }
923
924#ifdef HAVE_IPV6
925 if (rtm->rtm_family == AF_INET6)
926 {
927 struct prefix_ipv6 p;
928 char buf[BUFSIZ];
929
930 p.family = AF_INET6;
931 memcpy (&p.prefix, dest, 16);
932 p.prefixlen = rtm->rtm_dst_len;
933
934 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000935 {
936 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000937 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000938 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
939 p.prefixlen);
940 else
ajsb6178002004-12-07 21:12:56 +0000941 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000942 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
943 p.prefixlen);
944 }
paul718e3742002-12-13 20:15:29 +0000945
946 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000947 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000948 else
paul7021c422003-07-15 12:52:22 +0000949 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000950 }
951#endif /* HAVE_IPV6 */
952
953 return 0;
954}
955
956int
957netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
958{
959 int len;
960 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000961 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000962 struct interface *ifp;
963 char *name;
964
965 ifi = NLMSG_DATA (h);
966
paul7021c422003-07-15 12:52:22 +0000967 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000968 {
969 /* If this is not link add/delete message so print warning. */
970 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000971 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000972 return 0;
973 }
974
975 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
976 if (len < 0)
977 return -1;
978
979 /* Looking up interface name. */
980 memset (tb, 0, sizeof tb);
981 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000982
paul1e193152005-02-14 23:53:05 +0000983#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000984 /* check for wireless messages to ignore */
985 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
986 {
987 if (IS_ZEBRA_DEBUG_KERNEL)
988 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
989 return 0;
990 }
paul1e193152005-02-14 23:53:05 +0000991#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000992
paul718e3742002-12-13 20:15:29 +0000993 if (tb[IFLA_IFNAME] == NULL)
994 return -1;
paul7021c422003-07-15 12:52:22 +0000995 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000996
997 /* Add interface. */
998 if (h->nlmsg_type == RTM_NEWLINK)
999 {
1000 ifp = if_lookup_by_name (name);
1001
paul7021c422003-07-15 12:52:22 +00001002 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1003 {
1004 if (ifp == NULL)
1005 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001006
ajsd2fc8892005-04-02 18:38:43 +00001007 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001008 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001009 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001010 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001011
paul7021c422003-07-15 12:52:22 +00001012 /* If new link is added. */
1013 if_add_update (ifp);
1014 }
paul718e3742002-12-13 20:15:29 +00001015 else
paul7021c422003-07-15 12:52:22 +00001016 {
1017 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001018 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001019 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001020 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001021
paul7021c422003-07-15 12:52:22 +00001022 if (if_is_operative (ifp))
1023 {
1024 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1025 if (!if_is_operative (ifp))
1026 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001027 else
1028 /* Must notify client daemons of new interface status. */
1029 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001030 }
1031 else
1032 {
1033 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1034 if (if_is_operative (ifp))
1035 if_up (ifp);
1036 }
1037 }
paul718e3742002-12-13 20:15:29 +00001038 }
1039 else
1040 {
1041 /* RTM_DELLINK. */
1042 ifp = if_lookup_by_name (name);
1043
1044 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001045 {
1046 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001047 name);
paul7021c422003-07-15 12:52:22 +00001048 return 0;
1049 }
1050
paul718e3742002-12-13 20:15:29 +00001051 if_delete_update (ifp);
1052 }
1053
1054 return 0;
1055}
1056
1057int
1058netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1059{
1060 switch (h->nlmsg_type)
1061 {
1062 case RTM_NEWROUTE:
1063 return netlink_route_change (snl, h);
1064 break;
1065 case RTM_DELROUTE:
1066 return netlink_route_change (snl, h);
1067 break;
1068 case RTM_NEWLINK:
1069 return netlink_link_change (snl, h);
1070 break;
1071 case RTM_DELLINK:
1072 return netlink_link_change (snl, h);
1073 break;
1074 case RTM_NEWADDR:
1075 return netlink_interface_addr (snl, h);
1076 break;
1077 case RTM_DELADDR:
1078 return netlink_interface_addr (snl, h);
1079 break;
1080 default:
1081 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1082 break;
1083 }
1084 return 0;
1085}
1086
1087/* Interface lookup by netlink socket. */
1088int
1089interface_lookup_netlink ()
1090{
1091 int ret;
paul5f37d862003-04-19 00:11:28 +00001092 int flags;
1093 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001094
paul5f37d862003-04-19 00:11:28 +00001095 /*
1096 * Change netlink socket flags to blocking to ensure we get
1097 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001098 */
1099 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1100 if (snb_ret < 0)
1101 zlog (NULL, LOG_WARNING,
1102 "%s:%i Warning: Could not set netlink socket to blocking.",
1103 __FUNCTION__, __LINE__);
1104
paul718e3742002-12-13 20:15:29 +00001105 /* Get interface information. */
1106 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1107 if (ret < 0)
1108 return ret;
1109 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1110 if (ret < 0)
1111 return ret;
1112
1113 /* Get IPv4 address of the interfaces. */
1114 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1115 if (ret < 0)
1116 return ret;
1117 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1118 if (ret < 0)
1119 return ret;
1120
1121#ifdef HAVE_IPV6
1122 /* Get IPv6 address of the interfaces. */
1123 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1124 if (ret < 0)
1125 return ret;
1126 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1127 if (ret < 0)
1128 return ret;
1129#endif /* HAVE_IPV6 */
1130
paul7021c422003-07-15 12:52:22 +00001131 /* restore socket flags */
1132 if (snb_ret == 0)
1133 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001134 return 0;
1135}
1136
1137/* Routing table read function using netlink interface. Only called
1138 bootstrap time. */
1139int
1140netlink_route_read ()
1141{
1142 int ret;
paul5f37d862003-04-19 00:11:28 +00001143 int flags;
1144 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001145
paul5f37d862003-04-19 00:11:28 +00001146 /*
1147 * Change netlink socket flags to blocking to ensure we get
1148 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001149 */
1150 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1151 if (snb_ret < 0)
1152 zlog (NULL, LOG_WARNING,
1153 "%s:%i Warning: Could not set netlink socket to blocking.",
1154 __FUNCTION__, __LINE__);
1155
paul718e3742002-12-13 20:15:29 +00001156 /* Get IPv4 routing table. */
1157 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1158 if (ret < 0)
1159 return ret;
1160 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1161 if (ret < 0)
1162 return ret;
1163
1164#ifdef HAVE_IPV6
1165 /* Get IPv6 routing table. */
1166 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1167 if (ret < 0)
1168 return ret;
1169 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1170 if (ret < 0)
1171 return ret;
1172#endif /* HAVE_IPV6 */
1173
paul5f37d862003-04-19 00:11:28 +00001174 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001175 if (snb_ret == 0)
1176 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001177 return 0;
1178}
1179
1180/* Utility function comes from iproute2.
1181 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1182int
1183addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1184{
1185 int len;
1186 struct rtattr *rta;
1187
paul7021c422003-07-15 12:52:22 +00001188 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001189
paul7021c422003-07-15 12:52:22 +00001190 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001191 return -1;
1192
paul7021c422003-07-15 12:52:22 +00001193 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001194 rta->rta_type = type;
1195 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001196 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001197 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1198
1199 return 0;
1200}
1201
1202int
1203rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1204{
1205 int len;
1206 struct rtattr *subrta;
1207
paul7021c422003-07-15 12:52:22 +00001208 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001209
paul7021c422003-07-15 12:52:22 +00001210 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001211 return -1;
1212
paul7021c422003-07-15 12:52:22 +00001213 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001214 subrta->rta_type = type;
1215 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001216 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001217 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1218
1219 return 0;
1220}
1221
1222/* Utility function comes from iproute2.
1223 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1224int
1225addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1226{
1227 int len;
1228 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001229
1230 len = RTA_LENGTH (4);
1231
paul718e3742002-12-13 20:15:29 +00001232 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1233 return -1;
1234
paul7021c422003-07-15 12:52:22 +00001235 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001236 rta->rta_type = type;
1237 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001238 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001239 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1240
1241 return 0;
1242}
1243
1244static int
1245netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1246{
hassob7ed1ec2005-03-31 20:13:49 +00001247 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001248 return 0;
1249}
1250
1251/* sendmsg() to netlink socket then recvmsg(). */
1252int
1253netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1254{
1255 int status;
1256 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001257 struct iovec iov = { (void *) n, n->nlmsg_len };
1258 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001259 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001260 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001261 int save_errno;
paul7021c422003-07-15 12:52:22 +00001262
paul718e3742002-12-13 20:15:29 +00001263 memset (&snl, 0, sizeof snl);
1264 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001265
hassob7ed1ec2005-03-31 20:13:49 +00001266 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001267
1268 /* Request an acknowledgement by setting NLM_F_ACK */
1269 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001270
1271 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001272 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001273 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1274 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001275
1276 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001277 if (zserv_privs.change (ZPRIVS_RAISE))
1278 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001279 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001280 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001281 if (zserv_privs.change (ZPRIVS_LOWER))
1282 zlog (NULL, LOG_ERR, "Can't lower privileges");
1283
paul718e3742002-12-13 20:15:29 +00001284 if (status < 0)
1285 {
1286 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001287 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001288 return -1;
1289 }
paul7021c422003-07-15 12:52:22 +00001290
paul718e3742002-12-13 20:15:29 +00001291 /*
1292 * Change socket flags for blocking I/O.
1293 * This ensures we wait for a reply in netlink_parse_info().
1294 */
paul7021c422003-07-15 12:52:22 +00001295 snb_ret = set_netlink_blocking (nl, &flags);
1296 if (snb_ret < 0)
1297 zlog (NULL, LOG_WARNING,
1298 "%s:%i Warning: Could not set netlink socket to blocking.",
1299 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001300
1301 /*
1302 * Get reply from netlink socket.
1303 * The reply should either be an acknowlegement or an error.
1304 */
1305 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001306
paul718e3742002-12-13 20:15:29 +00001307 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001308 if (snb_ret == 0)
1309 set_netlink_nonblocking (nl, &flags);
1310
paul718e3742002-12-13 20:15:29 +00001311 return status;
1312}
1313
1314/* Routing table change via netlink interface. */
1315int
1316netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001317 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001318{
1319 int ret;
1320 int bytelen;
1321 struct sockaddr_nl snl;
1322 int discard;
1323
paul7021c422003-07-15 12:52:22 +00001324 struct
paul718e3742002-12-13 20:15:29 +00001325 {
1326 struct nlmsghdr n;
1327 struct rtmsg r;
1328 char buf[1024];
1329 } req;
1330
1331 memset (&req, 0, sizeof req);
1332
1333 bytelen = (family == AF_INET ? 4 : 16);
1334
1335 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1336 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1337 req.n.nlmsg_type = cmd;
1338 req.r.rtm_family = family;
1339 req.r.rtm_table = table;
1340 req.r.rtm_dst_len = length;
1341
hasso81dfcaa2003-05-25 19:21:25 +00001342 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1343 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001344 discard = 1;
1345 else
1346 discard = 0;
1347
paul7021c422003-07-15 12:52:22 +00001348 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001349 {
1350 req.r.rtm_protocol = RTPROT_ZEBRA;
1351 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1352
paul7021c422003-07-15 12:52:22 +00001353 if (discard)
paul595db7f2003-05-25 21:35:06 +00001354 {
1355 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1356 req.r.rtm_type = RTN_BLACKHOLE;
1357 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1358 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001359 else
1360 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1361 }
paul595db7f2003-05-25 21:35:06 +00001362 else
paul7021c422003-07-15 12:52:22 +00001363 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001364 }
1365
1366 if (dest)
1367 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1368
paul7021c422003-07-15 12:52:22 +00001369 if (!discard)
paul718e3742002-12-13 20:15:29 +00001370 {
1371 if (gate)
paul7021c422003-07-15 12:52:22 +00001372 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001373 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001374 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001375 }
1376
1377 /* Destination netlink address. */
1378 memset (&snl, 0, sizeof snl);
1379 snl.nl_family = AF_NETLINK;
1380
1381 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001382 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001383 if (ret < 0)
1384 return -1;
1385
1386 return 0;
1387}
1388
1389/* Routing table change via netlink interface. */
1390int
1391netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001392 int family)
paul718e3742002-12-13 20:15:29 +00001393{
1394 int bytelen;
1395 struct sockaddr_nl snl;
1396 struct nexthop *nexthop = NULL;
1397 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001398 int discard;
1399
paul7021c422003-07-15 12:52:22 +00001400 struct
paul718e3742002-12-13 20:15:29 +00001401 {
1402 struct nlmsghdr n;
1403 struct rtmsg r;
1404 char buf[1024];
1405 } req;
1406
1407 memset (&req, 0, sizeof req);
1408
1409 bytelen = (family == AF_INET ? 4 : 16);
1410
1411 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1412 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1413 req.n.nlmsg_type = cmd;
1414 req.r.rtm_family = family;
1415 req.r.rtm_table = rib->table;
1416 req.r.rtm_dst_len = p->prefixlen;
1417
paul7021c422003-07-15 12:52:22 +00001418 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001419 discard = 1;
1420 else
1421 discard = 0;
1422
paul7021c422003-07-15 12:52:22 +00001423 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001424 {
1425 req.r.rtm_protocol = RTPROT_ZEBRA;
1426 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1427
paul7021c422003-07-15 12:52:22 +00001428 if (discard)
paul595db7f2003-05-25 21:35:06 +00001429 {
1430 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1431 req.r.rtm_type = RTN_BLACKHOLE;
1432 else if (rib->flags & ZEBRA_FLAG_REJECT)
1433 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001434 else
1435 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1436 }
paul595db7f2003-05-25 21:35:06 +00001437 else
paul7021c422003-07-15 12:52:22 +00001438 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001439 }
1440
1441 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1442
1443 /* Metric. */
1444 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1445
1446 if (discard)
1447 {
1448 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001449 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1450 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001451 goto skip;
1452 }
1453
1454 /* Multipath case. */
1455 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1456 {
1457 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001458 {
paul5ec90d22003-06-19 01:41:37 +00001459
paul7021c422003-07-15 12:52:22 +00001460 if ((cmd == RTM_NEWROUTE
1461 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1462 || (cmd == RTM_DELROUTE
1463 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1464 {
paul5ec90d22003-06-19 01:41:37 +00001465
paul7021c422003-07-15 12:52:22 +00001466 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1467 {
1468 if (IS_ZEBRA_DEBUG_KERNEL)
1469 {
ajsb6178002004-12-07 21:12:56 +00001470 zlog_debug
paul7021c422003-07-15 12:52:22 +00001471 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001472 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001473#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001474 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001475 inet6_ntoa (p->u.prefix6),
1476#else
1477 inet_ntoa (p->u.prefix4),
1478#endif /* HAVE_IPV6 */
1479
1480 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001481 }
paul5ec90d22003-06-19 01:41:37 +00001482
paul7021c422003-07-15 12:52:22 +00001483 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1484 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001485 {
1486 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1487 &nexthop->rgate.ipv4, bytelen);
1488
1489 if (IS_ZEBRA_DEBUG_KERNEL)
1490 zlog_debug("netlink_route_multipath() (recursive, "
1491 "1 hop): nexthop via %s if %u",
1492 inet_ntoa (nexthop->rgate.ipv4),
1493 nexthop->rifindex);
1494 }
paul718e3742002-12-13 20:15:29 +00001495#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001496 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1497 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1498 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001499 {
1500 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1501 &nexthop->rgate.ipv6, bytelen);
1502
1503 if (IS_ZEBRA_DEBUG_KERNEL)
1504 zlog_debug("netlink_route_multipath() (recursive, "
1505 "1 hop): nexthop via %s if %u",
1506 inet6_ntoa (nexthop->rgate.ipv6),
1507 nexthop->rifindex);
1508 }
paul718e3742002-12-13 20:15:29 +00001509#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001510 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1511 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1512 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1513 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1514 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001515 {
1516 addattr32 (&req.n, sizeof req, RTA_OIF,
1517 nexthop->rifindex);
1518
1519 if (IS_ZEBRA_DEBUG_KERNEL)
1520 zlog_debug("netlink_route_multipath() (recursive, "
1521 "1 hop): nexthop via if %u",
1522 nexthop->rifindex);
1523 }
paul7021c422003-07-15 12:52:22 +00001524 }
1525 else
1526 {
1527 if (IS_ZEBRA_DEBUG_KERNEL)
1528 {
ajsb6178002004-12-07 21:12:56 +00001529 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001530 ("netlink_route_multipath() (single hop): "
1531 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001532#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001533 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001534 inet6_ntoa (p->u.prefix6),
1535#else
1536 inet_ntoa (p->u.prefix4),
1537#endif /* HAVE_IPV6 */
1538 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001539 }
paul5ec90d22003-06-19 01:41:37 +00001540
paul7021c422003-07-15 12:52:22 +00001541 if (nexthop->type == NEXTHOP_TYPE_IPV4
1542 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001543 {
1544 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1545 &nexthop->gate.ipv4, bytelen);
1546
1547 if (IS_ZEBRA_DEBUG_KERNEL)
1548 zlog_debug("netlink_route_multipath() (single hop): "
1549 "nexthop via %s if %u",
1550 inet_ntoa (nexthop->gate.ipv4),
1551 nexthop->ifindex);
1552 }
paul718e3742002-12-13 20:15:29 +00001553#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001554 if (nexthop->type == NEXTHOP_TYPE_IPV6
1555 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1556 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001557 {
1558 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1559 &nexthop->gate.ipv6, bytelen);
1560
1561 if (IS_ZEBRA_DEBUG_KERNEL)
1562 zlog_debug("netlink_route_multipath() (single hop): "
1563 "nexthop via %s if %u",
1564 inet6_ntoa (nexthop->gate.ipv6),
1565 nexthop->ifindex);
1566 }
paul718e3742002-12-13 20:15:29 +00001567#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001568 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1569 || nexthop->type == NEXTHOP_TYPE_IFNAME
1570 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1571 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1572 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001573 {
1574 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1575
1576 if (IS_ZEBRA_DEBUG_KERNEL)
1577 zlog_debug("netlink_route_multipath() (single hop): "
1578 "nexthop via if %u", nexthop->ifindex);
1579 }
paul7021c422003-07-15 12:52:22 +00001580 }
paul718e3742002-12-13 20:15:29 +00001581
paul7021c422003-07-15 12:52:22 +00001582 if (cmd == RTM_NEWROUTE)
1583 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001584
paul7021c422003-07-15 12:52:22 +00001585 nexthop_num++;
1586 break;
1587 }
1588 }
paul718e3742002-12-13 20:15:29 +00001589 }
1590 else
1591 {
1592 char buf[1024];
1593 struct rtattr *rta = (void *) buf;
1594 struct rtnexthop *rtnh;
1595
1596 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001597 rta->rta_len = RTA_LENGTH (0);
1598 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001599
1600 nexthop_num = 0;
1601 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001602 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1603 nexthop = nexthop->next)
1604 {
1605 if ((cmd == RTM_NEWROUTE
1606 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1607 || (cmd == RTM_DELROUTE
1608 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1609 {
1610 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001611
paul7021c422003-07-15 12:52:22 +00001612 rtnh->rtnh_len = sizeof (*rtnh);
1613 rtnh->rtnh_flags = 0;
1614 rtnh->rtnh_hops = 0;
1615 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001616
paul7021c422003-07-15 12:52:22 +00001617 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1618 {
1619 if (IS_ZEBRA_DEBUG_KERNEL)
1620 {
ajsb6178002004-12-07 21:12:56 +00001621 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001622 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001623 lookup (nlmsg_str, cmd),
1624#ifdef HAVE_IPV6
1625 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1626 inet6_ntoa (p->u.prefix6),
1627#else
1628 inet_ntoa (p->u.prefix4),
1629#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001630 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001631 }
1632 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1633 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1634 {
1635 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1636 &nexthop->rgate.ipv4, bytelen);
1637 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001638
1639 if (IS_ZEBRA_DEBUG_KERNEL)
1640 zlog_debug("netlink_route_multipath() (recursive, "
1641 "multihop): nexthop via %s if %u",
1642 inet_ntoa (nexthop->rgate.ipv4),
1643 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001644 }
paul718e3742002-12-13 20:15:29 +00001645#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001646 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1647 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1648 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001649 {
1650 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1651 &nexthop->rgate.ipv6, bytelen);
1652
1653 if (IS_ZEBRA_DEBUG_KERNEL)
1654 zlog_debug("netlink_route_multipath() (recursive, "
1655 "multihop): nexthop via %s if %u",
1656 inet6_ntoa (nexthop->rgate.ipv6),
1657 nexthop->rifindex);
1658 }
paul718e3742002-12-13 20:15:29 +00001659#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001660 /* ifindex */
1661 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1662 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1663 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1664 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1665 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001666 {
1667 rtnh->rtnh_ifindex = nexthop->rifindex;
1668
1669 if (IS_ZEBRA_DEBUG_KERNEL)
1670 zlog_debug("netlink_route_multipath() (recursive, "
1671 "multihop): nexthop via if %u",
1672 nexthop->rifindex);
1673 }
paul7021c422003-07-15 12:52:22 +00001674 else
hasso206d8052005-04-09 16:38:51 +00001675 {
1676 rtnh->rtnh_ifindex = 0;
1677 }
paul7021c422003-07-15 12:52:22 +00001678 }
1679 else
1680 {
1681 if (IS_ZEBRA_DEBUG_KERNEL)
1682 {
hasso206d8052005-04-09 16:38:51 +00001683 zlog_debug ("netlink_route_multipath() (multihop): "
1684 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001685#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001686 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001687 inet6_ntoa (p->u.prefix6),
1688#else
1689 inet_ntoa (p->u.prefix4),
1690#endif /* HAVE_IPV6 */
1691 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001692 }
1693 if (nexthop->type == NEXTHOP_TYPE_IPV4
1694 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1695 {
hasso206d8052005-04-09 16:38:51 +00001696 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1697 &nexthop->gate.ipv4, bytelen);
1698 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1699
1700 if (IS_ZEBRA_DEBUG_KERNEL)
1701 zlog_debug("netlink_route_multipath() (multihop): "
1702 "nexthop via %s if %u",
1703 inet_ntoa (nexthop->gate.ipv4),
1704 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001705 }
paul718e3742002-12-13 20:15:29 +00001706#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001707 if (nexthop->type == NEXTHOP_TYPE_IPV6
1708 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1709 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001710 {
1711 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1712 &nexthop->gate.ipv6, bytelen);
1713
1714 if (IS_ZEBRA_DEBUG_KERNEL)
1715 zlog_debug("netlink_route_multipath() (multihop): "
1716 "nexthop via %s if %u",
1717 inet6_ntoa (nexthop->gate.ipv6),
1718 nexthop->ifindex);
1719 }
paul718e3742002-12-13 20:15:29 +00001720#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001721 /* ifindex */
1722 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1723 || nexthop->type == NEXTHOP_TYPE_IFNAME
1724 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1725 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1726 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001727 {
1728 rtnh->rtnh_ifindex = nexthop->ifindex;
1729
1730 if (IS_ZEBRA_DEBUG_KERNEL)
1731 zlog_debug("netlink_route_multipath() (multihop): "
1732 "nexthop via if %u", nexthop->ifindex);
1733 }
paul7021c422003-07-15 12:52:22 +00001734 else
hasso206d8052005-04-09 16:38:51 +00001735 {
1736 rtnh->rtnh_ifindex = 0;
1737 }
paul7021c422003-07-15 12:52:22 +00001738 }
1739 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001740
paul7021c422003-07-15 12:52:22 +00001741 if (cmd == RTM_NEWROUTE)
1742 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1743 }
1744 }
paul718e3742002-12-13 20:15:29 +00001745
1746 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001747 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1748 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001749 }
1750
1751 /* If there is no useful nexthop then return. */
1752 if (nexthop_num == 0)
1753 {
1754 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001755 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001756 return 0;
1757 }
1758
paul7021c422003-07-15 12:52:22 +00001759skip:
paul718e3742002-12-13 20:15:29 +00001760
1761 /* Destination netlink address. */
1762 memset (&snl, 0, sizeof snl);
1763 snl.nl_family = AF_NETLINK;
1764
paul718e3742002-12-13 20:15:29 +00001765 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001766 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001767}
1768
1769int
1770kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1771{
1772 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1773}
1774
1775int
1776kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1777{
1778 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1779}
1780
1781#ifdef HAVE_IPV6
1782int
1783kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1784{
1785 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1786}
1787
1788int
1789kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1790{
1791 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1792}
1793
1794/* Delete IPv6 route from the kernel. */
1795int
1796kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001797 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001798{
paul7021c422003-07-15 12:52:22 +00001799 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1800 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001801}
1802#endif /* HAVE_IPV6 */
1803
1804/* Interface address modification. */
1805int
1806netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001807 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001808{
1809 int bytelen;
1810 struct prefix *p;
1811
paul7021c422003-07-15 12:52:22 +00001812 struct
paul718e3742002-12-13 20:15:29 +00001813 {
1814 struct nlmsghdr n;
1815 struct ifaddrmsg ifa;
1816 char buf[1024];
1817 } req;
1818
1819 p = ifc->address;
1820 memset (&req, 0, sizeof req);
1821
1822 bytelen = (family == AF_INET ? 4 : 16);
1823
paul7021c422003-07-15 12:52:22 +00001824 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001825 req.n.nlmsg_flags = NLM_F_REQUEST;
1826 req.n.nlmsg_type = cmd;
1827 req.ifa.ifa_family = family;
1828
1829 req.ifa.ifa_index = ifp->ifindex;
1830 req.ifa.ifa_prefixlen = p->prefixlen;
1831
1832 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1833
1834 if (family == AF_INET && cmd == RTM_NEWADDR)
1835 {
1836 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001837 {
1838 p = ifc->destination;
1839 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1840 bytelen);
1841 }
paul718e3742002-12-13 20:15:29 +00001842 }
1843
1844 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1845 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001846
paul718e3742002-12-13 20:15:29 +00001847 if (ifc->label)
1848 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001849 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001850
1851 return netlink_talk (&req.n, &netlink_cmd);
1852}
1853
1854int
1855kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1856{
1857 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1858}
1859
1860int
1861kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1862{
1863 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1864}
1865
paul718e3742002-12-13 20:15:29 +00001866
1867extern struct thread_master *master;
1868
1869/* Kernel route reflection. */
1870int
1871kernel_read (struct thread *thread)
1872{
1873 int ret;
1874 int sock;
1875
1876 sock = THREAD_FD (thread);
1877 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001878 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001879
1880 return 0;
1881}
1882
1883/* Exported interface function. This function simply calls
1884 netlink_socket (). */
1885void
1886kernel_init ()
1887{
1888 unsigned long groups;
1889
paul7021c422003-07-15 12:52:22 +00001890 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001891#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001892 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001893#endif /* HAVE_IPV6 */
1894 netlink_socket (&netlink, groups);
1895 netlink_socket (&netlink_cmd, 0);
1896
1897 /* Register kernel socket. */
1898 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001899 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001900}