blob: 592dfe2e1f263b8d661a0d5021fcc339f778f3b5 [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"
paul6621ca82005-11-23 13:02:08 +000040#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000041#include "zebra/redistribute.h"
42#include "zebra/interface.h"
43#include "zebra/debug.h"
44
45/* Socket interface to kernel */
46struct nlsock
47{
48 int sock;
49 int seq;
50 struct sockaddr_nl snl;
hassofce954f2004-10-07 20:29:24 +000051 const char *name;
paul7021c422003-07-15 12:52:22 +000052} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
hasso1ada8192005-06-12 11:28:18 +000053 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
paul718e3742002-12-13 20:15:29 +000054
Stephen Hemminger1423c802008-08-14 17:59:25 +010055static const struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000056 {RTM_NEWROUTE, "RTM_NEWROUTE"},
57 {RTM_DELROUTE, "RTM_DELROUTE"},
58 {RTM_GETROUTE, "RTM_GETROUTE"},
59 {RTM_NEWLINK, "RTM_NEWLINK"},
60 {RTM_DELLINK, "RTM_DELLINK"},
61 {RTM_GETLINK, "RTM_GETLINK"},
62 {RTM_NEWADDR, "RTM_NEWADDR"},
63 {RTM_DELADDR, "RTM_DELADDR"},
64 {RTM_GETADDR, "RTM_GETADDR"},
paul7021c422003-07-15 12:52:22 +000065 {0, NULL}
paul718e3742002-12-13 20:15:29 +000066};
67
Stephen Hemminger6072b242008-08-14 16:52:26 +010068static const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000069{
70 "none",
71 "Directly connected",
72 "Interface route",
73 "IPv4 nexthop",
74 "IPv4 nexthop with ifindex",
75 "IPv4 nexthop with ifname",
hassofa599802005-04-09 16:59:28 +000076 "IPv6 nexthop",
paul7021c422003-07-15 12:52:22 +000077 "IPv6 nexthop with ifindex",
78 "IPv6 nexthop with ifname",
79 "Null0 nexthop",
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
Stephen Hemminger6072b242008-08-14 16:52:26 +0100224static int
paul7021c422003-07-15 12:52:22 +0000225set_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
Stephen Hemminger6072b242008-08-14 16:52:26 +0100245static int
paul7021c422003-07-15 12:52:22 +0000246set_netlink_nonblocking (struct nlsock *nl, int *flags)
247{
paul5f37d862003-04-19 00:11:28 +0000248 /* Restore socket flags for nonblocking I/O */
249 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000250 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000251 {
paul7021c422003-07-15 12:52:22 +0000252 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000253 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000254 return -1;
255 }
256 return 0;
257}
258
paul718e3742002-12-13 20:15:29 +0000259/* Get type specified information from netlink. */
260static int
261netlink_request (int family, int type, struct nlsock *nl)
262{
263 int ret;
264 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000265 int save_errno;
paul718e3742002-12-13 20:15:29 +0000266
267 struct
268 {
269 struct nlmsghdr nlh;
270 struct rtgenmsg g;
271 } req;
272
273
274 /* Check netlink socket. */
275 if (nl->sock < 0)
276 {
277 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
278 return -1;
279 }
280
281 memset (&snl, 0, sizeof snl);
282 snl.nl_family = AF_NETLINK;
283
ajsc05612b2005-10-01 16:36:54 +0000284 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000285 req.nlh.nlmsg_len = sizeof req;
286 req.nlh.nlmsg_type = type;
287 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100288 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000289 req.nlh.nlmsg_seq = ++nl->seq;
290 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000291
292 /* linux appears to check capabilities on every message
293 * have to raise caps for every message sent
294 */
paul7021c422003-07-15 12:52:22 +0000295 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000296 {
297 zlog (NULL, LOG_ERR, "Can't raise privileges");
298 return -1;
299 }
paul7021c422003-07-15 12:52:22 +0000300
301 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
302 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000303 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000304
305 if (zserv_privs.change (ZPRIVS_LOWER))
306 zlog (NULL, LOG_ERR, "Can't lower privileges");
307
paul718e3742002-12-13 20:15:29 +0000308 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000309 {
310 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000311 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000312 return -1;
313 }
pauledd7c242003-06-04 13:59:38 +0000314
paul718e3742002-12-13 20:15:29 +0000315 return 0;
316}
317
318/* Receive message from netlink interface and pass those information
319 to the given function. */
320static int
321netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000322 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000323{
324 int status;
325 int ret = 0;
326 int error;
327
328 while (1)
329 {
330 char buf[4096];
331 struct iovec iov = { buf, sizeof buf };
332 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000333 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000334 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000335 int save_errno;
paul718e3742002-12-13 20:15:29 +0000336
paul7021c422003-07-15 12:52:22 +0000337 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000338 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000339
paul718e3742002-12-13 20:15:29 +0000340 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000341 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000342
343 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000344 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000345
346 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000347 {
ajs4be019d2005-01-29 16:12:41 +0000348 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000349 continue;
ajs4be019d2005-01-29 16:12:41 +0000350 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000351 break;
ajs4be019d2005-01-29 16:12:41 +0000352 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
353 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000354 continue;
355 }
paul718e3742002-12-13 20:15:29 +0000356
357 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000358 {
359 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
360 return -1;
361 }
paul718e3742002-12-13 20:15:29 +0000362
363 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000364 {
365 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
366 nl->name, msg.msg_namelen);
367 return -1;
368 }
paulb84d3a12003-11-17 10:31:01 +0000369
hasso206d8052005-04-09 16:38:51 +0000370 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000371 h = NLMSG_NEXT (h, status))
372 {
373 /* Finish of reading. */
374 if (h->nlmsg_type == NLMSG_DONE)
375 return ret;
paul718e3742002-12-13 20:15:29 +0000376
paul7021c422003-07-15 12:52:22 +0000377 /* Error handling. */
378 if (h->nlmsg_type == NLMSG_ERROR)
379 {
380 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
381
paul718e3742002-12-13 20:15:29 +0000382 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000383 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000384 {
paul7021c422003-07-15 12:52:22 +0000385 if (IS_ZEBRA_DEBUG_KERNEL)
386 {
hasso1ada8192005-06-12 11:28:18 +0000387 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000388 __FUNCTION__, nl->name,
389 lookup (nlmsg_str, err->msg.nlmsg_type),
390 err->msg.nlmsg_type, err->msg.nlmsg_seq,
391 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000392 }
paul7021c422003-07-15 12:52:22 +0000393
394 /* return if not a multipart message, otherwise continue */
395 if (!(h->nlmsg_flags & NLM_F_MULTI))
396 {
397 return 0;
paul718e3742002-12-13 20:15:29 +0000398 }
paul7021c422003-07-15 12:52:22 +0000399 continue;
paul718e3742002-12-13 20:15:29 +0000400 }
paul7021c422003-07-15 12:52:22 +0000401
paul718e3742002-12-13 20:15:29 +0000402 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000403 {
404 zlog (NULL, LOG_ERR, "%s error: message truncated",
405 nl->name);
406 return -1;
407 }
pauld753e9e2003-01-22 19:45:50 +0000408
paul7021c422003-07-15 12:52:22 +0000409 /* Deal with Error Noise - MAG */
410 {
411 int loglvl = LOG_ERR;
412 int errnum = err->error;
413 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000414
paul7021c422003-07-15 12:52:22 +0000415 if (nl == &netlink_cmd
416 && (-errnum == ENODEV || -errnum == ESRCH)
417 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
418 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000419
paul7021c422003-07-15 12:52:22 +0000420 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
hasso1ada8192005-06-12 11:28:18 +0000421 "seq=%u, pid=%u",
ajs6099b3b2004-11-20 02:06:59 +0000422 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000423 lookup (nlmsg_str, msg_type),
424 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
425 }
426 /*
427 ret = -1;
428 continue;
429 */
430 return -1;
431 }
paul718e3742002-12-13 20:15:29 +0000432
paul7021c422003-07-15 12:52:22 +0000433 /* OK we got netlink message. */
434 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000435 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000436 nl->name,
437 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
438 h->nlmsg_seq, h->nlmsg_pid);
439
440 /* skip unsolicited messages originating from command socket */
441 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
442 {
443 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000444 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000445 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000446 continue;
447 }
448
449 error = (*filter) (&snl, h);
450 if (error < 0)
451 {
452 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
453 ret = error;
454 }
455 }
paul718e3742002-12-13 20:15:29 +0000456
457 /* After error care. */
458 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000459 {
460 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
461 continue;
462 }
paul718e3742002-12-13 20:15:29 +0000463 if (status)
paul7021c422003-07-15 12:52:22 +0000464 {
465 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
466 status);
467 return -1;
468 }
paul718e3742002-12-13 20:15:29 +0000469 }
470 return ret;
471}
472
473/* Utility function for parse rtattr. */
474static void
paul7021c422003-07-15 12:52:22 +0000475netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
476 int len)
paul718e3742002-12-13 20:15:29 +0000477{
paul7021c422003-07-15 12:52:22 +0000478 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000479 {
480 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000481 tb[rta->rta_type] = rta;
482 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000483 }
484}
485
486/* Called from interface_lookup_netlink(). This function is only used
487 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100488static int
paul718e3742002-12-13 20:15:29 +0000489netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
490{
491 int len;
492 struct ifinfomsg *ifi;
493 struct rtattr *tb[IFLA_MAX + 1];
494 struct interface *ifp;
495 char *name;
496 int i;
497
498 ifi = NLMSG_DATA (h);
499
500 if (h->nlmsg_type != RTM_NEWLINK)
501 return 0;
502
503 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
504 if (len < 0)
505 return -1;
506
507 /* Looking up interface name. */
508 memset (tb, 0, sizeof tb);
509 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000510
paul1e193152005-02-14 23:53:05 +0000511#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000512 /* check for wireless messages to ignore */
513 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
514 {
515 if (IS_ZEBRA_DEBUG_KERNEL)
516 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
517 return 0;
518 }
paul1e193152005-02-14 23:53:05 +0000519#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000520
paul718e3742002-12-13 20:15:29 +0000521 if (tb[IFLA_IFNAME] == NULL)
522 return -1;
paul7021c422003-07-15 12:52:22 +0000523 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000524
525 /* Add interface. */
526 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000527 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000528 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000529 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000530 ifp->metric = 1;
531
532 /* Hardware type and address. */
533 ifp->hw_type = ifi->ifi_type;
534
535 if (tb[IFLA_ADDRESS])
536 {
537 int hw_addr_len;
538
paul7021c422003-07-15 12:52:22 +0000539 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000540
541 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000542 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000543 else
paul7021c422003-07-15 12:52:22 +0000544 {
545 ifp->hw_addr_len = hw_addr_len;
546 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000547
paul7021c422003-07-15 12:52:22 +0000548 for (i = 0; i < hw_addr_len; i++)
549 if (ifp->hw_addr[i] != 0)
550 break;
paul718e3742002-12-13 20:15:29 +0000551
paul7021c422003-07-15 12:52:22 +0000552 if (i == hw_addr_len)
553 ifp->hw_addr_len = 0;
554 else
555 ifp->hw_addr_len = hw_addr_len;
556 }
paul718e3742002-12-13 20:15:29 +0000557 }
558
559 if_add_update (ifp);
560
561 return 0;
562}
563
564/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100565static int
paul718e3742002-12-13 20:15:29 +0000566netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
567{
568 int len;
569 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000570 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000571 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000572 void *addr;
573 void *broad;
paul718e3742002-12-13 20:15:29 +0000574 u_char flags = 0;
575 char *label = NULL;
576
577 ifa = NLMSG_DATA (h);
578
paul7021c422003-07-15 12:52:22 +0000579 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000580#ifdef HAVE_IPV6
581 && ifa->ifa_family != AF_INET6
582#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000583 )
paul718e3742002-12-13 20:15:29 +0000584 return 0;
585
586 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
587 return 0;
588
paul7021c422003-07-15 12:52:22 +0000589 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000590 if (len < 0)
591 return -1;
592
593 memset (tb, 0, sizeof tb);
594 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
595
596 ifp = if_lookup_by_index (ifa->ifa_index);
597 if (ifp == NULL)
598 {
599 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000600 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000601 return -1;
602 }
603
paul7021c422003-07-15 12:52:22 +0000604 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000605 {
paul00df0c12002-12-13 21:07:36 +0000606 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000607 zlog_debug ("netlink_interface_addr %s %s:",
608 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000609 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000610 zlog_debug (" IFA_LOCAL %s/%d",
611 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
612 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000613 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000614 zlog_debug (" IFA_ADDRESS %s/%d",
615 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
616 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000617 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000618 zlog_debug (" IFA_BROADCAST %s/%d",
619 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
620 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000621 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000622 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000623
624 if (tb[IFA_CACHEINFO])
625 {
626 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
627 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
628 ci->ifa_prefered, ci->ifa_valid);
629 }
paul718e3742002-12-13 20:15:29 +0000630 }
paul31a476c2003-09-29 19:54:53 +0000631
Andrew J. Schorre4529632006-12-12 19:18:21 +0000632 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
633 if (tb[IFA_LOCAL] == NULL)
634 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000635 if (tb[IFA_ADDRESS] == NULL)
636 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
637
Andrew J. Schorre4529632006-12-12 19:18:21 +0000638 /* local interface address */
639 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
640
641 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000642 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000643 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000644 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000645 broad = RTA_DATA(tb[IFA_ADDRESS]);
646 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000647 }
paul31a476c2003-09-29 19:54:53 +0000648 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000649 /* seeking a broadcast address */
650 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000651
Paul Jakma27b47252006-07-02 16:38:54 +0000652 /* addr is primary key, SOL if we don't have one */
653 if (addr == NULL)
654 {
655 zlog_debug ("%s: NULL address", __func__);
656 return -1;
657 }
658
paul718e3742002-12-13 20:15:29 +0000659 /* Flags. */
660 if (ifa->ifa_flags & IFA_F_SECONDARY)
661 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
662
663 /* Label */
664 if (tb[IFA_LABEL])
665 label = (char *) RTA_DATA (tb[IFA_LABEL]);
666
667 if (ifp && label && strcmp (ifp->name, label) == 0)
668 label = NULL;
669
670 /* Register interface address to the interface. */
671 if (ifa->ifa_family == AF_INET)
672 {
paul7021c422003-07-15 12:52:22 +0000673 if (h->nlmsg_type == RTM_NEWADDR)
674 connected_add_ipv4 (ifp, flags,
675 (struct in_addr *) addr, ifa->ifa_prefixlen,
676 (struct in_addr *) broad, label);
677 else
678 connected_delete_ipv4 (ifp, flags,
679 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000680 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000681 }
682#ifdef HAVE_IPV6
683 if (ifa->ifa_family == AF_INET6)
684 {
685 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000686 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000687 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000688 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000689 else
paul7021c422003-07-15 12:52:22 +0000690 connected_delete_ipv6 (ifp,
691 (struct in6_addr *) addr, ifa->ifa_prefixlen,
692 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000693 }
paul7021c422003-07-15 12:52:22 +0000694#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000695
696 return 0;
697}
698
699/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100700static int
paul718e3742002-12-13 20:15:29 +0000701netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
702{
703 int len;
704 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000705 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000706 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000707
708 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000709
710 int index;
711 int table;
hasso34195bf2004-04-06 12:07:06 +0000712 int metric;
713
paul718e3742002-12-13 20:15:29 +0000714 void *dest;
715 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000716 void *src;
paul718e3742002-12-13 20:15:29 +0000717
718 rtm = NLMSG_DATA (h);
719
720 if (h->nlmsg_type != RTM_NEWROUTE)
721 return 0;
722 if (rtm->rtm_type != RTN_UNICAST)
723 return 0;
724
725 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000726#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000727 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000728 return 0;
729#endif
730
paul7021c422003-07-15 12:52:22 +0000731 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000732 if (len < 0)
733 return -1;
734
735 memset (tb, 0, sizeof tb);
736 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
737
738 if (rtm->rtm_flags & RTM_F_CLONED)
739 return 0;
740 if (rtm->rtm_protocol == RTPROT_REDIRECT)
741 return 0;
742 if (rtm->rtm_protocol == RTPROT_KERNEL)
743 return 0;
744
745 if (rtm->rtm_src_len != 0)
746 return 0;
747
748 /* Route which inserted by Zebra. */
749 if (rtm->rtm_protocol == RTPROT_ZEBRA)
750 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000751
paul718e3742002-12-13 20:15:29 +0000752 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000753 metric = 0;
paul718e3742002-12-13 20:15:29 +0000754 dest = NULL;
755 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000756 src = NULL;
paul718e3742002-12-13 20:15:29 +0000757
758 if (tb[RTA_OIF])
759 index = *(int *) RTA_DATA (tb[RTA_OIF]);
760
761 if (tb[RTA_DST])
762 dest = RTA_DATA (tb[RTA_DST]);
763 else
764 dest = anyaddr;
765
Paul Jakma7514fb72007-05-02 16:05:35 +0000766 if (tb[RTA_PREFSRC])
767 src = RTA_DATA (tb[RTA_PREFSRC]);
768
paul718e3742002-12-13 20:15:29 +0000769 /* Multipath treatment is needed. */
770 if (tb[RTA_GATEWAY])
771 gate = RTA_DATA (tb[RTA_GATEWAY]);
772
hasso34195bf2004-04-06 12:07:06 +0000773 if (tb[RTA_PRIORITY])
774 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
775
paul718e3742002-12-13 20:15:29 +0000776 if (rtm->rtm_family == AF_INET)
777 {
778 struct prefix_ipv4 p;
779 p.family = AF_INET;
780 memcpy (&p.prefix, dest, 4);
781 p.prefixlen = rtm->rtm_dst_len;
782
Paul Jakma7514fb72007-05-02 16:05:35 +0000783 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000784 }
785#ifdef HAVE_IPV6
786 if (rtm->rtm_family == AF_INET6)
787 {
788 struct prefix_ipv6 p;
789 p.family = AF_INET6;
790 memcpy (&p.prefix, dest, 16);
791 p.prefixlen = rtm->rtm_dst_len;
792
hassobe61c4e2005-08-27 06:05:47 +0000793 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
794 metric, 0);
paul718e3742002-12-13 20:15:29 +0000795 }
796#endif /* HAVE_IPV6 */
797
798 return 0;
799}
800
Stephen Hemminger1423c802008-08-14 17:59:25 +0100801static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000802 {RTPROT_REDIRECT, "redirect"},
803 {RTPROT_KERNEL, "kernel"},
804 {RTPROT_BOOT, "boot"},
805 {RTPROT_STATIC, "static"},
806 {RTPROT_GATED, "GateD"},
807 {RTPROT_RA, "router advertisement"},
808 {RTPROT_MRT, "MRT"},
809 {RTPROT_ZEBRA, "Zebra"},
810#ifdef RTPROT_BIRD
811 {RTPROT_BIRD, "BIRD"},
812#endif /* RTPROT_BIRD */
813 {0, NULL}
814};
815
816/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100817static int
paul718e3742002-12-13 20:15:29 +0000818netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
819{
820 int len;
821 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000822 struct rtattr *tb[RTA_MAX + 1];
823
824 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000825
826 int index;
827 int table;
828 void *dest;
829 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000830 void *src;
paul718e3742002-12-13 20:15:29 +0000831
832 rtm = NLMSG_DATA (h);
833
paul7021c422003-07-15 12:52:22 +0000834 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000835 {
836 /* If this is not route add/delete message print warning. */
837 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
838 return 0;
839 }
840
841 /* Connected route. */
842 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000843 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000844 h->nlmsg_type ==
845 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
846 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
847 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
848 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000849
850 if (rtm->rtm_type != RTN_UNICAST)
851 {
852 return 0;
853 }
854
855 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000856 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000857 {
858 return 0;
859 }
860
paul7021c422003-07-15 12:52:22 +0000861 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000862 if (len < 0)
863 return -1;
864
865 memset (tb, 0, sizeof tb);
866 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
867
868 if (rtm->rtm_flags & RTM_F_CLONED)
869 return 0;
870 if (rtm->rtm_protocol == RTPROT_REDIRECT)
871 return 0;
872 if (rtm->rtm_protocol == RTPROT_KERNEL)
873 return 0;
874
875 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
876 return 0;
877
878 if (rtm->rtm_src_len != 0)
879 {
880 zlog_warn ("netlink_route_change(): no src len");
881 return 0;
882 }
paul7021c422003-07-15 12:52:22 +0000883
paul718e3742002-12-13 20:15:29 +0000884 index = 0;
885 dest = NULL;
886 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000887 src = NULL;
paul718e3742002-12-13 20:15:29 +0000888
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
Paul Jakma7514fb72007-05-02 16:05:35 +0000900 if (tb[RTA_PREFSRC])
901 src = RTA_DATA (tb[RTA_PREFSRC]);
902
paul718e3742002-12-13 20:15:29 +0000903 if (rtm->rtm_family == AF_INET)
904 {
905 struct prefix_ipv4 p;
906 p.family = AF_INET;
907 memcpy (&p.prefix, dest, 4);
908 p.prefixlen = rtm->rtm_dst_len;
909
910 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000911 {
912 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000913 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000914 inet_ntoa (p.prefix), p.prefixlen);
915 else
ajsb6178002004-12-07 21:12:56 +0000916 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000917 inet_ntoa (p.prefix), p.prefixlen);
918 }
paul718e3742002-12-13 20:15:29 +0000919
920 if (h->nlmsg_type == RTM_NEWROUTE)
Paul Jakma7514fb72007-05-02 16:05:35 +0000921 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000922 else
paul7021c422003-07-15 12:52:22 +0000923 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000924 }
925
926#ifdef HAVE_IPV6
927 if (rtm->rtm_family == AF_INET6)
928 {
929 struct prefix_ipv6 p;
930 char buf[BUFSIZ];
931
932 p.family = AF_INET6;
933 memcpy (&p.prefix, dest, 16);
934 p.prefixlen = rtm->rtm_dst_len;
935
936 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000937 {
938 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000939 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000940 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
941 p.prefixlen);
942 else
ajsb6178002004-12-07 21:12:56 +0000943 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000944 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
945 p.prefixlen);
946 }
paul718e3742002-12-13 20:15:29 +0000947
948 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000949 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000950 else
paul7021c422003-07-15 12:52:22 +0000951 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000952 }
953#endif /* HAVE_IPV6 */
954
955 return 0;
956}
957
Stephen Hemminger6072b242008-08-14 16:52:26 +0100958static int
paul718e3742002-12-13 20:15:29 +0000959netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
960{
961 int len;
962 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000963 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000964 struct interface *ifp;
965 char *name;
966
967 ifi = NLMSG_DATA (h);
968
paul7021c422003-07-15 12:52:22 +0000969 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000970 {
971 /* If this is not link add/delete message so print warning. */
972 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000973 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000974 return 0;
975 }
976
977 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
978 if (len < 0)
979 return -1;
980
981 /* Looking up interface name. */
982 memset (tb, 0, sizeof tb);
983 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000984
paul1e193152005-02-14 23:53:05 +0000985#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000986 /* check for wireless messages to ignore */
987 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
988 {
989 if (IS_ZEBRA_DEBUG_KERNEL)
990 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
991 return 0;
992 }
paul1e193152005-02-14 23:53:05 +0000993#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000994
paul718e3742002-12-13 20:15:29 +0000995 if (tb[IFLA_IFNAME] == NULL)
996 return -1;
paul7021c422003-07-15 12:52:22 +0000997 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000998
999 /* Add interface. */
1000 if (h->nlmsg_type == RTM_NEWLINK)
1001 {
1002 ifp = if_lookup_by_name (name);
1003
paul7021c422003-07-15 12:52:22 +00001004 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1005 {
1006 if (ifp == NULL)
1007 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001008
ajsd2fc8892005-04-02 18:38:43 +00001009 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001010 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001011 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001012 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001013
paul7021c422003-07-15 12:52:22 +00001014 /* If new link is added. */
1015 if_add_update (ifp);
1016 }
paul718e3742002-12-13 20:15:29 +00001017 else
paul7021c422003-07-15 12:52:22 +00001018 {
1019 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001020 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001021 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001022 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001023
paul7021c422003-07-15 12:52:22 +00001024 if (if_is_operative (ifp))
1025 {
1026 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1027 if (!if_is_operative (ifp))
1028 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001029 else
1030 /* Must notify client daemons of new interface status. */
1031 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001032 }
1033 else
1034 {
1035 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1036 if (if_is_operative (ifp))
1037 if_up (ifp);
1038 }
1039 }
paul718e3742002-12-13 20:15:29 +00001040 }
1041 else
1042 {
1043 /* RTM_DELLINK. */
1044 ifp = if_lookup_by_name (name);
1045
1046 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001047 {
1048 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001049 name);
paul7021c422003-07-15 12:52:22 +00001050 return 0;
1051 }
1052
paul718e3742002-12-13 20:15:29 +00001053 if_delete_update (ifp);
1054 }
1055
1056 return 0;
1057}
1058
Stephen Hemminger6072b242008-08-14 16:52:26 +01001059static int
paul718e3742002-12-13 20:15:29 +00001060netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1061{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001062 /* JF: Ignore messages that aren't from the kernel */
1063 if ( snl->nl_pid != 0 )
1064 {
1065 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1066 return 0;
1067 }
1068
paul718e3742002-12-13 20:15:29 +00001069 switch (h->nlmsg_type)
1070 {
1071 case RTM_NEWROUTE:
1072 return netlink_route_change (snl, h);
1073 break;
1074 case RTM_DELROUTE:
1075 return netlink_route_change (snl, h);
1076 break;
1077 case RTM_NEWLINK:
1078 return netlink_link_change (snl, h);
1079 break;
1080 case RTM_DELLINK:
1081 return netlink_link_change (snl, h);
1082 break;
1083 case RTM_NEWADDR:
1084 return netlink_interface_addr (snl, h);
1085 break;
1086 case RTM_DELADDR:
1087 return netlink_interface_addr (snl, h);
1088 break;
1089 default:
1090 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1091 break;
1092 }
1093 return 0;
1094}
1095
1096/* Interface lookup by netlink socket. */
1097int
paul6621ca82005-11-23 13:02:08 +00001098interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001099{
1100 int ret;
paul5f37d862003-04-19 00:11:28 +00001101 int flags;
1102 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001103
paul5f37d862003-04-19 00:11:28 +00001104 /*
1105 * Change netlink socket flags to blocking to ensure we get
1106 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001107 */
1108 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1109 if (snb_ret < 0)
1110 zlog (NULL, LOG_WARNING,
1111 "%s:%i Warning: Could not set netlink socket to blocking.",
1112 __FUNCTION__, __LINE__);
1113
paul718e3742002-12-13 20:15:29 +00001114 /* Get interface information. */
1115 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1116 if (ret < 0)
1117 return ret;
1118 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1119 if (ret < 0)
1120 return ret;
1121
1122 /* Get IPv4 address of the interfaces. */
1123 ret = netlink_request (AF_INET, 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
1130#ifdef HAVE_IPV6
1131 /* Get IPv6 address of the interfaces. */
1132 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1133 if (ret < 0)
1134 return ret;
1135 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1136 if (ret < 0)
1137 return ret;
1138#endif /* HAVE_IPV6 */
1139
paul7021c422003-07-15 12:52:22 +00001140 /* restore socket flags */
1141 if (snb_ret == 0)
1142 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001143 return 0;
1144}
1145
1146/* Routing table read function using netlink interface. Only called
1147 bootstrap time. */
1148int
paul6621ca82005-11-23 13:02:08 +00001149netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001150{
1151 int ret;
paul5f37d862003-04-19 00:11:28 +00001152 int flags;
1153 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001154
paul5f37d862003-04-19 00:11:28 +00001155 /*
1156 * Change netlink socket flags to blocking to ensure we get
1157 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001158 */
1159 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1160 if (snb_ret < 0)
1161 zlog (NULL, LOG_WARNING,
1162 "%s:%i Warning: Could not set netlink socket to blocking.",
1163 __FUNCTION__, __LINE__);
1164
paul718e3742002-12-13 20:15:29 +00001165 /* Get IPv4 routing table. */
1166 ret = netlink_request (AF_INET, 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
1173#ifdef HAVE_IPV6
1174 /* Get IPv6 routing table. */
1175 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1176 if (ret < 0)
1177 return ret;
1178 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1179 if (ret < 0)
1180 return ret;
1181#endif /* HAVE_IPV6 */
1182
paul5f37d862003-04-19 00:11:28 +00001183 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001184 if (snb_ret == 0)
1185 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001186 return 0;
1187}
1188
1189/* Utility function comes from iproute2.
1190 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001191static int
paul718e3742002-12-13 20:15:29 +00001192addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1193{
1194 int len;
1195 struct rtattr *rta;
1196
paul7021c422003-07-15 12:52:22 +00001197 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001198
paul7021c422003-07-15 12:52:22 +00001199 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001200 return -1;
1201
paul7021c422003-07-15 12:52:22 +00001202 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001203 rta->rta_type = type;
1204 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001205 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001206 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1207
1208 return 0;
1209}
1210
Stephen Hemminger6072b242008-08-14 16:52:26 +01001211static int
paul718e3742002-12-13 20:15:29 +00001212rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1213{
1214 int len;
1215 struct rtattr *subrta;
1216
paul7021c422003-07-15 12:52:22 +00001217 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001218
paul7021c422003-07-15 12:52:22 +00001219 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001220 return -1;
1221
paul7021c422003-07-15 12:52:22 +00001222 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001223 subrta->rta_type = type;
1224 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001225 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001226 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1227
1228 return 0;
1229}
1230
1231/* Utility function comes from iproute2.
1232 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001233static int
paul718e3742002-12-13 20:15:29 +00001234addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1235{
1236 int len;
1237 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001238
1239 len = RTA_LENGTH (4);
1240
paul718e3742002-12-13 20:15:29 +00001241 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1242 return -1;
1243
paul7021c422003-07-15 12:52:22 +00001244 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001245 rta->rta_type = type;
1246 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001247 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001248 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1249
1250 return 0;
1251}
1252
1253static int
1254netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1255{
hassob7ed1ec2005-03-31 20:13:49 +00001256 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001257 return 0;
1258}
1259
1260/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001261static int
paul718e3742002-12-13 20:15:29 +00001262netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1263{
1264 int status;
1265 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001266 struct iovec iov = { (void *) n, n->nlmsg_len };
1267 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001268 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001269 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001270 int save_errno;
paul7021c422003-07-15 12:52:22 +00001271
paul718e3742002-12-13 20:15:29 +00001272 memset (&snl, 0, sizeof snl);
1273 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001274
hassob7ed1ec2005-03-31 20:13:49 +00001275 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001276
1277 /* Request an acknowledgement by setting NLM_F_ACK */
1278 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001279
1280 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001281 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001282 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1283 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001284
1285 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001286 if (zserv_privs.change (ZPRIVS_RAISE))
1287 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001288 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001289 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001290 if (zserv_privs.change (ZPRIVS_LOWER))
1291 zlog (NULL, LOG_ERR, "Can't lower privileges");
1292
paul718e3742002-12-13 20:15:29 +00001293 if (status < 0)
1294 {
1295 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001296 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001297 return -1;
1298 }
paul7021c422003-07-15 12:52:22 +00001299
paul718e3742002-12-13 20:15:29 +00001300 /*
1301 * Change socket flags for blocking I/O.
1302 * This ensures we wait for a reply in netlink_parse_info().
1303 */
paul7021c422003-07-15 12:52:22 +00001304 snb_ret = set_netlink_blocking (nl, &flags);
1305 if (snb_ret < 0)
1306 zlog (NULL, LOG_WARNING,
1307 "%s:%i Warning: Could not set netlink socket to blocking.",
1308 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001309
1310 /*
1311 * Get reply from netlink socket.
1312 * The reply should either be an acknowlegement or an error.
1313 */
1314 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001315
paul718e3742002-12-13 20:15:29 +00001316 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001317 if (snb_ret == 0)
1318 set_netlink_nonblocking (nl, &flags);
1319
paul718e3742002-12-13 20:15:29 +00001320 return status;
1321}
1322
1323/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001324static int
paul718e3742002-12-13 20:15:29 +00001325netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001326 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001327{
1328 int ret;
1329 int bytelen;
1330 struct sockaddr_nl snl;
1331 int discard;
1332
paul7021c422003-07-15 12:52:22 +00001333 struct
paul718e3742002-12-13 20:15:29 +00001334 {
1335 struct nlmsghdr n;
1336 struct rtmsg r;
1337 char buf[1024];
1338 } req;
1339
1340 memset (&req, 0, sizeof req);
1341
1342 bytelen = (family == AF_INET ? 4 : 16);
1343
1344 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1345 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1346 req.n.nlmsg_type = cmd;
1347 req.r.rtm_family = family;
1348 req.r.rtm_table = table;
1349 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001350 req.r.rtm_protocol = RTPROT_ZEBRA;
1351 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001352
hasso81dfcaa2003-05-25 19:21:25 +00001353 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1354 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001355 discard = 1;
1356 else
1357 discard = 0;
1358
paul7021c422003-07-15 12:52:22 +00001359 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001360 {
paul7021c422003-07-15 12:52:22 +00001361 if (discard)
paul595db7f2003-05-25 21:35:06 +00001362 {
1363 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1364 req.r.rtm_type = RTN_BLACKHOLE;
1365 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1366 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001367 else
1368 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1369 }
paul595db7f2003-05-25 21:35:06 +00001370 else
paul7021c422003-07-15 12:52:22 +00001371 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001372 }
1373
1374 if (dest)
1375 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1376
paul7021c422003-07-15 12:52:22 +00001377 if (!discard)
paul718e3742002-12-13 20:15:29 +00001378 {
1379 if (gate)
paul7021c422003-07-15 12:52:22 +00001380 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001381 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001382 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001383 }
1384
1385 /* Destination netlink address. */
1386 memset (&snl, 0, sizeof snl);
1387 snl.nl_family = AF_NETLINK;
1388
1389 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001390 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001391 if (ret < 0)
1392 return -1;
1393
1394 return 0;
1395}
1396
1397/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001398static int
paul718e3742002-12-13 20:15:29 +00001399netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001400 int family)
paul718e3742002-12-13 20:15:29 +00001401{
1402 int bytelen;
1403 struct sockaddr_nl snl;
1404 struct nexthop *nexthop = NULL;
1405 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001406 int discard;
1407
paul7021c422003-07-15 12:52:22 +00001408 struct
paul718e3742002-12-13 20:15:29 +00001409 {
1410 struct nlmsghdr n;
1411 struct rtmsg r;
1412 char buf[1024];
1413 } req;
1414
1415 memset (&req, 0, sizeof req);
1416
1417 bytelen = (family == AF_INET ? 4 : 16);
1418
1419 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1420 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1421 req.n.nlmsg_type = cmd;
1422 req.r.rtm_family = family;
1423 req.r.rtm_table = rib->table;
1424 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001425 req.r.rtm_protocol = RTPROT_ZEBRA;
1426 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001427
paul7021c422003-07-15 12:52:22 +00001428 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001429 discard = 1;
1430 else
1431 discard = 0;
1432
paul7021c422003-07-15 12:52:22 +00001433 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001434 {
paul7021c422003-07-15 12:52:22 +00001435 if (discard)
paul595db7f2003-05-25 21:35:06 +00001436 {
1437 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1438 req.r.rtm_type = RTN_BLACKHOLE;
1439 else if (rib->flags & ZEBRA_FLAG_REJECT)
1440 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001441 else
1442 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1443 }
paul595db7f2003-05-25 21:35:06 +00001444 else
paul7021c422003-07-15 12:52:22 +00001445 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001446 }
1447
1448 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1449
1450 /* Metric. */
1451 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1452
1453 if (discard)
1454 {
1455 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001456 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1457 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001458 goto skip;
1459 }
1460
1461 /* Multipath case. */
1462 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1463 {
1464 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001465 {
paul5ec90d22003-06-19 01:41:37 +00001466
paul7021c422003-07-15 12:52:22 +00001467 if ((cmd == RTM_NEWROUTE
1468 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1469 || (cmd == RTM_DELROUTE
1470 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1471 {
paul5ec90d22003-06-19 01:41:37 +00001472
paul7021c422003-07-15 12:52:22 +00001473 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1474 {
1475 if (IS_ZEBRA_DEBUG_KERNEL)
1476 {
ajsb6178002004-12-07 21:12:56 +00001477 zlog_debug
paul7021c422003-07-15 12:52:22 +00001478 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001479 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001480#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001481 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001482 inet6_ntoa (p->u.prefix6),
1483#else
1484 inet_ntoa (p->u.prefix4),
1485#endif /* HAVE_IPV6 */
1486
1487 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001488 }
paul5ec90d22003-06-19 01:41:37 +00001489
paul7021c422003-07-15 12:52:22 +00001490 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1491 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001492 {
1493 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1494 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001495 if (nexthop->src.ipv4.s_addr)
1496 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1497 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001498 if (IS_ZEBRA_DEBUG_KERNEL)
1499 zlog_debug("netlink_route_multipath() (recursive, "
1500 "1 hop): nexthop via %s if %u",
1501 inet_ntoa (nexthop->rgate.ipv4),
1502 nexthop->rifindex);
1503 }
paul718e3742002-12-13 20:15:29 +00001504#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001505 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1506 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1507 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001508 {
1509 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1510 &nexthop->rgate.ipv6, bytelen);
1511
1512 if (IS_ZEBRA_DEBUG_KERNEL)
1513 zlog_debug("netlink_route_multipath() (recursive, "
1514 "1 hop): nexthop via %s if %u",
1515 inet6_ntoa (nexthop->rgate.ipv6),
1516 nexthop->rifindex);
1517 }
paul718e3742002-12-13 20:15:29 +00001518#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001519 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1520 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1521 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1522 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1523 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001524 {
1525 addattr32 (&req.n, sizeof req, RTA_OIF,
1526 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001527 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1528 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1529 && nexthop->src.ipv4.s_addr)
1530 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1531 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001532
1533 if (IS_ZEBRA_DEBUG_KERNEL)
1534 zlog_debug("netlink_route_multipath() (recursive, "
1535 "1 hop): nexthop via if %u",
1536 nexthop->rifindex);
1537 }
paul7021c422003-07-15 12:52:22 +00001538 }
1539 else
1540 {
1541 if (IS_ZEBRA_DEBUG_KERNEL)
1542 {
ajsb6178002004-12-07 21:12:56 +00001543 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001544 ("netlink_route_multipath() (single hop): "
1545 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001546#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001547 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001548 inet6_ntoa (p->u.prefix6),
1549#else
1550 inet_ntoa (p->u.prefix4),
1551#endif /* HAVE_IPV6 */
1552 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001553 }
paul5ec90d22003-06-19 01:41:37 +00001554
paul7021c422003-07-15 12:52:22 +00001555 if (nexthop->type == NEXTHOP_TYPE_IPV4
1556 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001557 {
1558 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1559 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001560 if (nexthop->src.ipv4.s_addr)
1561 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1562 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001563
1564 if (IS_ZEBRA_DEBUG_KERNEL)
1565 zlog_debug("netlink_route_multipath() (single hop): "
1566 "nexthop via %s if %u",
1567 inet_ntoa (nexthop->gate.ipv4),
1568 nexthop->ifindex);
1569 }
paul718e3742002-12-13 20:15:29 +00001570#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001571 if (nexthop->type == NEXTHOP_TYPE_IPV6
1572 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1573 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001574 {
1575 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1576 &nexthop->gate.ipv6, bytelen);
1577
1578 if (IS_ZEBRA_DEBUG_KERNEL)
1579 zlog_debug("netlink_route_multipath() (single hop): "
1580 "nexthop via %s if %u",
1581 inet6_ntoa (nexthop->gate.ipv6),
1582 nexthop->ifindex);
1583 }
paul718e3742002-12-13 20:15:29 +00001584#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001585 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1586 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001587 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1588 {
1589 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1590
1591 if (nexthop->src.ipv4.s_addr)
1592 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1593 &nexthop->src.ipv4, bytelen);
1594
1595 if (IS_ZEBRA_DEBUG_KERNEL)
1596 zlog_debug("netlink_route_multipath() (single hop): "
1597 "nexthop via if %u", nexthop->ifindex);
1598 }
1599 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001600 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001601 {
1602 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1603
1604 if (IS_ZEBRA_DEBUG_KERNEL)
1605 zlog_debug("netlink_route_multipath() (single hop): "
1606 "nexthop via if %u", nexthop->ifindex);
1607 }
paul7021c422003-07-15 12:52:22 +00001608 }
paul718e3742002-12-13 20:15:29 +00001609
paul7021c422003-07-15 12:52:22 +00001610 if (cmd == RTM_NEWROUTE)
1611 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001612
paul7021c422003-07-15 12:52:22 +00001613 nexthop_num++;
1614 break;
1615 }
1616 }
paul718e3742002-12-13 20:15:29 +00001617 }
1618 else
1619 {
1620 char buf[1024];
1621 struct rtattr *rta = (void *) buf;
1622 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001623 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001624
1625 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001626 rta->rta_len = RTA_LENGTH (0);
1627 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001628
1629 nexthop_num = 0;
1630 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001631 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1632 nexthop = nexthop->next)
1633 {
1634 if ((cmd == RTM_NEWROUTE
1635 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1636 || (cmd == RTM_DELROUTE
1637 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1638 {
1639 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001640
paul7021c422003-07-15 12:52:22 +00001641 rtnh->rtnh_len = sizeof (*rtnh);
1642 rtnh->rtnh_flags = 0;
1643 rtnh->rtnh_hops = 0;
1644 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001645
paul7021c422003-07-15 12:52:22 +00001646 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1647 {
1648 if (IS_ZEBRA_DEBUG_KERNEL)
1649 {
ajsb6178002004-12-07 21:12:56 +00001650 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001651 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001652 lookup (nlmsg_str, cmd),
1653#ifdef HAVE_IPV6
1654 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1655 inet6_ntoa (p->u.prefix6),
1656#else
1657 inet_ntoa (p->u.prefix4),
1658#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001659 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001660 }
1661 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1662 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1663 {
1664 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1665 &nexthop->rgate.ipv4, bytelen);
1666 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001667
Paul Jakma7514fb72007-05-02 16:05:35 +00001668 if (nexthop->src.ipv4.s_addr)
1669 src = &nexthop->src;
1670
hasso206d8052005-04-09 16:38:51 +00001671 if (IS_ZEBRA_DEBUG_KERNEL)
1672 zlog_debug("netlink_route_multipath() (recursive, "
1673 "multihop): nexthop via %s if %u",
1674 inet_ntoa (nexthop->rgate.ipv4),
1675 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001676 }
paul718e3742002-12-13 20:15:29 +00001677#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001678 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1679 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1680 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001681 {
1682 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1683 &nexthop->rgate.ipv6, bytelen);
1684
1685 if (IS_ZEBRA_DEBUG_KERNEL)
1686 zlog_debug("netlink_route_multipath() (recursive, "
1687 "multihop): nexthop via %s if %u",
1688 inet6_ntoa (nexthop->rgate.ipv6),
1689 nexthop->rifindex);
1690 }
paul718e3742002-12-13 20:15:29 +00001691#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001692 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001693 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1694 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1695 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1696 {
1697 rtnh->rtnh_ifindex = nexthop->rifindex;
1698 if (nexthop->src.ipv4.s_addr)
1699 src = &nexthop->src;
1700
1701 if (IS_ZEBRA_DEBUG_KERNEL)
1702 zlog_debug("netlink_route_multipath() (recursive, "
1703 "multihop): nexthop via if %u",
1704 nexthop->rifindex);
1705 }
1706 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001707 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001708 {
1709 rtnh->rtnh_ifindex = nexthop->rifindex;
1710
1711 if (IS_ZEBRA_DEBUG_KERNEL)
1712 zlog_debug("netlink_route_multipath() (recursive, "
1713 "multihop): nexthop via if %u",
1714 nexthop->rifindex);
1715 }
paul7021c422003-07-15 12:52:22 +00001716 else
hasso206d8052005-04-09 16:38:51 +00001717 {
1718 rtnh->rtnh_ifindex = 0;
1719 }
paul7021c422003-07-15 12:52:22 +00001720 }
1721 else
1722 {
1723 if (IS_ZEBRA_DEBUG_KERNEL)
1724 {
hasso206d8052005-04-09 16:38:51 +00001725 zlog_debug ("netlink_route_multipath() (multihop): "
1726 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001727#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001728 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001729 inet6_ntoa (p->u.prefix6),
1730#else
1731 inet_ntoa (p->u.prefix4),
1732#endif /* HAVE_IPV6 */
1733 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001734 }
1735 if (nexthop->type == NEXTHOP_TYPE_IPV4
1736 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1737 {
hasso206d8052005-04-09 16:38:51 +00001738 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1739 &nexthop->gate.ipv4, bytelen);
1740 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1741
Paul Jakma7514fb72007-05-02 16:05:35 +00001742 if (nexthop->src.ipv4.s_addr)
1743 src = &nexthop->src;
1744
hasso206d8052005-04-09 16:38:51 +00001745 if (IS_ZEBRA_DEBUG_KERNEL)
1746 zlog_debug("netlink_route_multipath() (multihop): "
1747 "nexthop via %s if %u",
1748 inet_ntoa (nexthop->gate.ipv4),
1749 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001750 }
paul718e3742002-12-13 20:15:29 +00001751#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001752 if (nexthop->type == NEXTHOP_TYPE_IPV6
1753 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1754 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001755 {
1756 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1757 &nexthop->gate.ipv6, bytelen);
1758
1759 if (IS_ZEBRA_DEBUG_KERNEL)
1760 zlog_debug("netlink_route_multipath() (multihop): "
1761 "nexthop via %s if %u",
1762 inet6_ntoa (nexthop->gate.ipv6),
1763 nexthop->ifindex);
1764 }
paul718e3742002-12-13 20:15:29 +00001765#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001766 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001767 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1768 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1769 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1770 {
1771 rtnh->rtnh_ifindex = nexthop->ifindex;
1772 if (nexthop->src.ipv4.s_addr)
1773 src = &nexthop->src;
1774 if (IS_ZEBRA_DEBUG_KERNEL)
1775 zlog_debug("netlink_route_multipath() (multihop): "
1776 "nexthop via if %u", nexthop->ifindex);
1777 }
1778 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001779 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001780 {
1781 rtnh->rtnh_ifindex = nexthop->ifindex;
1782
1783 if (IS_ZEBRA_DEBUG_KERNEL)
1784 zlog_debug("netlink_route_multipath() (multihop): "
1785 "nexthop via if %u", nexthop->ifindex);
1786 }
paul7021c422003-07-15 12:52:22 +00001787 else
hasso206d8052005-04-09 16:38:51 +00001788 {
1789 rtnh->rtnh_ifindex = 0;
1790 }
paul7021c422003-07-15 12:52:22 +00001791 }
1792 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001793
paul7021c422003-07-15 12:52:22 +00001794 if (cmd == RTM_NEWROUTE)
1795 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1796 }
1797 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001798 if (src)
1799 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001800
1801 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001802 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1803 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001804 }
1805
1806 /* If there is no useful nexthop then return. */
1807 if (nexthop_num == 0)
1808 {
1809 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001810 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001811 return 0;
1812 }
1813
paul7021c422003-07-15 12:52:22 +00001814skip:
paul718e3742002-12-13 20:15:29 +00001815
1816 /* Destination netlink address. */
1817 memset (&snl, 0, sizeof snl);
1818 snl.nl_family = AF_NETLINK;
1819
paul718e3742002-12-13 20:15:29 +00001820 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001821 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001822}
1823
1824int
1825kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1826{
1827 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1828}
1829
1830int
1831kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1832{
1833 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1834}
1835
1836#ifdef HAVE_IPV6
1837int
1838kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1839{
1840 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1841}
1842
1843int
1844kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1845{
1846 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1847}
1848
1849/* Delete IPv6 route from the kernel. */
1850int
1851kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001852 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001853{
paul7021c422003-07-15 12:52:22 +00001854 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1855 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001856}
1857#endif /* HAVE_IPV6 */
1858
1859/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001860static int
paul718e3742002-12-13 20:15:29 +00001861netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001862 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001863{
1864 int bytelen;
1865 struct prefix *p;
1866
paul7021c422003-07-15 12:52:22 +00001867 struct
paul718e3742002-12-13 20:15:29 +00001868 {
1869 struct nlmsghdr n;
1870 struct ifaddrmsg ifa;
1871 char buf[1024];
1872 } req;
1873
1874 p = ifc->address;
1875 memset (&req, 0, sizeof req);
1876
1877 bytelen = (family == AF_INET ? 4 : 16);
1878
paul7021c422003-07-15 12:52:22 +00001879 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001880 req.n.nlmsg_flags = NLM_F_REQUEST;
1881 req.n.nlmsg_type = cmd;
1882 req.ifa.ifa_family = family;
1883
1884 req.ifa.ifa_index = ifp->ifindex;
1885 req.ifa.ifa_prefixlen = p->prefixlen;
1886
1887 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1888
1889 if (family == AF_INET && cmd == RTM_NEWADDR)
1890 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001891 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001892 {
1893 p = ifc->destination;
1894 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1895 bytelen);
1896 }
paul718e3742002-12-13 20:15:29 +00001897 }
1898
1899 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1900 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001901
paul718e3742002-12-13 20:15:29 +00001902 if (ifc->label)
1903 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001904 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001905
1906 return netlink_talk (&req.n, &netlink_cmd);
1907}
1908
1909int
1910kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1911{
1912 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1913}
1914
1915int
1916kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1917{
1918 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1919}
1920
paul718e3742002-12-13 20:15:29 +00001921
1922extern struct thread_master *master;
1923
1924/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001925static int
paul718e3742002-12-13 20:15:29 +00001926kernel_read (struct thread *thread)
1927{
1928 int ret;
1929 int sock;
1930
1931 sock = THREAD_FD (thread);
1932 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001933 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001934
1935 return 0;
1936}
1937
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001938/* Filter out messages from self that occur on listener socket,
1939 caused by our actions on the command socket
1940 */
1941static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001942{
Paul Jakma768a27e2008-05-29 18:23:08 +00001943 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001944 /* 0: ldh [4] */
1945 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1946 /* 1: jeq 0x18 jt 3 jf 6 */
1947 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1948 /* 2: jeq 0x19 jt 3 jf 6 */
1949 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1950 /* 3: ldw [12] */
1951 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1952 /* 4: jeq XX jt 5 jf 6 */
1953 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1954 /* 5: ret 0 (skip) */
1955 BPF_STMT(BPF_RET|BPF_K, 0),
1956 /* 6: ret 0xffff (keep) */
1957 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001958 };
1959
1960 struct sock_fprog prog = {
1961 .len = sizeof(filter) / sizeof(filter[0]),
1962 .filter = filter,
1963 };
1964
1965 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1966 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1967}
1968
paul718e3742002-12-13 20:15:29 +00001969/* Exported interface function. This function simply calls
1970 netlink_socket (). */
1971void
paul6621ca82005-11-23 13:02:08 +00001972kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001973{
1974 unsigned long groups;
1975
paul7021c422003-07-15 12:52:22 +00001976 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001977#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001978 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001979#endif /* HAVE_IPV6 */
1980 netlink_socket (&netlink, groups);
1981 netlink_socket (&netlink_cmd, 0);
1982
1983 /* Register kernel socket. */
1984 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001985 {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001986 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001987 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1988 }
paul718e3742002-12-13 20:15:29 +00001989}