blob: a2efa17ac472852aa54f72b0d3ede369fb6ed0a9 [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 }
paul718e3742002-12-13 20:15:29 +0000293
paul7021c422003-07-15 12:52:22 +0000294 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, status);
295 h = NLMSG_NEXT (h, status))
296 {
297 /* Finish of reading. */
298 if (h->nlmsg_type == NLMSG_DONE)
299 return ret;
paul718e3742002-12-13 20:15:29 +0000300
paul7021c422003-07-15 12:52:22 +0000301 /* Error handling. */
302 if (h->nlmsg_type == NLMSG_ERROR)
303 {
304 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
305
paul718e3742002-12-13 20:15:29 +0000306 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000307 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000308 {
paul7021c422003-07-15 12:52:22 +0000309 if (IS_ZEBRA_DEBUG_KERNEL)
310 {
311 zlog_info ("%s: %s ACK: type=%s(%u), seq=%u, pid=%d",
312 __FUNCTION__, nl->name,
313 lookup (nlmsg_str, err->msg.nlmsg_type),
314 err->msg.nlmsg_type, err->msg.nlmsg_seq,
315 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000316 }
paul7021c422003-07-15 12:52:22 +0000317
318 /* return if not a multipart message, otherwise continue */
319 if (!(h->nlmsg_flags & NLM_F_MULTI))
320 {
321 return 0;
paul718e3742002-12-13 20:15:29 +0000322 }
paul7021c422003-07-15 12:52:22 +0000323 continue;
paul718e3742002-12-13 20:15:29 +0000324 }
paul7021c422003-07-15 12:52:22 +0000325
paul718e3742002-12-13 20:15:29 +0000326 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000327 {
328 zlog (NULL, LOG_ERR, "%s error: message truncated",
329 nl->name);
330 return -1;
331 }
pauld753e9e2003-01-22 19:45:50 +0000332
paul7021c422003-07-15 12:52:22 +0000333 /* Deal with Error Noise - MAG */
334 {
335 int loglvl = LOG_ERR;
336 int errnum = err->error;
337 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000338
paul7021c422003-07-15 12:52:22 +0000339 if (nl == &netlink_cmd
340 && (-errnum == ENODEV || -errnum == ESRCH)
341 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
342 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000343
paul7021c422003-07-15 12:52:22 +0000344 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
345 "seq=%u, pid=%d",
346 nl->name, strerror (-errnum),
347 lookup (nlmsg_str, msg_type),
348 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
349 }
350 /*
351 ret = -1;
352 continue;
353 */
354 return -1;
355 }
paul718e3742002-12-13 20:15:29 +0000356
paul7021c422003-07-15 12:52:22 +0000357 /* OK we got netlink message. */
358 if (IS_ZEBRA_DEBUG_KERNEL)
359 zlog_info ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%d",
360 nl->name,
361 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
362 h->nlmsg_seq, h->nlmsg_pid);
363
364 /* skip unsolicited messages originating from command socket */
365 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
366 {
367 if (IS_ZEBRA_DEBUG_KERNEL)
368 zlog_info ("netlink_parse_info: %s packet comes from %s",
369 nl->name, netlink_cmd.name);
370 continue;
371 }
372
373 error = (*filter) (&snl, h);
374 if (error < 0)
375 {
376 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
377 ret = error;
378 }
379 }
paul718e3742002-12-13 20:15:29 +0000380
381 /* After error care. */
382 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000383 {
384 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
385 continue;
386 }
paul718e3742002-12-13 20:15:29 +0000387 if (status)
paul7021c422003-07-15 12:52:22 +0000388 {
389 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
390 status);
391 return -1;
392 }
paul718e3742002-12-13 20:15:29 +0000393 }
394 return ret;
395}
396
397/* Utility function for parse rtattr. */
398static void
paul7021c422003-07-15 12:52:22 +0000399netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
400 int len)
paul718e3742002-12-13 20:15:29 +0000401{
paul7021c422003-07-15 12:52:22 +0000402 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000403 {
404 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000405 tb[rta->rta_type] = rta;
406 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000407 }
408}
409
410/* Called from interface_lookup_netlink(). This function is only used
411 during bootstrap. */
412int
413netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
414{
415 int len;
416 struct ifinfomsg *ifi;
417 struct rtattr *tb[IFLA_MAX + 1];
418 struct interface *ifp;
419 char *name;
420 int i;
421
422 ifi = NLMSG_DATA (h);
423
424 if (h->nlmsg_type != RTM_NEWLINK)
425 return 0;
426
427 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
428 if (len < 0)
429 return -1;
430
431 /* Looking up interface name. */
432 memset (tb, 0, sizeof tb);
433 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
434 if (tb[IFLA_IFNAME] == NULL)
435 return -1;
paul7021c422003-07-15 12:52:22 +0000436 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000437
438 /* Add interface. */
439 ifp = if_get_by_name (name);
paul7021c422003-07-15 12:52:22 +0000440
paul718e3742002-12-13 20:15:29 +0000441 ifp->ifindex = ifi->ifi_index;
442 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul7021c422003-07-15 12:52:22 +0000443 ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000444 ifp->metric = 1;
445
446 /* Hardware type and address. */
447 ifp->hw_type = ifi->ifi_type;
448
449 if (tb[IFLA_ADDRESS])
450 {
451 int hw_addr_len;
452
paul7021c422003-07-15 12:52:22 +0000453 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000454
455 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000456 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000457 else
paul7021c422003-07-15 12:52:22 +0000458 {
459 ifp->hw_addr_len = hw_addr_len;
460 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000461
paul7021c422003-07-15 12:52:22 +0000462 for (i = 0; i < hw_addr_len; i++)
463 if (ifp->hw_addr[i] != 0)
464 break;
paul718e3742002-12-13 20:15:29 +0000465
paul7021c422003-07-15 12:52:22 +0000466 if (i == hw_addr_len)
467 ifp->hw_addr_len = 0;
468 else
469 ifp->hw_addr_len = hw_addr_len;
470 }
paul718e3742002-12-13 20:15:29 +0000471 }
472
473 if_add_update (ifp);
474
475 return 0;
476}
477
478/* Lookup interface IPv4/IPv6 address. */
479int
480netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
481{
482 int len;
483 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000484 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000485 struct interface *ifp;
486 void *addr = NULL;
487 void *broad = NULL;
488 u_char flags = 0;
489 char *label = NULL;
paul00df0c12002-12-13 21:07:36 +0000490 int peeronly = 0;
paul718e3742002-12-13 20:15:29 +0000491
492 ifa = NLMSG_DATA (h);
493
paul7021c422003-07-15 12:52:22 +0000494 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000495#ifdef HAVE_IPV6
496 && ifa->ifa_family != AF_INET6
497#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000498 )
paul718e3742002-12-13 20:15:29 +0000499 return 0;
500
501 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
502 return 0;
503
paul7021c422003-07-15 12:52:22 +0000504 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000505 if (len < 0)
506 return -1;
507
508 memset (tb, 0, sizeof tb);
509 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
510
511 ifp = if_lookup_by_index (ifa->ifa_index);
512 if (ifp == NULL)
513 {
514 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000515 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000516 return -1;
517 }
518
paul7021c422003-07-15 12:52:22 +0000519 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000520 {
paul00df0c12002-12-13 21:07:36 +0000521 char buf[BUFSIZ];
522 zlog_info ("netlink_interface_addr %s %s/%d:",
paul7021c422003-07-15 12:52:22 +0000523 lookup (nlmsg_str, h->nlmsg_type),
524 ifp->name, ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000525 if (tb[IFA_LOCAL])
paul7021c422003-07-15 12:52:22 +0000526 zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family,
527 RTA_DATA (tb[IFA_LOCAL]),
528 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000529 if (tb[IFA_ADDRESS])
paul7021c422003-07-15 12:52:22 +0000530 zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family,
531 RTA_DATA (tb
532 [IFA_ADDRESS]),
533 buf, BUFSIZ));
paul718e3742002-12-13 20:15:29 +0000534 if (tb[IFA_BROADCAST])
paul7021c422003-07-15 12:52:22 +0000535 zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
536 RTA_DATA (tb
537 [IFA_BROADCAST]),
538 buf, BUFSIZ));
paul00df0c12002-12-13 21:07:36 +0000539 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
paul7021c422003-07-15 12:52:22 +0000540 zlog_info (" IFA_LABEL %s", RTA_DATA (tb[IFA_LABEL]));
paul718e3742002-12-13 20:15:29 +0000541 }
542
paul00df0c12002-12-13 21:07:36 +0000543 /* peer or broadcast network? */
544 if (ifa->ifa_family == AF_INET)
545 peeronly = if_is_pointopoint (ifp) ||
paul7021c422003-07-15 12:52:22 +0000546 ifa->ifa_prefixlen >= IPV4_MAX_PREFIXLEN - 1;
paul00df0c12002-12-13 21:07:36 +0000547#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +0000548 if (ifa->ifa_family == AF_INET6)
549 {
550 peeronly = if_is_pointopoint (ifp) ||
551 ifa->ifa_prefixlen >= IPV6_MAX_PREFIXLEN - 1;
552 }
553#endif /* HAVE_IPV6 */
554 if (!(tb[IFA_LOCAL] && tb[IFA_ADDRESS]))
555 {
556 /* FIXME: IPv6 Appears to have only IFA_ADDRESS */
557 peeronly = 0;
558 }
paul00df0c12002-12-13 21:07:36 +0000559
560 /* network. prefixlen applies to IFA_ADDRESS rather than IFA_LOCAL */
561 if (tb[IFA_ADDRESS] && !peeronly)
562 addr = RTA_DATA (tb[IFA_ADDRESS]);
563 else if (tb[IFA_LOCAL])
564 addr = RTA_DATA (tb[IFA_LOCAL]);
565 else
566 addr = NULL;
567
568 /* broadcast/peer */
569 if (tb[IFA_BROADCAST])
570 broad = RTA_DATA (tb[IFA_BROADCAST]);
571 else if (tb[IFA_ADDRESS] && peeronly)
paul7021c422003-07-15 12:52:22 +0000572 broad = RTA_DATA (tb[IFA_ADDRESS]); /* peer address specified */
paul00df0c12002-12-13 21:07:36 +0000573 else
574 broad = NULL;
575
paul718e3742002-12-13 20:15:29 +0000576 /* Flags. */
577 if (ifa->ifa_flags & IFA_F_SECONDARY)
578 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
579
580 /* Label */
581 if (tb[IFA_LABEL])
582 label = (char *) RTA_DATA (tb[IFA_LABEL]);
583
584 if (ifp && label && strcmp (ifp->name, label) == 0)
585 label = NULL;
586
587 /* Register interface address to the interface. */
588 if (ifa->ifa_family == AF_INET)
589 {
paul7021c422003-07-15 12:52:22 +0000590 if (h->nlmsg_type == RTM_NEWADDR)
591 connected_add_ipv4 (ifp, flags,
592 (struct in_addr *) addr, ifa->ifa_prefixlen,
593 (struct in_addr *) broad, label);
594 else
595 connected_delete_ipv4 (ifp, flags,
596 (struct in_addr *) addr, ifa->ifa_prefixlen,
597 (struct in_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000598 }
599#ifdef HAVE_IPV6
600 if (ifa->ifa_family == AF_INET6)
601 {
602 if (h->nlmsg_type == RTM_NEWADDR)
paul7021c422003-07-15 12:52:22 +0000603 connected_add_ipv6 (ifp,
604 (struct in6_addr *) addr, ifa->ifa_prefixlen,
605 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000606 else
paul7021c422003-07-15 12:52:22 +0000607 connected_delete_ipv6 (ifp,
608 (struct in6_addr *) addr, ifa->ifa_prefixlen,
609 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000610 }
paul7021c422003-07-15 12:52:22 +0000611#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000612
613 return 0;
614}
615
616/* Looking up routing table by netlink interface. */
617int
618netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
619{
620 int len;
621 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000622 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000623 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000624
625 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000626
627 int index;
628 int table;
629 void *dest;
630 void *gate;
631
632 rtm = NLMSG_DATA (h);
633
634 if (h->nlmsg_type != RTM_NEWROUTE)
635 return 0;
636 if (rtm->rtm_type != RTN_UNICAST)
637 return 0;
638
639 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000640#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000641 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000642 return 0;
643#endif
644
paul7021c422003-07-15 12:52:22 +0000645 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000646 if (len < 0)
647 return -1;
648
649 memset (tb, 0, sizeof tb);
650 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
651
652 if (rtm->rtm_flags & RTM_F_CLONED)
653 return 0;
654 if (rtm->rtm_protocol == RTPROT_REDIRECT)
655 return 0;
656 if (rtm->rtm_protocol == RTPROT_KERNEL)
657 return 0;
658
659 if (rtm->rtm_src_len != 0)
660 return 0;
661
662 /* Route which inserted by Zebra. */
663 if (rtm->rtm_protocol == RTPROT_ZEBRA)
664 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000665
paul718e3742002-12-13 20:15:29 +0000666 index = 0;
667 dest = NULL;
668 gate = NULL;
669
670 if (tb[RTA_OIF])
671 index = *(int *) RTA_DATA (tb[RTA_OIF]);
672
673 if (tb[RTA_DST])
674 dest = RTA_DATA (tb[RTA_DST]);
675 else
676 dest = anyaddr;
677
678 /* Multipath treatment is needed. */
679 if (tb[RTA_GATEWAY])
680 gate = RTA_DATA (tb[RTA_GATEWAY]);
681
682 if (rtm->rtm_family == AF_INET)
683 {
684 struct prefix_ipv4 p;
685 p.family = AF_INET;
686 memcpy (&p.prefix, dest, 4);
687 p.prefixlen = rtm->rtm_dst_len;
688
689 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, 0, 0);
690 }
691#ifdef HAVE_IPV6
692 if (rtm->rtm_family == AF_INET6)
693 {
694 struct prefix_ipv6 p;
695 p.family = AF_INET6;
696 memcpy (&p.prefix, dest, 16);
697 p.prefixlen = rtm->rtm_dst_len;
698
699 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
700 }
701#endif /* HAVE_IPV6 */
702
703 return 0;
704}
705
paul7021c422003-07-15 12:52:22 +0000706struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000707 {RTPROT_REDIRECT, "redirect"},
708 {RTPROT_KERNEL, "kernel"},
709 {RTPROT_BOOT, "boot"},
710 {RTPROT_STATIC, "static"},
711 {RTPROT_GATED, "GateD"},
712 {RTPROT_RA, "router advertisement"},
713 {RTPROT_MRT, "MRT"},
714 {RTPROT_ZEBRA, "Zebra"},
715#ifdef RTPROT_BIRD
716 {RTPROT_BIRD, "BIRD"},
717#endif /* RTPROT_BIRD */
718 {0, NULL}
719};
720
721/* Routing information change from the kernel. */
722int
723netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
724{
725 int len;
726 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000727 struct rtattr *tb[RTA_MAX + 1];
728
729 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000730
731 int index;
732 int table;
733 void *dest;
734 void *gate;
735
736 rtm = NLMSG_DATA (h);
737
paul7021c422003-07-15 12:52:22 +0000738 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000739 {
740 /* If this is not route add/delete message print warning. */
741 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
742 return 0;
743 }
744
745 /* Connected route. */
746 if (IS_ZEBRA_DEBUG_KERNEL)
747 zlog_info ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000748 h->nlmsg_type ==
749 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
750 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
751 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
752 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000753
754 if (rtm->rtm_type != RTN_UNICAST)
755 {
756 return 0;
757 }
758
759 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000760 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000761 {
762 return 0;
763 }
764
paul7021c422003-07-15 12:52:22 +0000765 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000766 if (len < 0)
767 return -1;
768
769 memset (tb, 0, sizeof tb);
770 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
771
772 if (rtm->rtm_flags & RTM_F_CLONED)
773 return 0;
774 if (rtm->rtm_protocol == RTPROT_REDIRECT)
775 return 0;
776 if (rtm->rtm_protocol == RTPROT_KERNEL)
777 return 0;
778
779 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
780 return 0;
781
782 if (rtm->rtm_src_len != 0)
783 {
784 zlog_warn ("netlink_route_change(): no src len");
785 return 0;
786 }
paul7021c422003-07-15 12:52:22 +0000787
paul718e3742002-12-13 20:15:29 +0000788 index = 0;
789 dest = NULL;
790 gate = NULL;
791
792 if (tb[RTA_OIF])
793 index = *(int *) RTA_DATA (tb[RTA_OIF]);
794
795 if (tb[RTA_DST])
796 dest = RTA_DATA (tb[RTA_DST]);
797 else
798 dest = anyaddr;
799
800 if (tb[RTA_GATEWAY])
801 gate = RTA_DATA (tb[RTA_GATEWAY]);
802
803 if (rtm->rtm_family == AF_INET)
804 {
805 struct prefix_ipv4 p;
806 p.family = AF_INET;
807 memcpy (&p.prefix, dest, 4);
808 p.prefixlen = rtm->rtm_dst_len;
809
810 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000811 {
812 if (h->nlmsg_type == RTM_NEWROUTE)
813 zlog_info ("RTM_NEWROUTE %s/%d",
814 inet_ntoa (p.prefix), p.prefixlen);
815 else
816 zlog_info ("RTM_DELROUTE %s/%d",
817 inet_ntoa (p.prefix), p.prefixlen);
818 }
paul718e3742002-12-13 20:15:29 +0000819
820 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000821 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000822 else
paul7021c422003-07-15 12:52:22 +0000823 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000824 }
825
826#ifdef HAVE_IPV6
827 if (rtm->rtm_family == AF_INET6)
828 {
829 struct prefix_ipv6 p;
830 char buf[BUFSIZ];
831
832 p.family = AF_INET6;
833 memcpy (&p.prefix, dest, 16);
834 p.prefixlen = rtm->rtm_dst_len;
835
836 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000837 {
838 if (h->nlmsg_type == RTM_NEWROUTE)
839 zlog_info ("RTM_NEWROUTE %s/%d",
840 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
841 p.prefixlen);
842 else
843 zlog_info ("RTM_DELROUTE %s/%d",
844 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
845 p.prefixlen);
846 }
paul718e3742002-12-13 20:15:29 +0000847
848 if (h->nlmsg_type == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +0000849 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000850 else
paul7021c422003-07-15 12:52:22 +0000851 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000852 }
853#endif /* HAVE_IPV6 */
854
855 return 0;
856}
857
858int
859netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
860{
861 int len;
862 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000863 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000864 struct interface *ifp;
865 char *name;
866
867 ifi = NLMSG_DATA (h);
868
paul7021c422003-07-15 12:52:22 +0000869 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000870 {
871 /* If this is not link add/delete message so print warning. */
872 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000873 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000874 return 0;
875 }
876
877 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
878 if (len < 0)
879 return -1;
880
881 /* Looking up interface name. */
882 memset (tb, 0, sizeof tb);
883 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
884 if (tb[IFLA_IFNAME] == NULL)
885 return -1;
paul7021c422003-07-15 12:52:22 +0000886 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000887
888 /* Add interface. */
889 if (h->nlmsg_type == RTM_NEWLINK)
890 {
891 ifp = if_lookup_by_name (name);
892
paul7021c422003-07-15 12:52:22 +0000893 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
894 {
895 if (ifp == NULL)
896 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000897
paul7021c422003-07-15 12:52:22 +0000898 ifp->ifindex = ifi->ifi_index;
899 ifp->flags = ifi->ifi_flags & 0x0000fffff;
900 ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
901 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000902
paul7021c422003-07-15 12:52:22 +0000903 /* If new link is added. */
904 if_add_update (ifp);
905 }
paul718e3742002-12-13 20:15:29 +0000906 else
paul7021c422003-07-15 12:52:22 +0000907 {
908 /* Interface status change. */
909 ifp->ifindex = ifi->ifi_index;
910 ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
911 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000912
paul7021c422003-07-15 12:52:22 +0000913 if (if_is_operative (ifp))
914 {
915 ifp->flags = ifi->ifi_flags & 0x0000fffff;
916 if (!if_is_operative (ifp))
917 if_down (ifp);
918 }
919 else
920 {
921 ifp->flags = ifi->ifi_flags & 0x0000fffff;
922 if (if_is_operative (ifp))
923 if_up (ifp);
924 }
925 }
paul718e3742002-12-13 20:15:29 +0000926 }
927 else
928 {
929 /* RTM_DELLINK. */
930 ifp = if_lookup_by_name (name);
931
932 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000933 {
934 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000935 name);
paul7021c422003-07-15 12:52:22 +0000936 return 0;
937 }
938
paul718e3742002-12-13 20:15:29 +0000939 if_delete_update (ifp);
940 }
941
942 return 0;
943}
944
945int
946netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
947{
948 switch (h->nlmsg_type)
949 {
950 case RTM_NEWROUTE:
951 return netlink_route_change (snl, h);
952 break;
953 case RTM_DELROUTE:
954 return netlink_route_change (snl, h);
955 break;
956 case RTM_NEWLINK:
957 return netlink_link_change (snl, h);
958 break;
959 case RTM_DELLINK:
960 return netlink_link_change (snl, h);
961 break;
962 case RTM_NEWADDR:
963 return netlink_interface_addr (snl, h);
964 break;
965 case RTM_DELADDR:
966 return netlink_interface_addr (snl, h);
967 break;
968 default:
969 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
970 break;
971 }
972 return 0;
973}
974
975/* Interface lookup by netlink socket. */
976int
977interface_lookup_netlink ()
978{
979 int ret;
paul5f37d862003-04-19 00:11:28 +0000980 int flags;
981 int snb_ret;
paul7021c422003-07-15 12:52:22 +0000982
paul5f37d862003-04-19 00:11:28 +0000983 /*
984 * Change netlink socket flags to blocking to ensure we get
985 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +0000986 */
987 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
988 if (snb_ret < 0)
989 zlog (NULL, LOG_WARNING,
990 "%s:%i Warning: Could not set netlink socket to blocking.",
991 __FUNCTION__, __LINE__);
992
paul718e3742002-12-13 20:15:29 +0000993 /* Get interface information. */
994 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
995 if (ret < 0)
996 return ret;
997 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
998 if (ret < 0)
999 return ret;
1000
1001 /* Get IPv4 address of the interfaces. */
1002 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1003 if (ret < 0)
1004 return ret;
1005 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1006 if (ret < 0)
1007 return ret;
1008
1009#ifdef HAVE_IPV6
1010 /* Get IPv6 address of the interfaces. */
1011 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1012 if (ret < 0)
1013 return ret;
1014 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1015 if (ret < 0)
1016 return ret;
1017#endif /* HAVE_IPV6 */
1018
paul7021c422003-07-15 12:52:22 +00001019 /* restore socket flags */
1020 if (snb_ret == 0)
1021 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001022 return 0;
1023}
1024
1025/* Routing table read function using netlink interface. Only called
1026 bootstrap time. */
1027int
1028netlink_route_read ()
1029{
1030 int ret;
paul5f37d862003-04-19 00:11:28 +00001031 int flags;
1032 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001033
paul5f37d862003-04-19 00:11:28 +00001034 /*
1035 * Change netlink socket flags to blocking to ensure we get
1036 * a reply via nelink_parse_info
paul7021c422003-07-15 12:52:22 +00001037 */
1038 snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
1039 if (snb_ret < 0)
1040 zlog (NULL, LOG_WARNING,
1041 "%s:%i Warning: Could not set netlink socket to blocking.",
1042 __FUNCTION__, __LINE__);
1043
paul718e3742002-12-13 20:15:29 +00001044 /* Get IPv4 routing table. */
1045 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1046 if (ret < 0)
1047 return ret;
1048 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1049 if (ret < 0)
1050 return ret;
1051
1052#ifdef HAVE_IPV6
1053 /* Get IPv6 routing table. */
1054 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1055 if (ret < 0)
1056 return ret;
1057 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1058 if (ret < 0)
1059 return ret;
1060#endif /* HAVE_IPV6 */
1061
paul5f37d862003-04-19 00:11:28 +00001062 /* restore flags */
paul7021c422003-07-15 12:52:22 +00001063 if (snb_ret == 0)
1064 set_netlink_nonblocking (&netlink_cmd, &flags);
paul718e3742002-12-13 20:15:29 +00001065 return 0;
1066}
1067
1068/* Utility function comes from iproute2.
1069 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1070int
1071addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1072{
1073 int len;
1074 struct rtattr *rta;
1075
paul7021c422003-07-15 12:52:22 +00001076 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001077
paul7021c422003-07-15 12:52:22 +00001078 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001079 return -1;
1080
paul7021c422003-07-15 12:52:22 +00001081 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001082 rta->rta_type = type;
1083 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001084 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001085 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1086
1087 return 0;
1088}
1089
1090int
1091rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1092{
1093 int len;
1094 struct rtattr *subrta;
1095
paul7021c422003-07-15 12:52:22 +00001096 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001097
paul7021c422003-07-15 12:52:22 +00001098 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001099 return -1;
1100
paul7021c422003-07-15 12:52:22 +00001101 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001102 subrta->rta_type = type;
1103 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001104 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001105 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1106
1107 return 0;
1108}
1109
1110/* Utility function comes from iproute2.
1111 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
1112int
1113addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1114{
1115 int len;
1116 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001117
1118 len = RTA_LENGTH (4);
1119
paul718e3742002-12-13 20:15:29 +00001120 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1121 return -1;
1122
paul7021c422003-07-15 12:52:22 +00001123 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001124 rta->rta_type = type;
1125 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001126 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001127 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1128
1129 return 0;
1130}
1131
1132static int
1133netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1134{
1135 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
1136 return 0;
1137}
1138
1139/* sendmsg() to netlink socket then recvmsg(). */
1140int
1141netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1142{
1143 int status;
1144 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001145 struct iovec iov = { (void *) n, n->nlmsg_len };
1146 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +00001147 int flags = 0;
paul5f37d862003-04-19 00:11:28 +00001148 int snb_ret;
paul7021c422003-07-15 12:52:22 +00001149
paul718e3742002-12-13 20:15:29 +00001150 memset (&snl, 0, sizeof snl);
1151 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001152
paul718e3742002-12-13 20:15:29 +00001153 n->nlmsg_seq = ++netlink_cmd.seq;
1154
1155 /* Request an acknowledgement by setting NLM_F_ACK */
1156 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001157
1158 if (IS_ZEBRA_DEBUG_KERNEL)
paul718e3742002-12-13 20:15:29 +00001159 zlog_info ("netlink_talk: %s type %s(%u), seq=%u", netlink_cmd.name,
paul7021c422003-07-15 12:52:22 +00001160 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1161 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001162
1163 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001164 if (zserv_privs.change (ZPRIVS_RAISE))
1165 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001166 status = sendmsg (nl->sock, &msg, 0);
paul7021c422003-07-15 12:52:22 +00001167 if (zserv_privs.change (ZPRIVS_LOWER))
1168 zlog (NULL, LOG_ERR, "Can't lower privileges");
1169
paul718e3742002-12-13 20:15:29 +00001170 if (status < 0)
1171 {
1172 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
paul7021c422003-07-15 12:52:22 +00001173 strerror (errno));
paul718e3742002-12-13 20:15:29 +00001174 return -1;
1175 }
paul7021c422003-07-15 12:52:22 +00001176
paul718e3742002-12-13 20:15:29 +00001177 /*
1178 * Change socket flags for blocking I/O.
1179 * This ensures we wait for a reply in netlink_parse_info().
1180 */
paul7021c422003-07-15 12:52:22 +00001181 snb_ret = set_netlink_blocking (nl, &flags);
1182 if (snb_ret < 0)
1183 zlog (NULL, LOG_WARNING,
1184 "%s:%i Warning: Could not set netlink socket to blocking.",
1185 __FUNCTION__, __LINE__);
paul718e3742002-12-13 20:15:29 +00001186
1187 /*
1188 * Get reply from netlink socket.
1189 * The reply should either be an acknowlegement or an error.
1190 */
1191 status = netlink_parse_info (netlink_talk_filter, nl);
paul7021c422003-07-15 12:52:22 +00001192
paul718e3742002-12-13 20:15:29 +00001193 /* Restore socket flags for nonblocking I/O */
paul7021c422003-07-15 12:52:22 +00001194 if (snb_ret == 0)
1195 set_netlink_nonblocking (nl, &flags);
1196
paul718e3742002-12-13 20:15:29 +00001197 return status;
1198}
1199
1200/* Routing table change via netlink interface. */
1201int
1202netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001203 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001204{
1205 int ret;
1206 int bytelen;
1207 struct sockaddr_nl snl;
1208 int discard;
1209
paul7021c422003-07-15 12:52:22 +00001210 struct
paul718e3742002-12-13 20:15:29 +00001211 {
1212 struct nlmsghdr n;
1213 struct rtmsg r;
1214 char buf[1024];
1215 } req;
1216
1217 memset (&req, 0, sizeof req);
1218
1219 bytelen = (family == AF_INET ? 4 : 16);
1220
1221 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1222 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1223 req.n.nlmsg_type = cmd;
1224 req.r.rtm_family = family;
1225 req.r.rtm_table = table;
1226 req.r.rtm_dst_len = length;
1227
hasso81dfcaa2003-05-25 19:21:25 +00001228 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1229 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001230 discard = 1;
1231 else
1232 discard = 0;
1233
paul7021c422003-07-15 12:52:22 +00001234 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001235 {
1236 req.r.rtm_protocol = RTPROT_ZEBRA;
1237 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1238
paul7021c422003-07-15 12:52:22 +00001239 if (discard)
paul595db7f2003-05-25 21:35:06 +00001240 {
1241 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1242 req.r.rtm_type = RTN_BLACKHOLE;
1243 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1244 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001245 else
1246 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1247 }
paul595db7f2003-05-25 21:35:06 +00001248 else
paul7021c422003-07-15 12:52:22 +00001249 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001250 }
1251
1252 if (dest)
1253 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1254
paul7021c422003-07-15 12:52:22 +00001255 if (!discard)
paul718e3742002-12-13 20:15:29 +00001256 {
1257 if (gate)
paul7021c422003-07-15 12:52:22 +00001258 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001259 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001260 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001261 }
1262
1263 /* Destination netlink address. */
1264 memset (&snl, 0, sizeof snl);
1265 snl.nl_family = AF_NETLINK;
1266
1267 /* Talk to netlink socket. */
1268 ret = netlink_talk (&req.n, &netlink);
1269 if (ret < 0)
1270 return -1;
1271
1272 return 0;
1273}
1274
1275/* Routing table change via netlink interface. */
1276int
1277netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001278 int family)
paul718e3742002-12-13 20:15:29 +00001279{
1280 int bytelen;
1281 struct sockaddr_nl snl;
1282 struct nexthop *nexthop = NULL;
1283 int nexthop_num = 0;
1284 struct nlsock *nl;
1285 int discard;
1286
paul7021c422003-07-15 12:52:22 +00001287 struct
paul718e3742002-12-13 20:15:29 +00001288 {
1289 struct nlmsghdr n;
1290 struct rtmsg r;
1291 char buf[1024];
1292 } req;
1293
1294 memset (&req, 0, sizeof req);
1295
1296 bytelen = (family == AF_INET ? 4 : 16);
1297
1298 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1299 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1300 req.n.nlmsg_type = cmd;
1301 req.r.rtm_family = family;
1302 req.r.rtm_table = rib->table;
1303 req.r.rtm_dst_len = p->prefixlen;
1304
paul13766da2003-02-07 14:46:23 +00001305#ifdef RTM_F_EQUALIZE
1306 req.r.rtm_flags |= RTM_F_EQUALIZE;
1307#endif /* RTM_F_EQUALIZE */
1308
paul7021c422003-07-15 12:52:22 +00001309 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001310 discard = 1;
1311 else
1312 discard = 0;
1313
paul7021c422003-07-15 12:52:22 +00001314 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001315 {
1316 req.r.rtm_protocol = RTPROT_ZEBRA;
1317 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1318
paul7021c422003-07-15 12:52:22 +00001319 if (discard)
paul595db7f2003-05-25 21:35:06 +00001320 {
1321 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1322 req.r.rtm_type = RTN_BLACKHOLE;
1323 else if (rib->flags & ZEBRA_FLAG_REJECT)
1324 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001325 else
1326 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1327 }
paul595db7f2003-05-25 21:35:06 +00001328 else
paul7021c422003-07-15 12:52:22 +00001329 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001330 }
1331
1332 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1333
1334 /* Metric. */
1335 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1336
1337 if (discard)
1338 {
1339 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001340 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1341 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001342 goto skip;
1343 }
1344
1345 /* Multipath case. */
1346 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1347 {
1348 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001349 {
paul5ec90d22003-06-19 01:41:37 +00001350
paul7021c422003-07-15 12:52:22 +00001351 if ((cmd == RTM_NEWROUTE
1352 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1353 || (cmd == RTM_DELROUTE
1354 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1355 {
paul5ec90d22003-06-19 01:41:37 +00001356
paul7021c422003-07-15 12:52:22 +00001357 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1358 {
1359 if (IS_ZEBRA_DEBUG_KERNEL)
1360 {
1361 zlog_info
1362 ("netlink_route_multipath() (recursive, 1 hop): "
1363 "%s %s/%d via %s if %u, type %s",
1364 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1365 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1366 nexthop->rifindex,
1367 nexthop_types_desc[nexthop->rtype]);
1368 }
paul5ec90d22003-06-19 01:41:37 +00001369
paul7021c422003-07-15 12:52:22 +00001370 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1371 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1372 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1373 &nexthop->rgate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001374#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001375 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1376 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1377 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1378 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1379 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001380#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001381 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1382 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1383 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1384 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1385 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1386 addattr32 (&req.n, sizeof req, RTA_OIF,
1387 nexthop->rifindex);
1388 }
1389 else
1390 {
1391 if (IS_ZEBRA_DEBUG_KERNEL)
1392 {
1393 zlog_info
1394 ("netlink_route_multipath(): (single hop)"
1395 "%s %s/%d via %s if %u, type %s",
1396 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1397 p->prefixlen, inet_ntoa (nexthop->gate.ipv4),
1398 nexthop->ifindex,
1399 nexthop_types_desc[nexthop->type]);
1400 }
paul5ec90d22003-06-19 01:41:37 +00001401
paul7021c422003-07-15 12:52:22 +00001402 if (nexthop->type == NEXTHOP_TYPE_IPV4
1403 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1404 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1405 &nexthop->gate.ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001406#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001407 if (nexthop->type == NEXTHOP_TYPE_IPV6
1408 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1409 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1410 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1411 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001412#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001413 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1414 || nexthop->type == NEXTHOP_TYPE_IFNAME
1415 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1416 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1417 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1418 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1419 }
paul718e3742002-12-13 20:15:29 +00001420
paul7021c422003-07-15 12:52:22 +00001421 if (cmd == RTM_NEWROUTE)
1422 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001423
paul7021c422003-07-15 12:52:22 +00001424 nexthop_num++;
1425 break;
1426 }
1427 }
paul718e3742002-12-13 20:15:29 +00001428 }
1429 else
1430 {
1431 char buf[1024];
1432 struct rtattr *rta = (void *) buf;
1433 struct rtnexthop *rtnh;
1434
1435 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001436 rta->rta_len = RTA_LENGTH (0);
1437 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001438
1439 nexthop_num = 0;
1440 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001441 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1442 nexthop = nexthop->next)
1443 {
1444 if ((cmd == RTM_NEWROUTE
1445 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1446 || (cmd == RTM_DELROUTE
1447 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1448 {
1449 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001450
paul7021c422003-07-15 12:52:22 +00001451 rtnh->rtnh_len = sizeof (*rtnh);
1452 rtnh->rtnh_flags = 0;
1453 rtnh->rtnh_hops = 0;
1454 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001455
paul7021c422003-07-15 12:52:22 +00001456 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1457 {
1458 if (IS_ZEBRA_DEBUG_KERNEL)
1459 {
1460 zlog_info ("netlink_route_multipath() "
1461 "(recursive, multihop): "
1462 "%s %s/%d via %s if %u, type %s",
1463 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1464 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1465 nexthop->rifindex,
1466 nexthop_types_desc[nexthop->type]);
1467 }
1468 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1469 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1470 {
1471 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1472 &nexthop->rgate.ipv4, bytelen);
1473 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1474 }
paul718e3742002-12-13 20:15:29 +00001475#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001476 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1477 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1478 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
1479 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1480 &nexthop->rgate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001481#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001482 /* ifindex */
1483 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1484 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1485 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1486 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1487 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
1488 rtnh->rtnh_ifindex = nexthop->rifindex;
1489 else
1490 rtnh->rtnh_ifindex = 0;
1491 }
1492 else
1493 {
1494 if (IS_ZEBRA_DEBUG_KERNEL)
1495 {
1496 zlog_info ("netlink_route_multipath() "
1497 "(multihop): "
1498 "%s %s/%d via %s if %u, type %s",
1499 lookup (nlmsg_str, cmd), inet_ntoa (p->u.prefix4),
1500 p->prefixlen, inet_ntoa (nexthop->rgate.ipv4),
1501 nexthop->rifindex,
1502 nexthop_types_desc[nexthop->type]);
1503 }
1504 if (nexthop->type == NEXTHOP_TYPE_IPV4
1505 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1506 {
1507 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1508 &nexthop->gate.ipv4, bytelen);
1509 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1510 }
paul718e3742002-12-13 20:15:29 +00001511#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001512 if (nexthop->type == NEXTHOP_TYPE_IPV6
1513 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1514 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1515 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1516 &nexthop->gate.ipv6, bytelen);
paul718e3742002-12-13 20:15:29 +00001517#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001518 /* ifindex */
1519 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1520 || nexthop->type == NEXTHOP_TYPE_IFNAME
1521 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1522 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1523 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1524 rtnh->rtnh_ifindex = nexthop->ifindex;
1525 else
1526 rtnh->rtnh_ifindex = 0;
1527 }
1528 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001529
paul7021c422003-07-15 12:52:22 +00001530 if (cmd == RTM_NEWROUTE)
1531 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1532 }
1533 }
paul718e3742002-12-13 20:15:29 +00001534
1535 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001536 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1537 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001538 }
1539
1540 /* If there is no useful nexthop then return. */
1541 if (nexthop_num == 0)
1542 {
1543 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001544 zlog_info ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001545 return 0;
1546 }
1547
paul7021c422003-07-15 12:52:22 +00001548skip:
paul718e3742002-12-13 20:15:29 +00001549
1550 /* Destination netlink address. */
1551 memset (&snl, 0, sizeof snl);
1552 snl.nl_family = AF_NETLINK;
1553
1554 if (family == AF_INET)
1555 nl = &netlink_cmd;
1556 else
1557 nl = &netlink;
1558
1559 /* Talk to netlink socket. */
1560 return netlink_talk (&req.n, nl);
1561}
1562
1563int
1564kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1565{
1566 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1567}
1568
1569int
1570kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1571{
1572 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1573}
1574
1575#ifdef HAVE_IPV6
1576int
1577kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1578{
1579 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1580}
1581
1582int
1583kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1584{
1585 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1586}
1587
1588/* Delete IPv6 route from the kernel. */
1589int
1590kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul7021c422003-07-15 12:52:22 +00001591 int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001592{
paul7021c422003-07-15 12:52:22 +00001593 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1594 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001595}
1596#endif /* HAVE_IPV6 */
1597
1598/* Interface address modification. */
1599int
1600netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001601 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001602{
1603 int bytelen;
1604 struct prefix *p;
1605
paul7021c422003-07-15 12:52:22 +00001606 struct
paul718e3742002-12-13 20:15:29 +00001607 {
1608 struct nlmsghdr n;
1609 struct ifaddrmsg ifa;
1610 char buf[1024];
1611 } req;
1612
1613 p = ifc->address;
1614 memset (&req, 0, sizeof req);
1615
1616 bytelen = (family == AF_INET ? 4 : 16);
1617
paul7021c422003-07-15 12:52:22 +00001618 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001619 req.n.nlmsg_flags = NLM_F_REQUEST;
1620 req.n.nlmsg_type = cmd;
1621 req.ifa.ifa_family = family;
1622
1623 req.ifa.ifa_index = ifp->ifindex;
1624 req.ifa.ifa_prefixlen = p->prefixlen;
1625
1626 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1627
1628 if (family == AF_INET && cmd == RTM_NEWADDR)
1629 {
1630 if (if_is_broadcast (ifp) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001631 {
1632 p = ifc->destination;
1633 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1634 bytelen);
1635 }
paul718e3742002-12-13 20:15:29 +00001636 }
1637
1638 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1639 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001640
paul718e3742002-12-13 20:15:29 +00001641 if (ifc->label)
1642 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001643 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001644
1645 return netlink_talk (&req.n, &netlink_cmd);
1646}
1647
1648int
1649kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1650{
1651 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1652}
1653
1654int
1655kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1656{
1657 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1658}
1659
paul718e3742002-12-13 20:15:29 +00001660
1661extern struct thread_master *master;
1662
1663/* Kernel route reflection. */
1664int
1665kernel_read (struct thread *thread)
1666{
1667 int ret;
1668 int sock;
1669
1670 sock = THREAD_FD (thread);
1671 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001672 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001673
1674 return 0;
1675}
1676
1677/* Exported interface function. This function simply calls
1678 netlink_socket (). */
1679void
1680kernel_init ()
1681{
1682 unsigned long groups;
1683
paul7021c422003-07-15 12:52:22 +00001684 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001685#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001686 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001687#endif /* HAVE_IPV6 */
1688 netlink_socket (&netlink, groups);
1689 netlink_socket (&netlink_cmd, 0);
1690
1691 /* Register kernel socket. */
1692 if (netlink.sock > 0)
paulb21b19c2003-06-15 01:28:29 +00001693 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001694}