blob: 9b13bca445dbdf4d1814dc91b1fe1c7eb2246e6a [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;
paul7021c422003-07-15 12:52:22 +0000450 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])))
paul7021c422003-07-15 12:52:22 +0000546 zlog_info (" IFA_LABEL %s", 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;
636 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;
674 dest = NULL;
675 gate = NULL;
676
677 if (tb[RTA_OIF])
678 index = *(int *) RTA_DATA (tb[RTA_OIF]);
679
680 if (tb[RTA_DST])
681 dest = RTA_DATA (tb[RTA_DST]);
682 else
683 dest = anyaddr;
684
685 /* Multipath treatment is needed. */
686 if (tb[RTA_GATEWAY])
687 gate = RTA_DATA (tb[RTA_GATEWAY]);
688
689 if (rtm->rtm_family == AF_INET)
690 {
691 struct prefix_ipv4 p;
692 p.family = AF_INET;
693 memcpy (&p.prefix, dest, 4);
694 p.prefixlen = rtm->rtm_dst_len;
695
696 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
697 }
698#ifdef HAVE_IPV6
699 if (rtm->rtm_family == AF_INET6)
700 {
701 struct prefix_ipv6 p;
702 p.family = AF_INET6;
703 memcpy (&p.prefix, dest, 16);
704 p.prefixlen = rtm->rtm_dst_len;
705
706 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
707 }
708#endif /* HAVE_IPV6 */
709
710 return 0;
711}
712
paul7021c422003-07-15 12:52:22 +0000713struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000714 {RTPROT_REDIRECT, "redirect"},
715 {RTPROT_KERNEL, "kernel"},
716 {RTPROT_BOOT, "boot"},
717 {RTPROT_STATIC, "static"},
718 {RTPROT_GATED, "GateD"},
719 {RTPROT_RA, "router advertisement"},
720 {RTPROT_MRT, "MRT"},
721 {RTPROT_ZEBRA, "Zebra"},
722#ifdef RTPROT_BIRD
723 {RTPROT_BIRD, "BIRD"},
724#endif /* RTPROT_BIRD */
725 {0, NULL}
726};
727
728/* Routing information change from the kernel. */
729int
730netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
731{
732 int len;
733 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000734 struct rtattr *tb[RTA_MAX + 1];
735
736 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000737
738 int index;
739 int table;
740 void *dest;
741 void *gate;
742
743 rtm = NLMSG_DATA (h);
744
paul7021c422003-07-15 12:52:22 +0000745 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000746 {
747 /* If this is not route add/delete message print warning. */
748 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
749 return 0;
750 }
751
752 /* Connected route. */
753 if (IS_ZEBRA_DEBUG_KERNEL)
754 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000755 h->nlmsg_type ==
756 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
757 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
758 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
759 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000760
761 if (rtm->rtm_type != RTN_UNICAST)
762 {
763 return 0;
764 }
765
766 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000767 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000768 {
769 return 0;
770 }
771
paul7021c422003-07-15 12:52:22 +0000772 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000773 if (len < 0)
774 return -1;
775
776 memset (tb, 0, sizeof tb);
777 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
778
779 if (rtm->rtm_flags & RTM_F_CLONED)
780 return 0;
781 if (rtm->rtm_protocol == RTPROT_REDIRECT)
782 return 0;
783 if (rtm->rtm_protocol == RTPROT_KERNEL)
784 return 0;
785
786 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
787 return 0;
788
789 if (rtm->rtm_src_len != 0)
790 {
791 zlog_warn ("netlink_route_change(): no src len");
792 return 0;
793 }
paul7021c422003-07-15 12:52:22 +0000794
paul718e3742002-12-13 20:15:29 +0000795 index = 0;
796 dest = NULL;
797 gate = NULL;
798
799 if (tb[RTA_OIF])
800 index = *(int *) RTA_DATA (tb[RTA_OIF]);
801
802 if (tb[RTA_DST])
803 dest = RTA_DATA (tb[RTA_DST]);
804 else
805 dest = anyaddr;
806
807 if (tb[RTA_GATEWAY])
808 gate = RTA_DATA (tb[RTA_GATEWAY]);
809
810 if (rtm->rtm_family == AF_INET)
811 {
812 struct prefix_ipv4 p;
813 p.family = AF_INET;
814 memcpy (&p.prefix, dest, 4);
815 p.prefixlen = rtm->rtm_dst_len;
816
817 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000818 {
819 if (h->nlmsg_type == RTM_NEWROUTE)
820 zlog_info ("RTM_NEWROUTE %s/%d",
821 inet_ntoa (p.prefix), p.prefixlen);
822 else
823 zlog_info ("RTM_DELROUTE %s/%d",
824 inet_ntoa (p.prefix), p.prefixlen);
825 }
paul718e3742002-12-13 20:15:29 +0000826
827 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000828 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000829 else
paul7021c422003-07-15 12:52:22 +0000830 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000831 }
832
833#ifdef HAVE_IPV6
834 if (rtm->rtm_family == AF_INET6)
835 {
836 struct prefix_ipv6 p;
837 char buf[BUFSIZ];
838
839 p.family = AF_INET6;
840 memcpy (&p.prefix, dest, 16);
841 p.prefixlen = rtm->rtm_dst_len;
842
843 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000844 {
845 if (h->nlmsg_type == RTM_NEWROUTE)
846 zlog_info ("RTM_NEWROUTE %s/%d",
847 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
848 p.prefixlen);
849 else
850 zlog_info ("RTM_DELROUTE %s/%d",
851 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
852 p.prefixlen);
853 }
paul718e3742002-12-13 20:15:29 +0000854
855 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000856 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000857 else
paul7021c422003-07-15 12:52:22 +0000858 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000859 }
860#endif /* HAVE_IPV6 */
861
862 return 0;
863}
864
865int
866netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
867{
868 int len;
869 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000870 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000871 struct interface *ifp;
872 char *name;
873
874 ifi = NLMSG_DATA (h);
875
paul7021c422003-07-15 12:52:22 +0000876 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000877 {
878 /* If this is not link add/delete message so print warning. */
879 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000880 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000881 return 0;
882 }
883
884 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
885 if (len < 0)
886 return -1;
887
888 /* Looking up interface name. */
889 memset (tb, 0, sizeof tb);
890 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
891 if (tb[IFLA_IFNAME] == NULL)
892 return -1;
paul7021c422003-07-15 12:52:22 +0000893 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000894
895 /* Add interface. */
896 if (h->nlmsg_type == RTM_NEWLINK)
897 {
898 ifp = if_lookup_by_name (name);
899
paul7021c422003-07-15 12:52:22 +0000900 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
901 {
902 if (ifp == NULL)
903 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000904
paul7021c422003-07-15 12:52:22 +0000905 ifp->ifindex = ifi->ifi_index;
906 ifp->flags = ifi->ifi_flags & 0x0000fffff;
907 ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
908 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000909
paul7021c422003-07-15 12:52:22 +0000910 /* If new link is added. */
911 if_add_update (ifp);
912 }
paul718e3742002-12-13 20:15:29 +0000913 else
paul7021c422003-07-15 12:52:22 +0000914 {
915 /* Interface status change. */
916 ifp->ifindex = ifi->ifi_index;
917 ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
918 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000919
paul7021c422003-07-15 12:52:22 +0000920 if (if_is_operative (ifp))
921 {
922 ifp->flags = ifi->ifi_flags & 0x0000fffff;
923 if (!if_is_operative (ifp))
924 if_down (ifp);
925 }
926 else
927 {
928 ifp->flags = ifi->ifi_flags & 0x0000fffff;
929 if (if_is_operative (ifp))
930 if_up (ifp);
931 }
932 }
paul718e3742002-12-13 20:15:29 +0000933 }
934 else
935 {
936 /* RTM_DELLINK. */
937 ifp = if_lookup_by_name (name);
938
939 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000940 {
941 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000942 name);
paul7021c422003-07-15 12:52:22 +0000943 return 0;
944 }
945
paul718e3742002-12-13 20:15:29 +0000946 if_delete_update (ifp);
947 }
948
949 return 0;
950}
951
952int
953netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
954{
955 switch (h->nlmsg_type)
956 {
957 case RTM_NEWROUTE:
958 return netlink_route_change (snl, h);
959 break;
960 case RTM_DELROUTE:
961 return netlink_route_change (snl, h);
962 break;
963 case RTM_NEWLINK:
964 return netlink_link_change (snl, h);
965 break;
966 case RTM_DELLINK:
967 return netlink_link_change (snl, h);
968 break;
969 case RTM_NEWADDR:
970 return netlink_interface_addr (snl, h);
971 break;
972 case RTM_DELADDR:
973 return netlink_interface_addr (snl, h);
974 break;
975 default:
976 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
977 break;
978 }
979 return 0;
980}
981
982/* Interface lookup by netlink socket. */
983int
984interface_lookup_netlink ()
985{
986 int ret;
paul5f37d862003-04-19 00:11:28 +0000987 int flags;
988 int snb_ret;
paul7021c422003-07-15 12:52:22 +0000989
paul5f37d862003-04-19 00:11:28 +0000990 /*
991 * Change netlink socket flags to blocking to ensure we get
992 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +0000993 */
994 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
995 if (snb_ret < 0)
996 zlog (NULL, LOG_WARNING,
997 "%s:%i Warning: Could not set netlink socket to blocking.",
998 __FUNCTION__, __LINE__);
999
paul718e3742002-12-13 20:15:29 +00001000 /* Get interface information. */
1001 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1002 if (ret < 0)
1003 return ret;
1004 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1005 if (ret < 0)
1006 return ret;
1007
1008 /* Get IPv4 address of the interfaces. */
1009 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1010 if (ret < 0)
1011 return ret;
1012 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1013 if (ret < 0)
1014 return ret;
1015
1016#ifdef HAVE_IPV6
1017 /* Get IPv6 address of the interfaces. */
1018 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1019 if (ret < 0)
1020 return ret;
1021 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1022 if (ret < 0)
1023 return ret;
1024#endif /* HAVE_IPV6 */
1025
paul7021c422003-07-15 12:52:22 +00001026 /* restore socket flags */
1027 if (snb_ret == 0)
1028 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001029 return 0;
1030}
1031
1032/* Routing table read function using netlink interface. Only called
1033 bootstrap time. */
1034int
1035netlink_route_read ()
1036{
1037 int ret;
paul5f37d862003-04-19 00:11:28 +00001038 int flags;
1039 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001040
paul5f37d862003-04-19 00:11:28 +00001041 /*
1042 * Change netlink socket flags to blocking to ensure we get
1043 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001044 */
1045 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1046 if (snb_ret < 0)
1047 zlog (NULL, LOG_WARNING,
1048 "%s:%i Warning: Could not set netlink socket to blocking.",
1049 __FUNCTION__, __LINE__);
1050
paul718e3742002-12-13 20:15:29 +00001051 /* Get IPv4 routing table. */
1052 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1053 if (ret < 0)
1054 return ret;
1055 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1056 if (ret < 0)
1057 return ret;
1058
1059#ifdef HAVE_IPV6
1060 /* Get IPv6 routing table. */
1061 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1062 if (ret < 0)
1063 return ret;
1064 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1065 if (ret < 0)
1066 return ret;
1067#endif /* HAVE_IPV6 */
1068
paul5f37d862003-04-19 00:11:28 +00001069 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001070 if (snb_ret == 0)
1071 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001072 return 0;
1073}
1074
1075/* Utility function comes from iproute2.
1076 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1077int
1078addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1079{
1080 int len;
1081 struct rtattr *rta;
1082
paul7021c422003-07-15 12:52:22 +00001083 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001084
paul7021c422003-07-15 12:52:22 +00001085 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001086 return -1;
1087
paul7021c422003-07-15 12:52:22 +00001088 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001089 rta->rta_type = type;
1090 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001091 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001092 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1093
1094 return 0;
1095}
1096
1097int
1098rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1099{
1100 int len;
1101 struct rtattr *subrta;
1102
paul7021c422003-07-15 12:52:22 +00001103 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001104
paul7021c422003-07-15 12:52:22 +00001105 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001106 return -1;
1107
paul7021c422003-07-15 12:52:22 +00001108 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001109 subrta->rta_type = type;
1110 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001111 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001112 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1113
1114 return 0;
1115}
1116
1117/* Utility function comes from iproute2.
1118 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1119int
1120addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1121{
1122 int len;
1123 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001124
1125 len = RTA_LENGTH (4);
1126
paul718e3742002-12-13 20:15:29 +00001127 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1128 return -1;
1129
paul7021c422003-07-15 12:52:22 +00001130 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001131 rta->rta_type = type;
1132 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001133 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001134 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1135
1136 return 0;
1137}
1138
1139static int
1140netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1141{
1142 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1143 return 0;
1144}
1145
1146/* sendmsg() to netlink socket then recvmsg(). */
1147int
1148netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1149{
1150 int status;
1151 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001152 struct iovec iov = { (void *) n, n->nlmsg_len };
1153 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001154 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001155 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001156
paul718e3742002-12-13 20:15:29 +00001157 memset (&snl, 0, sizeof snl);
1158 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001159
paul718e3742002-12-13 20:15:29 +00001160 n->nlmsg_seq = ++netlink_cmd.seq;
1161
1162 /* Request an acknowledgement by setting NLM_F_ACK */
1163 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001164
1165 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001166 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001167 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1168 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001169
1170 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001171 if (zserv_privs.change (ZPRIVS_RAISE))
1172 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001173 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001174 if (zserv_privs.change (ZPRIVS_LOWER))
1175 zlog (NULL, LOG_ERR, "Can't lower privileges");
1176
paul718e3742002-12-13 20:15:29 +00001177 if (status < 0)
1178 {
1179 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001180 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001181 return -1;
1182 }
paul7021c422003-07-15 12:52:22 +00001183
paul718e3742002-12-13 20:15:29 +00001184 /*
1185 * Change socket flags for blocking I/O.
1186 * This ensures we wait for a reply in netlink_parse_info().
1187 */
paul7021c422003-07-15 12:52:22 +00001188 snb_ret = set_netlink_blocking (nl, &flags);
1189 if (snb_ret < 0)
1190 zlog (NULL, LOG_WARNING,
1191 "%s:%i Warning: Could not set netlink socket to blocking.",
1192 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001193
1194 /*
1195 * Get reply from netlink socket.
1196 * The reply should either be an acknowlegement or an error.
1197 */
1198 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001199
paul718e3742002-12-13 20:15:29 +00001200 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001201 if (snb_ret == 0)
1202 set_netlink_nonblocking (nl, &flags);
1203
paul718e3742002-12-13 20:15:29 +00001204 return status;
1205}
1206
1207/* Routing table change via netlink interface. */
1208int
1209netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001210 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001211{
1212 int ret;
1213 int bytelen;
1214 struct sockaddr_nl snl;
1215 int discard;
1216
paul7021c422003-07-15 12:52:22 +00001217 struct
paul718e3742002-12-13 20:15:29 +00001218 {
1219 struct nlmsghdr n;
1220 struct rtmsg r;
1221 char buf[1024];
1222 } req;
1223
1224 memset (&req, 0, sizeof req);
1225
1226 bytelen = (family == AF_INET ? 4 : 16);
1227
1228 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1229 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1230 req.n.nlmsg_type = cmd;
1231 req.r.rtm_family = family;
1232 req.r.rtm_table = table;
1233 req.r.rtm_dst_len = length;
1234
hasso81dfcaa2003-05-25 19:21:25 +00001235 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1236 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001237 discard = 1;
1238 else
1239 discard = 0;
1240
paul7021c422003-07-15 12:52:22 +00001241 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001242 {
1243 req.r.rtm_protocol = RTPROT_ZEBRA;
1244 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1245
paul7021c422003-07-15 12:52:22 +00001246 if (discard)
paul595db7f2003-05-25 21:35:06 +00001247 {
1248 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1249 req.r.rtm_type = RTN_BLACKHOLE;
1250 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1251 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001252 else
1253 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1254 }
paul595db7f2003-05-25 21:35:06 +00001255 else
paul7021c422003-07-15 12:52:22 +00001256 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001257 }
1258
1259 if (dest)
1260 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1261
paul7021c422003-07-15 12:52:22 +00001262 if (!discard)
paul718e3742002-12-13 20:15:29 +00001263 {
1264 if (gate)
paul7021c422003-07-15 12:52:22 +00001265 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001266 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001267 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001268 }
1269
1270 /* Destination netlink address. */
1271 memset (&snl, 0, sizeof snl);
1272 snl.nl_family = AF_NETLINK;
1273
1274 /* Talk to netlink socket. */
1275 ret = netlink_talk (&req.n, &netlink);
1276 if (ret < 0)
1277 return -1;
1278
1279 return 0;
1280}
1281
1282/* Routing table change via netlink interface. */
1283int
1284netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001285 int family)
paul718e3742002-12-13 20:15:29 +00001286{
1287 int bytelen;
1288 struct sockaddr_nl snl;
1289 struct nexthop *nexthop = NULL;
1290 int nexthop_num = 0;
1291 struct nlsock *nl;
1292 int discard;
1293
paul7021c422003-07-15 12:52:22 +00001294 struct
paul718e3742002-12-13 20:15:29 +00001295 {
1296 struct nlmsghdr n;
1297 struct rtmsg r;
1298 char buf[1024];
1299 } req;
1300
1301 memset (&req, 0, sizeof req);
1302
1303 bytelen = (family == AF_INET ? 4 : 16);
1304
1305 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1306 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1307 req.n.nlmsg_type = cmd;
1308 req.r.rtm_family = family;
1309 req.r.rtm_table = rib->table;
1310 req.r.rtm_dst_len = p->prefixlen;
1311
paul13766da2003-02-07 14:46:23 +00001312#ifdef RTM_F_EQUALIZE
1313 req.r.rtm_flags |= RTM_F_EQUALIZE;
1314#endif /* RTM_F_EQUALIZE */
1315
paul7021c422003-07-15 12:52:22 +00001316 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001317 discard = 1;
1318 else
1319 discard = 0;
1320
paul7021c422003-07-15 12:52:22 +00001321 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001322 {
1323 req.r.rtm_protocol = RTPROT_ZEBRA;
1324 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1325
paul7021c422003-07-15 12:52:22 +00001326 if (discard)
paul595db7f2003-05-25 21:35:06 +00001327 {
1328 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1329 req.r.rtm_type = RTN_BLACKHOLE;
1330 else if (rib->flags & ZEBRA_FLAG_REJECT)
1331 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001332 else
1333 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1334 }
paul595db7f2003-05-25 21:35:06 +00001335 else
paul7021c422003-07-15 12:52:22 +00001336 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001337 }
1338
1339 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1340
1341 /* Metric. */
1342 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1343
1344 if (discard)
1345 {
1346 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001347 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1348 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001349 goto skip;
1350 }
1351
1352 /* Multipath case. */
1353 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1354 {
1355 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001356 {
paul5ec90d22003-06-19 01:41:37 +00001357
paul7021c422003-07-15 12:52:22 +00001358 if ((cmd == RTM_NEWROUTE
1359 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1360 || (cmd == RTM_DELROUTE
1361 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1362 {
paul5ec90d22003-06-19 01:41:37 +00001363
paul7021c422003-07-15 12:52:22 +00001364 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1365 {
1366 if (IS_ZEBRA_DEBUG_KERNEL)
1367 {
1368 zlog_info
1369 ("netlink_route_multipath() (recursive, 1 hop): "
1370 "%s %s/%d via %s if %u, type %s",
1371 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1372 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1373 nexthop->rifindex,
1374 nexthop_types_desc[nexthop->rtype]);
1375 }
paul5ec90d22003-06-19 01:41:37 +00001376
paul7021c422003-07-15 12:52:22 +00001377 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1378 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1379 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1380 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001381#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001382 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1383 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1384 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1385 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1386 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001387#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001388 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1389 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1390 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1391 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1392 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1393 addattr32 (&req.n, sizeof req, RTA_OIF,
1394 nexthop->rifindex);
1395 }
1396 else
1397 {
1398 if (IS_ZEBRA_DEBUG_KERNEL)
1399 {
1400 zlog_info
1401 ("netlink_route_multipath(): (single hop)"
1402 "%s %s/%d via %s if %u, type %s",
1403 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1404 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1405 nexthop->ifindex,
1406 nexthop_types_desc[nexthop->type]);
1407 }
paul5ec90d22003-06-19 01:41:37 +00001408
paul7021c422003-07-15 12:52:22 +00001409 if (nexthop->type == NEXTHOP_TYPE_IPV4
1410 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1411 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1412 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001413#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001414 if (nexthop->type == NEXTHOP_TYPE_IPV6
1415 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1416 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1417 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1418 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001419#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001420 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1421 || nexthop->type == NEXTHOP_TYPE_IFNAME
1422 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1423 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1424 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1425 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1426 }
paul718e3742002-12-13 20:15:29 +00001427
paul7021c422003-07-15 12:52:22 +00001428 if (cmd == RTM_NEWROUTE)
1429 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001430
paul7021c422003-07-15 12:52:22 +00001431 nexthop_num++;
1432 break;
1433 }
1434 }
paul718e3742002-12-13 20:15:29 +00001435 }
1436 else
1437 {
1438 char buf[1024];
1439 struct rtattr *rta = (void *) buf;
1440 struct rtnexthop *rtnh;
1441
1442 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001443 rta->rta_len = RTA_LENGTH (0);
1444 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001445
1446 nexthop_num = 0;
1447 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001448 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1449 nexthop = nexthop->next)
1450 {
1451 if ((cmd == RTM_NEWROUTE
1452 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1453 || (cmd == RTM_DELROUTE
1454 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1455 {
1456 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001457
paul7021c422003-07-15 12:52:22 +00001458 rtnh->rtnh_len = sizeof (*rtnh);
1459 rtnh->rtnh_flags = 0;
1460 rtnh->rtnh_hops = 0;
1461 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001462
paul7021c422003-07-15 12:52:22 +00001463 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1464 {
1465 if (IS_ZEBRA_DEBUG_KERNEL)
1466 {
1467 zlog_info ("netlink_route_multipath() "
1468 "(recursive, multihop): "
1469 "%s %s/%d via %s if %u, type %s",
1470 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1471 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1472 nexthop->rifindex,
1473 nexthop_types_desc[nexthop->type]);
1474 }
1475 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1476 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1477 {
1478 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1479 &nexthop->rgate.ipv4, bytelen);
1480 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1481 }
paul718e3742002-12-13 20:15:29 +00001482#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001483 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1484 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1485 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1486 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1487 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001488#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001489 /* ifindex */
1490 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1491 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1492 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1493 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1494 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1495 rtnh->rtnh_ifindex = nexthop->rifindex;
1496 else
1497 rtnh->rtnh_ifindex = 0;
1498 }
1499 else
1500 {
1501 if (IS_ZEBRA_DEBUG_KERNEL)
1502 {
1503 zlog_info ("netlink_route_multipath() "
1504 "(multihop): "
1505 "%s %s/%d via %s if %u, type %s",
1506 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1507 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1508 nexthop->rifindex,
1509 nexthop_types_desc[nexthop->type]);
1510 }
1511 if (nexthop->type == NEXTHOP_TYPE_IPV4
1512 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1513 {
1514 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1515 &nexthop->gate.ipv4, bytelen);
1516 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1517 }
paul718e3742002-12-13 20:15:29 +00001518#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001519 if (nexthop->type == NEXTHOP_TYPE_IPV6
1520 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1521 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1522 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1523 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001524#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001525 /* ifindex */
1526 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1527 || nexthop->type == NEXTHOP_TYPE_IFNAME
1528 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1529 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1530 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1531 rtnh->rtnh_ifindex = nexthop->ifindex;
1532 else
1533 rtnh->rtnh_ifindex = 0;
1534 }
1535 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001536
paul7021c422003-07-15 12:52:22 +00001537 if (cmd == RTM_NEWROUTE)
1538 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1539 }
1540 }
paul718e3742002-12-13 20:15:29 +00001541
1542 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001543 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1544 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001545 }
1546
1547 /* If there is no useful nexthop then return. */
1548 if (nexthop_num == 0)
1549 {
1550 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001551 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001552 return 0;
1553 }
1554
paul7021c422003-07-15 12:52:22 +00001555skip:
paul718e3742002-12-13 20:15:29 +00001556
1557 /* Destination netlink address. */
1558 memset (&snl, 0, sizeof snl);
1559 snl.nl_family = AF_NETLINK;
1560
1561 if (family == AF_INET)
1562 nl = &netlink_cmd;
1563 else
1564 nl = &netlink;
1565
1566 /* Talk to netlink socket. */
1567 return netlink_talk (&req.n, nl);
1568}
1569
1570int
1571kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1572{
1573 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1574}
1575
1576int
1577kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1578{
1579 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1580}
1581
1582#ifdef HAVE_IPV6
1583int
1584kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1585{
1586 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1587}
1588
1589int
1590kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1591{
1592 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1593}
1594
1595/* Delete IPv6 route from the kernel. */
1596int
1597kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001598 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001599{
paul7021c422003-07-15 12:52:22 +00001600 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1601 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001602}
1603#endif /* HAVE_IPV6 */
1604
1605/* Interface address modification. */
1606int
1607netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001608 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001609{
1610 int bytelen;
1611 struct prefix *p;
1612
paul7021c422003-07-15 12:52:22 +00001613 struct
paul718e3742002-12-13 20:15:29 +00001614 {
1615 struct nlmsghdr n;
1616 struct ifaddrmsg ifa;
1617 char buf[1024];
1618 } req;
1619
1620 p = ifc->address;
1621 memset (&req, 0, sizeof req);
1622
1623 bytelen = (family == AF_INET ? 4 : 16);
1624
paul7021c422003-07-15 12:52:22 +00001625 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001626 req.n.nlmsg_flags = NLM_F_REQUEST;
1627 req.n.nlmsg_type = cmd;
1628 req.ifa.ifa_family = family;
1629
1630 req.ifa.ifa_index = ifp->ifindex;
1631 req.ifa.ifa_prefixlen = p->prefixlen;
1632
1633 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1634
1635 if (family == AF_INET && cmd == RTM_NEWADDR)
1636 {
1637 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001638 {
1639 p = ifc->destination;
1640 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1641 bytelen);
1642 }
paul718e3742002-12-13 20:15:29 +00001643 }
1644
1645 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1646 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001647
paul718e3742002-12-13 20:15:29 +00001648 if (ifc->label)
1649 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001650 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001651
1652 return netlink_talk (&req.n, &netlink_cmd);
1653}
1654
1655int
1656kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1657{
1658 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1659}
1660
1661int
1662kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1663{
1664 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1665}
1666
paul718e3742002-12-13 20:15:29 +00001667
1668extern struct thread_master *master;
1669
1670/* Kernel route reflection. */
1671int
1672kernel_read (struct thread *thread)
1673{
1674 int ret;
1675 int sock;
1676
1677 sock = THREAD_FD (thread);
1678 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001679 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001680
1681 return 0;
1682}
1683
1684/* Exported interface function. This function simply calls
1685 netlink_socket (). */
1686void
1687kernel_init ()
1688{
1689 unsigned long groups;
1690
paul7021c422003-07-15 12:52:22 +00001691 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001692#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001693 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001694#endif /* HAVE_IPV6 */
1695 netlink_socket (&netlink, groups);
1696 netlink_socket (&netlink_cmd, 0);
1697
1698 /* Register kernel socket. */
1699 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001700 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001701}