blob: cb69187c89bfffc290cc27b2eb7e5bb4a1715d09 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Kernel routing table updates using netlink over GNU/Linux system.
2 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24/* Hack for GNU libc version 2. */
25#ifndef MSG_TRUNC
26#define MSG_TRUNC 0x20
27#endif /* MSG_TRUNC */
28
29#include "linklist.h"
30#include "if.h"
31#include "log.h"
32#include "prefix.h"
33#include "connected.h"
34#include "table.h"
35#include "rib.h"
paule04ab742003-01-17 23:47:00 +000036#include "thread.h"
pauledd7c242003-06-04 13:59:38 +000037#include "privs.h"
paul718e3742002-12-13 20:15:29 +000038
39#include "zebra/zserv.h"
40#include "zebra/redistribute.h"
41#include "zebra/interface.h"
42#include "zebra/debug.h"
43
44/* Socket interface to kernel */
45struct nlsock
46{
47 int sock;
48 int seq;
49 struct sockaddr_nl snl;
50 char *name;
paul7021c422003-07-15 12:52:22 +000051} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
52 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}, /* command channel */
53 netlink_addr = { -1, 0, {0}, "netlink-addr"}; /* address 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
paul7021c422003-07-15 12:52:22 +000068char *nexthop_types_desc[] =
69{
70 "none",
71 "Directly connected",
72 "Interface route",
73 "IPv4 nexthop",
74 "IPv4 nexthop with ifindex",
75 "IPv4 nexthop with ifname",
76 "IPv6 nexthop"
77 "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
paul718e3742002-12-13 20:15:29 +000089/* Make socket for Linux netlink interface. */
90static int
91netlink_socket (struct nlsock *nl, unsigned long groups)
92{
93 int ret;
94 struct sockaddr_nl snl;
95 int sock;
96 int namelen;
97
98 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
99 if (sock < 0)
100 {
101 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000102 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000103 return -1;
104 }
105
106 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
107 if (ret < 0)
108 {
109 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000110 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000111 close (sock);
112 return -1;
113 }
paul7021c422003-07-15 12:52:22 +0000114
hassoc34b6b52004-08-31 13:41:49 +0000115 /* Set receive buffer size if it's set from command line */
116 if (nl_rcvbufsize)
117 {
118 u_int32_t oldsize, oldlen;
119 u_int32_t newsize, newlen;
120
121 oldlen = sizeof(oldsize);
122 newlen = sizeof(newsize);
123
124 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
125 if (ret < 0)
126 {
127 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
128 strerror (errno));
129 close (sock);
130 return -1;
131 }
132
133 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
134 sizeof(nl_rcvbufsize));
135 if (ret < 0)
136 {
137 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
138 strerror (errno));
139 close (sock);
140 return -1;
141 }
142
143 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
144 if (ret < 0)
145 {
146 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
147 strerror (errno));
148 close (sock);
149 return -1;
150 }
151
152 zlog (NULL, LOG_INFO,
153 "Setting netlink socket receive buffer size: %u -> %u",
154 oldsize, newsize);
155 }
156
paul718e3742002-12-13 20:15:29 +0000157 memset (&snl, 0, sizeof snl);
158 snl.nl_family = AF_NETLINK;
159 snl.nl_groups = groups;
160
161 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000162 if (zserv_privs.change (ZPRIVS_RAISE))
163 {
164 zlog (NULL, LOG_ERR, "Can't raise privileges");
165 return -1;
166 }
pauledd7c242003-06-04 13:59:38 +0000167
paul718e3742002-12-13 20:15:29 +0000168 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
hasso55e7ecd2004-08-06 08:41:56 +0000169 if (zserv_privs.change (ZPRIVS_LOWER))
170 zlog (NULL, LOG_ERR, "Can't lower privileges");
171
paul718e3742002-12-13 20:15:29 +0000172 if (ret < 0)
173 {
paul7021c422003-07-15 12:52:22 +0000174 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
175 nl->name, snl.nl_groups, strerror (errno));
paul718e3742002-12-13 20:15:29 +0000176 close (sock);
177 return -1;
178 }
paul7021c422003-07-15 12:52:22 +0000179
paul718e3742002-12-13 20:15:29 +0000180 /* multiple netlink sockets will have different nl_pid */
181 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000182 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000183 if (ret < 0 || namelen != sizeof snl)
184 {
185 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000186 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000187 close (sock);
188 return -1;
189 }
190
191 nl->snl = snl;
192 nl->sock = sock;
193 return ret;
194}
195
paul7021c422003-07-15 12:52:22 +0000196int
197set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000198{
199
200 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000201 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000202 {
paul7021c422003-07-15 12:52:22 +0000203 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
204 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000205 return -1;
206 }
207 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000208 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000209 {
paul7021c422003-07-15 12:52:22 +0000210 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
211 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000212 return -1;
213 }
214 return 0;
215}
216
paul7021c422003-07-15 12:52:22 +0000217int
218set_netlink_nonblocking (struct nlsock *nl, int *flags)
219{
paul5f37d862003-04-19 00:11:28 +0000220 /* Restore socket flags for nonblocking I/O */
221 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000222 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000223 {
paul7021c422003-07-15 12:52:22 +0000224 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
225 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000226 return -1;
227 }
228 return 0;
229}
230
paul718e3742002-12-13 20:15:29 +0000231/* Get type specified information from netlink. */
232static int
233netlink_request (int family, int type, struct nlsock *nl)
234{
235 int ret;
236 struct sockaddr_nl snl;
237
238 struct
239 {
240 struct nlmsghdr nlh;
241 struct rtgenmsg g;
242 } req;
243
244
245 /* Check netlink socket. */
246 if (nl->sock < 0)
247 {
248 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
249 return -1;
250 }
251
252 memset (&snl, 0, sizeof snl);
253 snl.nl_family = AF_NETLINK;
254
255 req.nlh.nlmsg_len = sizeof req;
256 req.nlh.nlmsg_type = type;
257 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
258 req.nlh.nlmsg_pid = 0;
259 req.nlh.nlmsg_seq = ++nl->seq;
260 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000261
262 /* linux appears to check capabilities on every message
263 * have to raise caps for every message sent
264 */
paul7021c422003-07-15 12:52:22 +0000265 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000266 {
267 zlog (NULL, LOG_ERR, "Can't raise privileges");
268 return -1;
269 }
paul7021c422003-07-15 12:52:22 +0000270
271 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
272 (struct sockaddr *) &snl, sizeof snl);
273
274 if (zserv_privs.change (ZPRIVS_LOWER))
275 zlog (NULL, LOG_ERR, "Can't lower privileges");
276
paul718e3742002-12-13 20:15:29 +0000277 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000278 {
279 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
280 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000281 return -1;
282 }
pauledd7c242003-06-04 13:59:38 +0000283
paul718e3742002-12-13 20:15:29 +0000284 return 0;
285}
286
287/* Receive message from netlink interface and pass those information
288 to the given function. */
289static int
290netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000291 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000292{
293 int status;
294 int ret = 0;
295 int error;
296
297 while (1)
298 {
299 char buf[4096];
300 struct iovec iov = { buf, sizeof buf };
301 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000302 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000303 struct nlmsghdr *h;
304
paul7021c422003-07-15 12:52:22 +0000305 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000306 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000307
paul718e3742002-12-13 20:15:29 +0000308 status = recvmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +0000309
310 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000311 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000312
313 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000314 {
315 if (errno == EINTR)
316 continue;
317 if (errno == EWOULDBLOCK || errno == EAGAIN)
318 break;
319 zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
320 continue;
321 }
paul718e3742002-12-13 20:15:29 +0000322
323 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000324 {
325 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
326 return -1;
327 }
paul718e3742002-12-13 20:15:29 +0000328
329 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000330 {
331 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
332 nl->name, msg.msg_namelen);
333 return -1;
334 }
paulb84d3a12003-11-17 10:31:01 +0000335
336 /* JF: Ignore messages that aren't from the kernel */
337 if ( snl.nl_pid != 0 )
338 {
339 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
340 continue;
341 }
paul718e3742002-12-13 20:15:29 +0000342
paul7021c422003-07-15 12:52:22 +0000343 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
344 h = NLMSG_NEXT (h, status))
345 {
346 /* Finish of reading. */
347 if (h->nlmsg_type == NLMSG_DONE)
348 return ret;
paul718e3742002-12-13 20:15:29 +0000349
paul7021c422003-07-15 12:52:22 +0000350 /* Error handling. */
351 if (h->nlmsg_type == NLMSG_ERROR)
352 {
353 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
354
paul718e3742002-12-13 20:15:29 +0000355 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000356 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000357 {
paul7021c422003-07-15 12:52:22 +0000358 if (IS_ZEBRA_DEBUG_KERNEL)
359 {
360 zlog_info ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
361 __FUNCTION__, nl->name,
362 lookup (nlmsg_str, err->msg.nlmsg_type),
363 err->msg.nlmsg_type, err->msg.nlmsg_seq,
364 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000365 }
paul7021c422003-07-15 12:52:22 +0000366
367 /* return if not a multipart message, otherwise continue */
368 if (!(h->nlmsg_flags & NLM_F_MULTI))
369 {
370 return 0;
paul718e3742002-12-13 20:15:29 +0000371 }
paul7021c422003-07-15 12:52:22 +0000372 continue;
paul718e3742002-12-13 20:15:29 +0000373 }
paul7021c422003-07-15 12:52:22 +0000374
paul718e3742002-12-13 20:15:29 +0000375 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000376 {
377 zlog (NULL, LOG_ERR, "%s error: message truncated",
378 nl->name);
379 return -1;
380 }
pauld753e9e2003-01-22 19:45:50 +0000381
paul7021c422003-07-15 12:52:22 +0000382 /* Deal with Error Noise - MAG */
383 {
384 int loglvl = LOG_ERR;
385 int errnum = err->error;
386 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000387
paul7021c422003-07-15 12:52:22 +0000388 if (nl == &netlink_cmd
389 && (-errnum == ENODEV || -errnum == ESRCH)
390 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
391 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000392
paul7021c422003-07-15 12:52:22 +0000393 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
394 "seq=%u, pid=%d",
395 nl->name, strerror (-errnum),
396 lookup (nlmsg_str, msg_type),
397 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
398 }
399 /*
400 ret = -1;
401 continue;
402 */
403 return -1;
404 }
paul718e3742002-12-13 20:15:29 +0000405
paul7021c422003-07-15 12:52:22 +0000406 /* OK we got netlink message. */
407 if (IS_ZEBRA_DEBUG_KERNEL)
408 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
409 nl->name,
410 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
411 h->nlmsg_seq, h->nlmsg_pid);
412
413 /* skip unsolicited messages originating from command socket */
414 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
415 {
416 if (IS_ZEBRA_DEBUG_KERNEL)
417 zlog_info ("netlink_parse_info: %s packet comes from %s",
418 nl->name, netlink_cmd.name);
419 continue;
420 }
421
422 error = (*filter) (&snl, h);
423 if (error < 0)
424 {
425 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
426 ret = error;
427 }
428 }
paul718e3742002-12-13 20:15:29 +0000429
430 /* After error care. */
431 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000432 {
433 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
434 continue;
435 }
paul718e3742002-12-13 20:15:29 +0000436 if (status)
paul7021c422003-07-15 12:52:22 +0000437 {
438 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
439 status);
440 return -1;
441 }
paul718e3742002-12-13 20:15:29 +0000442 }
443 return ret;
444}
445
446/* Utility function for parse rtattr. */
447static void
paul7021c422003-07-15 12:52:22 +0000448netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
449 int len)
paul718e3742002-12-13 20:15:29 +0000450{
paul7021c422003-07-15 12:52:22 +0000451 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000452 {
453 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000454 tb[rta->rta_type] = rta;
455 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000456 }
457}
458
459/* Called from interface_lookup_netlink(). This function is only used
460 during bootstrap. */
461int
462netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
463{
464 int len;
465 struct ifinfomsg *ifi;
466 struct rtattr *tb[IFLA_MAX + 1];
467 struct interface *ifp;
468 char *name;
469 int i;
470
471 ifi = NLMSG_DATA (h);
472
473 if (h->nlmsg_type != RTM_NEWLINK)
474 return 0;
475
476 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
477 if (len < 0)
478 return -1;
479
480 /* Looking up interface name. */
481 memset (tb, 0, sizeof tb);
482 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
483 if (tb[IFLA_IFNAME] == NULL)
484 return -1;
paul7021c422003-07-15 12:52:22 +0000485 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000486
487 /* Add interface. */
488 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000489
paul718e3742002-12-13 20:15:29 +0000490 ifp->ifindex = ifi->ifi_index;
491 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000492 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000493 ifp->metric = 1;
494
495 /* Hardware type and address. */
496 ifp->hw_type = ifi->ifi_type;
497
498 if (tb[IFLA_ADDRESS])
499 {
500 int hw_addr_len;
501
paul7021c422003-07-15 12:52:22 +0000502 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000503
504 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000505 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000506 else
paul7021c422003-07-15 12:52:22 +0000507 {
508 ifp->hw_addr_len = hw_addr_len;
509 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000510
paul7021c422003-07-15 12:52:22 +0000511 for (i = 0; i < hw_addr_len; i++)
512 if (ifp->hw_addr[i] != 0)
513 break;
paul718e3742002-12-13 20:15:29 +0000514
paul7021c422003-07-15 12:52:22 +0000515 if (i == hw_addr_len)
516 ifp->hw_addr_len = 0;
517 else
518 ifp->hw_addr_len = hw_addr_len;
519 }
paul718e3742002-12-13 20:15:29 +0000520 }
521
522 if_add_update (ifp);
523
524 return 0;
525}
526
527/* Lookup interface IPv4/IPv6 address. */
528int
529netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
530{
531 int len;
532 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000533 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000534 struct interface *ifp;
535 void *addr = NULL;
536 void *broad = NULL;
537 u_char flags = 0;
538 char *label = NULL;
539
540 ifa = NLMSG_DATA (h);
541
paul7021c422003-07-15 12:52:22 +0000542 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000543#ifdef HAVE_IPV6
544 && ifa->ifa_family != AF_INET6
545#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000546 )
paul718e3742002-12-13 20:15:29 +0000547 return 0;
548
549 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
550 return 0;
551
paul7021c422003-07-15 12:52:22 +0000552 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000553 if (len < 0)
554 return -1;
555
556 memset (tb, 0, sizeof tb);
557 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
558
559 ifp = if_lookup_by_index (ifa->ifa_index);
560 if (ifp == NULL)
561 {
562 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000563 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000564 return -1;
565 }
566
paul7021c422003-07-15 12:52:22 +0000567 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000568 {
paul00df0c12002-12-13 21:07:36 +0000569 char buf[BUFSIZ];
570 zlog_info ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000571 lookup (nlmsg_str, h->nlmsg_type),
572 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000573 if (tb[IFA_LOCAL])
paul7021c422003-07-15 12:52:22 +0000574 zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
575 RTA_DATA (tb[IFA_LOCAL]),
576 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000577 if (tb[IFA_ADDRESS])
paul7021c422003-07-15 12:52:22 +0000578 zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
579 RTA_DATA (tb
580 [IFA_ADDRESS]),
581 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000582 if (tb[IFA_BROADCAST])
paul7021c422003-07-15 12:52:22 +0000583 zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
584 RTA_DATA (tb
585 [IFA_BROADCAST]),
586 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000587 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
hasso5707cce2004-03-04 19:20:44 +0000588 zlog_info (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000589 }
paul31a476c2003-09-29 19:54:53 +0000590
591 if (tb[IFA_ADDRESS] == NULL)
592 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
593
594 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000595 {
paul31a476c2003-09-29 19:54:53 +0000596 if (tb[IFA_LOCAL])
597 {
598 addr = RTA_DATA (tb[IFA_LOCAL]);
599 if (tb[IFA_ADDRESS])
600 broad = RTA_DATA (tb[IFA_ADDRESS]);
601 else
602 broad = NULL;
603 }
604 else
605 {
606 if (tb[IFA_ADDRESS])
607 addr = RTA_DATA (tb[IFA_ADDRESS]);
608 else
609 addr = NULL;
610 }
paul7021c422003-07-15 12:52:22 +0000611 }
paul31a476c2003-09-29 19:54:53 +0000612 else
paul7021c422003-07-15 12:52:22 +0000613 {
paul31a476c2003-09-29 19:54:53 +0000614 if (tb[IFA_ADDRESS])
615 addr = RTA_DATA (tb[IFA_ADDRESS]);
616 else
617 addr = NULL;
618
619 if (tb[IFA_BROADCAST])
620 broad = RTA_DATA(tb[IFA_BROADCAST]);
621 else
622 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000623 }
paul00df0c12002-12-13 21:07:36 +0000624
paul718e3742002-12-13 20:15:29 +0000625 /* Flags. */
626 if (ifa->ifa_flags & IFA_F_SECONDARY)
627 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
628
629 /* Label */
630 if (tb[IFA_LABEL])
631 label = (char *) RTA_DATA (tb[IFA_LABEL]);
632
633 if (ifp && label && strcmp (ifp->name, label) == 0)
634 label = NULL;
635
636 /* Register interface address to the interface. */
637 if (ifa->ifa_family == AF_INET)
638 {
paul7021c422003-07-15 12:52:22 +0000639 if (h->nlmsg_type == RTM_NEWADDR)
640 connected_add_ipv4 (ifp, flags,
641 (struct in_addr *) addr, ifa->ifa_prefixlen,
642 (struct in_addr *) broad, label);
643 else
644 connected_delete_ipv4 (ifp, flags,
645 (struct in_addr *) addr, ifa->ifa_prefixlen,
646 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000647 }
648#ifdef HAVE_IPV6
649 if (ifa->ifa_family == AF_INET6)
650 {
651 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000652 connected_add_ipv6 (ifp,
653 (struct in6_addr *) addr, ifa->ifa_prefixlen,
654 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000655 else
paul7021c422003-07-15 12:52:22 +0000656 connected_delete_ipv6 (ifp,
657 (struct in6_addr *) addr, ifa->ifa_prefixlen,
658 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000659 }
paul7021c422003-07-15 12:52:22 +0000660#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000661
662 return 0;
663}
664
665/* Looking up routing table by netlink interface. */
666int
667netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
668{
669 int len;
670 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000671 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000672 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000673
674 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000675
676 int index;
677 int table;
hasso34195bf2004-04-06 12:07:06 +0000678 int metric;
679
paul718e3742002-12-13 20:15:29 +0000680 void *dest;
681 void *gate;
682
683 rtm = NLMSG_DATA (h);
684
685 if (h->nlmsg_type != RTM_NEWROUTE)
686 return 0;
687 if (rtm->rtm_type != RTN_UNICAST)
688 return 0;
689
690 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000691#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000692 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000693 return 0;
694#endif
695
paul7021c422003-07-15 12:52:22 +0000696 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000697 if (len < 0)
698 return -1;
699
700 memset (tb, 0, sizeof tb);
701 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
702
703 if (rtm->rtm_flags & RTM_F_CLONED)
704 return 0;
705 if (rtm->rtm_protocol == RTPROT_REDIRECT)
706 return 0;
707 if (rtm->rtm_protocol == RTPROT_KERNEL)
708 return 0;
709
710 if (rtm->rtm_src_len != 0)
711 return 0;
712
713 /* Route which inserted by Zebra. */
714 if (rtm->rtm_protocol == RTPROT_ZEBRA)
715 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000716
paul718e3742002-12-13 20:15:29 +0000717 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000718 metric = 0;
paul718e3742002-12-13 20:15:29 +0000719 dest = NULL;
720 gate = NULL;
721
722 if (tb[RTA_OIF])
723 index = *(int *) RTA_DATA (tb[RTA_OIF]);
724
725 if (tb[RTA_DST])
726 dest = RTA_DATA (tb[RTA_DST]);
727 else
728 dest = anyaddr;
729
730 /* Multipath treatment is needed. */
731 if (tb[RTA_GATEWAY])
732 gate = RTA_DATA (tb[RTA_GATEWAY]);
733
hasso34195bf2004-04-06 12:07:06 +0000734 if (tb[RTA_PRIORITY])
735 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
736
paul718e3742002-12-13 20:15:29 +0000737 if (rtm->rtm_family == AF_INET)
738 {
739 struct prefix_ipv4 p;
740 p.family = AF_INET;
741 memcpy (&p.prefix, dest, 4);
742 p.prefixlen = rtm->rtm_dst_len;
743
hasso34195bf2004-04-06 12:07:06 +0000744 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000745 }
746#ifdef HAVE_IPV6
747 if (rtm->rtm_family == AF_INET6)
748 {
749 struct prefix_ipv6 p;
750 p.family = AF_INET6;
751 memcpy (&p.prefix, dest, 16);
752 p.prefixlen = rtm->rtm_dst_len;
753
754 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
755 }
756#endif /* HAVE_IPV6 */
757
758 return 0;
759}
760
paul7021c422003-07-15 12:52:22 +0000761struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000762 {RTPROT_REDIRECT, "redirect"},
763 {RTPROT_KERNEL, "kernel"},
764 {RTPROT_BOOT, "boot"},
765 {RTPROT_STATIC, "static"},
766 {RTPROT_GATED, "GateD"},
767 {RTPROT_RA, "router advertisement"},
768 {RTPROT_MRT, "MRT"},
769 {RTPROT_ZEBRA, "Zebra"},
770#ifdef RTPROT_BIRD
771 {RTPROT_BIRD, "BIRD"},
772#endif /* RTPROT_BIRD */
773 {0, NULL}
774};
775
776/* Routing information change from the kernel. */
777int
778netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
779{
780 int len;
781 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000782 struct rtattr *tb[RTA_MAX + 1];
783
784 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000785
786 int index;
787 int table;
788 void *dest;
789 void *gate;
790
791 rtm = NLMSG_DATA (h);
792
paul7021c422003-07-15 12:52:22 +0000793 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000794 {
795 /* If this is not route add/delete message print warning. */
796 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
797 return 0;
798 }
799
800 /* Connected route. */
801 if (IS_ZEBRA_DEBUG_KERNEL)
802 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000803 h->nlmsg_type ==
804 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
805 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
806 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
807 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000808
809 if (rtm->rtm_type != RTN_UNICAST)
810 {
811 return 0;
812 }
813
814 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000815 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000816 {
817 return 0;
818 }
819
paul7021c422003-07-15 12:52:22 +0000820 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000821 if (len < 0)
822 return -1;
823
824 memset (tb, 0, sizeof tb);
825 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
826
827 if (rtm->rtm_flags & RTM_F_CLONED)
828 return 0;
829 if (rtm->rtm_protocol == RTPROT_REDIRECT)
830 return 0;
831 if (rtm->rtm_protocol == RTPROT_KERNEL)
832 return 0;
833
834 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
835 return 0;
836
837 if (rtm->rtm_src_len != 0)
838 {
839 zlog_warn ("netlink_route_change(): no src len");
840 return 0;
841 }
paul7021c422003-07-15 12:52:22 +0000842
paul718e3742002-12-13 20:15:29 +0000843 index = 0;
844 dest = NULL;
845 gate = NULL;
846
847 if (tb[RTA_OIF])
848 index = *(int *) RTA_DATA (tb[RTA_OIF]);
849
850 if (tb[RTA_DST])
851 dest = RTA_DATA (tb[RTA_DST]);
852 else
853 dest = anyaddr;
854
855 if (tb[RTA_GATEWAY])
856 gate = RTA_DATA (tb[RTA_GATEWAY]);
857
858 if (rtm->rtm_family == AF_INET)
859 {
860 struct prefix_ipv4 p;
861 p.family = AF_INET;
862 memcpy (&p.prefix, dest, 4);
863 p.prefixlen = rtm->rtm_dst_len;
864
865 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000866 {
867 if (h->nlmsg_type == RTM_NEWROUTE)
868 zlog_info ("RTM_NEWROUTE %s/%d",
869 inet_ntoa (p.prefix), p.prefixlen);
870 else
871 zlog_info ("RTM_DELROUTE %s/%d",
872 inet_ntoa (p.prefix), p.prefixlen);
873 }
paul718e3742002-12-13 20:15:29 +0000874
875 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000876 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000877 else
paul7021c422003-07-15 12:52:22 +0000878 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000879 }
880
881#ifdef HAVE_IPV6
882 if (rtm->rtm_family == AF_INET6)
883 {
884 struct prefix_ipv6 p;
885 char buf[BUFSIZ];
886
887 p.family = AF_INET6;
888 memcpy (&p.prefix, dest, 16);
889 p.prefixlen = rtm->rtm_dst_len;
890
891 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000892 {
893 if (h->nlmsg_type == RTM_NEWROUTE)
894 zlog_info ("RTM_NEWROUTE %s/%d",
895 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
896 p.prefixlen);
897 else
898 zlog_info ("RTM_DELROUTE %s/%d",
899 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
900 p.prefixlen);
901 }
paul718e3742002-12-13 20:15:29 +0000902
903 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000904 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000905 else
paul7021c422003-07-15 12:52:22 +0000906 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000907 }
908#endif /* HAVE_IPV6 */
909
910 return 0;
911}
912
913int
914netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
915{
916 int len;
917 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000918 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000919 struct interface *ifp;
920 char *name;
921
922 ifi = NLMSG_DATA (h);
923
paul7021c422003-07-15 12:52:22 +0000924 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000925 {
926 /* If this is not link add/delete message so print warning. */
927 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000928 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000929 return 0;
930 }
931
932 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
933 if (len < 0)
934 return -1;
935
936 /* Looking up interface name. */
937 memset (tb, 0, sizeof tb);
938 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
939 if (tb[IFLA_IFNAME] == NULL)
940 return -1;
paul7021c422003-07-15 12:52:22 +0000941 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000942
943 /* Add interface. */
944 if (h->nlmsg_type == RTM_NEWLINK)
945 {
946 ifp = if_lookup_by_name (name);
947
paul7021c422003-07-15 12:52:22 +0000948 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
949 {
950 if (ifp == NULL)
951 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000952
paul7021c422003-07-15 12:52:22 +0000953 ifp->ifindex = ifi->ifi_index;
954 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000955 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000956 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000957
paul7021c422003-07-15 12:52:22 +0000958 /* If new link is added. */
959 if_add_update (ifp);
960 }
paul718e3742002-12-13 20:15:29 +0000961 else
paul7021c422003-07-15 12:52:22 +0000962 {
963 /* Interface status change. */
964 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000965 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000966 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000967
paul7021c422003-07-15 12:52:22 +0000968 if (if_is_operative (ifp))
969 {
970 ifp->flags = ifi->ifi_flags & 0x0000fffff;
971 if (!if_is_operative (ifp))
972 if_down (ifp);
973 }
974 else
975 {
976 ifp->flags = ifi->ifi_flags & 0x0000fffff;
977 if (if_is_operative (ifp))
978 if_up (ifp);
979 }
980 }
paul718e3742002-12-13 20:15:29 +0000981 }
982 else
983 {
984 /* RTM_DELLINK. */
985 ifp = if_lookup_by_name (name);
986
987 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000988 {
989 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000990 name);
paul7021c422003-07-15 12:52:22 +0000991 return 0;
992 }
993
paul718e3742002-12-13 20:15:29 +0000994 if_delete_update (ifp);
995 }
996
997 return 0;
998}
999
1000int
1001netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1002{
1003 switch (h->nlmsg_type)
1004 {
1005 case RTM_NEWROUTE:
1006 return netlink_route_change (snl, h);
1007 break;
1008 case RTM_DELROUTE:
1009 return netlink_route_change (snl, h);
1010 break;
1011 case RTM_NEWLINK:
1012 return netlink_link_change (snl, h);
1013 break;
1014 case RTM_DELLINK:
1015 return netlink_link_change (snl, h);
1016 break;
1017 case RTM_NEWADDR:
1018 return netlink_interface_addr (snl, h);
1019 break;
1020 case RTM_DELADDR:
1021 return netlink_interface_addr (snl, h);
1022 break;
1023 default:
1024 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1025 break;
1026 }
1027 return 0;
1028}
1029
1030/* Interface lookup by netlink socket. */
1031int
1032interface_lookup_netlink ()
1033{
1034 int ret;
paul5f37d862003-04-19 00:11:28 +00001035 int flags;
1036 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001037
paul5f37d862003-04-19 00:11:28 +00001038 /*
1039 * Change netlink socket flags to blocking to ensure we get
1040 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001041 */
1042 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1043 if (snb_ret < 0)
1044 zlog (NULL, LOG_WARNING,
1045 "%s:%i Warning: Could not set netlink socket to blocking.",
1046 __FUNCTION__, __LINE__);
1047
paul718e3742002-12-13 20:15:29 +00001048 /* Get interface information. */
1049 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1050 if (ret < 0)
1051 return ret;
1052 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1053 if (ret < 0)
1054 return ret;
1055
1056 /* Get IPv4 address of the interfaces. */
1057 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1058 if (ret < 0)
1059 return ret;
1060 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1061 if (ret < 0)
1062 return ret;
1063
1064#ifdef HAVE_IPV6
1065 /* Get IPv6 address of the interfaces. */
1066 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1067 if (ret < 0)
1068 return ret;
1069 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1070 if (ret < 0)
1071 return ret;
1072#endif /* HAVE_IPV6 */
1073
paul7021c422003-07-15 12:52:22 +00001074 /* restore socket flags */
1075 if (snb_ret == 0)
1076 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001077 return 0;
1078}
1079
1080/* Routing table read function using netlink interface. Only called
1081 bootstrap time. */
1082int
1083netlink_route_read ()
1084{
1085 int ret;
paul5f37d862003-04-19 00:11:28 +00001086 int flags;
1087 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001088
paul5f37d862003-04-19 00:11:28 +00001089 /*
1090 * Change netlink socket flags to blocking to ensure we get
1091 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001092 */
1093 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1094 if (snb_ret < 0)
1095 zlog (NULL, LOG_WARNING,
1096 "%s:%i Warning: Could not set netlink socket to blocking.",
1097 __FUNCTION__, __LINE__);
1098
paul718e3742002-12-13 20:15:29 +00001099 /* Get IPv4 routing table. */
1100 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1101 if (ret < 0)
1102 return ret;
1103 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1104 if (ret < 0)
1105 return ret;
1106
1107#ifdef HAVE_IPV6
1108 /* Get IPv6 routing table. */
1109 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1110 if (ret < 0)
1111 return ret;
1112 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1113 if (ret < 0)
1114 return ret;
1115#endif /* HAVE_IPV6 */
1116
paul5f37d862003-04-19 00:11:28 +00001117 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001118 if (snb_ret == 0)
1119 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001120 return 0;
1121}
1122
1123/* Utility function comes from iproute2.
1124 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1125int
1126addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1127{
1128 int len;
1129 struct rtattr *rta;
1130
paul7021c422003-07-15 12:52:22 +00001131 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001132
paul7021c422003-07-15 12:52:22 +00001133 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001134 return -1;
1135
paul7021c422003-07-15 12:52:22 +00001136 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001137 rta->rta_type = type;
1138 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001139 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001140 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1141
1142 return 0;
1143}
1144
1145int
1146rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1147{
1148 int len;
1149 struct rtattr *subrta;
1150
paul7021c422003-07-15 12:52:22 +00001151 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001152
paul7021c422003-07-15 12:52:22 +00001153 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001154 return -1;
1155
paul7021c422003-07-15 12:52:22 +00001156 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001157 subrta->rta_type = type;
1158 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001159 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001160 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1161
1162 return 0;
1163}
1164
1165/* Utility function comes from iproute2.
1166 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1167int
1168addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1169{
1170 int len;
1171 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001172
1173 len = RTA_LENGTH (4);
1174
paul718e3742002-12-13 20:15:29 +00001175 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1176 return -1;
1177
paul7021c422003-07-15 12:52:22 +00001178 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001179 rta->rta_type = type;
1180 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001181 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001182 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1183
1184 return 0;
1185}
1186
1187static int
1188netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1189{
1190 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1191 return 0;
1192}
1193
1194/* sendmsg() to netlink socket then recvmsg(). */
1195int
1196netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1197{
1198 int status;
1199 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001200 struct iovec iov = { (void *) n, n->nlmsg_len };
1201 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001202 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001203 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001204
paul718e3742002-12-13 20:15:29 +00001205 memset (&snl, 0, sizeof snl);
1206 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001207
paul718e3742002-12-13 20:15:29 +00001208 n->nlmsg_seq = ++netlink_cmd.seq;
1209
1210 /* Request an acknowledgement by setting NLM_F_ACK */
1211 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001212
1213 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001214 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001215 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1216 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001217
1218 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001219 if (zserv_privs.change (ZPRIVS_RAISE))
1220 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001221 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001222 if (zserv_privs.change (ZPRIVS_LOWER))
1223 zlog (NULL, LOG_ERR, "Can't lower privileges");
1224
paul718e3742002-12-13 20:15:29 +00001225 if (status < 0)
1226 {
1227 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001228 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001229 return -1;
1230 }
paul7021c422003-07-15 12:52:22 +00001231
paul718e3742002-12-13 20:15:29 +00001232 /*
1233 * Change socket flags for blocking I/O.
1234 * This ensures we wait for a reply in netlink_parse_info().
1235 */
paul7021c422003-07-15 12:52:22 +00001236 snb_ret = set_netlink_blocking (nl, &flags);
1237 if (snb_ret < 0)
1238 zlog (NULL, LOG_WARNING,
1239 "%s:%i Warning: Could not set netlink socket to blocking.",
1240 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001241
1242 /*
1243 * Get reply from netlink socket.
1244 * The reply should either be an acknowlegement or an error.
1245 */
1246 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001247
paul718e3742002-12-13 20:15:29 +00001248 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001249 if (snb_ret == 0)
1250 set_netlink_nonblocking (nl, &flags);
1251
paul718e3742002-12-13 20:15:29 +00001252 return status;
1253}
1254
1255/* Routing table change via netlink interface. */
1256int
1257netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001258 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001259{
1260 int ret;
1261 int bytelen;
1262 struct sockaddr_nl snl;
1263 int discard;
1264
paul7021c422003-07-15 12:52:22 +00001265 struct
paul718e3742002-12-13 20:15:29 +00001266 {
1267 struct nlmsghdr n;
1268 struct rtmsg r;
1269 char buf[1024];
1270 } req;
1271
1272 memset (&req, 0, sizeof req);
1273
1274 bytelen = (family == AF_INET ? 4 : 16);
1275
1276 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1277 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1278 req.n.nlmsg_type = cmd;
1279 req.r.rtm_family = family;
1280 req.r.rtm_table = table;
1281 req.r.rtm_dst_len = length;
1282
hasso81dfcaa2003-05-25 19:21:25 +00001283 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1284 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001285 discard = 1;
1286 else
1287 discard = 0;
1288
paul7021c422003-07-15 12:52:22 +00001289 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001290 {
1291 req.r.rtm_protocol = RTPROT_ZEBRA;
1292 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1293
paul7021c422003-07-15 12:52:22 +00001294 if (discard)
paul595db7f2003-05-25 21:35:06 +00001295 {
1296 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1297 req.r.rtm_type = RTN_BLACKHOLE;
1298 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1299 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001300 else
1301 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1302 }
paul595db7f2003-05-25 21:35:06 +00001303 else
paul7021c422003-07-15 12:52:22 +00001304 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001305 }
1306
1307 if (dest)
1308 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1309
paul7021c422003-07-15 12:52:22 +00001310 if (!discard)
paul718e3742002-12-13 20:15:29 +00001311 {
1312 if (gate)
paul7021c422003-07-15 12:52:22 +00001313 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001314 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001315 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001316 }
1317
1318 /* Destination netlink address. */
1319 memset (&snl, 0, sizeof snl);
1320 snl.nl_family = AF_NETLINK;
1321
1322 /* Talk to netlink socket. */
1323 ret = netlink_talk (&req.n, &netlink);
1324 if (ret < 0)
1325 return -1;
1326
1327 return 0;
1328}
1329
1330/* Routing table change via netlink interface. */
1331int
1332netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001333 int family)
paul718e3742002-12-13 20:15:29 +00001334{
1335 int bytelen;
1336 struct sockaddr_nl snl;
1337 struct nexthop *nexthop = NULL;
1338 int nexthop_num = 0;
1339 struct nlsock *nl;
1340 int discard;
1341
paul7021c422003-07-15 12:52:22 +00001342 struct
paul718e3742002-12-13 20:15:29 +00001343 {
1344 struct nlmsghdr n;
1345 struct rtmsg r;
1346 char buf[1024];
1347 } req;
1348
1349 memset (&req, 0, sizeof req);
1350
1351 bytelen = (family == AF_INET ? 4 : 16);
1352
1353 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1354 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1355 req.n.nlmsg_type = cmd;
1356 req.r.rtm_family = family;
1357 req.r.rtm_table = rib->table;
1358 req.r.rtm_dst_len = p->prefixlen;
1359
paul13766da2003-02-07 14:46:23 +00001360#ifdef RTM_F_EQUALIZE
1361 req.r.rtm_flags |= RTM_F_EQUALIZE;
1362#endif /* RTM_F_EQUALIZE */
1363
paul7021c422003-07-15 12:52:22 +00001364 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001365 discard = 1;
1366 else
1367 discard = 0;
1368
paul7021c422003-07-15 12:52:22 +00001369 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001370 {
1371 req.r.rtm_protocol = RTPROT_ZEBRA;
1372 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1373
paul7021c422003-07-15 12:52:22 +00001374 if (discard)
paul595db7f2003-05-25 21:35:06 +00001375 {
1376 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1377 req.r.rtm_type = RTN_BLACKHOLE;
1378 else if (rib->flags & ZEBRA_FLAG_REJECT)
1379 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001380 else
1381 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1382 }
paul595db7f2003-05-25 21:35:06 +00001383 else
paul7021c422003-07-15 12:52:22 +00001384 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001385 }
1386
1387 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1388
1389 /* Metric. */
1390 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1391
1392 if (discard)
1393 {
1394 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001395 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1396 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001397 goto skip;
1398 }
1399
1400 /* Multipath case. */
1401 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1402 {
1403 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001404 {
paul5ec90d22003-06-19 01:41:37 +00001405
paul7021c422003-07-15 12:52:22 +00001406 if ((cmd == RTM_NEWROUTE
1407 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1408 || (cmd == RTM_DELROUTE
1409 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1410 {
paul5ec90d22003-06-19 01:41:37 +00001411
paul7021c422003-07-15 12:52:22 +00001412 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1413 {
1414 if (IS_ZEBRA_DEBUG_KERNEL)
1415 {
1416 zlog_info
1417 ("netlink_route_multipath() (recursive, 1 hop): "
1418 "%s %s/%d via %s if %u, type %s",
1419 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1420 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1421 nexthop->rifindex,
1422 nexthop_types_desc[nexthop->rtype]);
1423 }
paul5ec90d22003-06-19 01:41:37 +00001424
paul7021c422003-07-15 12:52:22 +00001425 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1426 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1427 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1428 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001429#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001430 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1431 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1432 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1433 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1434 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001435#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001436 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1437 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1438 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1439 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1440 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1441 addattr32 (&req.n, sizeof req, RTA_OIF,
1442 nexthop->rifindex);
1443 }
1444 else
1445 {
1446 if (IS_ZEBRA_DEBUG_KERNEL)
1447 {
1448 zlog_info
1449 ("netlink_route_multipath(): (single hop)"
1450 "%s %s/%d via %s if %u, type %s",
1451 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1452 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1453 nexthop->ifindex,
1454 nexthop_types_desc[nexthop->type]);
1455 }
paul5ec90d22003-06-19 01:41:37 +00001456
paul7021c422003-07-15 12:52:22 +00001457 if (nexthop->type == NEXTHOP_TYPE_IPV4
1458 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1459 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1460 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001461#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001462 if (nexthop->type == NEXTHOP_TYPE_IPV6
1463 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1464 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1465 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1466 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001467#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001468 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1469 || nexthop->type == NEXTHOP_TYPE_IFNAME
1470 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1471 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1472 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1473 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1474 }
paul718e3742002-12-13 20:15:29 +00001475
paul7021c422003-07-15 12:52:22 +00001476 if (cmd == RTM_NEWROUTE)
1477 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001478
paul7021c422003-07-15 12:52:22 +00001479 nexthop_num++;
1480 break;
1481 }
1482 }
paul718e3742002-12-13 20:15:29 +00001483 }
1484 else
1485 {
1486 char buf[1024];
1487 struct rtattr *rta = (void *) buf;
1488 struct rtnexthop *rtnh;
1489
1490 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001491 rta->rta_len = RTA_LENGTH (0);
1492 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001493
1494 nexthop_num = 0;
1495 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001496 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1497 nexthop = nexthop->next)
1498 {
1499 if ((cmd == RTM_NEWROUTE
1500 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1501 || (cmd == RTM_DELROUTE
1502 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1503 {
1504 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001505
paul7021c422003-07-15 12:52:22 +00001506 rtnh->rtnh_len = sizeof (*rtnh);
1507 rtnh->rtnh_flags = 0;
1508 rtnh->rtnh_hops = 0;
1509 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001510
paul7021c422003-07-15 12:52:22 +00001511 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1512 {
1513 if (IS_ZEBRA_DEBUG_KERNEL)
1514 {
1515 zlog_info ("netlink_route_multipath() "
1516 "(recursive, multihop): "
1517 "%s %s/%d via %s if %u, type %s",
1518 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1519 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1520 nexthop->rifindex,
1521 nexthop_types_desc[nexthop->type]);
1522 }
1523 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1524 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1525 {
1526 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1527 &nexthop->rgate.ipv4, bytelen);
1528 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1529 }
paul718e3742002-12-13 20:15:29 +00001530#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001531 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1532 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1533 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1534 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1535 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001536#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001537 /* ifindex */
1538 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1539 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1540 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1541 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1542 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1543 rtnh->rtnh_ifindex = nexthop->rifindex;
1544 else
1545 rtnh->rtnh_ifindex = 0;
1546 }
1547 else
1548 {
1549 if (IS_ZEBRA_DEBUG_KERNEL)
1550 {
1551 zlog_info ("netlink_route_multipath() "
1552 "(multihop): "
1553 "%s %s/%d via %s if %u, type %s",
1554 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1555 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1556 nexthop->rifindex,
1557 nexthop_types_desc[nexthop->type]);
1558 }
1559 if (nexthop->type == NEXTHOP_TYPE_IPV4
1560 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1561 {
1562 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1563 &nexthop->gate.ipv4, bytelen);
1564 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1565 }
paul718e3742002-12-13 20:15:29 +00001566#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001567 if (nexthop->type == NEXTHOP_TYPE_IPV6
1568 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1569 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1570 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1571 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001572#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001573 /* ifindex */
1574 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1575 || nexthop->type == NEXTHOP_TYPE_IFNAME
1576 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1577 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1578 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1579 rtnh->rtnh_ifindex = nexthop->ifindex;
1580 else
1581 rtnh->rtnh_ifindex = 0;
1582 }
1583 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001584
paul7021c422003-07-15 12:52:22 +00001585 if (cmd == RTM_NEWROUTE)
1586 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1587 }
1588 }
paul718e3742002-12-13 20:15:29 +00001589
1590 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001591 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1592 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001593 }
1594
1595 /* If there is no useful nexthop then return. */
1596 if (nexthop_num == 0)
1597 {
1598 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001599 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001600 return 0;
1601 }
1602
paul7021c422003-07-15 12:52:22 +00001603skip:
paul718e3742002-12-13 20:15:29 +00001604
1605 /* Destination netlink address. */
1606 memset (&snl, 0, sizeof snl);
1607 snl.nl_family = AF_NETLINK;
1608
1609 if (family == AF_INET)
1610 nl = &netlink_cmd;
1611 else
1612 nl = &netlink;
1613
1614 /* Talk to netlink socket. */
1615 return netlink_talk (&req.n, nl);
1616}
1617
1618int
1619kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1620{
1621 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1622}
1623
1624int
1625kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1626{
1627 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1628}
1629
1630#ifdef HAVE_IPV6
1631int
1632kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1633{
1634 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1635}
1636
1637int
1638kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1639{
1640 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1641}
1642
1643/* Delete IPv6 route from the kernel. */
1644int
1645kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001646 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001647{
paul7021c422003-07-15 12:52:22 +00001648 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1649 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001650}
1651#endif /* HAVE_IPV6 */
1652
1653/* Interface address modification. */
1654int
1655netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001656 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001657{
1658 int bytelen;
1659 struct prefix *p;
1660
paul7021c422003-07-15 12:52:22 +00001661 struct
paul718e3742002-12-13 20:15:29 +00001662 {
1663 struct nlmsghdr n;
1664 struct ifaddrmsg ifa;
1665 char buf[1024];
1666 } req;
1667
1668 p = ifc->address;
1669 memset (&req, 0, sizeof req);
1670
1671 bytelen = (family == AF_INET ? 4 : 16);
1672
paul7021c422003-07-15 12:52:22 +00001673 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001674 req.n.nlmsg_flags = NLM_F_REQUEST;
1675 req.n.nlmsg_type = cmd;
1676 req.ifa.ifa_family = family;
1677
1678 req.ifa.ifa_index = ifp->ifindex;
1679 req.ifa.ifa_prefixlen = p->prefixlen;
1680
1681 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1682
1683 if (family == AF_INET && cmd == RTM_NEWADDR)
1684 {
1685 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001686 {
1687 p = ifc->destination;
1688 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1689 bytelen);
1690 }
paul718e3742002-12-13 20:15:29 +00001691 }
1692
1693 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1694 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001695
paul718e3742002-12-13 20:15:29 +00001696 if (ifc->label)
1697 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001698 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001699
1700 return netlink_talk (&req.n, &netlink_cmd);
1701}
1702
1703int
1704kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1705{
1706 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1707}
1708
1709int
1710kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1711{
1712 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1713}
1714
paul718e3742002-12-13 20:15:29 +00001715
1716extern struct thread_master *master;
1717
1718/* Kernel route reflection. */
1719int
1720kernel_read (struct thread *thread)
1721{
1722 int ret;
1723 int sock;
1724
1725 sock = THREAD_FD (thread);
1726 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001727 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001728
1729 return 0;
1730}
1731
1732/* Exported interface function. This function simply calls
1733 netlink_socket (). */
1734void
1735kernel_init ()
1736{
1737 unsigned long groups;
1738
paul7021c422003-07-15 12:52:22 +00001739 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001740#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001741 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001742#endif /* HAVE_IPV6 */
1743 netlink_socket (&netlink, groups);
1744 netlink_socket (&netlink_cmd, 0);
1745
1746 /* Register kernel socket. */
1747 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001748 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001749}