blob: 26369dd85f68c653fefab7c034c024ffb8972d34 [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);
125 if (ret < 0)
126 {
paul7021c422003-07-15 12:52:22 +0000127 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000128 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul7021c422003-07-15 12:52:22 +0000129 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
130 nl->name, snl.nl_groups, strerror (errno));
paul718e3742002-12-13 20:15:29 +0000131 close (sock);
132 return -1;
133 }
paul7021c422003-07-15 12:52:22 +0000134
135 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000136 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000137
138 /* multiple netlink sockets will have different nl_pid */
139 namelen = sizeof snl;
140 ret = getsockname (sock, (struct sockaddr *) &snl, &namelen);
141 if (ret < 0 || namelen != sizeof snl)
142 {
143 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
paul7021c422003-07-15 12:52:22 +0000144 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000145 close (sock);
146 return -1;
147 }
148
149 nl->snl = snl;
150 nl->sock = sock;
151 return ret;
152}
153
paul7021c422003-07-15 12:52:22 +0000154int
155set_netlink_blocking (struct nlsock *nl, int *flags)
paul5f37d862003-04-19 00:11:28 +0000156{
157
158 /* Change socket flags for blocking I/O. */
paul7021c422003-07-15 12:52:22 +0000159 if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
paul5f37d862003-04-19 00:11:28 +0000160 {
paul7021c422003-07-15 12:52:22 +0000161 zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
162 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000163 return -1;
164 }
165 *flags &= ~O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000166 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000167 {
paul7021c422003-07-15 12:52:22 +0000168 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
169 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000170 return -1;
171 }
172 return 0;
173}
174
paul7021c422003-07-15 12:52:22 +0000175int
176set_netlink_nonblocking (struct nlsock *nl, int *flags)
177{
paul5f37d862003-04-19 00:11:28 +0000178 /* Restore socket flags for nonblocking I/O */
179 *flags |= O_NONBLOCK;
paul7021c422003-07-15 12:52:22 +0000180 if (fcntl (nl->sock, F_SETFL, *flags) < 0)
paul5f37d862003-04-19 00:11:28 +0000181 {
paul7021c422003-07-15 12:52:22 +0000182 zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
183 __FUNCTION__, __LINE__, strerror (errno));
paul5f37d862003-04-19 00:11:28 +0000184 return -1;
185 }
186 return 0;
187}
188
paul718e3742002-12-13 20:15:29 +0000189/* Get type specified information from netlink. */
190static int
191netlink_request (int family, int type, struct nlsock *nl)
192{
193 int ret;
194 struct sockaddr_nl snl;
195
196 struct
197 {
198 struct nlmsghdr nlh;
199 struct rtgenmsg g;
200 } req;
201
202
203 /* Check netlink socket. */
204 if (nl->sock < 0)
205 {
206 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
207 return -1;
208 }
209
210 memset (&snl, 0, sizeof snl);
211 snl.nl_family = AF_NETLINK;
212
213 req.nlh.nlmsg_len = sizeof req;
214 req.nlh.nlmsg_type = type;
215 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
216 req.nlh.nlmsg_pid = 0;
217 req.nlh.nlmsg_seq = ++nl->seq;
218 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000219
220 /* linux appears to check capabilities on every message
221 * have to raise caps for every message sent
222 */
paul7021c422003-07-15 12:52:22 +0000223 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000224 {
225 zlog (NULL, LOG_ERR, "Can't raise privileges");
226 return -1;
227 }
paul7021c422003-07-15 12:52:22 +0000228
229 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
230 (struct sockaddr *) &snl, sizeof snl);
231
232 if (zserv_privs.change (ZPRIVS_LOWER))
233 zlog (NULL, LOG_ERR, "Can't lower privileges");
234
paul718e3742002-12-13 20:15:29 +0000235 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000236 {
237 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
238 strerror (errno));
paul718e3742002-12-13 20:15:29 +0000239 return -1;
240 }
pauledd7c242003-06-04 13:59:38 +0000241
paul718e3742002-12-13 20:15:29 +0000242 return 0;
243}
244
245/* Receive message from netlink interface and pass those information
246 to the given function. */
247static int
248netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000249 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000250{
251 int status;
252 int ret = 0;
253 int error;
254
255 while (1)
256 {
257 char buf[4096];
258 struct iovec iov = { buf, sizeof buf };
259 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000260 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000261 struct nlmsghdr *h;
262
paul7021c422003-07-15 12:52:22 +0000263 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000264 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000265
paul718e3742002-12-13 20:15:29 +0000266 status = recvmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +0000267
268 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000269 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000270
271 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000272 {
273 if (errno == EINTR)
274 continue;
275 if (errno == EWOULDBLOCK || errno == EAGAIN)
276 break;
277 zlog (NULL, LOG_ERR, "%s recvmsg overrun", nl->name);
278 continue;
279 }
paul718e3742002-12-13 20:15:29 +0000280
281 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000282 {
283 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
284 return -1;
285 }
paul718e3742002-12-13 20:15:29 +0000286
287 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000288 {
289 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
290 nl->name, msg.msg_namelen);
291 return -1;
292 }
paulb84d3a12003-11-17 10:31:01 +0000293
294 /* JF: Ignore messages that aren't from the kernel */
295 if ( snl.nl_pid != 0 )
296 {
297 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
298 continue;
299 }
paul718e3742002-12-13 20:15:29 +0000300
paul7021c422003-07-15 12:52:22 +0000301 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
302 h = NLMSG_NEXT (h, status))
303 {
304 /* Finish of reading. */
305 if (h->nlmsg_type == NLMSG_DONE)
306 return ret;
paul718e3742002-12-13 20:15:29 +0000307
paul7021c422003-07-15 12:52:22 +0000308 /* Error handling. */
309 if (h->nlmsg_type == NLMSG_ERROR)
310 {
311 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
312
paul718e3742002-12-13 20:15:29 +0000313 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000314 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000315 {
paul7021c422003-07-15 12:52:22 +0000316 if (IS_ZEBRA_DEBUG_KERNEL)
317 {
318 zlog_info ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
319 __FUNCTION__, nl->name,
320 lookup (nlmsg_str, err->msg.nlmsg_type),
321 err->msg.nlmsg_type, err->msg.nlmsg_seq,
322 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000323 }
paul7021c422003-07-15 12:52:22 +0000324
325 /* return if not a multipart message, otherwise continue */
326 if (!(h->nlmsg_flags & NLM_F_MULTI))
327 {
328 return 0;
paul718e3742002-12-13 20:15:29 +0000329 }
paul7021c422003-07-15 12:52:22 +0000330 continue;
paul718e3742002-12-13 20:15:29 +0000331 }
paul7021c422003-07-15 12:52:22 +0000332
paul718e3742002-12-13 20:15:29 +0000333 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000334 {
335 zlog (NULL, LOG_ERR, "%s error: message truncated",
336 nl->name);
337 return -1;
338 }
pauld753e9e2003-01-22 19:45:50 +0000339
paul7021c422003-07-15 12:52:22 +0000340 /* Deal with Error Noise - MAG */
341 {
342 int loglvl = LOG_ERR;
343 int errnum = err->error;
344 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000345
paul7021c422003-07-15 12:52:22 +0000346 if (nl == &netlink_cmd
347 && (-errnum == ENODEV || -errnum == ESRCH)
348 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
349 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000350
paul7021c422003-07-15 12:52:22 +0000351 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
352 "seq=%u, pid=%d",
353 nl->name, strerror (-errnum),
354 lookup (nlmsg_str, msg_type),
355 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
356 }
357 /*
358 ret = -1;
359 continue;
360 */
361 return -1;
362 }
paul718e3742002-12-13 20:15:29 +0000363
paul7021c422003-07-15 12:52:22 +0000364 /* OK we got netlink message. */
365 if (IS_ZEBRA_DEBUG_KERNEL)
366 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
367 nl->name,
368 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
369 h->nlmsg_seq, h->nlmsg_pid);
370
371 /* skip unsolicited messages originating from command socket */
372 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
373 {
374 if (IS_ZEBRA_DEBUG_KERNEL)
375 zlog_info ("netlink_parse_info: %s packet comes from %s",
376 nl->name, netlink_cmd.name);
377 continue;
378 }
379
380 error = (*filter) (&snl, h);
381 if (error < 0)
382 {
383 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
384 ret = error;
385 }
386 }
paul718e3742002-12-13 20:15:29 +0000387
388 /* After error care. */
389 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000390 {
391 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
392 continue;
393 }
paul718e3742002-12-13 20:15:29 +0000394 if (status)
paul7021c422003-07-15 12:52:22 +0000395 {
396 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
397 status);
398 return -1;
399 }
paul718e3742002-12-13 20:15:29 +0000400 }
401 return ret;
402}
403
404/* Utility function for parse rtattr. */
405static void
paul7021c422003-07-15 12:52:22 +0000406netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
407 int len)
paul718e3742002-12-13 20:15:29 +0000408{
paul7021c422003-07-15 12:52:22 +0000409 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000410 {
411 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000412 tb[rta->rta_type] = rta;
413 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000414 }
415}
416
417/* Called from interface_lookup_netlink(). This function is only used
418 during bootstrap. */
419int
420netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
421{
422 int len;
423 struct ifinfomsg *ifi;
424 struct rtattr *tb[IFLA_MAX + 1];
425 struct interface *ifp;
426 char *name;
427 int i;
428
429 ifi = NLMSG_DATA (h);
430
431 if (h->nlmsg_type != RTM_NEWLINK)
432 return 0;
433
434 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
435 if (len < 0)
436 return -1;
437
438 /* Looking up interface name. */
439 memset (tb, 0, sizeof tb);
440 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
441 if (tb[IFLA_IFNAME] == NULL)
442 return -1;
paul7021c422003-07-15 12:52:22 +0000443 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000444
445 /* Add interface. */
446 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000447
paul718e3742002-12-13 20:15:29 +0000448 ifp->ifindex = ifi->ifi_index;
449 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000450 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000451 ifp->metric = 1;
452
453 /* Hardware type and address. */
454 ifp->hw_type = ifi->ifi_type;
455
456 if (tb[IFLA_ADDRESS])
457 {
458 int hw_addr_len;
459
paul7021c422003-07-15 12:52:22 +0000460 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000461
462 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000463 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000464 else
paul7021c422003-07-15 12:52:22 +0000465 {
466 ifp->hw_addr_len = hw_addr_len;
467 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000468
paul7021c422003-07-15 12:52:22 +0000469 for (i = 0; i < hw_addr_len; i++)
470 if (ifp->hw_addr[i] != 0)
471 break;
paul718e3742002-12-13 20:15:29 +0000472
paul7021c422003-07-15 12:52:22 +0000473 if (i == hw_addr_len)
474 ifp->hw_addr_len = 0;
475 else
476 ifp->hw_addr_len = hw_addr_len;
477 }
paul718e3742002-12-13 20:15:29 +0000478 }
479
480 if_add_update (ifp);
481
482 return 0;
483}
484
485/* Lookup interface IPv4/IPv6 address. */
486int
487netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
488{
489 int len;
490 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000491 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000492 struct interface *ifp;
493 void *addr = NULL;
494 void *broad = NULL;
495 u_char flags = 0;
496 char *label = NULL;
497
498 ifa = NLMSG_DATA (h);
499
paul7021c422003-07-15 12:52:22 +0000500 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000501#ifdef HAVE_IPV6
502 && ifa->ifa_family != AF_INET6
503#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000504 )
paul718e3742002-12-13 20:15:29 +0000505 return 0;
506
507 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
508 return 0;
509
paul7021c422003-07-15 12:52:22 +0000510 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000511 if (len < 0)
512 return -1;
513
514 memset (tb, 0, sizeof tb);
515 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
516
517 ifp = if_lookup_by_index (ifa->ifa_index);
518 if (ifp == NULL)
519 {
520 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000521 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000522 return -1;
523 }
524
paul7021c422003-07-15 12:52:22 +0000525 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000526 {
paul00df0c12002-12-13 21:07:36 +0000527 char buf[BUFSIZ];
528 zlog_info ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000529 lookup (nlmsg_str, h->nlmsg_type),
530 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000531 if (tb[IFA_LOCAL])
paul7021c422003-07-15 12:52:22 +0000532 zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
533 RTA_DATA (tb[IFA_LOCAL]),
534 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000535 if (tb[IFA_ADDRESS])
paul7021c422003-07-15 12:52:22 +0000536 zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
537 RTA_DATA (tb
538 [IFA_ADDRESS]),
539 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000540 if (tb[IFA_BROADCAST])
paul7021c422003-07-15 12:52:22 +0000541 zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
542 RTA_DATA (tb
543 [IFA_BROADCAST]),
544 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000545 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
hasso5707cce2004-03-04 19:20:44 +0000546 zlog_info (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000547 }
paul31a476c2003-09-29 19:54:53 +0000548
549 if (tb[IFA_ADDRESS] == NULL)
550 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
551
552 if (ifp->flags & IFF_POINTOPOINT)
paul7021c422003-07-15 12:52:22 +0000553 {
paul31a476c2003-09-29 19:54:53 +0000554 if (tb[IFA_LOCAL])
555 {
556 addr = RTA_DATA (tb[IFA_LOCAL]);
557 if (tb[IFA_ADDRESS])
558 broad = RTA_DATA (tb[IFA_ADDRESS]);
559 else
560 broad = NULL;
561 }
562 else
563 {
564 if (tb[IFA_ADDRESS])
565 addr = RTA_DATA (tb[IFA_ADDRESS]);
566 else
567 addr = NULL;
568 }
paul7021c422003-07-15 12:52:22 +0000569 }
paul31a476c2003-09-29 19:54:53 +0000570 else
paul7021c422003-07-15 12:52:22 +0000571 {
paul31a476c2003-09-29 19:54:53 +0000572 if (tb[IFA_ADDRESS])
573 addr = RTA_DATA (tb[IFA_ADDRESS]);
574 else
575 addr = NULL;
576
577 if (tb[IFA_BROADCAST])
578 broad = RTA_DATA(tb[IFA_BROADCAST]);
579 else
580 broad = NULL;
paul7021c422003-07-15 12:52:22 +0000581 }
paul00df0c12002-12-13 21:07:36 +0000582
paul718e3742002-12-13 20:15:29 +0000583 /* Flags. */
584 if (ifa->ifa_flags & IFA_F_SECONDARY)
585 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
586
587 /* Label */
588 if (tb[IFA_LABEL])
589 label = (char *) RTA_DATA (tb[IFA_LABEL]);
590
591 if (ifp && label && strcmp (ifp->name, label) == 0)
592 label = NULL;
593
594 /* Register interface address to the interface. */
595 if (ifa->ifa_family == AF_INET)
596 {
paul7021c422003-07-15 12:52:22 +0000597 if (h->nlmsg_type == RTM_NEWADDR)
598 connected_add_ipv4 (ifp, flags,
599 (struct in_addr *) addr, ifa->ifa_prefixlen,
600 (struct in_addr *) broad, label);
601 else
602 connected_delete_ipv4 (ifp, flags,
603 (struct in_addr *) addr, ifa->ifa_prefixlen,
604 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000605 }
606#ifdef HAVE_IPV6
607 if (ifa->ifa_family == AF_INET6)
608 {
609 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000610 connected_add_ipv6 (ifp,
611 (struct in6_addr *) addr, ifa->ifa_prefixlen,
612 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000613 else
paul7021c422003-07-15 12:52:22 +0000614 connected_delete_ipv6 (ifp,
615 (struct in6_addr *) addr, ifa->ifa_prefixlen,
616 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000617 }
paul7021c422003-07-15 12:52:22 +0000618#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000619
620 return 0;
621}
622
623/* Looking up routing table by netlink interface. */
624int
625netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
626{
627 int len;
628 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000629 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000630 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000631
632 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000633
634 int index;
635 int table;
hasso34195bf2004-04-06 12:07:06 +0000636 int metric;
637
paul718e3742002-12-13 20:15:29 +0000638 void *dest;
639 void *gate;
640
641 rtm = NLMSG_DATA (h);
642
643 if (h->nlmsg_type != RTM_NEWROUTE)
644 return 0;
645 if (rtm->rtm_type != RTN_UNICAST)
646 return 0;
647
648 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000649#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000650 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000651 return 0;
652#endif
653
paul7021c422003-07-15 12:52:22 +0000654 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000655 if (len < 0)
656 return -1;
657
658 memset (tb, 0, sizeof tb);
659 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
660
661 if (rtm->rtm_flags & RTM_F_CLONED)
662 return 0;
663 if (rtm->rtm_protocol == RTPROT_REDIRECT)
664 return 0;
665 if (rtm->rtm_protocol == RTPROT_KERNEL)
666 return 0;
667
668 if (rtm->rtm_src_len != 0)
669 return 0;
670
671 /* Route which inserted by Zebra. */
672 if (rtm->rtm_protocol == RTPROT_ZEBRA)
673 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000674
paul718e3742002-12-13 20:15:29 +0000675 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000676 metric = 0;
paul718e3742002-12-13 20:15:29 +0000677 dest = NULL;
678 gate = NULL;
679
680 if (tb[RTA_OIF])
681 index = *(int *) RTA_DATA (tb[RTA_OIF]);
682
683 if (tb[RTA_DST])
684 dest = RTA_DATA (tb[RTA_DST]);
685 else
686 dest = anyaddr;
687
688 /* Multipath treatment is needed. */
689 if (tb[RTA_GATEWAY])
690 gate = RTA_DATA (tb[RTA_GATEWAY]);
691
hasso34195bf2004-04-06 12:07:06 +0000692 if (tb[RTA_PRIORITY])
693 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
694
paul718e3742002-12-13 20:15:29 +0000695 if (rtm->rtm_family == AF_INET)
696 {
697 struct prefix_ipv4 p;
698 p.family = AF_INET;
699 memcpy (&p.prefix, dest, 4);
700 p.prefixlen = rtm->rtm_dst_len;
701
hasso34195bf2004-04-06 12:07:06 +0000702 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000703 }
704#ifdef HAVE_IPV6
705 if (rtm->rtm_family == AF_INET6)
706 {
707 struct prefix_ipv6 p;
708 p.family = AF_INET6;
709 memcpy (&p.prefix, dest, 16);
710 p.prefixlen = rtm->rtm_dst_len;
711
712 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
713 }
714#endif /* HAVE_IPV6 */
715
716 return 0;
717}
718
paul7021c422003-07-15 12:52:22 +0000719struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000720 {RTPROT_REDIRECT, "redirect"},
721 {RTPROT_KERNEL, "kernel"},
722 {RTPROT_BOOT, "boot"},
723 {RTPROT_STATIC, "static"},
724 {RTPROT_GATED, "GateD"},
725 {RTPROT_RA, "router advertisement"},
726 {RTPROT_MRT, "MRT"},
727 {RTPROT_ZEBRA, "Zebra"},
728#ifdef RTPROT_BIRD
729 {RTPROT_BIRD, "BIRD"},
730#endif /* RTPROT_BIRD */
731 {0, NULL}
732};
733
734/* Routing information change from the kernel. */
735int
736netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
737{
738 int len;
739 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000740 struct rtattr *tb[RTA_MAX + 1];
741
742 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000743
744 int index;
745 int table;
746 void *dest;
747 void *gate;
748
749 rtm = NLMSG_DATA (h);
750
paul7021c422003-07-15 12:52:22 +0000751 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000752 {
753 /* If this is not route add/delete message print warning. */
754 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
755 return 0;
756 }
757
758 /* Connected route. */
759 if (IS_ZEBRA_DEBUG_KERNEL)
760 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000761 h->nlmsg_type ==
762 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
763 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
764 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
765 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000766
767 if (rtm->rtm_type != RTN_UNICAST)
768 {
769 return 0;
770 }
771
772 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000773 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000774 {
775 return 0;
776 }
777
paul7021c422003-07-15 12:52:22 +0000778 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000779 if (len < 0)
780 return -1;
781
782 memset (tb, 0, sizeof tb);
783 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
784
785 if (rtm->rtm_flags & RTM_F_CLONED)
786 return 0;
787 if (rtm->rtm_protocol == RTPROT_REDIRECT)
788 return 0;
789 if (rtm->rtm_protocol == RTPROT_KERNEL)
790 return 0;
791
792 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
793 return 0;
794
795 if (rtm->rtm_src_len != 0)
796 {
797 zlog_warn ("netlink_route_change(): no src len");
798 return 0;
799 }
paul7021c422003-07-15 12:52:22 +0000800
paul718e3742002-12-13 20:15:29 +0000801 index = 0;
802 dest = NULL;
803 gate = NULL;
804
805 if (tb[RTA_OIF])
806 index = *(int *) RTA_DATA (tb[RTA_OIF]);
807
808 if (tb[RTA_DST])
809 dest = RTA_DATA (tb[RTA_DST]);
810 else
811 dest = anyaddr;
812
813 if (tb[RTA_GATEWAY])
814 gate = RTA_DATA (tb[RTA_GATEWAY]);
815
816 if (rtm->rtm_family == AF_INET)
817 {
818 struct prefix_ipv4 p;
819 p.family = AF_INET;
820 memcpy (&p.prefix, dest, 4);
821 p.prefixlen = rtm->rtm_dst_len;
822
823 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000824 {
825 if (h->nlmsg_type == RTM_NEWROUTE)
826 zlog_info ("RTM_NEWROUTE %s/%d",
827 inet_ntoa (p.prefix), p.prefixlen);
828 else
829 zlog_info ("RTM_DELROUTE %s/%d",
830 inet_ntoa (p.prefix), p.prefixlen);
831 }
paul718e3742002-12-13 20:15:29 +0000832
833 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000834 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000835 else
paul7021c422003-07-15 12:52:22 +0000836 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000837 }
838
839#ifdef HAVE_IPV6
840 if (rtm->rtm_family == AF_INET6)
841 {
842 struct prefix_ipv6 p;
843 char buf[BUFSIZ];
844
845 p.family = AF_INET6;
846 memcpy (&p.prefix, dest, 16);
847 p.prefixlen = rtm->rtm_dst_len;
848
849 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000850 {
851 if (h->nlmsg_type == RTM_NEWROUTE)
852 zlog_info ("RTM_NEWROUTE %s/%d",
853 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
854 p.prefixlen);
855 else
856 zlog_info ("RTM_DELROUTE %s/%d",
857 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
858 p.prefixlen);
859 }
paul718e3742002-12-13 20:15:29 +0000860
861 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000862 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000863 else
paul7021c422003-07-15 12:52:22 +0000864 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000865 }
866#endif /* HAVE_IPV6 */
867
868 return 0;
869}
870
871int
872netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
873{
874 int len;
875 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000876 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000877 struct interface *ifp;
878 char *name;
879
880 ifi = NLMSG_DATA (h);
881
paul7021c422003-07-15 12:52:22 +0000882 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000883 {
884 /* If this is not link add/delete message so print warning. */
885 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000886 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000887 return 0;
888 }
889
890 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
891 if (len < 0)
892 return -1;
893
894 /* Looking up interface name. */
895 memset (tb, 0, sizeof tb);
896 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
897 if (tb[IFLA_IFNAME] == NULL)
898 return -1;
paul7021c422003-07-15 12:52:22 +0000899 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000900
901 /* Add interface. */
902 if (h->nlmsg_type == RTM_NEWLINK)
903 {
904 ifp = if_lookup_by_name (name);
905
paul7021c422003-07-15 12:52:22 +0000906 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
907 {
908 if (ifp == NULL)
909 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000910
paul7021c422003-07-15 12:52:22 +0000911 ifp->ifindex = ifi->ifi_index;
912 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000913 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000914 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000915
paul7021c422003-07-15 12:52:22 +0000916 /* If new link is added. */
917 if_add_update (ifp);
918 }
paul718e3742002-12-13 20:15:29 +0000919 else
paul7021c422003-07-15 12:52:22 +0000920 {
921 /* Interface status change. */
922 ifp->ifindex = ifi->ifi_index;
paul44145db2004-05-09 11:00:23 +0000923 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000924 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000925
paul7021c422003-07-15 12:52:22 +0000926 if (if_is_operative (ifp))
927 {
928 ifp->flags = ifi->ifi_flags & 0x0000fffff;
929 if (!if_is_operative (ifp))
930 if_down (ifp);
931 }
932 else
933 {
934 ifp->flags = ifi->ifi_flags & 0x0000fffff;
935 if (if_is_operative (ifp))
936 if_up (ifp);
937 }
938 }
paul718e3742002-12-13 20:15:29 +0000939 }
940 else
941 {
942 /* RTM_DELLINK. */
943 ifp = if_lookup_by_name (name);
944
945 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000946 {
947 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000948 name);
paul7021c422003-07-15 12:52:22 +0000949 return 0;
950 }
951
paul718e3742002-12-13 20:15:29 +0000952 if_delete_update (ifp);
953 }
954
955 return 0;
956}
957
958int
959netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
960{
961 switch (h->nlmsg_type)
962 {
963 case RTM_NEWROUTE:
964 return netlink_route_change (snl, h);
965 break;
966 case RTM_DELROUTE:
967 return netlink_route_change (snl, h);
968 break;
969 case RTM_NEWLINK:
970 return netlink_link_change (snl, h);
971 break;
972 case RTM_DELLINK:
973 return netlink_link_change (snl, h);
974 break;
975 case RTM_NEWADDR:
976 return netlink_interface_addr (snl, h);
977 break;
978 case RTM_DELADDR:
979 return netlink_interface_addr (snl, h);
980 break;
981 default:
982 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
983 break;
984 }
985 return 0;
986}
987
988/* Interface lookup by netlink socket. */
989int
990interface_lookup_netlink ()
991{
992 int ret;
paul5f37d862003-04-19 00:11:28 +0000993 int flags;
994 int snb_ret;
paul7021c422003-07-15 12:52:22 +0000995
paul5f37d862003-04-19 00:11:28 +0000996 /*
997 * Change netlink socket flags to blocking to ensure we get
998 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +0000999 */
1000 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1001 if (snb_ret < 0)
1002 zlog (NULL, LOG_WARNING,
1003 "%s:%i Warning: Could not set netlink socket to blocking.",
1004 __FUNCTION__, __LINE__);
1005
paul718e3742002-12-13 20:15:29 +00001006 /* Get interface information. */
1007 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1008 if (ret < 0)
1009 return ret;
1010 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1011 if (ret < 0)
1012 return ret;
1013
1014 /* Get IPv4 address of the interfaces. */
1015 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1016 if (ret < 0)
1017 return ret;
1018 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1019 if (ret < 0)
1020 return ret;
1021
1022#ifdef HAVE_IPV6
1023 /* Get IPv6 address of the interfaces. */
1024 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1025 if (ret < 0)
1026 return ret;
1027 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1028 if (ret < 0)
1029 return ret;
1030#endif /* HAVE_IPV6 */
1031
paul7021c422003-07-15 12:52:22 +00001032 /* restore socket flags */
1033 if (snb_ret == 0)
1034 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001035 return 0;
1036}
1037
1038/* Routing table read function using netlink interface. Only called
1039 bootstrap time. */
1040int
1041netlink_route_read ()
1042{
1043 int ret;
paul5f37d862003-04-19 00:11:28 +00001044 int flags;
1045 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001046
paul5f37d862003-04-19 00:11:28 +00001047 /*
1048 * Change netlink socket flags to blocking to ensure we get
1049 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001050 */
1051 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1052 if (snb_ret < 0)
1053 zlog (NULL, LOG_WARNING,
1054 "%s:%i Warning: Could not set netlink socket to blocking.",
1055 __FUNCTION__, __LINE__);
1056
paul718e3742002-12-13 20:15:29 +00001057 /* Get IPv4 routing table. */
1058 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1059 if (ret < 0)
1060 return ret;
1061 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1062 if (ret < 0)
1063 return ret;
1064
1065#ifdef HAVE_IPV6
1066 /* Get IPv6 routing table. */
1067 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1068 if (ret < 0)
1069 return ret;
1070 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1071 if (ret < 0)
1072 return ret;
1073#endif /* HAVE_IPV6 */
1074
paul5f37d862003-04-19 00:11:28 +00001075 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001076 if (snb_ret == 0)
1077 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001078 return 0;
1079}
1080
1081/* Utility function comes from iproute2.
1082 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1083int
1084addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1085{
1086 int len;
1087 struct rtattr *rta;
1088
paul7021c422003-07-15 12:52:22 +00001089 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001090
paul7021c422003-07-15 12:52:22 +00001091 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001092 return -1;
1093
paul7021c422003-07-15 12:52:22 +00001094 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001095 rta->rta_type = type;
1096 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001097 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001098 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1099
1100 return 0;
1101}
1102
1103int
1104rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1105{
1106 int len;
1107 struct rtattr *subrta;
1108
paul7021c422003-07-15 12:52:22 +00001109 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001110
paul7021c422003-07-15 12:52:22 +00001111 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001112 return -1;
1113
paul7021c422003-07-15 12:52:22 +00001114 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001115 subrta->rta_type = type;
1116 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001117 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001118 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1119
1120 return 0;
1121}
1122
1123/* Utility function comes from iproute2.
1124 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1125int
1126addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1127{
1128 int len;
1129 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001130
1131 len = RTA_LENGTH (4);
1132
paul718e3742002-12-13 20:15:29 +00001133 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1134 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, 4);
paul718e3742002-12-13 20:15:29 +00001140 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1141
1142 return 0;
1143}
1144
1145static int
1146netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1147{
1148 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1149 return 0;
1150}
1151
1152/* sendmsg() to netlink socket then recvmsg(). */
1153int
1154netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1155{
1156 int status;
1157 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001158 struct iovec iov = { (void *) n, n->nlmsg_len };
1159 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001160 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001161 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001162
paul718e3742002-12-13 20:15:29 +00001163 memset (&snl, 0, sizeof snl);
1164 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001165
paul718e3742002-12-13 20:15:29 +00001166 n->nlmsg_seq = ++netlink_cmd.seq;
1167
1168 /* Request an acknowledgement by setting NLM_F_ACK */
1169 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001170
1171 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001172 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001173 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1174 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001175
1176 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001177 if (zserv_privs.change (ZPRIVS_RAISE))
1178 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001179 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001180 if (zserv_privs.change (ZPRIVS_LOWER))
1181 zlog (NULL, LOG_ERR, "Can't lower privileges");
1182
paul718e3742002-12-13 20:15:29 +00001183 if (status < 0)
1184 {
1185 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001186 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001187 return -1;
1188 }
paul7021c422003-07-15 12:52:22 +00001189
paul718e3742002-12-13 20:15:29 +00001190 /*
1191 * Change socket flags for blocking I/O.
1192 * This ensures we wait for a reply in netlink_parse_info().
1193 */
paul7021c422003-07-15 12:52:22 +00001194 snb_ret = set_netlink_blocking (nl, &flags);
1195 if (snb_ret < 0)
1196 zlog (NULL, LOG_WARNING,
1197 "%s:%i Warning: Could not set netlink socket to blocking.",
1198 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001199
1200 /*
1201 * Get reply from netlink socket.
1202 * The reply should either be an acknowlegement or an error.
1203 */
1204 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001205
paul718e3742002-12-13 20:15:29 +00001206 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001207 if (snb_ret == 0)
1208 set_netlink_nonblocking (nl, &flags);
1209
paul718e3742002-12-13 20:15:29 +00001210 return status;
1211}
1212
1213/* Routing table change via netlink interface. */
1214int
1215netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001216 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001217{
1218 int ret;
1219 int bytelen;
1220 struct sockaddr_nl snl;
1221 int discard;
1222
paul7021c422003-07-15 12:52:22 +00001223 struct
paul718e3742002-12-13 20:15:29 +00001224 {
1225 struct nlmsghdr n;
1226 struct rtmsg r;
1227 char buf[1024];
1228 } req;
1229
1230 memset (&req, 0, sizeof req);
1231
1232 bytelen = (family == AF_INET ? 4 : 16);
1233
1234 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1235 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1236 req.n.nlmsg_type = cmd;
1237 req.r.rtm_family = family;
1238 req.r.rtm_table = table;
1239 req.r.rtm_dst_len = length;
1240
hasso81dfcaa2003-05-25 19:21:25 +00001241 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1242 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001243 discard = 1;
1244 else
1245 discard = 0;
1246
paul7021c422003-07-15 12:52:22 +00001247 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001248 {
1249 req.r.rtm_protocol = RTPROT_ZEBRA;
1250 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1251
paul7021c422003-07-15 12:52:22 +00001252 if (discard)
paul595db7f2003-05-25 21:35:06 +00001253 {
1254 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1255 req.r.rtm_type = RTN_BLACKHOLE;
1256 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1257 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001258 else
1259 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1260 }
paul595db7f2003-05-25 21:35:06 +00001261 else
paul7021c422003-07-15 12:52:22 +00001262 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001263 }
1264
1265 if (dest)
1266 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1267
paul7021c422003-07-15 12:52:22 +00001268 if (!discard)
paul718e3742002-12-13 20:15:29 +00001269 {
1270 if (gate)
paul7021c422003-07-15 12:52:22 +00001271 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001272 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001273 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001274 }
1275
1276 /* Destination netlink address. */
1277 memset (&snl, 0, sizeof snl);
1278 snl.nl_family = AF_NETLINK;
1279
1280 /* Talk to netlink socket. */
1281 ret = netlink_talk (&req.n, &netlink);
1282 if (ret < 0)
1283 return -1;
1284
1285 return 0;
1286}
1287
1288/* Routing table change via netlink interface. */
1289int
1290netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001291 int family)
paul718e3742002-12-13 20:15:29 +00001292{
1293 int bytelen;
1294 struct sockaddr_nl snl;
1295 struct nexthop *nexthop = NULL;
1296 int nexthop_num = 0;
1297 struct nlsock *nl;
1298 int discard;
1299
paul7021c422003-07-15 12:52:22 +00001300 struct
paul718e3742002-12-13 20:15:29 +00001301 {
1302 struct nlmsghdr n;
1303 struct rtmsg r;
1304 char buf[1024];
1305 } req;
1306
1307 memset (&req, 0, sizeof req);
1308
1309 bytelen = (family == AF_INET ? 4 : 16);
1310
1311 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1312 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1313 req.n.nlmsg_type = cmd;
1314 req.r.rtm_family = family;
1315 req.r.rtm_table = rib->table;
1316 req.r.rtm_dst_len = p->prefixlen;
1317
paul13766da2003-02-07 14:46:23 +00001318#ifdef RTM_F_EQUALIZE
1319 req.r.rtm_flags |= RTM_F_EQUALIZE;
1320#endif /* RTM_F_EQUALIZE */
1321
paul7021c422003-07-15 12:52:22 +00001322 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001323 discard = 1;
1324 else
1325 discard = 0;
1326
paul7021c422003-07-15 12:52:22 +00001327 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001328 {
1329 req.r.rtm_protocol = RTPROT_ZEBRA;
1330 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1331
paul7021c422003-07-15 12:52:22 +00001332 if (discard)
paul595db7f2003-05-25 21:35:06 +00001333 {
1334 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1335 req.r.rtm_type = RTN_BLACKHOLE;
1336 else if (rib->flags & ZEBRA_FLAG_REJECT)
1337 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001338 else
1339 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1340 }
paul595db7f2003-05-25 21:35:06 +00001341 else
paul7021c422003-07-15 12:52:22 +00001342 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001343 }
1344
1345 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1346
1347 /* Metric. */
1348 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1349
1350 if (discard)
1351 {
1352 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001353 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1354 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001355 goto skip;
1356 }
1357
1358 /* Multipath case. */
1359 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1360 {
1361 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001362 {
paul5ec90d22003-06-19 01:41:37 +00001363
paul7021c422003-07-15 12:52:22 +00001364 if ((cmd == RTM_NEWROUTE
1365 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1366 || (cmd == RTM_DELROUTE
1367 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1368 {
paul5ec90d22003-06-19 01:41:37 +00001369
paul7021c422003-07-15 12:52:22 +00001370 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1371 {
1372 if (IS_ZEBRA_DEBUG_KERNEL)
1373 {
1374 zlog_info
1375 ("netlink_route_multipath() (recursive, 1 hop): "
1376 "%s %s/%d via %s if %u, type %s",
1377 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1378 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1379 nexthop->rifindex,
1380 nexthop_types_desc[nexthop->rtype]);
1381 }
paul5ec90d22003-06-19 01:41:37 +00001382
paul7021c422003-07-15 12:52:22 +00001383 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1384 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1385 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1386 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001387#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001388 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1389 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1390 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1391 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1392 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001393#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001394 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1395 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1396 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1397 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1398 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1399 addattr32 (&req.n, sizeof req, RTA_OIF,
1400 nexthop->rifindex);
1401 }
1402 else
1403 {
1404 if (IS_ZEBRA_DEBUG_KERNEL)
1405 {
1406 zlog_info
1407 ("netlink_route_multipath(): (single hop)"
1408 "%s %s/%d via %s if %u, type %s",
1409 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1410 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1411 nexthop->ifindex,
1412 nexthop_types_desc[nexthop->type]);
1413 }
paul5ec90d22003-06-19 01:41:37 +00001414
paul7021c422003-07-15 12:52:22 +00001415 if (nexthop->type == NEXTHOP_TYPE_IPV4
1416 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1417 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1418 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001419#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001420 if (nexthop->type == NEXTHOP_TYPE_IPV6
1421 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1422 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1423 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1424 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001425#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001426 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1427 || nexthop->type == NEXTHOP_TYPE_IFNAME
1428 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1429 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1430 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1431 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1432 }
paul718e3742002-12-13 20:15:29 +00001433
paul7021c422003-07-15 12:52:22 +00001434 if (cmd == RTM_NEWROUTE)
1435 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001436
paul7021c422003-07-15 12:52:22 +00001437 nexthop_num++;
1438 break;
1439 }
1440 }
paul718e3742002-12-13 20:15:29 +00001441 }
1442 else
1443 {
1444 char buf[1024];
1445 struct rtattr *rta = (void *) buf;
1446 struct rtnexthop *rtnh;
1447
1448 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001449 rta->rta_len = RTA_LENGTH (0);
1450 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001451
1452 nexthop_num = 0;
1453 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001454 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1455 nexthop = nexthop->next)
1456 {
1457 if ((cmd == RTM_NEWROUTE
1458 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1459 || (cmd == RTM_DELROUTE
1460 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1461 {
1462 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001463
paul7021c422003-07-15 12:52:22 +00001464 rtnh->rtnh_len = sizeof (*rtnh);
1465 rtnh->rtnh_flags = 0;
1466 rtnh->rtnh_hops = 0;
1467 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001468
paul7021c422003-07-15 12:52:22 +00001469 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1470 {
1471 if (IS_ZEBRA_DEBUG_KERNEL)
1472 {
1473 zlog_info ("netlink_route_multipath() "
1474 "(recursive, multihop): "
1475 "%s %s/%d via %s if %u, type %s",
1476 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1477 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1478 nexthop->rifindex,
1479 nexthop_types_desc[nexthop->type]);
1480 }
1481 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1482 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1483 {
1484 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1485 &nexthop->rgate.ipv4, bytelen);
1486 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1487 }
paul718e3742002-12-13 20:15:29 +00001488#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001489 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1490 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1491 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1492 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1493 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001494#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001495 /* ifindex */
1496 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1497 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1498 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1499 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1500 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1501 rtnh->rtnh_ifindex = nexthop->rifindex;
1502 else
1503 rtnh->rtnh_ifindex = 0;
1504 }
1505 else
1506 {
1507 if (IS_ZEBRA_DEBUG_KERNEL)
1508 {
1509 zlog_info ("netlink_route_multipath() "
1510 "(multihop): "
1511 "%s %s/%d via %s if %u, type %s",
1512 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1513 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1514 nexthop->rifindex,
1515 nexthop_types_desc[nexthop->type]);
1516 }
1517 if (nexthop->type == NEXTHOP_TYPE_IPV4
1518 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1519 {
1520 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1521 &nexthop->gate.ipv4, bytelen);
1522 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1523 }
paul718e3742002-12-13 20:15:29 +00001524#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001525 if (nexthop->type == NEXTHOP_TYPE_IPV6
1526 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1527 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1528 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1529 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001530#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001531 /* ifindex */
1532 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1533 || nexthop->type == NEXTHOP_TYPE_IFNAME
1534 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1535 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1536 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1537 rtnh->rtnh_ifindex = nexthop->ifindex;
1538 else
1539 rtnh->rtnh_ifindex = 0;
1540 }
1541 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001542
paul7021c422003-07-15 12:52:22 +00001543 if (cmd == RTM_NEWROUTE)
1544 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1545 }
1546 }
paul718e3742002-12-13 20:15:29 +00001547
1548 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001549 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1550 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001551 }
1552
1553 /* If there is no useful nexthop then return. */
1554 if (nexthop_num == 0)
1555 {
1556 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001557 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001558 return 0;
1559 }
1560
paul7021c422003-07-15 12:52:22 +00001561skip:
paul718e3742002-12-13 20:15:29 +00001562
1563 /* Destination netlink address. */
1564 memset (&snl, 0, sizeof snl);
1565 snl.nl_family = AF_NETLINK;
1566
1567 if (family == AF_INET)
1568 nl = &netlink_cmd;
1569 else
1570 nl = &netlink;
1571
1572 /* Talk to netlink socket. */
1573 return netlink_talk (&req.n, nl);
1574}
1575
1576int
1577kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1578{
1579 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1580}
1581
1582int
1583kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1584{
1585 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1586}
1587
1588#ifdef HAVE_IPV6
1589int
1590kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1591{
1592 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1593}
1594
1595int
1596kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1597{
1598 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1599}
1600
1601/* Delete IPv6 route from the kernel. */
1602int
1603kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001604 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001605{
paul7021c422003-07-15 12:52:22 +00001606 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1607 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001608}
1609#endif /* HAVE_IPV6 */
1610
1611/* Interface address modification. */
1612int
1613netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001614 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001615{
1616 int bytelen;
1617 struct prefix *p;
1618
paul7021c422003-07-15 12:52:22 +00001619 struct
paul718e3742002-12-13 20:15:29 +00001620 {
1621 struct nlmsghdr n;
1622 struct ifaddrmsg ifa;
1623 char buf[1024];
1624 } req;
1625
1626 p = ifc->address;
1627 memset (&req, 0, sizeof req);
1628
1629 bytelen = (family == AF_INET ? 4 : 16);
1630
paul7021c422003-07-15 12:52:22 +00001631 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001632 req.n.nlmsg_flags = NLM_F_REQUEST;
1633 req.n.nlmsg_type = cmd;
1634 req.ifa.ifa_family = family;
1635
1636 req.ifa.ifa_index = ifp->ifindex;
1637 req.ifa.ifa_prefixlen = p->prefixlen;
1638
1639 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1640
1641 if (family == AF_INET && cmd == RTM_NEWADDR)
1642 {
1643 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001644 {
1645 p = ifc->destination;
1646 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1647 bytelen);
1648 }
paul718e3742002-12-13 20:15:29 +00001649 }
1650
1651 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1652 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001653
paul718e3742002-12-13 20:15:29 +00001654 if (ifc->label)
1655 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001656 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001657
1658 return netlink_talk (&req.n, &netlink_cmd);
1659}
1660
1661int
1662kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1663{
1664 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1665}
1666
1667int
1668kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1669{
1670 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1671}
1672
paul718e3742002-12-13 20:15:29 +00001673
1674extern struct thread_master *master;
1675
1676/* Kernel route reflection. */
1677int
1678kernel_read (struct thread *thread)
1679{
1680 int ret;
1681 int sock;
1682
1683 sock = THREAD_FD (thread);
1684 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001685 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001686
1687 return 0;
1688}
1689
1690/* Exported interface function. This function simply calls
1691 netlink_socket (). */
1692void
1693kernel_init ()
1694{
1695 unsigned long groups;
1696
paul7021c422003-07-15 12:52:22 +00001697 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001698#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001699 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001700#endif /* HAVE_IPV6 */
1701 netlink_socket (&netlink, groups);
1702 netlink_socket (&netlink_cmd, 0);
1703
1704 /* Register kernel socket. */
1705 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001706 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001707}