blob: 2ca0de43f3dd135eff152dadae053a1751396501 [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
paul718e3742002-12-13 20:15:29 +000087/* Make socket for Linux netlink interface. */
88static int
89netlink_socket (struct nlsock *nl, unsigned long groups)
90{
91 int ret;
92 struct sockaddr_nl snl;
93 int sock;
94 int namelen;
95
96 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
97 if (sock < 0)
98 {
99 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000100 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000101 return -1;
102 }
103
104 ret = fcntl (sock, F_SETFL, O_NONBLOCK);
105 if (ret < 0)
106 {
107 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000108 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000109 close (sock);
110 return -1;
111 }
paul7021c422003-07-15 12:52:22 +0000112
paul718e3742002-12-13 20:15:29 +0000113 memset (&snl, 0, sizeof snl);
114 snl.nl_family = AF_NETLINK;
115 snl.nl_groups = groups;
116
117 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000118 if (zserv_privs.change (ZPRIVS_RAISE))
119 {
120 zlog (NULL, LOG_ERR, "Can't raise privileges");
121 return -1;
122 }
pauledd7c242003-06-04 13:59:38 +0000123
paul718e3742002-12-13 20:15:29 +0000124 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
hasso55e7ecd2004-08-06 08:41:56 +0000125 if (zserv_privs.change (ZPRIVS_LOWER))
126 zlog (NULL, LOG_ERR, "Can't lower privileges");
127
paul718e3742002-12-13 20:15:29 +0000128 if (ret < 0)
129 {
paul7021c422003-07-15 12:52:22 +0000130 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
131 nl->name, snl.nl_groups, strerror (errno));
paul718e3742002-12-13 20:15:29 +0000132 close (sock);
133 return -1;
134 }
paul7021c422003-07-15 12:52:22 +0000135
paul718e3742002-12-13 20:15:29 +0000136 /* multiple netlink sockets will have different nl_pid */
137 namelen = sizeof snl;
138 ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
139 if (ret < 0 || namelen != sizeof snl)
140 {
141 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000142 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000143 close (sock);
144 return -1;
145 }
146
147 nl->snl = snl;
148 nl->sock = sock;
149 return ret;
150}
151
paul7021c422003-07-15 12:52:22 +0000152int
153set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000154{
155
156 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000157 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000158 {
paul7021c422003-07-15 12:52:22 +0000159 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
160 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000161 return -1;
162 }
163 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000164 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000165 {
paul7021c422003-07-15 12:52:22 +0000166 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
167 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000168 return -1;
169 }
170 return 0;
171}
172
paul7021c422003-07-15 12:52:22 +0000173int
174set_netlink_nonblocking (struct nlsock *nl, int *flags)
175{
paul5f37d862003-04-19 00:11:28 +0000176 /* Restore socket flags for nonblocking I/O */
177 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000178 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000179 {
paul7021c422003-07-15 12:52:22 +0000180 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
181 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000182 return -1;
183 }
184 return 0;
185}
186
paul718e3742002-12-13 20:15:29 +0000187/* Get type specified information from netlink. */
188static int
189netlink_request (int family, int type, struct nlsock *nl)
190{
191 int ret;
192 struct sockaddr_nl snl;
193
194 struct
195 {
196 struct nlmsghdr nlh;
197 struct rtgenmsg g;
198 } req;
199
200
201 /* Check netlink socket. */
202 if (nl->sock < 0)
203 {
204 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
205 return -1;
206 }
207
208 memset (&snl, 0, sizeof snl);
209 snl.nl_family = AF_NETLINK;
210
211 req.nlh.nlmsg_len = sizeof req;
212 req.nlh.nlmsg_type = type;
213 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
214 req.nlh.nlmsg_pid = 0;
215 req.nlh.nlmsg_seq = ++nl->seq;
216 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000217
218 /* linux appears to check capabilities on every message
219 * have to raise caps for every message sent
220 */
paul7021c422003-07-15 12:52:22 +0000221 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000222 {
223 zlog (NULL, LOG_ERR, "Can't raise privileges");
224 return -1;
225 }
paul7021c422003-07-15 12:52:22 +0000226
227 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
228 (struct sockaddr *) &snl, sizeof snl);
229
230 if (zserv_privs.change (ZPRIVS_LOWER))
231 zlog (NULL, LOG_ERR, "Can't lower privileges");
232
paul718e3742002-12-13 20:15:29 +0000233 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000234 {
235 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
236 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000237 return -1;
238 }
pauledd7c242003-06-04 13:59:38 +0000239
paul718e3742002-12-13 20:15:29 +0000240 return 0;
241}
242
243/* Receive message from netlink interface and pass those information
244 to the given function. */
245static int
246netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000247 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000248{
249 int status;
250 int ret = 0;
251 int error;
252
253 while (1)
254 {
255 char buf[4096];
256 struct iovec iov = { buf, sizeof buf };
257 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000258 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000259 struct nlmsghdr *h;
260
paul7021c422003-07-15 12:52:22 +0000261 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000262 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000263
paul718e3742002-12-13 20:15:29 +0000264 status = recvmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +0000265
266 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000267 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000268
269 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000270 {
271 if (errno == EINTR)
272 continue;
273 if (errno == EWOULDBLOCK || errno == EAGAIN)
274 break;
275 zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
276 continue;
277 }
paul718e3742002-12-13 20:15:29 +0000278
279 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000280 {
281 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
282 return -1;
283 }
paul718e3742002-12-13 20:15:29 +0000284
285 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000286 {
287 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
288 nl->name, msg.msg_namelen);
289 return -1;
290 }
paulb84d3a12003-11-17 10:31:01 +0000291
292 /* JF: Ignore messages that aren't from the kernel */
293 if ( snl.nl_pid != 0 )
294 {
295 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
296 continue;
297 }
paul718e3742002-12-13 20:15:29 +0000298
paul7021c422003-07-15 12:52:22 +0000299 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
300 h = NLMSG_NEXT (h, status))
301 {
302 /* Finish of reading. */
303 if (h->nlmsg_type == NLMSG_DONE)
304 return ret;
paul718e3742002-12-13 20:15:29 +0000305
paul7021c422003-07-15 12:52:22 +0000306 /* Error handling. */
307 if (h->nlmsg_type == NLMSG_ERROR)
308 {
309 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
310
paul718e3742002-12-13 20:15:29 +0000311 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000312 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000313 {
paul7021c422003-07-15 12:52:22 +0000314 if (IS_ZEBRA_DEBUG_KERNEL)
315 {
316 zlog_info ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
317 __FUNCTION__, nl->name,
318 lookup (nlmsg_str, err->msg.nlmsg_type),
319 err->msg.nlmsg_type, err->msg.nlmsg_seq,
320 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000321 }
paul7021c422003-07-15 12:52:22 +0000322
323 /* return if not a multipart message, otherwise continue */
324 if (!(h->nlmsg_flags & NLM_F_MULTI))
325 {
326 return 0;
paul718e3742002-12-13 20:15:29 +0000327 }
paul7021c422003-07-15 12:52:22 +0000328 continue;
paul718e3742002-12-13 20:15:29 +0000329 }
paul7021c422003-07-15 12:52:22 +0000330
paul718e3742002-12-13 20:15:29 +0000331 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000332 {
333 zlog (NULL, LOG_ERR, "%s error: message truncated",
334 nl->name);
335 return -1;
336 }
pauld753e9e2003-01-22 19:45:50 +0000337
paul7021c422003-07-15 12:52:22 +0000338 /* Deal with Error Noise - MAG */
339 {
340 int loglvl = LOG_ERR;
341 int errnum = err->error;
342 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000343
paul7021c422003-07-15 12:52:22 +0000344 if (nl == &netlink_cmd
345 && (-errnum == ENODEV || -errnum == ESRCH)
346 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
347 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000348
paul7021c422003-07-15 12:52:22 +0000349 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
350 "seq=%u, pid=%d",
351 nl->name, strerror (-errnum),
352 lookup (nlmsg_str, msg_type),
353 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
354 }
355 /*
356 ret = -1;
357 continue;
358 */
359 return -1;
360 }
paul718e3742002-12-13 20:15:29 +0000361
paul7021c422003-07-15 12:52:22 +0000362 /* OK we got netlink message. */
363 if (IS_ZEBRA_DEBUG_KERNEL)
364 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
365 nl->name,
366 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
367 h->nlmsg_seq, h->nlmsg_pid);
368
369 /* skip unsolicited messages originating from command socket */
370 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
371 {
372 if (IS_ZEBRA_DEBUG_KERNEL)
373 zlog_info ("netlink_parse_info: %s packet comes from %s",
374 nl->name, netlink_cmd.name);
375 continue;
376 }
377
378 error = (*filter) (&snl, h);
379 if (error < 0)
380 {
381 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
382 ret = error;
383 }
384 }
paul718e3742002-12-13 20:15:29 +0000385
386 /* After error care. */
387 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000388 {
389 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
390 continue;
391 }
paul718e3742002-12-13 20:15:29 +0000392 if (status)
paul7021c422003-07-15 12:52:22 +0000393 {
394 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
395 status);
396 return -1;
397 }
paul718e3742002-12-13 20:15:29 +0000398 }
399 return ret;
400}
401
402/* Utility function for parse rtattr. */
403static void
paul7021c422003-07-15 12:52:22 +0000404netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
405 int len)
paul718e3742002-12-13 20:15:29 +0000406{
paul7021c422003-07-15 12:52:22 +0000407 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000408 {
409 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000410 tb[rta->rta_type] = rta;
411 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000412 }
413}
414
415/* Called from interface_lookup_netlink(). This function is only used
416 during bootstrap. */
417int
418netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
419{
420 int len;
421 struct ifinfomsg *ifi;
422 struct rtattr *tb[IFLA_MAX + 1];
423 struct interface *ifp;
424 char *name;
425 int i;
426
427 ifi = NLMSG_DATA (h);
428
429 if (h->nlmsg_type != RTM_NEWLINK)
430 return 0;
431
432 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
433 if (len < 0)
434 return -1;
435
436 /* Looking up interface name. */
437 memset (tb, 0, sizeof tb);
438 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
439 if (tb[IFLA_IFNAME] == NULL)
440 return -1;
paul7021c422003-07-15 12:52:22 +0000441 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000442
443 /* Add interface. */
444 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000445
paul718e3742002-12-13 20:15:29 +0000446 ifp->ifindex = ifi->ifi_index;
447 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000448 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000449 ifp->metric = 1;
450
451 /* Hardware type and address. */
452 ifp->hw_type = ifi->ifi_type;
453
454 if (tb[IFLA_ADDRESS])
455 {
456 int hw_addr_len;
457
paul7021c422003-07-15 12:52:22 +0000458 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000459
460 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000461 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000462 else
paul7021c422003-07-15 12:52:22 +0000463 {
464 ifp->hw_addr_len = hw_addr_len;
465 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000466
paul7021c422003-07-15 12:52:22 +0000467 for (i = 0; i < hw_addr_len; i++)
468 if (ifp->hw_addr[i] != 0)
469 break;
paul718e3742002-12-13 20:15:29 +0000470
paul7021c422003-07-15 12:52:22 +0000471 if (i == hw_addr_len)
472 ifp->hw_addr_len = 0;
473 else
474 ifp->hw_addr_len = hw_addr_len;
475 }
paul718e3742002-12-13 20:15:29 +0000476 }
477
478 if_add_update (ifp);
479
480 return 0;
481}
482
483/* Lookup interface IPv4/IPv6 address. */
484int
485netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
486{
487 int len;
488 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000489 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000490 struct interface *ifp;
491 void *addr = NULL;
492 void *broad = NULL;
493 u_char flags = 0;
494 char *label = NULL;
495
496 ifa = NLMSG_DATA (h);
497
paul7021c422003-07-15 12:52:22 +0000498 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000499#ifdef HAVE_IPV6
500 && ifa->ifa_family != AF_INET6
501#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000502 )
paul718e3742002-12-13 20:15:29 +0000503 return 0;
504
505 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
506 return 0;
507
paul7021c422003-07-15 12:52:22 +0000508 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000509 if (len < 0)
510 return -1;
511
512 memset (tb, 0, sizeof tb);
513 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
514
515 ifp = if_lookup_by_index (ifa->ifa_index);
516 if (ifp == NULL)
517 {
518 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000519 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000520 return -1;
521 }
522
paul7021c422003-07-15 12:52:22 +0000523 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000524 {
paul00df0c12002-12-13 21:07:36 +0000525 char buf[BUFSIZ];
526 zlog_info ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000527 lookup (nlmsg_str, h->nlmsg_type),
528 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000529 if (tb[IFA_LOCAL])
paul7021c422003-07-15 12:52:22 +0000530 zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
531 RTA_DATA (tb[IFA_LOCAL]),
532 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000533 if (tb[IFA_ADDRESS])
paul7021c422003-07-15 12:52:22 +0000534 zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
535 RTA_DATA (tb
536 [IFA_ADDRESS]),
537 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000538 if (tb[IFA_BROADCAST])
paul7021c422003-07-15 12:52:22 +0000539 zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
540 RTA_DATA (tb
541 [IFA_BROADCAST]),
542 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000543 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
hasso5707cce2004-03-04 19:20:44 +0000544 zlog_info (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000545 }
paul31a476c2003-09-29 19:54:53 +0000546
547 if (tb[IFA_ADDRESS] == NULL)
548 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
549
550 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000551 {
paul31a476c2003-09-29 19:54:53 +0000552 if (tb[IFA_LOCAL])
553 {
554 addr = RTA_DATA (tb[IFA_LOCAL]);
555 if (tb[IFA_ADDRESS])
556 broad = RTA_DATA (tb[IFA_ADDRESS]);
557 else
558 broad = NULL;
559 }
560 else
561 {
562 if (tb[IFA_ADDRESS])
563 addr = RTA_DATA (tb[IFA_ADDRESS]);
564 else
565 addr = NULL;
566 }
paul7021c422003-07-15 12:52:22 +0000567 }
paul31a476c2003-09-29 19:54:53 +0000568 else
paul7021c422003-07-15 12:52:22 +0000569 {
paul31a476c2003-09-29 19:54:53 +0000570 if (tb[IFA_ADDRESS])
571 addr = RTA_DATA (tb[IFA_ADDRESS]);
572 else
573 addr = NULL;
574
575 if (tb[IFA_BROADCAST])
576 broad = RTA_DATA(tb[IFA_BROADCAST]);
577 else
578 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000579 }
paul00df0c12002-12-13 21:07:36 +0000580
paul718e3742002-12-13 20:15:29 +0000581 /* Flags. */
582 if (ifa->ifa_flags & IFA_F_SECONDARY)
583 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
584
585 /* Label */
586 if (tb[IFA_LABEL])
587 label = (char *) RTA_DATA (tb[IFA_LABEL]);
588
589 if (ifp && label && strcmp (ifp->name, label) == 0)
590 label = NULL;
591
592 /* Register interface address to the interface. */
593 if (ifa->ifa_family == AF_INET)
594 {
paul7021c422003-07-15 12:52:22 +0000595 if (h->nlmsg_type == RTM_NEWADDR)
596 connected_add_ipv4 (ifp, flags,
597 (struct in_addr *) addr, ifa->ifa_prefixlen,
598 (struct in_addr *) broad, label);
599 else
600 connected_delete_ipv4 (ifp, flags,
601 (struct in_addr *) addr, ifa->ifa_prefixlen,
602 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000603 }
604#ifdef HAVE_IPV6
605 if (ifa->ifa_family == AF_INET6)
606 {
607 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000608 connected_add_ipv6 (ifp,
609 (struct in6_addr *) addr, ifa->ifa_prefixlen,
610 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000611 else
paul7021c422003-07-15 12:52:22 +0000612 connected_delete_ipv6 (ifp,
613 (struct in6_addr *) addr, ifa->ifa_prefixlen,
614 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000615 }
paul7021c422003-07-15 12:52:22 +0000616#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000617
618 return 0;
619}
620
621/* Looking up routing table by netlink interface. */
622int
623netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
624{
625 int len;
626 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000627 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000628 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000629
630 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000631
632 int index;
633 int table;
hasso34195bf2004-04-06 12:07:06 +0000634 int metric;
635
paul718e3742002-12-13 20:15:29 +0000636 void *dest;
637 void *gate;
638
639 rtm = NLMSG_DATA (h);
640
641 if (h->nlmsg_type != RTM_NEWROUTE)
642 return 0;
643 if (rtm->rtm_type != RTN_UNICAST)
644 return 0;
645
646 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000647#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000648 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000649 return 0;
650#endif
651
paul7021c422003-07-15 12:52:22 +0000652 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000653 if (len < 0)
654 return -1;
655
656 memset (tb, 0, sizeof tb);
657 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
658
659 if (rtm->rtm_flags & RTM_F_CLONED)
660 return 0;
661 if (rtm->rtm_protocol == RTPROT_REDIRECT)
662 return 0;
663 if (rtm->rtm_protocol == RTPROT_KERNEL)
664 return 0;
665
666 if (rtm->rtm_src_len != 0)
667 return 0;
668
669 /* Route which inserted by Zebra. */
670 if (rtm->rtm_protocol == RTPROT_ZEBRA)
671 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000672
paul718e3742002-12-13 20:15:29 +0000673 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000674 metric = 0;
paul718e3742002-12-13 20:15:29 +0000675 dest = NULL;
676 gate = NULL;
677
678 if (tb[RTA_OIF])
679 index = *(int *) RTA_DATA (tb[RTA_OIF]);
680
681 if (tb[RTA_DST])
682 dest = RTA_DATA (tb[RTA_DST]);
683 else
684 dest = anyaddr;
685
686 /* Multipath treatment is needed. */
687 if (tb[RTA_GATEWAY])
688 gate = RTA_DATA (tb[RTA_GATEWAY]);
689
hasso34195bf2004-04-06 12:07:06 +0000690 if (tb[RTA_PRIORITY])
691 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
692
paul718e3742002-12-13 20:15:29 +0000693 if (rtm->rtm_family == AF_INET)
694 {
695 struct prefix_ipv4 p;
696 p.family = AF_INET;
697 memcpy (&p.prefix, dest, 4);
698 p.prefixlen = rtm->rtm_dst_len;
699
hasso34195bf2004-04-06 12:07:06 +0000700 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000701 }
702#ifdef HAVE_IPV6
703 if (rtm->rtm_family == AF_INET6)
704 {
705 struct prefix_ipv6 p;
706 p.family = AF_INET6;
707 memcpy (&p.prefix, dest, 16);
708 p.prefixlen = rtm->rtm_dst_len;
709
710 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
711 }
712#endif /* HAVE_IPV6 */
713
714 return 0;
715}
716
paul7021c422003-07-15 12:52:22 +0000717struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000718 {RTPROT_REDIRECT, "redirect"},
719 {RTPROT_KERNEL, "kernel"},
720 {RTPROT_BOOT, "boot"},
721 {RTPROT_STATIC, "static"},
722 {RTPROT_GATED, "GateD"},
723 {RTPROT_RA, "router advertisement"},
724 {RTPROT_MRT, "MRT"},
725 {RTPROT_ZEBRA, "Zebra"},
726#ifdef RTPROT_BIRD
727 {RTPROT_BIRD, "BIRD"},
728#endif /* RTPROT_BIRD */
729 {0, NULL}
730};
731
732/* Routing information change from the kernel. */
733int
734netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
735{
736 int len;
737 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000738 struct rtattr *tb[RTA_MAX + 1];
739
740 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000741
742 int index;
743 int table;
744 void *dest;
745 void *gate;
746
747 rtm = NLMSG_DATA (h);
748
paul7021c422003-07-15 12:52:22 +0000749 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000750 {
751 /* If this is not route add/delete message print warning. */
752 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
753 return 0;
754 }
755
756 /* Connected route. */
757 if (IS_ZEBRA_DEBUG_KERNEL)
758 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000759 h->nlmsg_type ==
760 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
761 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
762 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
763 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000764
765 if (rtm->rtm_type != RTN_UNICAST)
766 {
767 return 0;
768 }
769
770 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000771 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000772 {
773 return 0;
774 }
775
paul7021c422003-07-15 12:52:22 +0000776 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000777 if (len < 0)
778 return -1;
779
780 memset (tb, 0, sizeof tb);
781 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
782
783 if (rtm->rtm_flags & RTM_F_CLONED)
784 return 0;
785 if (rtm->rtm_protocol == RTPROT_REDIRECT)
786 return 0;
787 if (rtm->rtm_protocol == RTPROT_KERNEL)
788 return 0;
789
790 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
791 return 0;
792
793 if (rtm->rtm_src_len != 0)
794 {
795 zlog_warn ("netlink_route_change(): no src len");
796 return 0;
797 }
paul7021c422003-07-15 12:52:22 +0000798
paul718e3742002-12-13 20:15:29 +0000799 index = 0;
800 dest = NULL;
801 gate = NULL;
802
803 if (tb[RTA_OIF])
804 index = *(int *) RTA_DATA (tb[RTA_OIF]);
805
806 if (tb[RTA_DST])
807 dest = RTA_DATA (tb[RTA_DST]);
808 else
809 dest = anyaddr;
810
811 if (tb[RTA_GATEWAY])
812 gate = RTA_DATA (tb[RTA_GATEWAY]);
813
814 if (rtm->rtm_family == AF_INET)
815 {
816 struct prefix_ipv4 p;
817 p.family = AF_INET;
818 memcpy (&p.prefix, dest, 4);
819 p.prefixlen = rtm->rtm_dst_len;
820
821 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000822 {
823 if (h->nlmsg_type == RTM_NEWROUTE)
824 zlog_info ("RTM_NEWROUTE %s/%d",
825 inet_ntoa (p.prefix), p.prefixlen);
826 else
827 zlog_info ("RTM_DELROUTE %s/%d",
828 inet_ntoa (p.prefix), p.prefixlen);
829 }
paul718e3742002-12-13 20:15:29 +0000830
831 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000832 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000833 else
paul7021c422003-07-15 12:52:22 +0000834 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000835 }
836
837#ifdef HAVE_IPV6
838 if (rtm->rtm_family == AF_INET6)
839 {
840 struct prefix_ipv6 p;
841 char buf[BUFSIZ];
842
843 p.family = AF_INET6;
844 memcpy (&p.prefix, dest, 16);
845 p.prefixlen = rtm->rtm_dst_len;
846
847 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000848 {
849 if (h->nlmsg_type == RTM_NEWROUTE)
850 zlog_info ("RTM_NEWROUTE %s/%d",
851 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
852 p.prefixlen);
853 else
854 zlog_info ("RTM_DELROUTE %s/%d",
855 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
856 p.prefixlen);
857 }
paul718e3742002-12-13 20:15:29 +0000858
859 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000860 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000861 else
paul7021c422003-07-15 12:52:22 +0000862 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000863 }
864#endif /* HAVE_IPV6 */
865
866 return 0;
867}
868
869int
870netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
871{
872 int len;
873 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000874 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000875 struct interface *ifp;
876 char *name;
877
878 ifi = NLMSG_DATA (h);
879
paul7021c422003-07-15 12:52:22 +0000880 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000881 {
882 /* If this is not link add/delete message so print warning. */
883 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000884 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000885 return 0;
886 }
887
888 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
889 if (len < 0)
890 return -1;
891
892 /* Looking up interface name. */
893 memset (tb, 0, sizeof tb);
894 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
895 if (tb[IFLA_IFNAME] == NULL)
896 return -1;
paul7021c422003-07-15 12:52:22 +0000897 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000898
899 /* Add interface. */
900 if (h->nlmsg_type == RTM_NEWLINK)
901 {
902 ifp = if_lookup_by_name (name);
903
paul7021c422003-07-15 12:52:22 +0000904 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
905 {
906 if (ifp == NULL)
907 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000908
paul7021c422003-07-15 12:52:22 +0000909 ifp->ifindex = ifi->ifi_index;
910 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000911 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000912 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000913
paul7021c422003-07-15 12:52:22 +0000914 /* If new link is added. */
915 if_add_update (ifp);
916 }
paul718e3742002-12-13 20:15:29 +0000917 else
paul7021c422003-07-15 12:52:22 +0000918 {
919 /* Interface status change. */
920 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000921 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000922 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000923
paul7021c422003-07-15 12:52:22 +0000924 if (if_is_operative (ifp))
925 {
926 ifp->flags = ifi->ifi_flags & 0x0000fffff;
927 if (!if_is_operative (ifp))
928 if_down (ifp);
929 }
930 else
931 {
932 ifp->flags = ifi->ifi_flags & 0x0000fffff;
933 if (if_is_operative (ifp))
934 if_up (ifp);
935 }
936 }
paul718e3742002-12-13 20:15:29 +0000937 }
938 else
939 {
940 /* RTM_DELLINK. */
941 ifp = if_lookup_by_name (name);
942
943 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000944 {
945 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000946 name);
paul7021c422003-07-15 12:52:22 +0000947 return 0;
948 }
949
paul718e3742002-12-13 20:15:29 +0000950 if_delete_update (ifp);
951 }
952
953 return 0;
954}
955
956int
957netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
958{
959 switch (h->nlmsg_type)
960 {
961 case RTM_NEWROUTE:
962 return netlink_route_change (snl, h);
963 break;
964 case RTM_DELROUTE:
965 return netlink_route_change (snl, h);
966 break;
967 case RTM_NEWLINK:
968 return netlink_link_change (snl, h);
969 break;
970 case RTM_DELLINK:
971 return netlink_link_change (snl, h);
972 break;
973 case RTM_NEWADDR:
974 return netlink_interface_addr (snl, h);
975 break;
976 case RTM_DELADDR:
977 return netlink_interface_addr (snl, h);
978 break;
979 default:
980 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
981 break;
982 }
983 return 0;
984}
985
986/* Interface lookup by netlink socket. */
987int
988interface_lookup_netlink ()
989{
990 int ret;
paul5f37d862003-04-19 00:11:28 +0000991 int flags;
992 int snb_ret;
paul7021c422003-07-15 12:52:22 +0000993
paul5f37d862003-04-19 00:11:28 +0000994 /*
995 * Change netlink socket flags to blocking to ensure we get
996 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +0000997 */
998 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
999 if (snb_ret < 0)
1000 zlog (NULL, LOG_WARNING,
1001 "%s:%i Warning: Could not set netlink socket to blocking.",
1002 __FUNCTION__, __LINE__);
1003
paul718e3742002-12-13 20:15:29 +00001004 /* Get interface information. */
1005 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1006 if (ret < 0)
1007 return ret;
1008 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1009 if (ret < 0)
1010 return ret;
1011
1012 /* Get IPv4 address of the interfaces. */
1013 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1014 if (ret < 0)
1015 return ret;
1016 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1017 if (ret < 0)
1018 return ret;
1019
1020#ifdef HAVE_IPV6
1021 /* Get IPv6 address of the interfaces. */
1022 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1023 if (ret < 0)
1024 return ret;
1025 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1026 if (ret < 0)
1027 return ret;
1028#endif /* HAVE_IPV6 */
1029
paul7021c422003-07-15 12:52:22 +00001030 /* restore socket flags */
1031 if (snb_ret == 0)
1032 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001033 return 0;
1034}
1035
1036/* Routing table read function using netlink interface. Only called
1037 bootstrap time. */
1038int
1039netlink_route_read ()
1040{
1041 int ret;
paul5f37d862003-04-19 00:11:28 +00001042 int flags;
1043 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001044
paul5f37d862003-04-19 00:11:28 +00001045 /*
1046 * Change netlink socket flags to blocking to ensure we get
1047 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001048 */
1049 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1050 if (snb_ret < 0)
1051 zlog (NULL, LOG_WARNING,
1052 "%s:%i Warning: Could not set netlink socket to blocking.",
1053 __FUNCTION__, __LINE__);
1054
paul718e3742002-12-13 20:15:29 +00001055 /* Get IPv4 routing table. */
1056 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1057 if (ret < 0)
1058 return ret;
1059 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1060 if (ret < 0)
1061 return ret;
1062
1063#ifdef HAVE_IPV6
1064 /* Get IPv6 routing table. */
1065 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1066 if (ret < 0)
1067 return ret;
1068 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1069 if (ret < 0)
1070 return ret;
1071#endif /* HAVE_IPV6 */
1072
paul5f37d862003-04-19 00:11:28 +00001073 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001074 if (snb_ret == 0)
1075 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001076 return 0;
1077}
1078
1079/* Utility function comes from iproute2.
1080 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1081int
1082addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1083{
1084 int len;
1085 struct rtattr *rta;
1086
paul7021c422003-07-15 12:52:22 +00001087 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001088
paul7021c422003-07-15 12:52:22 +00001089 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001090 return -1;
1091
paul7021c422003-07-15 12:52:22 +00001092 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001093 rta->rta_type = type;
1094 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001095 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001096 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1097
1098 return 0;
1099}
1100
1101int
1102rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1103{
1104 int len;
1105 struct rtattr *subrta;
1106
paul7021c422003-07-15 12:52:22 +00001107 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001108
paul7021c422003-07-15 12:52:22 +00001109 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001110 return -1;
1111
paul7021c422003-07-15 12:52:22 +00001112 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001113 subrta->rta_type = type;
1114 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001115 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001116 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1117
1118 return 0;
1119}
1120
1121/* Utility function comes from iproute2.
1122 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1123int
1124addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1125{
1126 int len;
1127 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001128
1129 len = RTA_LENGTH (4);
1130
paul718e3742002-12-13 20:15:29 +00001131 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1132 return -1;
1133
paul7021c422003-07-15 12:52:22 +00001134 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001135 rta->rta_type = type;
1136 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001137 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001138 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1139
1140 return 0;
1141}
1142
1143static int
1144netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1145{
1146 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1147 return 0;
1148}
1149
1150/* sendmsg() to netlink socket then recvmsg(). */
1151int
1152netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1153{
1154 int status;
1155 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001156 struct iovec iov = { (void *) n, n->nlmsg_len };
1157 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001158 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001159 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001160
paul718e3742002-12-13 20:15:29 +00001161 memset (&snl, 0, sizeof snl);
1162 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001163
paul718e3742002-12-13 20:15:29 +00001164 n->nlmsg_seq = ++netlink_cmd.seq;
1165
1166 /* Request an acknowledgement by setting NLM_F_ACK */
1167 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001168
1169 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001170 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001171 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1172 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001173
1174 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001175 if (zserv_privs.change (ZPRIVS_RAISE))
1176 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001177 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001178 if (zserv_privs.change (ZPRIVS_LOWER))
1179 zlog (NULL, LOG_ERR, "Can't lower privileges");
1180
paul718e3742002-12-13 20:15:29 +00001181 if (status < 0)
1182 {
1183 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001184 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001185 return -1;
1186 }
paul7021c422003-07-15 12:52:22 +00001187
paul718e3742002-12-13 20:15:29 +00001188 /*
1189 * Change socket flags for blocking I/O.
1190 * This ensures we wait for a reply in netlink_parse_info().
1191 */
paul7021c422003-07-15 12:52:22 +00001192 snb_ret = set_netlink_blocking (nl, &flags);
1193 if (snb_ret < 0)
1194 zlog (NULL, LOG_WARNING,
1195 "%s:%i Warning: Could not set netlink socket to blocking.",
1196 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001197
1198 /*
1199 * Get reply from netlink socket.
1200 * The reply should either be an acknowlegement or an error.
1201 */
1202 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001203
paul718e3742002-12-13 20:15:29 +00001204 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001205 if (snb_ret == 0)
1206 set_netlink_nonblocking (nl, &flags);
1207
paul718e3742002-12-13 20:15:29 +00001208 return status;
1209}
1210
1211/* Routing table change via netlink interface. */
1212int
1213netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001214 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001215{
1216 int ret;
1217 int bytelen;
1218 struct sockaddr_nl snl;
1219 int discard;
1220
paul7021c422003-07-15 12:52:22 +00001221 struct
paul718e3742002-12-13 20:15:29 +00001222 {
1223 struct nlmsghdr n;
1224 struct rtmsg r;
1225 char buf[1024];
1226 } req;
1227
1228 memset (&req, 0, sizeof req);
1229
1230 bytelen = (family == AF_INET ? 4 : 16);
1231
1232 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1233 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1234 req.n.nlmsg_type = cmd;
1235 req.r.rtm_family = family;
1236 req.r.rtm_table = table;
1237 req.r.rtm_dst_len = length;
1238
hasso81dfcaa2003-05-25 19:21:25 +00001239 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1240 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001241 discard = 1;
1242 else
1243 discard = 0;
1244
paul7021c422003-07-15 12:52:22 +00001245 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001246 {
1247 req.r.rtm_protocol = RTPROT_ZEBRA;
1248 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1249
paul7021c422003-07-15 12:52:22 +00001250 if (discard)
paul595db7f2003-05-25 21:35:06 +00001251 {
1252 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1253 req.r.rtm_type = RTN_BLACKHOLE;
1254 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1255 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001256 else
1257 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1258 }
paul595db7f2003-05-25 21:35:06 +00001259 else
paul7021c422003-07-15 12:52:22 +00001260 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001261 }
1262
1263 if (dest)
1264 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1265
paul7021c422003-07-15 12:52:22 +00001266 if (!discard)
paul718e3742002-12-13 20:15:29 +00001267 {
1268 if (gate)
paul7021c422003-07-15 12:52:22 +00001269 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001270 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001271 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001272 }
1273
1274 /* Destination netlink address. */
1275 memset (&snl, 0, sizeof snl);
1276 snl.nl_family = AF_NETLINK;
1277
1278 /* Talk to netlink socket. */
1279 ret = netlink_talk (&req.n, &netlink);
1280 if (ret < 0)
1281 return -1;
1282
1283 return 0;
1284}
1285
1286/* Routing table change via netlink interface. */
1287int
1288netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001289 int family)
paul718e3742002-12-13 20:15:29 +00001290{
1291 int bytelen;
1292 struct sockaddr_nl snl;
1293 struct nexthop *nexthop = NULL;
1294 int nexthop_num = 0;
1295 struct nlsock *nl;
1296 int discard;
1297
paul7021c422003-07-15 12:52:22 +00001298 struct
paul718e3742002-12-13 20:15:29 +00001299 {
1300 struct nlmsghdr n;
1301 struct rtmsg r;
1302 char buf[1024];
1303 } req;
1304
1305 memset (&req, 0, sizeof req);
1306
1307 bytelen = (family == AF_INET ? 4 : 16);
1308
1309 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1310 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1311 req.n.nlmsg_type = cmd;
1312 req.r.rtm_family = family;
1313 req.r.rtm_table = rib->table;
1314 req.r.rtm_dst_len = p->prefixlen;
1315
paul13766da2003-02-07 14:46:23 +00001316#ifdef RTM_F_EQUALIZE
1317 req.r.rtm_flags |= RTM_F_EQUALIZE;
1318#endif /* RTM_F_EQUALIZE */
1319
paul7021c422003-07-15 12:52:22 +00001320 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001321 discard = 1;
1322 else
1323 discard = 0;
1324
paul7021c422003-07-15 12:52:22 +00001325 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001326 {
1327 req.r.rtm_protocol = RTPROT_ZEBRA;
1328 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1329
paul7021c422003-07-15 12:52:22 +00001330 if (discard)
paul595db7f2003-05-25 21:35:06 +00001331 {
1332 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1333 req.r.rtm_type = RTN_BLACKHOLE;
1334 else if (rib->flags & ZEBRA_FLAG_REJECT)
1335 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001336 else
1337 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1338 }
paul595db7f2003-05-25 21:35:06 +00001339 else
paul7021c422003-07-15 12:52:22 +00001340 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001341 }
1342
1343 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1344
1345 /* Metric. */
1346 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1347
1348 if (discard)
1349 {
1350 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001351 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1352 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001353 goto skip;
1354 }
1355
1356 /* Multipath case. */
1357 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1358 {
1359 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001360 {
paul5ec90d22003-06-19 01:41:37 +00001361
paul7021c422003-07-15 12:52:22 +00001362 if ((cmd == RTM_NEWROUTE
1363 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1364 || (cmd == RTM_DELROUTE
1365 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1366 {
paul5ec90d22003-06-19 01:41:37 +00001367
paul7021c422003-07-15 12:52:22 +00001368 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1369 {
1370 if (IS_ZEBRA_DEBUG_KERNEL)
1371 {
1372 zlog_info
1373 ("netlink_route_multipath() (recursive, 1 hop): "
1374 "%s %s/%d via %s if %u, type %s",
1375 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1376 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1377 nexthop->rifindex,
1378 nexthop_types_desc[nexthop->rtype]);
1379 }
paul5ec90d22003-06-19 01:41:37 +00001380
paul7021c422003-07-15 12:52:22 +00001381 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1382 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1383 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1384 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001385#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001386 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1387 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1388 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1389 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1390 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001391#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001392 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1393 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1394 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1395 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1396 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1397 addattr32 (&req.n, sizeof req, RTA_OIF,
1398 nexthop->rifindex);
1399 }
1400 else
1401 {
1402 if (IS_ZEBRA_DEBUG_KERNEL)
1403 {
1404 zlog_info
1405 ("netlink_route_multipath(): (single hop)"
1406 "%s %s/%d via %s if %u, type %s",
1407 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1408 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1409 nexthop->ifindex,
1410 nexthop_types_desc[nexthop->type]);
1411 }
paul5ec90d22003-06-19 01:41:37 +00001412
paul7021c422003-07-15 12:52:22 +00001413 if (nexthop->type == NEXTHOP_TYPE_IPV4
1414 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1415 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1416 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001417#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001418 if (nexthop->type == NEXTHOP_TYPE_IPV6
1419 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1420 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1421 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1422 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001423#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001424 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1425 || nexthop->type == NEXTHOP_TYPE_IFNAME
1426 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1427 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1428 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1429 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1430 }
paul718e3742002-12-13 20:15:29 +00001431
paul7021c422003-07-15 12:52:22 +00001432 if (cmd == RTM_NEWROUTE)
1433 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001434
paul7021c422003-07-15 12:52:22 +00001435 nexthop_num++;
1436 break;
1437 }
1438 }
paul718e3742002-12-13 20:15:29 +00001439 }
1440 else
1441 {
1442 char buf[1024];
1443 struct rtattr *rta = (void *) buf;
1444 struct rtnexthop *rtnh;
1445
1446 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001447 rta->rta_len = RTA_LENGTH (0);
1448 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001449
1450 nexthop_num = 0;
1451 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001452 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1453 nexthop = nexthop->next)
1454 {
1455 if ((cmd == RTM_NEWROUTE
1456 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1457 || (cmd == RTM_DELROUTE
1458 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1459 {
1460 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001461
paul7021c422003-07-15 12:52:22 +00001462 rtnh->rtnh_len = sizeof (*rtnh);
1463 rtnh->rtnh_flags = 0;
1464 rtnh->rtnh_hops = 0;
1465 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001466
paul7021c422003-07-15 12:52:22 +00001467 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1468 {
1469 if (IS_ZEBRA_DEBUG_KERNEL)
1470 {
1471 zlog_info ("netlink_route_multipath() "
1472 "(recursive, multihop): "
1473 "%s %s/%d via %s if %u, type %s",
1474 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1475 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1476 nexthop->rifindex,
1477 nexthop_types_desc[nexthop->type]);
1478 }
1479 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1480 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1481 {
1482 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1483 &nexthop->rgate.ipv4, bytelen);
1484 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1485 }
paul718e3742002-12-13 20:15:29 +00001486#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001487 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1488 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1489 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1490 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1491 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001492#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001493 /* ifindex */
1494 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1495 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1496 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1497 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1498 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1499 rtnh->rtnh_ifindex = nexthop->rifindex;
1500 else
1501 rtnh->rtnh_ifindex = 0;
1502 }
1503 else
1504 {
1505 if (IS_ZEBRA_DEBUG_KERNEL)
1506 {
1507 zlog_info ("netlink_route_multipath() "
1508 "(multihop): "
1509 "%s %s/%d via %s if %u, type %s",
1510 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1511 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1512 nexthop->rifindex,
1513 nexthop_types_desc[nexthop->type]);
1514 }
1515 if (nexthop->type == NEXTHOP_TYPE_IPV4
1516 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1517 {
1518 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1519 &nexthop->gate.ipv4, bytelen);
1520 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1521 }
paul718e3742002-12-13 20:15:29 +00001522#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001523 if (nexthop->type == NEXTHOP_TYPE_IPV6
1524 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1525 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1526 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1527 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001528#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001529 /* ifindex */
1530 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1531 || nexthop->type == NEXTHOP_TYPE_IFNAME
1532 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1533 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1534 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1535 rtnh->rtnh_ifindex = nexthop->ifindex;
1536 else
1537 rtnh->rtnh_ifindex = 0;
1538 }
1539 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001540
paul7021c422003-07-15 12:52:22 +00001541 if (cmd == RTM_NEWROUTE)
1542 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1543 }
1544 }
paul718e3742002-12-13 20:15:29 +00001545
1546 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001547 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1548 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001549 }
1550
1551 /* If there is no useful nexthop then return. */
1552 if (nexthop_num == 0)
1553 {
1554 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001555 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001556 return 0;
1557 }
1558
paul7021c422003-07-15 12:52:22 +00001559skip:
paul718e3742002-12-13 20:15:29 +00001560
1561 /* Destination netlink address. */
1562 memset (&snl, 0, sizeof snl);
1563 snl.nl_family = AF_NETLINK;
1564
1565 if (family == AF_INET)
1566 nl = &netlink_cmd;
1567 else
1568 nl = &netlink;
1569
1570 /* Talk to netlink socket. */
1571 return netlink_talk (&req.n, nl);
1572}
1573
1574int
1575kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1576{
1577 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1578}
1579
1580int
1581kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1582{
1583 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1584}
1585
1586#ifdef HAVE_IPV6
1587int
1588kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1589{
1590 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1591}
1592
1593int
1594kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1595{
1596 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1597}
1598
1599/* Delete IPv6 route from the kernel. */
1600int
1601kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001602 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001603{
paul7021c422003-07-15 12:52:22 +00001604 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1605 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001606}
1607#endif /* HAVE_IPV6 */
1608
1609/* Interface address modification. */
1610int
1611netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001612 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001613{
1614 int bytelen;
1615 struct prefix *p;
1616
paul7021c422003-07-15 12:52:22 +00001617 struct
paul718e3742002-12-13 20:15:29 +00001618 {
1619 struct nlmsghdr n;
1620 struct ifaddrmsg ifa;
1621 char buf[1024];
1622 } req;
1623
1624 p = ifc->address;
1625 memset (&req, 0, sizeof req);
1626
1627 bytelen = (family == AF_INET ? 4 : 16);
1628
paul7021c422003-07-15 12:52:22 +00001629 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001630 req.n.nlmsg_flags = NLM_F_REQUEST;
1631 req.n.nlmsg_type = cmd;
1632 req.ifa.ifa_family = family;
1633
1634 req.ifa.ifa_index = ifp->ifindex;
1635 req.ifa.ifa_prefixlen = p->prefixlen;
1636
1637 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1638
1639 if (family == AF_INET && cmd == RTM_NEWADDR)
1640 {
1641 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001642 {
1643 p = ifc->destination;
1644 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1645 bytelen);
1646 }
paul718e3742002-12-13 20:15:29 +00001647 }
1648
1649 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1650 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001651
paul718e3742002-12-13 20:15:29 +00001652 if (ifc->label)
1653 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001654 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001655
1656 return netlink_talk (&req.n, &netlink_cmd);
1657}
1658
1659int
1660kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1661{
1662 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1663}
1664
1665int
1666kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1667{
1668 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1669}
1670
paul718e3742002-12-13 20:15:29 +00001671
1672extern struct thread_master *master;
1673
1674/* Kernel route reflection. */
1675int
1676kernel_read (struct thread *thread)
1677{
1678 int ret;
1679 int sock;
1680
1681 sock = THREAD_FD (thread);
1682 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001683 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001684
1685 return 0;
1686}
1687
1688/* Exported interface function. This function simply calls
1689 netlink_socket (). */
1690void
1691kernel_init ()
1692{
1693 unsigned long groups;
1694
paul7021c422003-07-15 12:52:22 +00001695 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001696#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001697 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001698#endif /* HAVE_IPV6 */
1699 netlink_socket (&netlink, groups);
1700 netlink_socket (&netlink_cmd, 0);
1701
1702 /* Register kernel socket. */
1703 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001704 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001705}