blob: 4234a4455f528878bcc2c9681e99193fafa93421 [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
paul7021c422003-07-15 12:52:22 +000055struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000056 {RTM_NEWROUTE, "RTM_NEWROUTE"},
57 {RTM_DELROUTE, "RTM_DELROUTE"},
58 {RTM_GETROUTE, "RTM_GETROUTE"},
59 {RTM_NEWLINK, "RTM_NEWLINK"},
60 {RTM_DELLINK, "RTM_DELLINK"},
61 {RTM_GETLINK, "RTM_GETLINK"},
62 {RTM_NEWADDR, "RTM_NEWADDR"},
63 {RTM_DELADDR, "RTM_DELADDR"},
64 {RTM_GETADDR, "RTM_GETADDR"},
paul7021c422003-07-15 12:52:22 +000065 {0, NULL}
paul718e3742002-12-13 20:15:29 +000066};
67
hassofce954f2004-10-07 20:29:24 +000068const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000069{
70 "none",
71 "Directly connected",
72 "Interface route",
73 "IPv4 nexthop",
74 "IPv4 nexthop with ifindex",
75 "IPv4 nexthop with ifname",
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
82
paulb21b19c2003-06-15 01:28:29 +000083extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000084
pauledd7c242003-06-04 13:59:38 +000085extern struct zebra_privs_t zserv_privs;
86
hassoc34b6b52004-08-31 13:41:49 +000087extern u_int32_t nl_rcvbufsize;
88
ajsd2fc8892005-04-02 18:38:43 +000089/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
90 names and ifindex values. */
91static void
92set_ifindex(struct interface *ifp, unsigned int ifi_index)
93{
94 struct interface *oifp;
95
96 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
97 {
98 if (ifi_index == IFINDEX_INTERNAL)
99 zlog_err("Netlink is setting interface %s ifindex to reserved "
100 "internal value %u", ifp->name, ifi_index);
101 else
102 {
103 if (IS_ZEBRA_DEBUG_KERNEL)
104 zlog_debug("interface index %d was renamed from %s to %s",
105 ifi_index, oifp->name, ifp->name);
106 if (if_is_up(oifp))
107 zlog_err("interface rename detected on up interface: index %d "
108 "was renamed from %s to %s, results are uncertain!",
109 ifi_index, oifp->name, ifp->name);
110 if_delete_update(oifp);
111 }
112 }
113 ifp->ifindex = ifi_index;
114}
115
paul718e3742002-12-13 20:15:29 +0000116/* Make socket for Linux netlink interface. */
117static int
118netlink_socket (struct nlsock *nl, unsigned long groups)
119{
120 int ret;
121 struct sockaddr_nl snl;
122 int sock;
123 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000124 int save_errno;
paul718e3742002-12-13 20:15:29 +0000125
126 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
127 if (sock < 0)
128 {
129 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000130 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000131 return -1;
132 }
133
134 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
135 if (ret < 0)
136 {
137 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000138 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000139 close (sock);
140 return -1;
141 }
paul7021c422003-07-15 12:52:22 +0000142
hassoc34b6b52004-08-31 13:41:49 +0000143 /* Set receive buffer size if it's set from command line */
144 if (nl_rcvbufsize)
145 {
146 u_int32_t oldsize, oldlen;
147 u_int32_t newsize, newlen;
148
149 oldlen = sizeof(oldsize);
150 newlen = sizeof(newsize);
151
152 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
153 if (ret < 0)
154 {
155 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000156 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000157 close (sock);
158 return -1;
159 }
160
161 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
162 sizeof(nl_rcvbufsize));
163 if (ret < 0)
164 {
165 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000166 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000167 close (sock);
168 return -1;
169 }
170
171 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
172 if (ret < 0)
173 {
174 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000175 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000176 close (sock);
177 return -1;
178 }
179
180 zlog (NULL, LOG_INFO,
181 "Setting netlink socket receive buffer size: %u -> %u",
182 oldsize, newsize);
183 }
184
paul718e3742002-12-13 20:15:29 +0000185 memset (&snl, 0, sizeof snl);
186 snl.nl_family = AF_NETLINK;
187 snl.nl_groups = groups;
188
189 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000190 if (zserv_privs.change (ZPRIVS_RAISE))
191 {
192 zlog (NULL, LOG_ERR, "Can't raise privileges");
193 return -1;
194 }
pauledd7c242003-06-04 13:59:38 +0000195
paul718e3742002-12-13 20:15:29 +0000196 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000197 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000198 if (zserv_privs.change (ZPRIVS_LOWER))
199 zlog (NULL, LOG_ERR, "Can't lower privileges");
200
paul718e3742002-12-13 20:15:29 +0000201 if (ret < 0)
202 {
paul7021c422003-07-15 12:52:22 +0000203 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000204 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000205 close (sock);
206 return -1;
207 }
paul7021c422003-07-15 12:52:22 +0000208
paul718e3742002-12-13 20:15:29 +0000209 /* multiple netlink sockets will have different nl_pid */
210 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000211 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000212 if (ret < 0 || namelen != sizeof snl)
213 {
214 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000215 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000216 close (sock);
217 return -1;
218 }
219
220 nl->snl = snl;
221 nl->sock = sock;
222 return ret;
223}
224
paul7021c422003-07-15 12:52:22 +0000225int
226set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000227{
228
229 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000230 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000231 {
paul7021c422003-07-15 12:52:22 +0000232 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000233 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000234 return -1;
235 }
236 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000237 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000238 {
paul7021c422003-07-15 12:52:22 +0000239 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000240 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000241 return -1;
242 }
243 return 0;
244}
245
paul7021c422003-07-15 12:52:22 +0000246int
247set_netlink_nonblocking (struct nlsock *nl, int *flags)
248{
paul5f37d862003-04-19 00:11:28 +0000249 /* Restore socket flags for nonblocking I/O */
250 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000251 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000252 {
paul7021c422003-07-15 12:52:22 +0000253 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
ajs6099b3b2004-11-20 02:06:59 +0000254 __FUNCTION__, __LINE__, safe_strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000255 return -1;
256 }
257 return 0;
258}
259
paul718e3742002-12-13 20:15:29 +0000260/* Get type specified information from netlink. */
261static int
262netlink_request (int family, int type, struct nlsock *nl)
263{
264 int ret;
265 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000266 int save_errno;
paul718e3742002-12-13 20:15:29 +0000267
268 struct
269 {
270 struct nlmsghdr nlh;
271 struct rtgenmsg g;
272 } req;
273
274
275 /* Check netlink socket. */
276 if (nl->sock < 0)
277 {
278 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
279 return -1;
280 }
281
282 memset (&snl, 0, sizeof snl);
283 snl.nl_family = AF_NETLINK;
284
ajsc05612b2005-10-01 16:36:54 +0000285 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000286 req.nlh.nlmsg_len = sizeof req;
287 req.nlh.nlmsg_type = type;
288 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
289 req.nlh.nlmsg_pid = 0;
290 req.nlh.nlmsg_seq = ++nl->seq;
291 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000292
293 /* linux appears to check capabilities on every message
294 * have to raise caps for every message sent
295 */
paul7021c422003-07-15 12:52:22 +0000296 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000297 {
298 zlog (NULL, LOG_ERR, "Can't raise privileges");
299 return -1;
300 }
paul7021c422003-07-15 12:52:22 +0000301
302 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
303 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000304 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000305
306 if (zserv_privs.change (ZPRIVS_LOWER))
307 zlog (NULL, LOG_ERR, "Can't lower privileges");
308
paul718e3742002-12-13 20:15:29 +0000309 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000310 {
311 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000312 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000313 return -1;
314 }
pauledd7c242003-06-04 13:59:38 +0000315
paul718e3742002-12-13 20:15:29 +0000316 return 0;
317}
318
319/* Receive message from netlink interface and pass those information
320 to the given function. */
321static int
322netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000323 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000324{
325 int status;
326 int ret = 0;
327 int error;
328
329 while (1)
330 {
331 char buf[4096];
332 struct iovec iov = { buf, sizeof buf };
333 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000334 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000335 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000336 int save_errno;
paul718e3742002-12-13 20:15:29 +0000337
paul7021c422003-07-15 12:52:22 +0000338 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000339 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000340
paul718e3742002-12-13 20:15:29 +0000341 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000342 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000343
344 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000345 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000346
347 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000348 {
ajs4be019d2005-01-29 16:12:41 +0000349 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000350 continue;
ajs4be019d2005-01-29 16:12:41 +0000351 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000352 break;
ajs4be019d2005-01-29 16:12:41 +0000353 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
354 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000355 continue;
356 }
paul718e3742002-12-13 20:15:29 +0000357
358 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000359 {
360 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
361 return -1;
362 }
paul718e3742002-12-13 20:15:29 +0000363
364 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000365 {
366 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
367 nl->name, msg.msg_namelen);
368 return -1;
369 }
paulb84d3a12003-11-17 10:31:01 +0000370
371 /* JF: Ignore messages that aren't from the kernel */
372 if ( snl.nl_pid != 0 )
373 {
374 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
375 continue;
376 }
paul718e3742002-12-13 20:15:29 +0000377
hasso206d8052005-04-09 16:38:51 +0000378 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000379 h = NLMSG_NEXT (h, status))
380 {
381 /* Finish of reading. */
382 if (h->nlmsg_type == NLMSG_DONE)
383 return ret;
paul718e3742002-12-13 20:15:29 +0000384
paul7021c422003-07-15 12:52:22 +0000385 /* Error handling. */
386 if (h->nlmsg_type == NLMSG_ERROR)
387 {
388 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
389
paul718e3742002-12-13 20:15:29 +0000390 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000391 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000392 {
paul7021c422003-07-15 12:52:22 +0000393 if (IS_ZEBRA_DEBUG_KERNEL)
394 {
hasso1ada8192005-06-12 11:28:18 +0000395 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000396 __FUNCTION__, nl->name,
397 lookup (nlmsg_str, err->msg.nlmsg_type),
398 err->msg.nlmsg_type, err->msg.nlmsg_seq,
399 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000400 }
paul7021c422003-07-15 12:52:22 +0000401
402 /* return if not a multipart message, otherwise continue */
403 if (!(h->nlmsg_flags & NLM_F_MULTI))
404 {
405 return 0;
paul718e3742002-12-13 20:15:29 +0000406 }
paul7021c422003-07-15 12:52:22 +0000407 continue;
paul718e3742002-12-13 20:15:29 +0000408 }
paul7021c422003-07-15 12:52:22 +0000409
paul718e3742002-12-13 20:15:29 +0000410 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000411 {
412 zlog (NULL, LOG_ERR, "%s error: message truncated",
413 nl->name);
414 return -1;
415 }
pauld753e9e2003-01-22 19:45:50 +0000416
paul7021c422003-07-15 12:52:22 +0000417 /* Deal with Error Noise - MAG */
418 {
419 int loglvl = LOG_ERR;
420 int errnum = err->error;
421 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000422
paul7021c422003-07-15 12:52:22 +0000423 if (nl == &netlink_cmd
424 && (-errnum == ENODEV || -errnum == ESRCH)
425 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
426 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000427
paul7021c422003-07-15 12:52:22 +0000428 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
hasso1ada8192005-06-12 11:28:18 +0000429 "seq=%u, pid=%u",
ajs6099b3b2004-11-20 02:06:59 +0000430 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000431 lookup (nlmsg_str, msg_type),
432 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
433 }
434 /*
435 ret = -1;
436 continue;
437 */
438 return -1;
439 }
paul718e3742002-12-13 20:15:29 +0000440
paul7021c422003-07-15 12:52:22 +0000441 /* OK we got netlink message. */
442 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000443 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000444 nl->name,
445 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
446 h->nlmsg_seq, h->nlmsg_pid);
447
448 /* skip unsolicited messages originating from command socket */
449 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
450 {
451 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000452 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000453 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000454 continue;
455 }
456
457 error = (*filter) (&snl, h);
458 if (error < 0)
459 {
460 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
461 ret = error;
462 }
463 }
paul718e3742002-12-13 20:15:29 +0000464
465 /* After error care. */
466 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000467 {
468 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
469 continue;
470 }
paul718e3742002-12-13 20:15:29 +0000471 if (status)
paul7021c422003-07-15 12:52:22 +0000472 {
473 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
474 status);
475 return -1;
476 }
paul718e3742002-12-13 20:15:29 +0000477 }
478 return ret;
479}
480
481/* Utility function for parse rtattr. */
482static void
paul7021c422003-07-15 12:52:22 +0000483netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
484 int len)
paul718e3742002-12-13 20:15:29 +0000485{
paul7021c422003-07-15 12:52:22 +0000486 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000487 {
488 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000489 tb[rta->rta_type] = rta;
490 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000491 }
492}
493
494/* Called from interface_lookup_netlink(). This function is only used
495 during bootstrap. */
496int
497netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
498{
499 int len;
500 struct ifinfomsg *ifi;
501 struct rtattr *tb[IFLA_MAX + 1];
502 struct interface *ifp;
503 char *name;
504 int i;
505
506 ifi = NLMSG_DATA (h);
507
508 if (h->nlmsg_type != RTM_NEWLINK)
509 return 0;
510
511 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
512 if (len < 0)
513 return -1;
514
515 /* Looking up interface name. */
516 memset (tb, 0, sizeof tb);
517 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000518
paul1e193152005-02-14 23:53:05 +0000519#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000520 /* check for wireless messages to ignore */
521 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
522 {
523 if (IS_ZEBRA_DEBUG_KERNEL)
524 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
525 return 0;
526 }
paul1e193152005-02-14 23:53:05 +0000527#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000528
paul718e3742002-12-13 20:15:29 +0000529 if (tb[IFLA_IFNAME] == NULL)
530 return -1;
paul7021c422003-07-15 12:52:22 +0000531 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000532
533 /* Add interface. */
534 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000535 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000536 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000537 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000538 ifp->metric = 1;
539
540 /* Hardware type and address. */
541 ifp->hw_type = ifi->ifi_type;
542
543 if (tb[IFLA_ADDRESS])
544 {
545 int hw_addr_len;
546
paul7021c422003-07-15 12:52:22 +0000547 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000548
549 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000550 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000551 else
paul7021c422003-07-15 12:52:22 +0000552 {
553 ifp->hw_addr_len = hw_addr_len;
554 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000555
paul7021c422003-07-15 12:52:22 +0000556 for (i = 0; i < hw_addr_len; i++)
557 if (ifp->hw_addr[i] != 0)
558 break;
paul718e3742002-12-13 20:15:29 +0000559
paul7021c422003-07-15 12:52:22 +0000560 if (i == hw_addr_len)
561 ifp->hw_addr_len = 0;
562 else
563 ifp->hw_addr_len = hw_addr_len;
564 }
paul718e3742002-12-13 20:15:29 +0000565 }
566
567 if_add_update (ifp);
568
569 return 0;
570}
571
572/* Lookup interface IPv4/IPv6 address. */
573int
574netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
575{
576 int len;
577 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000578 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000579 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000580 void *addr;
581 void *broad;
paul718e3742002-12-13 20:15:29 +0000582 u_char flags = 0;
583 char *label = NULL;
584
585 ifa = NLMSG_DATA (h);
586
paul7021c422003-07-15 12:52:22 +0000587 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000588#ifdef HAVE_IPV6
589 && ifa->ifa_family != AF_INET6
590#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000591 )
paul718e3742002-12-13 20:15:29 +0000592 return 0;
593
594 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
595 return 0;
596
paul7021c422003-07-15 12:52:22 +0000597 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000598 if (len < 0)
599 return -1;
600
601 memset (tb, 0, sizeof tb);
602 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
603
604 ifp = if_lookup_by_index (ifa->ifa_index);
605 if (ifp == NULL)
606 {
607 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000608 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000609 return -1;
610 }
611
paul7021c422003-07-15 12:52:22 +0000612 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000613 {
paul00df0c12002-12-13 21:07:36 +0000614 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000615 zlog_debug ("netlink_interface_addr %s %s:",
616 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000617 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000618 zlog_debug (" IFA_LOCAL %s/%d",
619 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
620 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000621 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000622 zlog_debug (" IFA_ADDRESS %s/%d",
623 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
624 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000625 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000626 zlog_debug (" IFA_BROADCAST %s/%d",
627 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
628 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000629 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000630 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000631
632 if (tb[IFA_CACHEINFO])
633 {
634 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
635 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
636 ci->ifa_prefered, ci->ifa_valid);
637 }
paul718e3742002-12-13 20:15:29 +0000638 }
paul31a476c2003-09-29 19:54:53 +0000639
Andrew J. Schorre4529632006-12-12 19:18:21 +0000640 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
641 if (tb[IFA_LOCAL] == NULL)
642 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000643 if (tb[IFA_ADDRESS] == NULL)
644 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
645
Andrew J. Schorre4529632006-12-12 19:18:21 +0000646 /* local interface address */
647 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
648
649 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000650 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000651 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000652 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000653 broad = RTA_DATA(tb[IFA_ADDRESS]);
654 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000655 }
paul31a476c2003-09-29 19:54:53 +0000656 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000657 /* seeking a broadcast address */
658 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000659
Paul Jakma27b47252006-07-02 16:38:54 +0000660 /* addr is primary key, SOL if we don't have one */
661 if (addr == NULL)
662 {
663 zlog_debug ("%s: NULL address", __func__);
664 return -1;
665 }
666
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,
paul0752ef02005-11-03 12:35:21 +0000688 (struct in_addr *) broad);
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)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000694 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000695 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000696 (struct in6_addr *) broad, label);
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;
Paul Jakma7514fb72007-05-02 16:05:35 +0000724 void *src;
paul718e3742002-12-13 20:15:29 +0000725
726 rtm = NLMSG_DATA (h);
727
728 if (h->nlmsg_type != RTM_NEWROUTE)
729 return 0;
730 if (rtm->rtm_type != RTN_UNICAST)
731 return 0;
732
733 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000734#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000735 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000736 return 0;
737#endif
738
paul7021c422003-07-15 12:52:22 +0000739 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000740 if (len < 0)
741 return -1;
742
743 memset (tb, 0, sizeof tb);
744 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
745
746 if (rtm->rtm_flags & RTM_F_CLONED)
747 return 0;
748 if (rtm->rtm_protocol == RTPROT_REDIRECT)
749 return 0;
750 if (rtm->rtm_protocol == RTPROT_KERNEL)
751 return 0;
752
753 if (rtm->rtm_src_len != 0)
754 return 0;
755
756 /* Route which inserted by Zebra. */
757 if (rtm->rtm_protocol == RTPROT_ZEBRA)
758 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000759
paul718e3742002-12-13 20:15:29 +0000760 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000761 metric = 0;
paul718e3742002-12-13 20:15:29 +0000762 dest = NULL;
763 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000764 src = NULL;
paul718e3742002-12-13 20:15:29 +0000765
766 if (tb[RTA_OIF])
767 index = *(int *) RTA_DATA (tb[RTA_OIF]);
768
769 if (tb[RTA_DST])
770 dest = RTA_DATA (tb[RTA_DST]);
771 else
772 dest = anyaddr;
773
Paul Jakma7514fb72007-05-02 16:05:35 +0000774 if (tb[RTA_PREFSRC])
775 src = RTA_DATA (tb[RTA_PREFSRC]);
776
paul718e3742002-12-13 20:15:29 +0000777 /* Multipath treatment is needed. */
778 if (tb[RTA_GATEWAY])
779 gate = RTA_DATA (tb[RTA_GATEWAY]);
780
hasso34195bf2004-04-06 12:07:06 +0000781 if (tb[RTA_PRIORITY])
782 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
783
paul718e3742002-12-13 20:15:29 +0000784 if (rtm->rtm_family == AF_INET)
785 {
786 struct prefix_ipv4 p;
787 p.family = AF_INET;
788 memcpy (&p.prefix, dest, 4);
789 p.prefixlen = rtm->rtm_dst_len;
790
Paul Jakma7514fb72007-05-02 16:05:35 +0000791 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000792 }
793#ifdef HAVE_IPV6
794 if (rtm->rtm_family == AF_INET6)
795 {
796 struct prefix_ipv6 p;
797 p.family = AF_INET6;
798 memcpy (&p.prefix, dest, 16);
799 p.prefixlen = rtm->rtm_dst_len;
800
hassobe61c4e2005-08-27 06:05:47 +0000801 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
802 metric, 0);
paul718e3742002-12-13 20:15:29 +0000803 }
804#endif /* HAVE_IPV6 */
805
806 return 0;
807}
808
paul7021c422003-07-15 12:52:22 +0000809struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000810 {RTPROT_REDIRECT, "redirect"},
811 {RTPROT_KERNEL, "kernel"},
812 {RTPROT_BOOT, "boot"},
813 {RTPROT_STATIC, "static"},
814 {RTPROT_GATED, "GateD"},
815 {RTPROT_RA, "router advertisement"},
816 {RTPROT_MRT, "MRT"},
817 {RTPROT_ZEBRA, "Zebra"},
818#ifdef RTPROT_BIRD
819 {RTPROT_BIRD, "BIRD"},
820#endif /* RTPROT_BIRD */
821 {0, NULL}
822};
823
824/* Routing information change from the kernel. */
825int
826netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
827{
828 int len;
829 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000830 struct rtattr *tb[RTA_MAX + 1];
831
832 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000833
834 int index;
835 int table;
836 void *dest;
837 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000838 void *src;
paul718e3742002-12-13 20:15:29 +0000839
840 rtm = NLMSG_DATA (h);
841
paul7021c422003-07-15 12:52:22 +0000842 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000843 {
844 /* If this is not route add/delete message print warning. */
845 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
846 return 0;
847 }
848
849 /* Connected route. */
850 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000851 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000852 h->nlmsg_type ==
853 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
854 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
855 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
856 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000857
858 if (rtm->rtm_type != RTN_UNICAST)
859 {
860 return 0;
861 }
862
863 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000864 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000865 {
866 return 0;
867 }
868
paul7021c422003-07-15 12:52:22 +0000869 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000870 if (len < 0)
871 return -1;
872
873 memset (tb, 0, sizeof tb);
874 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
875
876 if (rtm->rtm_flags & RTM_F_CLONED)
877 return 0;
878 if (rtm->rtm_protocol == RTPROT_REDIRECT)
879 return 0;
880 if (rtm->rtm_protocol == RTPROT_KERNEL)
881 return 0;
882
883 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
884 return 0;
885
886 if (rtm->rtm_src_len != 0)
887 {
888 zlog_warn ("netlink_route_change(): no src len");
889 return 0;
890 }
paul7021c422003-07-15 12:52:22 +0000891
paul718e3742002-12-13 20:15:29 +0000892 index = 0;
893 dest = NULL;
894 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000895 src = NULL;
paul718e3742002-12-13 20:15:29 +0000896
897 if (tb[RTA_OIF])
898 index = *(int *) RTA_DATA (tb[RTA_OIF]);
899
900 if (tb[RTA_DST])
901 dest = RTA_DATA (tb[RTA_DST]);
902 else
903 dest = anyaddr;
904
905 if (tb[RTA_GATEWAY])
906 gate = RTA_DATA (tb[RTA_GATEWAY]);
907
Paul Jakma7514fb72007-05-02 16:05:35 +0000908 if (tb[RTA_PREFSRC])
909 src = RTA_DATA (tb[RTA_PREFSRC]);
910
paul718e3742002-12-13 20:15:29 +0000911 if (rtm->rtm_family == AF_INET)
912 {
913 struct prefix_ipv4 p;
914 p.family = AF_INET;
915 memcpy (&p.prefix, dest, 4);
916 p.prefixlen = rtm->rtm_dst_len;
917
918 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000919 {
920 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000921 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000922 inet_ntoa (p.prefix), p.prefixlen);
923 else
ajsb6178002004-12-07 21:12:56 +0000924 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000925 inet_ntoa (p.prefix), p.prefixlen);
926 }
paul718e3742002-12-13 20:15:29 +0000927
928 if (h->nlmsg_type == RTM_NEWROUTE)
Paul Jakma7514fb72007-05-02 16:05:35 +0000929 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000930 else
paul7021c422003-07-15 12:52:22 +0000931 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000932 }
933
934#ifdef HAVE_IPV6
935 if (rtm->rtm_family == AF_INET6)
936 {
937 struct prefix_ipv6 p;
938 char buf[BUFSIZ];
939
940 p.family = AF_INET6;
941 memcpy (&p.prefix, dest, 16);
942 p.prefixlen = rtm->rtm_dst_len;
943
944 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000945 {
946 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000947 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000948 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
949 p.prefixlen);
950 else
ajsb6178002004-12-07 21:12:56 +0000951 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000952 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
953 p.prefixlen);
954 }
paul718e3742002-12-13 20:15:29 +0000955
956 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000957 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000958 else
paul7021c422003-07-15 12:52:22 +0000959 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000960 }
961#endif /* HAVE_IPV6 */
962
963 return 0;
964}
965
966int
967netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
968{
969 int len;
970 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000971 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000972 struct interface *ifp;
973 char *name;
974
975 ifi = NLMSG_DATA (h);
976
paul7021c422003-07-15 12:52:22 +0000977 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000978 {
979 /* If this is not link add/delete message so print warning. */
980 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000981 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000982 return 0;
983 }
984
985 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
986 if (len < 0)
987 return -1;
988
989 /* Looking up interface name. */
990 memset (tb, 0, sizeof tb);
991 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000992
paul1e193152005-02-14 23:53:05 +0000993#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000994 /* check for wireless messages to ignore */
995 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
996 {
997 if (IS_ZEBRA_DEBUG_KERNEL)
998 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
999 return 0;
1000 }
paul1e193152005-02-14 23:53:05 +00001001#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001002
paul718e3742002-12-13 20:15:29 +00001003 if (tb[IFLA_IFNAME] == NULL)
1004 return -1;
paul7021c422003-07-15 12:52:22 +00001005 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001006
1007 /* Add interface. */
1008 if (h->nlmsg_type == RTM_NEWLINK)
1009 {
1010 ifp = if_lookup_by_name (name);
1011
paul7021c422003-07-15 12:52:22 +00001012 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1013 {
1014 if (ifp == NULL)
1015 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001016
ajsd2fc8892005-04-02 18:38:43 +00001017 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001018 ifp->flags = ifi->ifi_flags & 0x0000fffff;
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 new link is added. */
1023 if_add_update (ifp);
1024 }
paul718e3742002-12-13 20:15:29 +00001025 else
paul7021c422003-07-15 12:52:22 +00001026 {
1027 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001028 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001029 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001030 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001031
paul7021c422003-07-15 12:52:22 +00001032 if (if_is_operative (ifp))
1033 {
1034 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1035 if (!if_is_operative (ifp))
1036 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001037 else
1038 /* Must notify client daemons of new interface status. */
1039 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001040 }
1041 else
1042 {
1043 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1044 if (if_is_operative (ifp))
1045 if_up (ifp);
1046 }
1047 }
paul718e3742002-12-13 20:15:29 +00001048 }
1049 else
1050 {
1051 /* RTM_DELLINK. */
1052 ifp = if_lookup_by_name (name);
1053
1054 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001055 {
1056 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001057 name);
paul7021c422003-07-15 12:52:22 +00001058 return 0;
1059 }
1060
paul718e3742002-12-13 20:15:29 +00001061 if_delete_update (ifp);
1062 }
1063
1064 return 0;
1065}
1066
1067int
1068netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1069{
1070 switch (h->nlmsg_type)
1071 {
1072 case RTM_NEWROUTE:
1073 return netlink_route_change (snl, h);
1074 break;
1075 case RTM_DELROUTE:
1076 return netlink_route_change (snl, h);
1077 break;
1078 case RTM_NEWLINK:
1079 return netlink_link_change (snl, h);
1080 break;
1081 case RTM_DELLINK:
1082 return netlink_link_change (snl, h);
1083 break;
1084 case RTM_NEWADDR:
1085 return netlink_interface_addr (snl, h);
1086 break;
1087 case RTM_DELADDR:
1088 return netlink_interface_addr (snl, h);
1089 break;
1090 default:
1091 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1092 break;
1093 }
1094 return 0;
1095}
1096
1097/* Interface lookup by netlink socket. */
1098int
paul6621ca82005-11-23 13:02:08 +00001099interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001100{
1101 int ret;
paul5f37d862003-04-19 00:11:28 +00001102 int flags;
1103 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001104
paul5f37d862003-04-19 00:11:28 +00001105 /*
1106 * Change netlink socket flags to blocking to ensure we get
1107 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001108 */
1109 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1110 if (snb_ret < 0)
1111 zlog (NULL, LOG_WARNING,
1112 "%s:%i Warning: Could not set netlink socket to blocking.",
1113 __FUNCTION__, __LINE__);
1114
paul718e3742002-12-13 20:15:29 +00001115 /* Get interface information. */
1116 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1117 if (ret < 0)
1118 return ret;
1119 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1120 if (ret < 0)
1121 return ret;
1122
1123 /* Get IPv4 address of the interfaces. */
1124 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1125 if (ret < 0)
1126 return ret;
1127 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1128 if (ret < 0)
1129 return ret;
1130
1131#ifdef HAVE_IPV6
1132 /* Get IPv6 address of the interfaces. */
1133 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1134 if (ret < 0)
1135 return ret;
1136 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1137 if (ret < 0)
1138 return ret;
1139#endif /* HAVE_IPV6 */
1140
paul7021c422003-07-15 12:52:22 +00001141 /* restore socket flags */
1142 if (snb_ret == 0)
1143 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001144 return 0;
1145}
1146
1147/* Routing table read function using netlink interface. Only called
1148 bootstrap time. */
1149int
paul6621ca82005-11-23 13:02:08 +00001150netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001151{
1152 int ret;
paul5f37d862003-04-19 00:11:28 +00001153 int flags;
1154 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001155
paul5f37d862003-04-19 00:11:28 +00001156 /*
1157 * Change netlink socket flags to blocking to ensure we get
1158 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001159 */
1160 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1161 if (snb_ret < 0)
1162 zlog (NULL, LOG_WARNING,
1163 "%s:%i Warning: Could not set netlink socket to blocking.",
1164 __FUNCTION__, __LINE__);
1165
paul718e3742002-12-13 20:15:29 +00001166 /* Get IPv4 routing table. */
1167 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1168 if (ret < 0)
1169 return ret;
1170 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1171 if (ret < 0)
1172 return ret;
1173
1174#ifdef HAVE_IPV6
1175 /* Get IPv6 routing table. */
1176 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1177 if (ret < 0)
1178 return ret;
1179 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1180 if (ret < 0)
1181 return ret;
1182#endif /* HAVE_IPV6 */
1183
paul5f37d862003-04-19 00:11:28 +00001184 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001185 if (snb_ret == 0)
1186 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001187 return 0;
1188}
1189
1190/* Utility function comes from iproute2.
1191 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1192int
1193addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1194{
1195 int len;
1196 struct rtattr *rta;
1197
paul7021c422003-07-15 12:52:22 +00001198 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001199
paul7021c422003-07-15 12:52:22 +00001200 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001201 return -1;
1202
paul7021c422003-07-15 12:52:22 +00001203 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001204 rta->rta_type = type;
1205 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001206 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001207 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1208
1209 return 0;
1210}
1211
1212int
1213rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1214{
1215 int len;
1216 struct rtattr *subrta;
1217
paul7021c422003-07-15 12:52:22 +00001218 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001219
paul7021c422003-07-15 12:52:22 +00001220 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001221 return -1;
1222
paul7021c422003-07-15 12:52:22 +00001223 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001224 subrta->rta_type = type;
1225 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001226 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001227 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1228
1229 return 0;
1230}
1231
1232/* Utility function comes from iproute2.
1233 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1234int
1235addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1236{
1237 int len;
1238 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001239
1240 len = RTA_LENGTH (4);
1241
paul718e3742002-12-13 20:15:29 +00001242 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1243 return -1;
1244
paul7021c422003-07-15 12:52:22 +00001245 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001246 rta->rta_type = type;
1247 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001248 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001249 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1250
1251 return 0;
1252}
1253
1254static int
1255netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1256{
hassob7ed1ec2005-03-31 20:13:49 +00001257 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001258 return 0;
1259}
1260
1261/* sendmsg() to netlink socket then recvmsg(). */
1262int
1263netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1264{
1265 int status;
1266 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001267 struct iovec iov = { (void *) n, n->nlmsg_len };
1268 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001269 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001270 int snb_ret;
ajs4be019d2005-01-29 16:12:41 +00001271 int save_errno;
paul7021c422003-07-15 12:52:22 +00001272
paul718e3742002-12-13 20:15:29 +00001273 memset (&snl, 0, sizeof snl);
1274 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001275
hassob7ed1ec2005-03-31 20:13:49 +00001276 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001277
1278 /* Request an acknowledgement by setting NLM_F_ACK */
1279 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001280
1281 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001282 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001283 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1284 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001285
1286 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001287 if (zserv_privs.change (ZPRIVS_RAISE))
1288 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001289 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001290 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001291 if (zserv_privs.change (ZPRIVS_LOWER))
1292 zlog (NULL, LOG_ERR, "Can't lower privileges");
1293
paul718e3742002-12-13 20:15:29 +00001294 if (status < 0)
1295 {
1296 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001297 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001298 return -1;
1299 }
paul7021c422003-07-15 12:52:22 +00001300
paul718e3742002-12-13 20:15:29 +00001301 /*
1302 * Change socket flags for blocking I/O.
1303 * This ensures we wait for a reply in netlink_parse_info().
1304 */
paul7021c422003-07-15 12:52:22 +00001305 snb_ret = set_netlink_blocking (nl, &flags);
1306 if (snb_ret < 0)
1307 zlog (NULL, LOG_WARNING,
1308 "%s:%i Warning: Could not set netlink socket to blocking.",
1309 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001310
1311 /*
1312 * Get reply from netlink socket.
1313 * The reply should either be an acknowlegement or an error.
1314 */
1315 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001316
paul718e3742002-12-13 20:15:29 +00001317 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001318 if (snb_ret == 0)
1319 set_netlink_nonblocking (nl, &flags);
1320
paul718e3742002-12-13 20:15:29 +00001321 return status;
1322}
1323
1324/* Routing table change via netlink interface. */
1325int
1326netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001327 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001328{
1329 int ret;
1330 int bytelen;
1331 struct sockaddr_nl snl;
1332 int discard;
1333
paul7021c422003-07-15 12:52:22 +00001334 struct
paul718e3742002-12-13 20:15:29 +00001335 {
1336 struct nlmsghdr n;
1337 struct rtmsg r;
1338 char buf[1024];
1339 } req;
1340
1341 memset (&req, 0, sizeof req);
1342
1343 bytelen = (family == AF_INET ? 4 : 16);
1344
1345 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1346 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1347 req.n.nlmsg_type = cmd;
1348 req.r.rtm_family = family;
1349 req.r.rtm_table = table;
1350 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001351 req.r.rtm_protocol = RTPROT_ZEBRA;
1352 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001353
hasso81dfcaa2003-05-25 19:21:25 +00001354 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1355 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001356 discard = 1;
1357 else
1358 discard = 0;
1359
paul7021c422003-07-15 12:52:22 +00001360 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001361 {
paul7021c422003-07-15 12:52:22 +00001362 if (discard)
paul595db7f2003-05-25 21:35:06 +00001363 {
1364 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1365 req.r.rtm_type = RTN_BLACKHOLE;
1366 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1367 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001368 else
1369 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1370 }
paul595db7f2003-05-25 21:35:06 +00001371 else
paul7021c422003-07-15 12:52:22 +00001372 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001373 }
1374
1375 if (dest)
1376 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1377
paul7021c422003-07-15 12:52:22 +00001378 if (!discard)
paul718e3742002-12-13 20:15:29 +00001379 {
1380 if (gate)
paul7021c422003-07-15 12:52:22 +00001381 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001382 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001383 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001384 }
1385
1386 /* Destination netlink address. */
1387 memset (&snl, 0, sizeof snl);
1388 snl.nl_family = AF_NETLINK;
1389
1390 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001391 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001392 if (ret < 0)
1393 return -1;
1394
1395 return 0;
1396}
1397
1398/* Routing table change via netlink interface. */
1399int
1400netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001401 int family)
paul718e3742002-12-13 20:15:29 +00001402{
1403 int bytelen;
1404 struct sockaddr_nl snl;
1405 struct nexthop *nexthop = NULL;
1406 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001407 int discard;
1408
paul7021c422003-07-15 12:52:22 +00001409 struct
paul718e3742002-12-13 20:15:29 +00001410 {
1411 struct nlmsghdr n;
1412 struct rtmsg r;
1413 char buf[1024];
1414 } req;
1415
1416 memset (&req, 0, sizeof req);
1417
1418 bytelen = (family == AF_INET ? 4 : 16);
1419
1420 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1421 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1422 req.n.nlmsg_type = cmd;
1423 req.r.rtm_family = family;
1424 req.r.rtm_table = rib->table;
1425 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001426 req.r.rtm_protocol = RTPROT_ZEBRA;
1427 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001428
paul7021c422003-07-15 12:52:22 +00001429 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001430 discard = 1;
1431 else
1432 discard = 0;
1433
paul7021c422003-07-15 12:52:22 +00001434 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001435 {
paul7021c422003-07-15 12:52:22 +00001436 if (discard)
paul595db7f2003-05-25 21:35:06 +00001437 {
1438 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1439 req.r.rtm_type = RTN_BLACKHOLE;
1440 else if (rib->flags & ZEBRA_FLAG_REJECT)
1441 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001442 else
1443 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1444 }
paul595db7f2003-05-25 21:35:06 +00001445 else
paul7021c422003-07-15 12:52:22 +00001446 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001447 }
1448
1449 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1450
1451 /* Metric. */
1452 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1453
1454 if (discard)
1455 {
1456 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001457 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1458 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001459 goto skip;
1460 }
1461
1462 /* Multipath case. */
1463 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1464 {
1465 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001466 {
paul5ec90d22003-06-19 01:41:37 +00001467
paul7021c422003-07-15 12:52:22 +00001468 if ((cmd == RTM_NEWROUTE
1469 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1470 || (cmd == RTM_DELROUTE
1471 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1472 {
paul5ec90d22003-06-19 01:41:37 +00001473
paul7021c422003-07-15 12:52:22 +00001474 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1475 {
1476 if (IS_ZEBRA_DEBUG_KERNEL)
1477 {
ajsb6178002004-12-07 21:12:56 +00001478 zlog_debug
paul7021c422003-07-15 12:52:22 +00001479 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001480 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001481#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001482 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001483 inet6_ntoa (p->u.prefix6),
1484#else
1485 inet_ntoa (p->u.prefix4),
1486#endif /* HAVE_IPV6 */
1487
1488 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001489 }
paul5ec90d22003-06-19 01:41:37 +00001490
paul7021c422003-07-15 12:52:22 +00001491 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1492 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001493 {
1494 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1495 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001496 if (nexthop->src.ipv4.s_addr)
1497 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1498 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001499 if (IS_ZEBRA_DEBUG_KERNEL)
1500 zlog_debug("netlink_route_multipath() (recursive, "
1501 "1 hop): nexthop via %s if %u",
1502 inet_ntoa (nexthop->rgate.ipv4),
1503 nexthop->rifindex);
1504 }
paul718e3742002-12-13 20:15:29 +00001505#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001506 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1507 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1508 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001509 {
1510 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1511 &nexthop->rgate.ipv6, bytelen);
1512
1513 if (IS_ZEBRA_DEBUG_KERNEL)
1514 zlog_debug("netlink_route_multipath() (recursive, "
1515 "1 hop): nexthop via %s if %u",
1516 inet6_ntoa (nexthop->rgate.ipv6),
1517 nexthop->rifindex);
1518 }
paul718e3742002-12-13 20:15:29 +00001519#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001520 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1521 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1522 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1523 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1524 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001525 {
1526 addattr32 (&req.n, sizeof req, RTA_OIF,
1527 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001528 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1529 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1530 && nexthop->src.ipv4.s_addr)
1531 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1532 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001533
1534 if (IS_ZEBRA_DEBUG_KERNEL)
1535 zlog_debug("netlink_route_multipath() (recursive, "
1536 "1 hop): nexthop via if %u",
1537 nexthop->rifindex);
1538 }
paul7021c422003-07-15 12:52:22 +00001539 }
1540 else
1541 {
1542 if (IS_ZEBRA_DEBUG_KERNEL)
1543 {
ajsb6178002004-12-07 21:12:56 +00001544 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001545 ("netlink_route_multipath() (single hop): "
1546 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001547#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001548 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001549 inet6_ntoa (p->u.prefix6),
1550#else
1551 inet_ntoa (p->u.prefix4),
1552#endif /* HAVE_IPV6 */
1553 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001554 }
paul5ec90d22003-06-19 01:41:37 +00001555
paul7021c422003-07-15 12:52:22 +00001556 if (nexthop->type == NEXTHOP_TYPE_IPV4
1557 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001558 {
1559 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1560 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001561 if (nexthop->src.ipv4.s_addr)
1562 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1563 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001564
1565 if (IS_ZEBRA_DEBUG_KERNEL)
1566 zlog_debug("netlink_route_multipath() (single hop): "
1567 "nexthop via %s if %u",
1568 inet_ntoa (nexthop->gate.ipv4),
1569 nexthop->ifindex);
1570 }
paul718e3742002-12-13 20:15:29 +00001571#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001572 if (nexthop->type == NEXTHOP_TYPE_IPV6
1573 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1574 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001575 {
1576 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1577 &nexthop->gate.ipv6, bytelen);
1578
1579 if (IS_ZEBRA_DEBUG_KERNEL)
1580 zlog_debug("netlink_route_multipath() (single hop): "
1581 "nexthop via %s if %u",
1582 inet6_ntoa (nexthop->gate.ipv6),
1583 nexthop->ifindex);
1584 }
paul718e3742002-12-13 20:15:29 +00001585#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001586 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1587 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001588 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1589 {
1590 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1591
1592 if (nexthop->src.ipv4.s_addr)
1593 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1594 &nexthop->src.ipv4, bytelen);
1595
1596 if (IS_ZEBRA_DEBUG_KERNEL)
1597 zlog_debug("netlink_route_multipath() (single hop): "
1598 "nexthop via if %u", nexthop->ifindex);
1599 }
1600 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001601 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001602 {
1603 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1604
1605 if (IS_ZEBRA_DEBUG_KERNEL)
1606 zlog_debug("netlink_route_multipath() (single hop): "
1607 "nexthop via if %u", nexthop->ifindex);
1608 }
paul7021c422003-07-15 12:52:22 +00001609 }
paul718e3742002-12-13 20:15:29 +00001610
paul7021c422003-07-15 12:52:22 +00001611 if (cmd == RTM_NEWROUTE)
1612 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001613
paul7021c422003-07-15 12:52:22 +00001614 nexthop_num++;
1615 break;
1616 }
1617 }
paul718e3742002-12-13 20:15:29 +00001618 }
1619 else
1620 {
1621 char buf[1024];
1622 struct rtattr *rta = (void *) buf;
1623 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001624 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001625
1626 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001627 rta->rta_len = RTA_LENGTH (0);
1628 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001629
1630 nexthop_num = 0;
1631 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001632 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1633 nexthop = nexthop->next)
1634 {
1635 if ((cmd == RTM_NEWROUTE
1636 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1637 || (cmd == RTM_DELROUTE
1638 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1639 {
1640 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001641
paul7021c422003-07-15 12:52:22 +00001642 rtnh->rtnh_len = sizeof (*rtnh);
1643 rtnh->rtnh_flags = 0;
1644 rtnh->rtnh_hops = 0;
1645 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001646
paul7021c422003-07-15 12:52:22 +00001647 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1648 {
1649 if (IS_ZEBRA_DEBUG_KERNEL)
1650 {
ajsb6178002004-12-07 21:12:56 +00001651 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001652 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001653 lookup (nlmsg_str, cmd),
1654#ifdef HAVE_IPV6
1655 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1656 inet6_ntoa (p->u.prefix6),
1657#else
1658 inet_ntoa (p->u.prefix4),
1659#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001660 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001661 }
1662 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1663 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1664 {
1665 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1666 &nexthop->rgate.ipv4, bytelen);
1667 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001668
Paul Jakma7514fb72007-05-02 16:05:35 +00001669 if (nexthop->src.ipv4.s_addr)
1670 src = &nexthop->src;
1671
hasso206d8052005-04-09 16:38:51 +00001672 if (IS_ZEBRA_DEBUG_KERNEL)
1673 zlog_debug("netlink_route_multipath() (recursive, "
1674 "multihop): nexthop via %s if %u",
1675 inet_ntoa (nexthop->rgate.ipv4),
1676 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001677 }
paul718e3742002-12-13 20:15:29 +00001678#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001679 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1680 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1681 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001682 {
1683 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1684 &nexthop->rgate.ipv6, bytelen);
1685
1686 if (IS_ZEBRA_DEBUG_KERNEL)
1687 zlog_debug("netlink_route_multipath() (recursive, "
1688 "multihop): nexthop via %s if %u",
1689 inet6_ntoa (nexthop->rgate.ipv6),
1690 nexthop->rifindex);
1691 }
paul718e3742002-12-13 20:15:29 +00001692#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001693 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001694 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1695 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1696 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1697 {
1698 rtnh->rtnh_ifindex = nexthop->rifindex;
1699 if (nexthop->src.ipv4.s_addr)
1700 src = &nexthop->src;
1701
1702 if (IS_ZEBRA_DEBUG_KERNEL)
1703 zlog_debug("netlink_route_multipath() (recursive, "
1704 "multihop): nexthop via if %u",
1705 nexthop->rifindex);
1706 }
1707 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001708 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001709 {
1710 rtnh->rtnh_ifindex = nexthop->rifindex;
1711
1712 if (IS_ZEBRA_DEBUG_KERNEL)
1713 zlog_debug("netlink_route_multipath() (recursive, "
1714 "multihop): nexthop via if %u",
1715 nexthop->rifindex);
1716 }
paul7021c422003-07-15 12:52:22 +00001717 else
hasso206d8052005-04-09 16:38:51 +00001718 {
1719 rtnh->rtnh_ifindex = 0;
1720 }
paul7021c422003-07-15 12:52:22 +00001721 }
1722 else
1723 {
1724 if (IS_ZEBRA_DEBUG_KERNEL)
1725 {
hasso206d8052005-04-09 16:38:51 +00001726 zlog_debug ("netlink_route_multipath() (multihop): "
1727 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001728#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001729 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001730 inet6_ntoa (p->u.prefix6),
1731#else
1732 inet_ntoa (p->u.prefix4),
1733#endif /* HAVE_IPV6 */
1734 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001735 }
1736 if (nexthop->type == NEXTHOP_TYPE_IPV4
1737 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1738 {
hasso206d8052005-04-09 16:38:51 +00001739 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1740 &nexthop->gate.ipv4, bytelen);
1741 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1742
Paul Jakma7514fb72007-05-02 16:05:35 +00001743 if (nexthop->src.ipv4.s_addr)
1744 src = &nexthop->src;
1745
hasso206d8052005-04-09 16:38:51 +00001746 if (IS_ZEBRA_DEBUG_KERNEL)
1747 zlog_debug("netlink_route_multipath() (multihop): "
1748 "nexthop via %s if %u",
1749 inet_ntoa (nexthop->gate.ipv4),
1750 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001751 }
paul718e3742002-12-13 20:15:29 +00001752#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001753 if (nexthop->type == NEXTHOP_TYPE_IPV6
1754 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1755 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001756 {
1757 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1758 &nexthop->gate.ipv6, bytelen);
1759
1760 if (IS_ZEBRA_DEBUG_KERNEL)
1761 zlog_debug("netlink_route_multipath() (multihop): "
1762 "nexthop via %s if %u",
1763 inet6_ntoa (nexthop->gate.ipv6),
1764 nexthop->ifindex);
1765 }
paul718e3742002-12-13 20:15:29 +00001766#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001767 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001768 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1769 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1770 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1771 {
1772 rtnh->rtnh_ifindex = nexthop->ifindex;
1773 if (nexthop->src.ipv4.s_addr)
1774 src = &nexthop->src;
1775 if (IS_ZEBRA_DEBUG_KERNEL)
1776 zlog_debug("netlink_route_multipath() (multihop): "
1777 "nexthop via if %u", nexthop->ifindex);
1778 }
1779 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001780 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001781 {
1782 rtnh->rtnh_ifindex = nexthop->ifindex;
1783
1784 if (IS_ZEBRA_DEBUG_KERNEL)
1785 zlog_debug("netlink_route_multipath() (multihop): "
1786 "nexthop via if %u", nexthop->ifindex);
1787 }
paul7021c422003-07-15 12:52:22 +00001788 else
hasso206d8052005-04-09 16:38:51 +00001789 {
1790 rtnh->rtnh_ifindex = 0;
1791 }
paul7021c422003-07-15 12:52:22 +00001792 }
1793 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001794
paul7021c422003-07-15 12:52:22 +00001795 if (cmd == RTM_NEWROUTE)
1796 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1797 }
1798 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001799 if (src)
1800 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001801
1802 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001803 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1804 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001805 }
1806
1807 /* If there is no useful nexthop then return. */
1808 if (nexthop_num == 0)
1809 {
1810 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001811 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001812 return 0;
1813 }
1814
paul7021c422003-07-15 12:52:22 +00001815skip:
paul718e3742002-12-13 20:15:29 +00001816
1817 /* Destination netlink address. */
1818 memset (&snl, 0, sizeof snl);
1819 snl.nl_family = AF_NETLINK;
1820
paul718e3742002-12-13 20:15:29 +00001821 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001822 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001823}
1824
1825int
1826kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1827{
1828 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1829}
1830
1831int
1832kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1833{
1834 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1835}
1836
1837#ifdef HAVE_IPV6
1838int
1839kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1840{
1841 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1842}
1843
1844int
1845kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1846{
1847 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1848}
1849
1850/* Delete IPv6 route from the kernel. */
1851int
1852kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001853 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001854{
paul7021c422003-07-15 12:52:22 +00001855 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1856 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001857}
1858#endif /* HAVE_IPV6 */
1859
1860/* Interface address modification. */
1861int
1862netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001863 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001864{
1865 int bytelen;
1866 struct prefix *p;
1867
paul7021c422003-07-15 12:52:22 +00001868 struct
paul718e3742002-12-13 20:15:29 +00001869 {
1870 struct nlmsghdr n;
1871 struct ifaddrmsg ifa;
1872 char buf[1024];
1873 } req;
1874
1875 p = ifc->address;
1876 memset (&req, 0, sizeof req);
1877
1878 bytelen = (family == AF_INET ? 4 : 16);
1879
paul7021c422003-07-15 12:52:22 +00001880 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001881 req.n.nlmsg_flags = NLM_F_REQUEST;
1882 req.n.nlmsg_type = cmd;
1883 req.ifa.ifa_family = family;
1884
1885 req.ifa.ifa_index = ifp->ifindex;
1886 req.ifa.ifa_prefixlen = p->prefixlen;
1887
1888 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1889
1890 if (family == AF_INET && cmd == RTM_NEWADDR)
1891 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001892 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001893 {
1894 p = ifc->destination;
1895 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1896 bytelen);
1897 }
paul718e3742002-12-13 20:15:29 +00001898 }
1899
1900 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1901 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001902
paul718e3742002-12-13 20:15:29 +00001903 if (ifc->label)
1904 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001905 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001906
1907 return netlink_talk (&req.n, &netlink_cmd);
1908}
1909
1910int
1911kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1912{
1913 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1914}
1915
1916int
1917kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1918{
1919 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1920}
1921
paul718e3742002-12-13 20:15:29 +00001922
1923extern struct thread_master *master;
1924
1925/* Kernel route reflection. */
1926int
1927kernel_read (struct thread *thread)
1928{
1929 int ret;
1930 int sock;
1931
1932 sock = THREAD_FD (thread);
1933 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001934 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001935
1936 return 0;
1937}
1938
Paul Jakma768a27e2008-05-29 18:23:08 +00001939/* Filter out messages from self that occur on listener socket */
1940static void netlink_install_filter (int sock)
1941{
1942 /*
1943 * Filter is equivalent to netlink_route_change
1944 *
1945 * if (h->nlmsg_type == RTM_DELROUTE || h->nlmsg_type == RTM_NEWROUTE) {
1946 * if (rtm->rtm_type != RTM_UNICAST)
1947 * return 0;
1948 * if (rtm->rtm_flags & RTM_F_CLONED)
1949 * return 0;
1950 * if (rtm->rtm_protocol == RTPROT_REDIRECT)
1951 * return 0;
1952 * if (rtm->rtm_protocol == RTPROT_KERNEL)
1953 * return 0;
1954 * if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
1955 * return 0;
1956 * }
1957 * return 0xffff;
1958 */
1959 struct sock_filter filter[] = {
1960 /* 0*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1961 /* 1*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 1, 0),
1962 /* 2*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 11),
1963 /* 3*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
1964 sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_type)),
1965 /* 4*/ BPF_JUMP(BPF_JMP|BPF_B, RTN_UNICAST, 0, 8),
1966 /* 5*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
1967 sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_flags)),
1968 /* 6*/ BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, RTM_F_CLONED, 6, 0),
1969 /* 7*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_B,
1970 sizeof(struct nlmsghdr) + offsetof(struct rtmsg, rtm_protocol)),
1971 /* 8*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_REDIRECT, 4, 0),
1972 /* 9*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_KERNEL, 0, 1),
1973 /*10*/ BPF_JUMP(BPF_JMP+ BPF_B, RTPROT_ZEBRA, 0, 3),
1974 /*11*/ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1975 /*12*/ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 0, 1),
1976 /*13*/ BPF_STMT(BPF_RET|BPF_K, 0), /* drop */
1977 /*14*/ BPF_STMT(BPF_RET|BPF_K, 0xffff), /* keep */
1978 };
1979
1980 struct sock_fprog prog = {
1981 .len = sizeof(filter) / sizeof(filter[0]),
1982 .filter = filter,
1983 };
1984
1985 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1986 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1987}
1988
paul718e3742002-12-13 20:15:29 +00001989/* Exported interface function. This function simply calls
1990 netlink_socket (). */
1991void
paul6621ca82005-11-23 13:02:08 +00001992kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001993{
1994 unsigned long groups;
1995
paul7021c422003-07-15 12:52:22 +00001996 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001997#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001998 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001999#endif /* HAVE_IPV6 */
2000 netlink_socket (&netlink, groups);
2001 netlink_socket (&netlink_cmd, 0);
2002
2003 /* Register kernel socket. */
2004 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00002005 {
2006 netlink_install_filter (netlink.sock);
2007 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
2008 }
paul718e3742002-12-13 20:15:29 +00002009}