blob: eb9eae3aab0ac5b1a70cf8ae62b4855f9693b87b [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"
paul6621ca82005-11-23 13:02:08 +000040#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000041#include "zebra/redistribute.h"
42#include "zebra/interface.h"
43#include "zebra/debug.h"
44
45/* Socket interface to kernel */
46struct nlsock
47{
48 int sock;
49 int seq;
50 struct sockaddr_nl snl;
hassofce954f2004-10-07 20:29:24 +000051 const char *name;
paul7021c422003-07-15 12:52:22 +000052} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
hasso1ada8192005-06-12 11:28:18 +000053 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
paul718e3742002-12-13 20:15:29 +000054
Stephen Hemminger1423c802008-08-14 17:59:25 +010055static const struct 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
Stephen Hemminger6072b242008-08-14 16:52:26 +010068static const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000069{
70 "none",
71 "Directly connected",
72 "Interface route",
73 "IPv4 nexthop",
74 "IPv4 nexthop with ifindex",
75 "IPv4 nexthop with ifname",
hassofa599802005-04-09 16:59:28 +000076 "IPv6 nexthop",
paul7021c422003-07-15 12:52:22 +000077 "IPv6 nexthop with ifindex",
78 "IPv6 nexthop with ifname",
79 "Null0 nexthop",
80};
81
paulb21b19c2003-06-15 01:28:29 +000082extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000083
pauledd7c242003-06-04 13:59:38 +000084extern struct zebra_privs_t zserv_privs;
85
hassoc34b6b52004-08-31 13:41:49 +000086extern u_int32_t nl_rcvbufsize;
87
ajsd2fc8892005-04-02 18:38:43 +000088/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
89 names and ifindex values. */
90static void
91set_ifindex(struct interface *ifp, unsigned int ifi_index)
92{
93 struct interface *oifp;
94
95 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
96 {
97 if (ifi_index == IFINDEX_INTERNAL)
98 zlog_err("Netlink is setting interface %s ifindex to reserved "
99 "internal value %u", ifp->name, ifi_index);
100 else
101 {
102 if (IS_ZEBRA_DEBUG_KERNEL)
103 zlog_debug("interface index %d was renamed from %s to %s",
104 ifi_index, oifp->name, ifp->name);
105 if (if_is_up(oifp))
106 zlog_err("interface rename detected on up interface: index %d "
107 "was renamed from %s to %s, results are uncertain!",
108 ifi_index, oifp->name, ifp->name);
109 if_delete_update(oifp);
110 }
111 }
112 ifp->ifindex = ifi_index;
113}
114
Stephen Hemminger30afea32008-08-16 18:25:47 +0100115static int
116netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
117{
118 u_int32_t oldsize;
119 socklen_t newlen = sizeof(newsize);
120 socklen_t oldlen = sizeof(oldsize);
121 int ret;
122
123 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
124 if (ret < 0)
125 {
126 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
127 safe_strerror (errno));
128 return -1;
129 }
130
131 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
132 sizeof(nl_rcvbufsize));
133 if (ret < 0)
134 {
135 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
136 safe_strerror (errno));
137 return -1;
138 }
139
140 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
141 if (ret < 0)
142 {
143 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
144 safe_strerror (errno));
145 return -1;
146 }
147
148 zlog (NULL, LOG_INFO,
149 "Setting netlink socket receive buffer size: %u -> %u",
150 oldsize, newsize);
151 return 0;
152}
153
paul718e3742002-12-13 20:15:29 +0000154/* Make socket for Linux netlink interface. */
155static int
156netlink_socket (struct nlsock *nl, unsigned long groups)
157{
158 int ret;
159 struct sockaddr_nl snl;
160 int sock;
161 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000162 int save_errno;
paul718e3742002-12-13 20:15:29 +0000163
164 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
165 if (sock < 0)
166 {
167 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000168 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000169 return -1;
170 }
171
paul718e3742002-12-13 20:15:29 +0000172 memset (&snl, 0, sizeof snl);
173 snl.nl_family = AF_NETLINK;
174 snl.nl_groups = groups;
175
176 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000177 if (zserv_privs.change (ZPRIVS_RAISE))
178 {
179 zlog (NULL, LOG_ERR, "Can't raise privileges");
180 return -1;
181 }
pauledd7c242003-06-04 13:59:38 +0000182
paul718e3742002-12-13 20:15:29 +0000183 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000184 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000185 if (zserv_privs.change (ZPRIVS_LOWER))
186 zlog (NULL, LOG_ERR, "Can't lower privileges");
187
paul718e3742002-12-13 20:15:29 +0000188 if (ret < 0)
189 {
paul7021c422003-07-15 12:52:22 +0000190 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000191 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000192 close (sock);
193 return -1;
194 }
paul7021c422003-07-15 12:52:22 +0000195
paul718e3742002-12-13 20:15:29 +0000196 /* multiple netlink sockets will have different nl_pid */
197 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000198 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000199 if (ret < 0 || namelen != sizeof snl)
200 {
201 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000202 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000203 close (sock);
204 return -1;
205 }
206
207 nl->snl = snl;
208 nl->sock = sock;
209 return ret;
210}
211
212/* Get type specified information from netlink. */
213static int
214netlink_request (int family, int type, struct nlsock *nl)
215{
216 int ret;
217 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000218 int save_errno;
paul718e3742002-12-13 20:15:29 +0000219
220 struct
221 {
222 struct nlmsghdr nlh;
223 struct rtgenmsg g;
224 } req;
225
226
227 /* Check netlink socket. */
228 if (nl->sock < 0)
229 {
230 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
231 return -1;
232 }
233
234 memset (&snl, 0, sizeof snl);
235 snl.nl_family = AF_NETLINK;
236
ajsc05612b2005-10-01 16:36:54 +0000237 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000238 req.nlh.nlmsg_len = sizeof req;
239 req.nlh.nlmsg_type = type;
240 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100241 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000242 req.nlh.nlmsg_seq = ++nl->seq;
243 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000244
245 /* linux appears to check capabilities on every message
246 * have to raise caps for every message sent
247 */
paul7021c422003-07-15 12:52:22 +0000248 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000249 {
250 zlog (NULL, LOG_ERR, "Can't raise privileges");
251 return -1;
252 }
paul7021c422003-07-15 12:52:22 +0000253
254 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
255 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000256 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000257
258 if (zserv_privs.change (ZPRIVS_LOWER))
259 zlog (NULL, LOG_ERR, "Can't lower privileges");
260
paul718e3742002-12-13 20:15:29 +0000261 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000262 {
263 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000264 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000265 return -1;
266 }
pauledd7c242003-06-04 13:59:38 +0000267
paul718e3742002-12-13 20:15:29 +0000268 return 0;
269}
270
271/* Receive message from netlink interface and pass those information
272 to the given function. */
273static int
274netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000275 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000276{
277 int status;
278 int ret = 0;
279 int error;
280
281 while (1)
282 {
283 char buf[4096];
284 struct iovec iov = { buf, sizeof buf };
285 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000286 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000287 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000288
paul718e3742002-12-13 20:15:29 +0000289 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000290 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000291 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100292 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000293 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100294 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000295 break;
ajs4be019d2005-01-29 16:12:41 +0000296 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100297 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000298 continue;
299 }
paul718e3742002-12-13 20:15:29 +0000300
301 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000302 {
303 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
304 return -1;
305 }
paul718e3742002-12-13 20:15:29 +0000306
307 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000308 {
309 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
310 nl->name, msg.msg_namelen);
311 return -1;
312 }
paulb84d3a12003-11-17 10:31:01 +0000313
hasso206d8052005-04-09 16:38:51 +0000314 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000315 h = NLMSG_NEXT (h, status))
316 {
317 /* Finish of reading. */
318 if (h->nlmsg_type == NLMSG_DONE)
319 return ret;
paul718e3742002-12-13 20:15:29 +0000320
paul7021c422003-07-15 12:52:22 +0000321 /* Error handling. */
322 if (h->nlmsg_type == NLMSG_ERROR)
323 {
324 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100325 int errnum = err->error;
326 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000327
paul718e3742002-12-13 20:15:29 +0000328 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000329 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000330 {
paul7021c422003-07-15 12:52:22 +0000331 if (IS_ZEBRA_DEBUG_KERNEL)
332 {
hasso1ada8192005-06-12 11:28:18 +0000333 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000334 __FUNCTION__, nl->name,
335 lookup (nlmsg_str, err->msg.nlmsg_type),
336 err->msg.nlmsg_type, err->msg.nlmsg_seq,
337 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000338 }
paul7021c422003-07-15 12:52:22 +0000339
340 /* return if not a multipart message, otherwise continue */
341 if (!(h->nlmsg_flags & NLM_F_MULTI))
342 {
343 return 0;
paul718e3742002-12-13 20:15:29 +0000344 }
paul7021c422003-07-15 12:52:22 +0000345 continue;
paul718e3742002-12-13 20:15:29 +0000346 }
paul7021c422003-07-15 12:52:22 +0000347
paul718e3742002-12-13 20:15:29 +0000348 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000349 {
350 zlog (NULL, LOG_ERR, "%s error: message truncated",
351 nl->name);
352 return -1;
353 }
pauld753e9e2003-01-22 19:45:50 +0000354
Stephen Hemminger898987e2008-08-17 16:56:15 +0100355 /* Deal with errors that occur because of races in link handling */
356 if (nl == &netlink_cmd
357 && ((msg_type == RTM_DELROUTE &&
358 (-errnum == ENODEV || -errnum == ESRCH))
359 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
360 {
361 if (IS_ZEBRA_DEBUG_KERNEL)
362 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
363 nl->name, safe_strerror (-errnum),
364 lookup (nlmsg_str, msg_type),
365 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
366 return 0;
367 }
paul718e3742002-12-13 20:15:29 +0000368
Stephen Hemminger898987e2008-08-17 16:56:15 +0100369 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
370 nl->name, safe_strerror (-errnum),
371 lookup (nlmsg_str, msg_type),
372 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000373 return -1;
374 }
paul718e3742002-12-13 20:15:29 +0000375
paul7021c422003-07-15 12:52:22 +0000376 /* OK we got netlink message. */
377 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000378 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000379 nl->name,
380 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
381 h->nlmsg_seq, h->nlmsg_pid);
382
383 /* skip unsolicited messages originating from command socket */
384 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
385 {
386 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000387 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000388 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000389 continue;
390 }
391
392 error = (*filter) (&snl, h);
393 if (error < 0)
394 {
395 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
396 ret = error;
397 }
398 }
paul718e3742002-12-13 20:15:29 +0000399
400 /* After error care. */
401 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000402 {
403 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
404 continue;
405 }
paul718e3742002-12-13 20:15:29 +0000406 if (status)
paul7021c422003-07-15 12:52:22 +0000407 {
408 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
409 status);
410 return -1;
411 }
paul718e3742002-12-13 20:15:29 +0000412 }
413 return ret;
414}
415
416/* Utility function for parse rtattr. */
417static void
paul7021c422003-07-15 12:52:22 +0000418netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
419 int len)
paul718e3742002-12-13 20:15:29 +0000420{
paul7021c422003-07-15 12:52:22 +0000421 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000422 {
423 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000424 tb[rta->rta_type] = rta;
425 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000426 }
427}
428
429/* Called from interface_lookup_netlink(). This function is only used
430 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100431static int
paul718e3742002-12-13 20:15:29 +0000432netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
433{
434 int len;
435 struct ifinfomsg *ifi;
436 struct rtattr *tb[IFLA_MAX + 1];
437 struct interface *ifp;
438 char *name;
439 int i;
440
441 ifi = NLMSG_DATA (h);
442
443 if (h->nlmsg_type != RTM_NEWLINK)
444 return 0;
445
446 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
447 if (len < 0)
448 return -1;
449
450 /* Looking up interface name. */
451 memset (tb, 0, sizeof tb);
452 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000453
paul1e193152005-02-14 23:53:05 +0000454#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000455 /* check for wireless messages to ignore */
456 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
457 {
458 if (IS_ZEBRA_DEBUG_KERNEL)
459 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
460 return 0;
461 }
paul1e193152005-02-14 23:53:05 +0000462#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000463
paul718e3742002-12-13 20:15:29 +0000464 if (tb[IFLA_IFNAME] == NULL)
465 return -1;
paul7021c422003-07-15 12:52:22 +0000466 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000467
468 /* Add interface. */
469 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000470 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000471 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800472 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000473 ifp->metric = 1;
474
475 /* Hardware type and address. */
476 ifp->hw_type = ifi->ifi_type;
477
478 if (tb[IFLA_ADDRESS])
479 {
480 int hw_addr_len;
481
paul7021c422003-07-15 12:52:22 +0000482 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000483
484 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000485 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000486 else
paul7021c422003-07-15 12:52:22 +0000487 {
488 ifp->hw_addr_len = hw_addr_len;
489 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000490
paul7021c422003-07-15 12:52:22 +0000491 for (i = 0; i < hw_addr_len; i++)
492 if (ifp->hw_addr[i] != 0)
493 break;
paul718e3742002-12-13 20:15:29 +0000494
paul7021c422003-07-15 12:52:22 +0000495 if (i == hw_addr_len)
496 ifp->hw_addr_len = 0;
497 else
498 ifp->hw_addr_len = hw_addr_len;
499 }
paul718e3742002-12-13 20:15:29 +0000500 }
501
502 if_add_update (ifp);
503
504 return 0;
505}
506
507/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100508static int
paul718e3742002-12-13 20:15:29 +0000509netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
510{
511 int len;
512 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000513 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000514 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000515 void *addr;
516 void *broad;
paul718e3742002-12-13 20:15:29 +0000517 u_char flags = 0;
518 char *label = NULL;
519
520 ifa = NLMSG_DATA (h);
521
paul7021c422003-07-15 12:52:22 +0000522 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000523#ifdef HAVE_IPV6
524 && ifa->ifa_family != AF_INET6
525#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000526 )
paul718e3742002-12-13 20:15:29 +0000527 return 0;
528
529 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
530 return 0;
531
paul7021c422003-07-15 12:52:22 +0000532 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000533 if (len < 0)
534 return -1;
535
536 memset (tb, 0, sizeof tb);
537 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
538
539 ifp = if_lookup_by_index (ifa->ifa_index);
540 if (ifp == NULL)
541 {
542 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000543 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000544 return -1;
545 }
546
paul7021c422003-07-15 12:52:22 +0000547 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000548 {
paul00df0c12002-12-13 21:07:36 +0000549 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000550 zlog_debug ("netlink_interface_addr %s %s:",
551 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000552 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000553 zlog_debug (" IFA_LOCAL %s/%d",
554 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
555 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000556 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000557 zlog_debug (" IFA_ADDRESS %s/%d",
558 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
559 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000560 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000561 zlog_debug (" IFA_BROADCAST %s/%d",
562 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
563 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000564 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000565 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000566
567 if (tb[IFA_CACHEINFO])
568 {
569 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
570 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
571 ci->ifa_prefered, ci->ifa_valid);
572 }
paul718e3742002-12-13 20:15:29 +0000573 }
paul31a476c2003-09-29 19:54:53 +0000574
Andrew J. Schorre4529632006-12-12 19:18:21 +0000575 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
576 if (tb[IFA_LOCAL] == NULL)
577 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000578 if (tb[IFA_ADDRESS] == NULL)
579 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
580
Andrew J. Schorre4529632006-12-12 19:18:21 +0000581 /* local interface address */
582 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
583
584 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000585 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000586 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000587 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000588 broad = RTA_DATA(tb[IFA_ADDRESS]);
589 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000590 }
paul31a476c2003-09-29 19:54:53 +0000591 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000592 /* seeking a broadcast address */
593 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000594
Paul Jakma27b47252006-07-02 16:38:54 +0000595 /* addr is primary key, SOL if we don't have one */
596 if (addr == NULL)
597 {
598 zlog_debug ("%s: NULL address", __func__);
599 return -1;
600 }
601
paul718e3742002-12-13 20:15:29 +0000602 /* Flags. */
603 if (ifa->ifa_flags & IFA_F_SECONDARY)
604 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
605
606 /* Label */
607 if (tb[IFA_LABEL])
608 label = (char *) RTA_DATA (tb[IFA_LABEL]);
609
610 if (ifp && label && strcmp (ifp->name, label) == 0)
611 label = NULL;
612
613 /* Register interface address to the interface. */
614 if (ifa->ifa_family == AF_INET)
615 {
paul7021c422003-07-15 12:52:22 +0000616 if (h->nlmsg_type == RTM_NEWADDR)
617 connected_add_ipv4 (ifp, flags,
618 (struct in_addr *) addr, ifa->ifa_prefixlen,
619 (struct in_addr *) broad, label);
620 else
621 connected_delete_ipv4 (ifp, flags,
622 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000623 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000624 }
625#ifdef HAVE_IPV6
626 if (ifa->ifa_family == AF_INET6)
627 {
628 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000629 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000630 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000631 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000632 else
paul7021c422003-07-15 12:52:22 +0000633 connected_delete_ipv6 (ifp,
634 (struct in6_addr *) addr, ifa->ifa_prefixlen,
635 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000636 }
paul7021c422003-07-15 12:52:22 +0000637#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000638
639 return 0;
640}
641
642/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100643static int
paul718e3742002-12-13 20:15:29 +0000644netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
645{
646 int len;
647 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000648 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000649 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000650
651 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000652
653 int index;
654 int table;
hasso34195bf2004-04-06 12:07:06 +0000655 int metric;
656
paul718e3742002-12-13 20:15:29 +0000657 void *dest;
658 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000659 void *src;
paul718e3742002-12-13 20:15:29 +0000660
661 rtm = NLMSG_DATA (h);
662
663 if (h->nlmsg_type != RTM_NEWROUTE)
664 return 0;
665 if (rtm->rtm_type != RTN_UNICAST)
666 return 0;
667
668 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000669#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000670 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000671 return 0;
672#endif
673
paul7021c422003-07-15 12:52:22 +0000674 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000675 if (len < 0)
676 return -1;
677
678 memset (tb, 0, sizeof tb);
679 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
680
681 if (rtm->rtm_flags & RTM_F_CLONED)
682 return 0;
683 if (rtm->rtm_protocol == RTPROT_REDIRECT)
684 return 0;
685 if (rtm->rtm_protocol == RTPROT_KERNEL)
686 return 0;
687
688 if (rtm->rtm_src_len != 0)
689 return 0;
690
691 /* Route which inserted by Zebra. */
692 if (rtm->rtm_protocol == RTPROT_ZEBRA)
693 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000694
paul718e3742002-12-13 20:15:29 +0000695 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000696 metric = 0;
paul718e3742002-12-13 20:15:29 +0000697 dest = NULL;
698 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000699 src = NULL;
paul718e3742002-12-13 20:15:29 +0000700
701 if (tb[RTA_OIF])
702 index = *(int *) RTA_DATA (tb[RTA_OIF]);
703
704 if (tb[RTA_DST])
705 dest = RTA_DATA (tb[RTA_DST]);
706 else
707 dest = anyaddr;
708
Paul Jakma7514fb72007-05-02 16:05:35 +0000709 if (tb[RTA_PREFSRC])
710 src = RTA_DATA (tb[RTA_PREFSRC]);
711
paul718e3742002-12-13 20:15:29 +0000712 /* Multipath treatment is needed. */
713 if (tb[RTA_GATEWAY])
714 gate = RTA_DATA (tb[RTA_GATEWAY]);
715
hasso34195bf2004-04-06 12:07:06 +0000716 if (tb[RTA_PRIORITY])
717 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
718
paul718e3742002-12-13 20:15:29 +0000719 if (rtm->rtm_family == AF_INET)
720 {
721 struct prefix_ipv4 p;
722 p.family = AF_INET;
723 memcpy (&p.prefix, dest, 4);
724 p.prefixlen = rtm->rtm_dst_len;
725
Paul Jakma7514fb72007-05-02 16:05:35 +0000726 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000727 }
728#ifdef HAVE_IPV6
729 if (rtm->rtm_family == AF_INET6)
730 {
731 struct prefix_ipv6 p;
732 p.family = AF_INET6;
733 memcpy (&p.prefix, dest, 16);
734 p.prefixlen = rtm->rtm_dst_len;
735
hassobe61c4e2005-08-27 06:05:47 +0000736 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
737 metric, 0);
paul718e3742002-12-13 20:15:29 +0000738 }
739#endif /* HAVE_IPV6 */
740
741 return 0;
742}
743
Stephen Hemminger1423c802008-08-14 17:59:25 +0100744static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000745 {RTPROT_REDIRECT, "redirect"},
746 {RTPROT_KERNEL, "kernel"},
747 {RTPROT_BOOT, "boot"},
748 {RTPROT_STATIC, "static"},
749 {RTPROT_GATED, "GateD"},
750 {RTPROT_RA, "router advertisement"},
751 {RTPROT_MRT, "MRT"},
752 {RTPROT_ZEBRA, "Zebra"},
753#ifdef RTPROT_BIRD
754 {RTPROT_BIRD, "BIRD"},
755#endif /* RTPROT_BIRD */
756 {0, NULL}
757};
758
759/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100760static int
paul718e3742002-12-13 20:15:29 +0000761netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
762{
763 int len;
764 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000765 struct rtattr *tb[RTA_MAX + 1];
766
767 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000768
769 int index;
770 int table;
Dmitry Popov83d16142011-09-11 13:48:25 +0400771 int metric;
772
paul718e3742002-12-13 20:15:29 +0000773 void *dest;
774 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000775 void *src;
paul718e3742002-12-13 20:15:29 +0000776
777 rtm = NLMSG_DATA (h);
778
paul7021c422003-07-15 12:52:22 +0000779 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000780 {
781 /* If this is not route add/delete message print warning. */
782 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
783 return 0;
784 }
785
786 /* Connected route. */
787 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000788 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000789 h->nlmsg_type ==
790 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
791 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
792 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
793 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000794
795 if (rtm->rtm_type != RTN_UNICAST)
796 {
797 return 0;
798 }
799
800 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000801 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000802 {
803 return 0;
804 }
805
paul7021c422003-07-15 12:52:22 +0000806 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000807 if (len < 0)
808 return -1;
809
810 memset (tb, 0, sizeof tb);
811 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
812
813 if (rtm->rtm_flags & RTM_F_CLONED)
814 return 0;
815 if (rtm->rtm_protocol == RTPROT_REDIRECT)
816 return 0;
817 if (rtm->rtm_protocol == RTPROT_KERNEL)
818 return 0;
819
820 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
821 return 0;
822
823 if (rtm->rtm_src_len != 0)
824 {
825 zlog_warn ("netlink_route_change(): no src len");
826 return 0;
827 }
paul7021c422003-07-15 12:52:22 +0000828
paul718e3742002-12-13 20:15:29 +0000829 index = 0;
Dmitry Popov83d16142011-09-11 13:48:25 +0400830 metric = 0;
paul718e3742002-12-13 20:15:29 +0000831 dest = NULL;
832 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000833 src = NULL;
paul718e3742002-12-13 20:15:29 +0000834
835 if (tb[RTA_OIF])
836 index = *(int *) RTA_DATA (tb[RTA_OIF]);
837
838 if (tb[RTA_DST])
839 dest = RTA_DATA (tb[RTA_DST]);
840 else
841 dest = anyaddr;
842
843 if (tb[RTA_GATEWAY])
844 gate = RTA_DATA (tb[RTA_GATEWAY]);
845
Paul Jakma7514fb72007-05-02 16:05:35 +0000846 if (tb[RTA_PREFSRC])
847 src = RTA_DATA (tb[RTA_PREFSRC]);
848
Dmitry Popov83d16142011-09-11 13:48:25 +0400849 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
850 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
851
paul718e3742002-12-13 20:15:29 +0000852 if (rtm->rtm_family == AF_INET)
853 {
854 struct prefix_ipv4 p;
855 p.family = AF_INET;
856 memcpy (&p.prefix, dest, 4);
857 p.prefixlen = rtm->rtm_dst_len;
858
859 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000860 {
861 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000862 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000863 inet_ntoa (p.prefix), p.prefixlen);
864 else
ajsb6178002004-12-07 21:12:56 +0000865 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000866 inet_ntoa (p.prefix), p.prefixlen);
867 }
paul718e3742002-12-13 20:15:29 +0000868
869 if (h->nlmsg_type == RTM_NEWROUTE)
Dmitry Popov83d16142011-09-11 13:48:25 +0400870 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000871 else
paul7021c422003-07-15 12:52:22 +0000872 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000873 }
874
875#ifdef HAVE_IPV6
876 if (rtm->rtm_family == AF_INET6)
877 {
878 struct prefix_ipv6 p;
879 char buf[BUFSIZ];
880
881 p.family = AF_INET6;
882 memcpy (&p.prefix, dest, 16);
883 p.prefixlen = rtm->rtm_dst_len;
884
885 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000886 {
887 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000888 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000889 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
890 p.prefixlen);
891 else
ajsb6178002004-12-07 21:12:56 +0000892 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000893 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
894 p.prefixlen);
895 }
paul718e3742002-12-13 20:15:29 +0000896
897 if (h->nlmsg_type == RTM_NEWROUTE)
Dmitry Popov83d16142011-09-11 13:48:25 +0400898 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000899 else
Mathieu Goessensd13c3b42009-06-23 15:59:45 +0100900 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000901 }
902#endif /* HAVE_IPV6 */
903
904 return 0;
905}
906
Stephen Hemminger6072b242008-08-14 16:52:26 +0100907static int
paul718e3742002-12-13 20:15:29 +0000908netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
909{
910 int len;
911 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000912 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000913 struct interface *ifp;
914 char *name;
915
916 ifi = NLMSG_DATA (h);
917
paul7021c422003-07-15 12:52:22 +0000918 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000919 {
920 /* If this is not link add/delete message so print warning. */
921 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000922 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000923 return 0;
924 }
925
926 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
927 if (len < 0)
928 return -1;
929
930 /* Looking up interface name. */
931 memset (tb, 0, sizeof tb);
932 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000933
paul1e193152005-02-14 23:53:05 +0000934#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000935 /* check for wireless messages to ignore */
936 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
937 {
938 if (IS_ZEBRA_DEBUG_KERNEL)
939 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
940 return 0;
941 }
paul1e193152005-02-14 23:53:05 +0000942#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000943
paul718e3742002-12-13 20:15:29 +0000944 if (tb[IFLA_IFNAME] == NULL)
945 return -1;
paul7021c422003-07-15 12:52:22 +0000946 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000947
948 /* Add interface. */
949 if (h->nlmsg_type == RTM_NEWLINK)
950 {
951 ifp = if_lookup_by_name (name);
952
paul7021c422003-07-15 12:52:22 +0000953 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
954 {
955 if (ifp == NULL)
956 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000957
ajsd2fc8892005-04-02 18:38:43 +0000958 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +0000959 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000960 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000961 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000962
paul7021c422003-07-15 12:52:22 +0000963 /* If new link is added. */
964 if_add_update (ifp);
965 }
paul718e3742002-12-13 20:15:29 +0000966 else
paul7021c422003-07-15 12:52:22 +0000967 {
968 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +0000969 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +0000970 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000971 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000972
paul7021c422003-07-15 12:52:22 +0000973 if (if_is_operative (ifp))
974 {
975 ifp->flags = ifi->ifi_flags & 0x0000fffff;
976 if (!if_is_operative (ifp))
977 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +0000978 else
979 /* Must notify client daemons of new interface status. */
980 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +0000981 }
982 else
983 {
984 ifp->flags = ifi->ifi_flags & 0x0000fffff;
985 if (if_is_operative (ifp))
986 if_up (ifp);
987 }
988 }
paul718e3742002-12-13 20:15:29 +0000989 }
990 else
991 {
992 /* RTM_DELLINK. */
993 ifp = if_lookup_by_name (name);
994
995 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000996 {
997 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +0000998 name);
paul7021c422003-07-15 12:52:22 +0000999 return 0;
1000 }
1001
paul718e3742002-12-13 20:15:29 +00001002 if_delete_update (ifp);
1003 }
1004
1005 return 0;
1006}
1007
Stephen Hemminger6072b242008-08-14 16:52:26 +01001008static int
paul718e3742002-12-13 20:15:29 +00001009netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1010{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001011 /* JF: Ignore messages that aren't from the kernel */
1012 if ( snl->nl_pid != 0 )
1013 {
1014 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1015 return 0;
1016 }
1017
paul718e3742002-12-13 20:15:29 +00001018 switch (h->nlmsg_type)
1019 {
1020 case RTM_NEWROUTE:
1021 return netlink_route_change (snl, h);
1022 break;
1023 case RTM_DELROUTE:
1024 return netlink_route_change (snl, h);
1025 break;
1026 case RTM_NEWLINK:
1027 return netlink_link_change (snl, h);
1028 break;
1029 case RTM_DELLINK:
1030 return netlink_link_change (snl, h);
1031 break;
1032 case RTM_NEWADDR:
1033 return netlink_interface_addr (snl, h);
1034 break;
1035 case RTM_DELADDR:
1036 return netlink_interface_addr (snl, h);
1037 break;
1038 default:
1039 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1040 break;
1041 }
1042 return 0;
1043}
1044
1045/* Interface lookup by netlink socket. */
1046int
paul6621ca82005-11-23 13:02:08 +00001047interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001048{
1049 int ret;
paul7021c422003-07-15 12:52:22 +00001050
paul718e3742002-12-13 20:15:29 +00001051 /* Get interface information. */
1052 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1053 if (ret < 0)
1054 return ret;
1055 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1056 if (ret < 0)
1057 return ret;
1058
1059 /* Get IPv4 address of the interfaces. */
1060 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1061 if (ret < 0)
1062 return ret;
1063 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1064 if (ret < 0)
1065 return ret;
1066
1067#ifdef HAVE_IPV6
1068 /* Get IPv6 address of the interfaces. */
1069 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1070 if (ret < 0)
1071 return ret;
1072 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1073 if (ret < 0)
1074 return ret;
1075#endif /* HAVE_IPV6 */
1076
1077 return 0;
1078}
1079
1080/* Routing table read function using netlink interface. Only called
1081 bootstrap time. */
1082int
paul6621ca82005-11-23 13:02:08 +00001083netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001084{
1085 int ret;
paul7021c422003-07-15 12:52:22 +00001086
paul718e3742002-12-13 20:15:29 +00001087 /* Get IPv4 routing table. */
1088 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1089 if (ret < 0)
1090 return ret;
1091 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1092 if (ret < 0)
1093 return ret;
1094
1095#ifdef HAVE_IPV6
1096 /* Get IPv6 routing table. */
1097 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1098 if (ret < 0)
1099 return ret;
1100 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1101 if (ret < 0)
1102 return ret;
1103#endif /* HAVE_IPV6 */
1104
1105 return 0;
1106}
1107
1108/* Utility function comes from iproute2.
1109 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001110static int
paul718e3742002-12-13 20:15:29 +00001111addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1112{
1113 int len;
1114 struct rtattr *rta;
1115
paul7021c422003-07-15 12:52:22 +00001116 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001117
paul7021c422003-07-15 12:52:22 +00001118 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001119 return -1;
1120
paul7021c422003-07-15 12:52:22 +00001121 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001122 rta->rta_type = type;
1123 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001124 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001125 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1126
1127 return 0;
1128}
1129
Stephen Hemminger6072b242008-08-14 16:52:26 +01001130static int
paul718e3742002-12-13 20:15:29 +00001131rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1132{
1133 int len;
1134 struct rtattr *subrta;
1135
paul7021c422003-07-15 12:52:22 +00001136 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001137
paul7021c422003-07-15 12:52:22 +00001138 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001139 return -1;
1140
paul7021c422003-07-15 12:52:22 +00001141 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001142 subrta->rta_type = type;
1143 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001144 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001145 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1146
1147 return 0;
1148}
1149
1150/* Utility function comes from iproute2.
1151 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001152static int
paul718e3742002-12-13 20:15:29 +00001153addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1154{
1155 int len;
1156 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001157
1158 len = RTA_LENGTH (4);
1159
paul718e3742002-12-13 20:15:29 +00001160 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1161 return -1;
1162
paul7021c422003-07-15 12:52:22 +00001163 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001164 rta->rta_type = type;
1165 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001166 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001167 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1168
1169 return 0;
1170}
1171
1172static int
1173netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1174{
hassob7ed1ec2005-03-31 20:13:49 +00001175 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001176 return 0;
1177}
1178
1179/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001180static int
paul718e3742002-12-13 20:15:29 +00001181netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1182{
1183 int status;
1184 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001185 struct iovec iov = { (void *) n, n->nlmsg_len };
1186 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001187 int save_errno;
paul7021c422003-07-15 12:52:22 +00001188
paul718e3742002-12-13 20:15:29 +00001189 memset (&snl, 0, sizeof snl);
1190 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001191
hassob7ed1ec2005-03-31 20:13:49 +00001192 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001193
1194 /* Request an acknowledgement by setting NLM_F_ACK */
1195 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001196
1197 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001198 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001199 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1200 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001201
1202 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001203 if (zserv_privs.change (ZPRIVS_RAISE))
1204 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001205 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001206 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001207 if (zserv_privs.change (ZPRIVS_LOWER))
1208 zlog (NULL, LOG_ERR, "Can't lower privileges");
1209
paul718e3742002-12-13 20:15:29 +00001210 if (status < 0)
1211 {
1212 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001213 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001214 return -1;
1215 }
paul7021c422003-07-15 12:52:22 +00001216
paul718e3742002-12-13 20:15:29 +00001217
1218 /*
1219 * Get reply from netlink socket.
1220 * The reply should either be an acknowlegement or an error.
1221 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001222 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001223}
1224
1225/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001226static int
paul718e3742002-12-13 20:15:29 +00001227netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001228 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001229{
1230 int ret;
1231 int bytelen;
1232 struct sockaddr_nl snl;
1233 int discard;
1234
paul7021c422003-07-15 12:52:22 +00001235 struct
paul718e3742002-12-13 20:15:29 +00001236 {
1237 struct nlmsghdr n;
1238 struct rtmsg r;
1239 char buf[1024];
1240 } req;
1241
1242 memset (&req, 0, sizeof req);
1243
1244 bytelen = (family == AF_INET ? 4 : 16);
1245
1246 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1247 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1248 req.n.nlmsg_type = cmd;
1249 req.r.rtm_family = family;
1250 req.r.rtm_table = table;
1251 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001252 req.r.rtm_protocol = RTPROT_ZEBRA;
1253 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001254
hasso81dfcaa2003-05-25 19:21:25 +00001255 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1256 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001257 discard = 1;
1258 else
1259 discard = 0;
1260
paul7021c422003-07-15 12:52:22 +00001261 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001262 {
paul7021c422003-07-15 12:52:22 +00001263 if (discard)
paul595db7f2003-05-25 21:35:06 +00001264 {
1265 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1266 req.r.rtm_type = RTN_BLACKHOLE;
1267 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1268 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001269 else
1270 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1271 }
paul595db7f2003-05-25 21:35:06 +00001272 else
paul7021c422003-07-15 12:52:22 +00001273 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001274 }
1275
1276 if (dest)
1277 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1278
paul7021c422003-07-15 12:52:22 +00001279 if (!discard)
paul718e3742002-12-13 20:15:29 +00001280 {
1281 if (gate)
paul7021c422003-07-15 12:52:22 +00001282 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001283 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001284 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001285 }
1286
1287 /* Destination netlink address. */
1288 memset (&snl, 0, sizeof snl);
1289 snl.nl_family = AF_NETLINK;
1290
1291 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001292 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001293 if (ret < 0)
1294 return -1;
1295
1296 return 0;
1297}
1298
1299/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001300static int
paul718e3742002-12-13 20:15:29 +00001301netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001302 int family)
paul718e3742002-12-13 20:15:29 +00001303{
1304 int bytelen;
1305 struct sockaddr_nl snl;
1306 struct nexthop *nexthop = NULL;
1307 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001308 int discard;
1309
paul7021c422003-07-15 12:52:22 +00001310 struct
paul718e3742002-12-13 20:15:29 +00001311 {
1312 struct nlmsghdr n;
1313 struct rtmsg r;
1314 char buf[1024];
1315 } req;
1316
1317 memset (&req, 0, sizeof req);
1318
1319 bytelen = (family == AF_INET ? 4 : 16);
1320
1321 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1322 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1323 req.n.nlmsg_type = cmd;
1324 req.r.rtm_family = family;
1325 req.r.rtm_table = rib->table;
1326 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001327 req.r.rtm_protocol = RTPROT_ZEBRA;
1328 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001329
paul7021c422003-07-15 12:52:22 +00001330 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001331 discard = 1;
1332 else
1333 discard = 0;
1334
paul7021c422003-07-15 12:52:22 +00001335 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001336 {
paul7021c422003-07-15 12:52:22 +00001337 if (discard)
paul595db7f2003-05-25 21:35:06 +00001338 {
1339 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1340 req.r.rtm_type = RTN_BLACKHOLE;
1341 else if (rib->flags & ZEBRA_FLAG_REJECT)
1342 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001343 else
1344 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1345 }
paul595db7f2003-05-25 21:35:06 +00001346 else
paul7021c422003-07-15 12:52:22 +00001347 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001348 }
1349
1350 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1351
1352 /* Metric. */
1353 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1354
1355 if (discard)
1356 {
1357 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001358 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1359 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001360 goto skip;
1361 }
1362
1363 /* Multipath case. */
1364 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1365 {
1366 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001367 {
paul5ec90d22003-06-19 01:41:37 +00001368
paul7021c422003-07-15 12:52:22 +00001369 if ((cmd == RTM_NEWROUTE
1370 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1371 || (cmd == RTM_DELROUTE
1372 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1373 {
paul5ec90d22003-06-19 01:41:37 +00001374
paul7021c422003-07-15 12:52:22 +00001375 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1376 {
1377 if (IS_ZEBRA_DEBUG_KERNEL)
1378 {
ajsb6178002004-12-07 21:12:56 +00001379 zlog_debug
paul7021c422003-07-15 12:52:22 +00001380 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001381 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001382#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001383 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001384 inet6_ntoa (p->u.prefix6),
1385#else
1386 inet_ntoa (p->u.prefix4),
1387#endif /* HAVE_IPV6 */
1388
1389 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001390 }
paul5ec90d22003-06-19 01:41:37 +00001391
paul7021c422003-07-15 12:52:22 +00001392 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1393 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001394 {
1395 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1396 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001397 if (nexthop->src.ipv4.s_addr)
1398 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1399 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001400 if (IS_ZEBRA_DEBUG_KERNEL)
1401 zlog_debug("netlink_route_multipath() (recursive, "
1402 "1 hop): nexthop via %s if %u",
1403 inet_ntoa (nexthop->rgate.ipv4),
1404 nexthop->rifindex);
1405 }
paul718e3742002-12-13 20:15:29 +00001406#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001407 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1408 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1409 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001410 {
1411 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1412 &nexthop->rgate.ipv6, bytelen);
1413
1414 if (IS_ZEBRA_DEBUG_KERNEL)
1415 zlog_debug("netlink_route_multipath() (recursive, "
1416 "1 hop): nexthop via %s if %u",
1417 inet6_ntoa (nexthop->rgate.ipv6),
1418 nexthop->rifindex);
1419 }
paul718e3742002-12-13 20:15:29 +00001420#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001421 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1422 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1423 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1424 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1425 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001426 {
1427 addattr32 (&req.n, sizeof req, RTA_OIF,
1428 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001429 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1430 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1431 && nexthop->src.ipv4.s_addr)
1432 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1433 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001434
1435 if (IS_ZEBRA_DEBUG_KERNEL)
1436 zlog_debug("netlink_route_multipath() (recursive, "
1437 "1 hop): nexthop via if %u",
1438 nexthop->rifindex);
1439 }
paul7021c422003-07-15 12:52:22 +00001440 }
1441 else
1442 {
1443 if (IS_ZEBRA_DEBUG_KERNEL)
1444 {
ajsb6178002004-12-07 21:12:56 +00001445 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001446 ("netlink_route_multipath() (single hop): "
1447 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001448#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001449 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001450 inet6_ntoa (p->u.prefix6),
1451#else
1452 inet_ntoa (p->u.prefix4),
1453#endif /* HAVE_IPV6 */
1454 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001455 }
paul5ec90d22003-06-19 01:41:37 +00001456
paul7021c422003-07-15 12:52:22 +00001457 if (nexthop->type == NEXTHOP_TYPE_IPV4
1458 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001459 {
1460 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1461 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001462 if (nexthop->src.ipv4.s_addr)
1463 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1464 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001465
1466 if (IS_ZEBRA_DEBUG_KERNEL)
1467 zlog_debug("netlink_route_multipath() (single hop): "
1468 "nexthop via %s if %u",
1469 inet_ntoa (nexthop->gate.ipv4),
1470 nexthop->ifindex);
1471 }
paul718e3742002-12-13 20:15:29 +00001472#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001473 if (nexthop->type == NEXTHOP_TYPE_IPV6
1474 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1475 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001476 {
1477 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1478 &nexthop->gate.ipv6, bytelen);
1479
1480 if (IS_ZEBRA_DEBUG_KERNEL)
1481 zlog_debug("netlink_route_multipath() (single hop): "
1482 "nexthop via %s if %u",
1483 inet6_ntoa (nexthop->gate.ipv6),
1484 nexthop->ifindex);
1485 }
paul718e3742002-12-13 20:15:29 +00001486#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001487 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1488 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001489 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1490 {
1491 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1492
1493 if (nexthop->src.ipv4.s_addr)
1494 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1495 &nexthop->src.ipv4, bytelen);
1496
1497 if (IS_ZEBRA_DEBUG_KERNEL)
1498 zlog_debug("netlink_route_multipath() (single hop): "
1499 "nexthop via if %u", nexthop->ifindex);
1500 }
1501 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001502 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001503 {
1504 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1505
1506 if (IS_ZEBRA_DEBUG_KERNEL)
1507 zlog_debug("netlink_route_multipath() (single hop): "
1508 "nexthop via if %u", nexthop->ifindex);
1509 }
paul7021c422003-07-15 12:52:22 +00001510 }
paul718e3742002-12-13 20:15:29 +00001511
paul7021c422003-07-15 12:52:22 +00001512 if (cmd == RTM_NEWROUTE)
1513 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001514
paul7021c422003-07-15 12:52:22 +00001515 nexthop_num++;
1516 break;
1517 }
1518 }
paul718e3742002-12-13 20:15:29 +00001519 }
1520 else
1521 {
1522 char buf[1024];
1523 struct rtattr *rta = (void *) buf;
1524 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001525 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001526
1527 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001528 rta->rta_len = RTA_LENGTH (0);
1529 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001530
1531 nexthop_num = 0;
1532 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001533 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1534 nexthop = nexthop->next)
1535 {
1536 if ((cmd == RTM_NEWROUTE
1537 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1538 || (cmd == RTM_DELROUTE
1539 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1540 {
1541 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001542
paul7021c422003-07-15 12:52:22 +00001543 rtnh->rtnh_len = sizeof (*rtnh);
1544 rtnh->rtnh_flags = 0;
1545 rtnh->rtnh_hops = 0;
1546 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001547
paul7021c422003-07-15 12:52:22 +00001548 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1549 {
1550 if (IS_ZEBRA_DEBUG_KERNEL)
1551 {
ajsb6178002004-12-07 21:12:56 +00001552 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001553 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001554 lookup (nlmsg_str, cmd),
1555#ifdef HAVE_IPV6
1556 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1557 inet6_ntoa (p->u.prefix6),
1558#else
1559 inet_ntoa (p->u.prefix4),
1560#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001561 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001562 }
1563 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1564 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1565 {
1566 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1567 &nexthop->rgate.ipv4, bytelen);
1568 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001569
Paul Jakma7514fb72007-05-02 16:05:35 +00001570 if (nexthop->src.ipv4.s_addr)
1571 src = &nexthop->src;
1572
hasso206d8052005-04-09 16:38:51 +00001573 if (IS_ZEBRA_DEBUG_KERNEL)
1574 zlog_debug("netlink_route_multipath() (recursive, "
1575 "multihop): nexthop via %s if %u",
1576 inet_ntoa (nexthop->rgate.ipv4),
1577 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001578 }
paul718e3742002-12-13 20:15:29 +00001579#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001580 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1581 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1582 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001583 {
1584 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1585 &nexthop->rgate.ipv6, bytelen);
1586
1587 if (IS_ZEBRA_DEBUG_KERNEL)
1588 zlog_debug("netlink_route_multipath() (recursive, "
1589 "multihop): nexthop via %s if %u",
1590 inet6_ntoa (nexthop->rgate.ipv6),
1591 nexthop->rifindex);
1592 }
paul718e3742002-12-13 20:15:29 +00001593#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001594 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001595 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1596 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1597 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1598 {
1599 rtnh->rtnh_ifindex = nexthop->rifindex;
1600 if (nexthop->src.ipv4.s_addr)
1601 src = &nexthop->src;
1602
1603 if (IS_ZEBRA_DEBUG_KERNEL)
1604 zlog_debug("netlink_route_multipath() (recursive, "
1605 "multihop): nexthop via if %u",
1606 nexthop->rifindex);
1607 }
1608 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001609 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001610 {
1611 rtnh->rtnh_ifindex = nexthop->rifindex;
1612
1613 if (IS_ZEBRA_DEBUG_KERNEL)
1614 zlog_debug("netlink_route_multipath() (recursive, "
1615 "multihop): nexthop via if %u",
1616 nexthop->rifindex);
1617 }
paul7021c422003-07-15 12:52:22 +00001618 else
hasso206d8052005-04-09 16:38:51 +00001619 {
1620 rtnh->rtnh_ifindex = 0;
1621 }
paul7021c422003-07-15 12:52:22 +00001622 }
1623 else
1624 {
1625 if (IS_ZEBRA_DEBUG_KERNEL)
1626 {
hasso206d8052005-04-09 16:38:51 +00001627 zlog_debug ("netlink_route_multipath() (multihop): "
1628 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001629#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001630 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001631 inet6_ntoa (p->u.prefix6),
1632#else
1633 inet_ntoa (p->u.prefix4),
1634#endif /* HAVE_IPV6 */
1635 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001636 }
1637 if (nexthop->type == NEXTHOP_TYPE_IPV4
1638 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1639 {
hasso206d8052005-04-09 16:38:51 +00001640 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1641 &nexthop->gate.ipv4, bytelen);
1642 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1643
Paul Jakma7514fb72007-05-02 16:05:35 +00001644 if (nexthop->src.ipv4.s_addr)
1645 src = &nexthop->src;
1646
hasso206d8052005-04-09 16:38:51 +00001647 if (IS_ZEBRA_DEBUG_KERNEL)
1648 zlog_debug("netlink_route_multipath() (multihop): "
1649 "nexthop via %s if %u",
1650 inet_ntoa (nexthop->gate.ipv4),
1651 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001652 }
paul718e3742002-12-13 20:15:29 +00001653#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001654 if (nexthop->type == NEXTHOP_TYPE_IPV6
1655 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1656 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001657 {
1658 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1659 &nexthop->gate.ipv6, bytelen);
1660
1661 if (IS_ZEBRA_DEBUG_KERNEL)
1662 zlog_debug("netlink_route_multipath() (multihop): "
1663 "nexthop via %s if %u",
1664 inet6_ntoa (nexthop->gate.ipv6),
1665 nexthop->ifindex);
1666 }
paul718e3742002-12-13 20:15:29 +00001667#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001668 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001669 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1670 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1671 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1672 {
1673 rtnh->rtnh_ifindex = nexthop->ifindex;
1674 if (nexthop->src.ipv4.s_addr)
1675 src = &nexthop->src;
1676 if (IS_ZEBRA_DEBUG_KERNEL)
1677 zlog_debug("netlink_route_multipath() (multihop): "
1678 "nexthop via if %u", nexthop->ifindex);
1679 }
1680 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001681 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001682 {
1683 rtnh->rtnh_ifindex = nexthop->ifindex;
1684
1685 if (IS_ZEBRA_DEBUG_KERNEL)
1686 zlog_debug("netlink_route_multipath() (multihop): "
1687 "nexthop via if %u", nexthop->ifindex);
1688 }
paul7021c422003-07-15 12:52:22 +00001689 else
hasso206d8052005-04-09 16:38:51 +00001690 {
1691 rtnh->rtnh_ifindex = 0;
1692 }
paul7021c422003-07-15 12:52:22 +00001693 }
1694 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001695
paul7021c422003-07-15 12:52:22 +00001696 if (cmd == RTM_NEWROUTE)
1697 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1698 }
1699 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001700 if (src)
1701 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001702
1703 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001704 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1705 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001706 }
1707
1708 /* If there is no useful nexthop then return. */
1709 if (nexthop_num == 0)
1710 {
1711 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001712 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001713 return 0;
1714 }
1715
paul7021c422003-07-15 12:52:22 +00001716skip:
paul718e3742002-12-13 20:15:29 +00001717
1718 /* Destination netlink address. */
1719 memset (&snl, 0, sizeof snl);
1720 snl.nl_family = AF_NETLINK;
1721
paul718e3742002-12-13 20:15:29 +00001722 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001723 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001724}
1725
1726int
1727kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1728{
1729 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1730}
1731
1732int
1733kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1734{
1735 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1736}
1737
1738#ifdef HAVE_IPV6
1739int
1740kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1741{
1742 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1743}
1744
1745int
1746kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1747{
1748 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1749}
1750
1751/* Delete IPv6 route from the kernel. */
1752int
1753kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001754 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001755{
paul7021c422003-07-15 12:52:22 +00001756 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1757 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001758}
1759#endif /* HAVE_IPV6 */
1760
1761/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001762static int
paul718e3742002-12-13 20:15:29 +00001763netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001764 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001765{
1766 int bytelen;
1767 struct prefix *p;
1768
paul7021c422003-07-15 12:52:22 +00001769 struct
paul718e3742002-12-13 20:15:29 +00001770 {
1771 struct nlmsghdr n;
1772 struct ifaddrmsg ifa;
1773 char buf[1024];
1774 } req;
1775
1776 p = ifc->address;
1777 memset (&req, 0, sizeof req);
1778
1779 bytelen = (family == AF_INET ? 4 : 16);
1780
paul7021c422003-07-15 12:52:22 +00001781 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001782 req.n.nlmsg_flags = NLM_F_REQUEST;
1783 req.n.nlmsg_type = cmd;
1784 req.ifa.ifa_family = family;
1785
1786 req.ifa.ifa_index = ifp->ifindex;
1787 req.ifa.ifa_prefixlen = p->prefixlen;
1788
1789 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1790
1791 if (family == AF_INET && cmd == RTM_NEWADDR)
1792 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001793 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001794 {
1795 p = ifc->destination;
1796 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1797 bytelen);
1798 }
paul718e3742002-12-13 20:15:29 +00001799 }
1800
1801 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1802 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001803
paul718e3742002-12-13 20:15:29 +00001804 if (ifc->label)
1805 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001806 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001807
1808 return netlink_talk (&req.n, &netlink_cmd);
1809}
1810
1811int
1812kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1813{
1814 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1815}
1816
1817int
1818kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1819{
1820 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1821}
1822
paul718e3742002-12-13 20:15:29 +00001823
1824extern struct thread_master *master;
1825
1826/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001827static int
paul718e3742002-12-13 20:15:29 +00001828kernel_read (struct thread *thread)
1829{
1830 int ret;
1831 int sock;
1832
1833 sock = THREAD_FD (thread);
1834 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001835 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001836
1837 return 0;
1838}
1839
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001840/* Filter out messages from self that occur on listener socket,
1841 caused by our actions on the command socket
1842 */
1843static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001844{
Paul Jakma768a27e2008-05-29 18:23:08 +00001845 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001846 /* 0: ldh [4] */
1847 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1848 /* 1: jeq 0x18 jt 3 jf 6 */
1849 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1850 /* 2: jeq 0x19 jt 3 jf 6 */
1851 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1852 /* 3: ldw [12] */
1853 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1854 /* 4: jeq XX jt 5 jf 6 */
1855 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1856 /* 5: ret 0 (skip) */
1857 BPF_STMT(BPF_RET|BPF_K, 0),
1858 /* 6: ret 0xffff (keep) */
1859 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001860 };
1861
1862 struct sock_fprog prog = {
1863 .len = sizeof(filter) / sizeof(filter[0]),
1864 .filter = filter,
1865 };
1866
1867 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1868 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1869}
1870
paul718e3742002-12-13 20:15:29 +00001871/* Exported interface function. This function simply calls
1872 netlink_socket (). */
1873void
paul6621ca82005-11-23 13:02:08 +00001874kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001875{
1876 unsigned long groups;
1877
paul7021c422003-07-15 12:52:22 +00001878 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001879#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001880 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001881#endif /* HAVE_IPV6 */
1882 netlink_socket (&netlink, groups);
1883 netlink_socket (&netlink_cmd, 0);
1884
1885 /* Register kernel socket. */
1886 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001887 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001888 /* Only want non-blocking on the netlink event socket */
1889 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1890 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1891 safe_strerror (errno));
1892
Stephen Hemminger30afea32008-08-16 18:25:47 +01001893 /* Set receive buffer size if it's set from command line */
1894 if (nl_rcvbufsize)
1895 netlink_recvbuf (&netlink, nl_rcvbufsize);
1896
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001897 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001898 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1899 }
paul718e3742002-12-13 20:15:29 +00001900}