blob: a0dad99701b51271e5cefba9336977e19c590f53 [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;
ajs4be019d2005-01-29 16:12:41 +0000288 int save_errno;
paul718e3742002-12-13 20:15:29 +0000289
paul7021c422003-07-15 12:52:22 +0000290 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000291 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000292
paul718e3742002-12-13 20:15:29 +0000293 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000294 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000295
296 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000297 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000298
299 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000300 {
ajs4be019d2005-01-29 16:12:41 +0000301 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000302 continue;
ajs4be019d2005-01-29 16:12:41 +0000303 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000304 break;
ajs4be019d2005-01-29 16:12:41 +0000305 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
306 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000307 continue;
308 }
paul718e3742002-12-13 20:15:29 +0000309
310 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000311 {
312 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
313 return -1;
314 }
paul718e3742002-12-13 20:15:29 +0000315
316 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000317 {
318 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
319 nl->name, msg.msg_namelen);
320 return -1;
321 }
paulb84d3a12003-11-17 10:31:01 +0000322
hasso206d8052005-04-09 16:38:51 +0000323 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000324 h = NLMSG_NEXT (h, status))
325 {
326 /* Finish of reading. */
327 if (h->nlmsg_type == NLMSG_DONE)
328 return ret;
paul718e3742002-12-13 20:15:29 +0000329
paul7021c422003-07-15 12:52:22 +0000330 /* Error handling. */
331 if (h->nlmsg_type == NLMSG_ERROR)
332 {
333 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
334
paul718e3742002-12-13 20:15:29 +0000335 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000336 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000337 {
paul7021c422003-07-15 12:52:22 +0000338 if (IS_ZEBRA_DEBUG_KERNEL)
339 {
hasso1ada8192005-06-12 11:28:18 +0000340 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000341 __FUNCTION__, nl->name,
342 lookup (nlmsg_str, err->msg.nlmsg_type),
343 err->msg.nlmsg_type, err->msg.nlmsg_seq,
344 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000345 }
paul7021c422003-07-15 12:52:22 +0000346
347 /* return if not a multipart message, otherwise continue */
348 if (!(h->nlmsg_flags & NLM_F_MULTI))
349 {
350 return 0;
paul718e3742002-12-13 20:15:29 +0000351 }
paul7021c422003-07-15 12:52:22 +0000352 continue;
paul718e3742002-12-13 20:15:29 +0000353 }
paul7021c422003-07-15 12:52:22 +0000354
paul718e3742002-12-13 20:15:29 +0000355 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000356 {
357 zlog (NULL, LOG_ERR, "%s error: message truncated",
358 nl->name);
359 return -1;
360 }
pauld753e9e2003-01-22 19:45:50 +0000361
paul7021c422003-07-15 12:52:22 +0000362 /* Deal with Error Noise - MAG */
363 {
364 int loglvl = LOG_ERR;
365 int errnum = err->error;
366 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000367
paul7021c422003-07-15 12:52:22 +0000368 if (nl == &netlink_cmd
369 && (-errnum == ENODEV || -errnum == ESRCH)
370 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
371 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000372
paul7021c422003-07-15 12:52:22 +0000373 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
hasso1ada8192005-06-12 11:28:18 +0000374 "seq=%u, pid=%u",
ajs6099b3b2004-11-20 02:06:59 +0000375 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000376 lookup (nlmsg_str, msg_type),
377 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
378 }
379 /*
380 ret = -1;
381 continue;
382 */
383 return -1;
384 }
paul718e3742002-12-13 20:15:29 +0000385
paul7021c422003-07-15 12:52:22 +0000386 /* OK we got netlink message. */
387 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000388 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000389 nl->name,
390 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
391 h->nlmsg_seq, h->nlmsg_pid);
392
393 /* skip unsolicited messages originating from command socket */
394 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
395 {
396 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000397 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000398 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000399 continue;
400 }
401
402 error = (*filter) (&snl, h);
403 if (error < 0)
404 {
405 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
406 ret = error;
407 }
408 }
paul718e3742002-12-13 20:15:29 +0000409
410 /* After error care. */
411 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000412 {
413 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
414 continue;
415 }
paul718e3742002-12-13 20:15:29 +0000416 if (status)
paul7021c422003-07-15 12:52:22 +0000417 {
418 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
419 status);
420 return -1;
421 }
paul718e3742002-12-13 20:15:29 +0000422 }
423 return ret;
424}
425
426/* Utility function for parse rtattr. */
427static void
paul7021c422003-07-15 12:52:22 +0000428netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
429 int len)
paul718e3742002-12-13 20:15:29 +0000430{
paul7021c422003-07-15 12:52:22 +0000431 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000432 {
433 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000434 tb[rta->rta_type] = rta;
435 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000436 }
437}
438
439/* Called from interface_lookup_netlink(). This function is only used
440 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100441static int
paul718e3742002-12-13 20:15:29 +0000442netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
443{
444 int len;
445 struct ifinfomsg *ifi;
446 struct rtattr *tb[IFLA_MAX + 1];
447 struct interface *ifp;
448 char *name;
449 int i;
450
451 ifi = NLMSG_DATA (h);
452
453 if (h->nlmsg_type != RTM_NEWLINK)
454 return 0;
455
456 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
457 if (len < 0)
458 return -1;
459
460 /* Looking up interface name. */
461 memset (tb, 0, sizeof tb);
462 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000463
paul1e193152005-02-14 23:53:05 +0000464#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000465 /* check for wireless messages to ignore */
466 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
467 {
468 if (IS_ZEBRA_DEBUG_KERNEL)
469 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
470 return 0;
471 }
paul1e193152005-02-14 23:53:05 +0000472#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000473
paul718e3742002-12-13 20:15:29 +0000474 if (tb[IFLA_IFNAME] == NULL)
475 return -1;
paul7021c422003-07-15 12:52:22 +0000476 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000477
478 /* Add interface. */
479 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000480 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000481 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000482 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000483 ifp->metric = 1;
484
485 /* Hardware type and address. */
486 ifp->hw_type = ifi->ifi_type;
487
488 if (tb[IFLA_ADDRESS])
489 {
490 int hw_addr_len;
491
paul7021c422003-07-15 12:52:22 +0000492 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000493
494 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000495 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000496 else
paul7021c422003-07-15 12:52:22 +0000497 {
498 ifp->hw_addr_len = hw_addr_len;
499 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000500
paul7021c422003-07-15 12:52:22 +0000501 for (i = 0; i < hw_addr_len; i++)
502 if (ifp->hw_addr[i] != 0)
503 break;
paul718e3742002-12-13 20:15:29 +0000504
paul7021c422003-07-15 12:52:22 +0000505 if (i == hw_addr_len)
506 ifp->hw_addr_len = 0;
507 else
508 ifp->hw_addr_len = hw_addr_len;
509 }
paul718e3742002-12-13 20:15:29 +0000510 }
511
512 if_add_update (ifp);
513
514 return 0;
515}
516
517/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100518static int
paul718e3742002-12-13 20:15:29 +0000519netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
520{
521 int len;
522 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000523 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000524 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000525 void *addr;
526 void *broad;
paul718e3742002-12-13 20:15:29 +0000527 u_char flags = 0;
528 char *label = NULL;
529
530 ifa = NLMSG_DATA (h);
531
paul7021c422003-07-15 12:52:22 +0000532 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000533#ifdef HAVE_IPV6
534 && ifa->ifa_family != AF_INET6
535#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000536 )
paul718e3742002-12-13 20:15:29 +0000537 return 0;
538
539 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
540 return 0;
541
paul7021c422003-07-15 12:52:22 +0000542 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000543 if (len < 0)
544 return -1;
545
546 memset (tb, 0, sizeof tb);
547 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
548
549 ifp = if_lookup_by_index (ifa->ifa_index);
550 if (ifp == NULL)
551 {
552 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000553 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000554 return -1;
555 }
556
paul7021c422003-07-15 12:52:22 +0000557 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000558 {
paul00df0c12002-12-13 21:07:36 +0000559 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000560 zlog_debug ("netlink_interface_addr %s %s:",
561 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000562 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000563 zlog_debug (" IFA_LOCAL %s/%d",
564 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
565 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000566 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000567 zlog_debug (" IFA_ADDRESS %s/%d",
568 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
569 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000570 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000571 zlog_debug (" IFA_BROADCAST %s/%d",
572 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
573 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000574 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000575 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000576
577 if (tb[IFA_CACHEINFO])
578 {
579 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
580 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
581 ci->ifa_prefered, ci->ifa_valid);
582 }
paul718e3742002-12-13 20:15:29 +0000583 }
paul31a476c2003-09-29 19:54:53 +0000584
Andrew J. Schorre4529632006-12-12 19:18:21 +0000585 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
586 if (tb[IFA_LOCAL] == NULL)
587 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000588 if (tb[IFA_ADDRESS] == NULL)
589 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
590
Andrew J. Schorre4529632006-12-12 19:18:21 +0000591 /* local interface address */
592 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
593
594 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000595 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000596 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000597 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000598 broad = RTA_DATA(tb[IFA_ADDRESS]);
599 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000600 }
paul31a476c2003-09-29 19:54:53 +0000601 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000602 /* seeking a broadcast address */
603 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000604
Paul Jakma27b47252006-07-02 16:38:54 +0000605 /* addr is primary key, SOL if we don't have one */
606 if (addr == NULL)
607 {
608 zlog_debug ("%s: NULL address", __func__);
609 return -1;
610 }
611
paul718e3742002-12-13 20:15:29 +0000612 /* Flags. */
613 if (ifa->ifa_flags & IFA_F_SECONDARY)
614 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
615
616 /* Label */
617 if (tb[IFA_LABEL])
618 label = (char *) RTA_DATA (tb[IFA_LABEL]);
619
620 if (ifp && label && strcmp (ifp->name, label) == 0)
621 label = NULL;
622
623 /* Register interface address to the interface. */
624 if (ifa->ifa_family == AF_INET)
625 {
paul7021c422003-07-15 12:52:22 +0000626 if (h->nlmsg_type == RTM_NEWADDR)
627 connected_add_ipv4 (ifp, flags,
628 (struct in_addr *) addr, ifa->ifa_prefixlen,
629 (struct in_addr *) broad, label);
630 else
631 connected_delete_ipv4 (ifp, flags,
632 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000633 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000634 }
635#ifdef HAVE_IPV6
636 if (ifa->ifa_family == AF_INET6)
637 {
638 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000639 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000640 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000641 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000642 else
paul7021c422003-07-15 12:52:22 +0000643 connected_delete_ipv6 (ifp,
644 (struct in6_addr *) addr, ifa->ifa_prefixlen,
645 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000646 }
paul7021c422003-07-15 12:52:22 +0000647#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000648
649 return 0;
650}
651
652/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100653static int
paul718e3742002-12-13 20:15:29 +0000654netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
655{
656 int len;
657 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000658 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000659 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000660
661 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000662
663 int index;
664 int table;
hasso34195bf2004-04-06 12:07:06 +0000665 int metric;
666
paul718e3742002-12-13 20:15:29 +0000667 void *dest;
668 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000669 void *src;
paul718e3742002-12-13 20:15:29 +0000670
671 rtm = NLMSG_DATA (h);
672
673 if (h->nlmsg_type != RTM_NEWROUTE)
674 return 0;
675 if (rtm->rtm_type != RTN_UNICAST)
676 return 0;
677
678 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000679#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000680 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000681 return 0;
682#endif
683
paul7021c422003-07-15 12:52:22 +0000684 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000685 if (len < 0)
686 return -1;
687
688 memset (tb, 0, sizeof tb);
689 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
690
691 if (rtm->rtm_flags & RTM_F_CLONED)
692 return 0;
693 if (rtm->rtm_protocol == RTPROT_REDIRECT)
694 return 0;
695 if (rtm->rtm_protocol == RTPROT_KERNEL)
696 return 0;
697
698 if (rtm->rtm_src_len != 0)
699 return 0;
700
701 /* Route which inserted by Zebra. */
702 if (rtm->rtm_protocol == RTPROT_ZEBRA)
703 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000704
paul718e3742002-12-13 20:15:29 +0000705 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000706 metric = 0;
paul718e3742002-12-13 20:15:29 +0000707 dest = NULL;
708 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000709 src = NULL;
paul718e3742002-12-13 20:15:29 +0000710
711 if (tb[RTA_OIF])
712 index = *(int *) RTA_DATA (tb[RTA_OIF]);
713
714 if (tb[RTA_DST])
715 dest = RTA_DATA (tb[RTA_DST]);
716 else
717 dest = anyaddr;
718
Paul Jakma7514fb72007-05-02 16:05:35 +0000719 if (tb[RTA_PREFSRC])
720 src = RTA_DATA (tb[RTA_PREFSRC]);
721
paul718e3742002-12-13 20:15:29 +0000722 /* Multipath treatment is needed. */
723 if (tb[RTA_GATEWAY])
724 gate = RTA_DATA (tb[RTA_GATEWAY]);
725
hasso34195bf2004-04-06 12:07:06 +0000726 if (tb[RTA_PRIORITY])
727 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
728
paul718e3742002-12-13 20:15:29 +0000729 if (rtm->rtm_family == AF_INET)
730 {
731 struct prefix_ipv4 p;
732 p.family = AF_INET;
733 memcpy (&p.prefix, dest, 4);
734 p.prefixlen = rtm->rtm_dst_len;
735
Paul Jakma7514fb72007-05-02 16:05:35 +0000736 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000737 }
738#ifdef HAVE_IPV6
739 if (rtm->rtm_family == AF_INET6)
740 {
741 struct prefix_ipv6 p;
742 p.family = AF_INET6;
743 memcpy (&p.prefix, dest, 16);
744 p.prefixlen = rtm->rtm_dst_len;
745
hassobe61c4e2005-08-27 06:05:47 +0000746 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
747 metric, 0);
paul718e3742002-12-13 20:15:29 +0000748 }
749#endif /* HAVE_IPV6 */
750
751 return 0;
752}
753
Stephen Hemminger1423c802008-08-14 17:59:25 +0100754static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000755 {RTPROT_REDIRECT, "redirect"},
756 {RTPROT_KERNEL, "kernel"},
757 {RTPROT_BOOT, "boot"},
758 {RTPROT_STATIC, "static"},
759 {RTPROT_GATED, "GateD"},
760 {RTPROT_RA, "router advertisement"},
761 {RTPROT_MRT, "MRT"},
762 {RTPROT_ZEBRA, "Zebra"},
763#ifdef RTPROT_BIRD
764 {RTPROT_BIRD, "BIRD"},
765#endif /* RTPROT_BIRD */
766 {0, NULL}
767};
768
769/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100770static int
paul718e3742002-12-13 20:15:29 +0000771netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
772{
773 int len;
774 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000775 struct rtattr *tb[RTA_MAX + 1];
776
777 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000778
779 int index;
780 int table;
781 void *dest;
782 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000783 void *src;
paul718e3742002-12-13 20:15:29 +0000784
785 rtm = NLMSG_DATA (h);
786
paul7021c422003-07-15 12:52:22 +0000787 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000788 {
789 /* If this is not route add/delete message print warning. */
790 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
791 return 0;
792 }
793
794 /* Connected route. */
795 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000796 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000797 h->nlmsg_type ==
798 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
799 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
800 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
801 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000802
803 if (rtm->rtm_type != RTN_UNICAST)
804 {
805 return 0;
806 }
807
808 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000809 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000810 {
811 return 0;
812 }
813
paul7021c422003-07-15 12:52:22 +0000814 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000815 if (len < 0)
816 return -1;
817
818 memset (tb, 0, sizeof tb);
819 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
820
821 if (rtm->rtm_flags & RTM_F_CLONED)
822 return 0;
823 if (rtm->rtm_protocol == RTPROT_REDIRECT)
824 return 0;
825 if (rtm->rtm_protocol == RTPROT_KERNEL)
826 return 0;
827
828 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
829 return 0;
830
831 if (rtm->rtm_src_len != 0)
832 {
833 zlog_warn ("netlink_route_change(): no src len");
834 return 0;
835 }
paul7021c422003-07-15 12:52:22 +0000836
paul718e3742002-12-13 20:15:29 +0000837 index = 0;
838 dest = NULL;
839 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000840 src = NULL;
paul718e3742002-12-13 20:15:29 +0000841
842 if (tb[RTA_OIF])
843 index = *(int *) RTA_DATA (tb[RTA_OIF]);
844
845 if (tb[RTA_DST])
846 dest = RTA_DATA (tb[RTA_DST]);
847 else
848 dest = anyaddr;
849
850 if (tb[RTA_GATEWAY])
851 gate = RTA_DATA (tb[RTA_GATEWAY]);
852
Paul Jakma7514fb72007-05-02 16:05:35 +0000853 if (tb[RTA_PREFSRC])
854 src = RTA_DATA (tb[RTA_PREFSRC]);
855
paul718e3742002-12-13 20:15:29 +0000856 if (rtm->rtm_family == AF_INET)
857 {
858 struct prefix_ipv4 p;
859 p.family = AF_INET;
860 memcpy (&p.prefix, dest, 4);
861 p.prefixlen = rtm->rtm_dst_len;
862
863 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000864 {
865 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000866 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000867 inet_ntoa (p.prefix), p.prefixlen);
868 else
ajsb6178002004-12-07 21:12:56 +0000869 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000870 inet_ntoa (p.prefix), p.prefixlen);
871 }
paul718e3742002-12-13 20:15:29 +0000872
873 if (h->nlmsg_type == RTM_NEWROUTE)
Paul Jakma7514fb72007-05-02 16:05:35 +0000874 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000875 else
paul7021c422003-07-15 12:52:22 +0000876 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000877 }
878
879#ifdef HAVE_IPV6
880 if (rtm->rtm_family == AF_INET6)
881 {
882 struct prefix_ipv6 p;
883 char buf[BUFSIZ];
884
885 p.family = AF_INET6;
886 memcpy (&p.prefix, dest, 16);
887 p.prefixlen = rtm->rtm_dst_len;
888
889 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000890 {
891 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000892 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000893 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
894 p.prefixlen);
895 else
ajsb6178002004-12-07 21:12:56 +0000896 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000897 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
898 p.prefixlen);
899 }
paul718e3742002-12-13 20:15:29 +0000900
901 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000902 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000903 else
paul7021c422003-07-15 12:52:22 +0000904 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000905 }
906#endif /* HAVE_IPV6 */
907
908 return 0;
909}
910
Stephen Hemminger6072b242008-08-14 16:52:26 +0100911static int
paul718e3742002-12-13 20:15:29 +0000912netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
913{
914 int len;
915 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000916 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000917 struct interface *ifp;
918 char *name;
919
920 ifi = NLMSG_DATA (h);
921
paul7021c422003-07-15 12:52:22 +0000922 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000923 {
924 /* If this is not link add/delete message so print warning. */
925 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000926 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000927 return 0;
928 }
929
930 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
931 if (len < 0)
932 return -1;
933
934 /* Looking up interface name. */
935 memset (tb, 0, sizeof tb);
936 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000937
paul1e193152005-02-14 23:53:05 +0000938#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000939 /* check for wireless messages to ignore */
940 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
941 {
942 if (IS_ZEBRA_DEBUG_KERNEL)
943 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
944 return 0;
945 }
paul1e193152005-02-14 23:53:05 +0000946#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000947
paul718e3742002-12-13 20:15:29 +0000948 if (tb[IFLA_IFNAME] == NULL)
949 return -1;
paul7021c422003-07-15 12:52:22 +0000950 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000951
952 /* Add interface. */
953 if (h->nlmsg_type == RTM_NEWLINK)
954 {
955 ifp = if_lookup_by_name (name);
956
paul7021c422003-07-15 12:52:22 +0000957 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
958 {
959 if (ifp == NULL)
960 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000961
ajsd2fc8892005-04-02 18:38:43 +0000962 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +0000963 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000964 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000965 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000966
paul7021c422003-07-15 12:52:22 +0000967 /* If new link is added. */
968 if_add_update (ifp);
969 }
paul718e3742002-12-13 20:15:29 +0000970 else
paul7021c422003-07-15 12:52:22 +0000971 {
972 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +0000973 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +0000974 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000975 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000976
paul7021c422003-07-15 12:52:22 +0000977 if (if_is_operative (ifp))
978 {
979 ifp->flags = ifi->ifi_flags & 0x0000fffff;
980 if (!if_is_operative (ifp))
981 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +0000982 else
983 /* Must notify client daemons of new interface status. */
984 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +0000985 }
986 else
987 {
988 ifp->flags = ifi->ifi_flags & 0x0000fffff;
989 if (if_is_operative (ifp))
990 if_up (ifp);
991 }
992 }
paul718e3742002-12-13 20:15:29 +0000993 }
994 else
995 {
996 /* RTM_DELLINK. */
997 ifp = if_lookup_by_name (name);
998
999 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001000 {
1001 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001002 name);
paul7021c422003-07-15 12:52:22 +00001003 return 0;
1004 }
1005
paul718e3742002-12-13 20:15:29 +00001006 if_delete_update (ifp);
1007 }
1008
1009 return 0;
1010}
1011
Stephen Hemminger6072b242008-08-14 16:52:26 +01001012static int
paul718e3742002-12-13 20:15:29 +00001013netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1014{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001015 /* JF: Ignore messages that aren't from the kernel */
1016 if ( snl->nl_pid != 0 )
1017 {
1018 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1019 return 0;
1020 }
1021
paul718e3742002-12-13 20:15:29 +00001022 switch (h->nlmsg_type)
1023 {
1024 case RTM_NEWROUTE:
1025 return netlink_route_change (snl, h);
1026 break;
1027 case RTM_DELROUTE:
1028 return netlink_route_change (snl, h);
1029 break;
1030 case RTM_NEWLINK:
1031 return netlink_link_change (snl, h);
1032 break;
1033 case RTM_DELLINK:
1034 return netlink_link_change (snl, h);
1035 break;
1036 case RTM_NEWADDR:
1037 return netlink_interface_addr (snl, h);
1038 break;
1039 case RTM_DELADDR:
1040 return netlink_interface_addr (snl, h);
1041 break;
1042 default:
1043 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1044 break;
1045 }
1046 return 0;
1047}
1048
1049/* Interface lookup by netlink socket. */
1050int
paul6621ca82005-11-23 13:02:08 +00001051interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001052{
1053 int ret;
paul7021c422003-07-15 12:52:22 +00001054
paul718e3742002-12-13 20:15:29 +00001055 /* Get interface information. */
1056 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1057 if (ret < 0)
1058 return ret;
1059 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1060 if (ret < 0)
1061 return ret;
1062
1063 /* Get IPv4 address of the interfaces. */
1064 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1065 if (ret < 0)
1066 return ret;
1067 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1068 if (ret < 0)
1069 return ret;
1070
1071#ifdef HAVE_IPV6
1072 /* Get IPv6 address of the interfaces. */
1073 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1074 if (ret < 0)
1075 return ret;
1076 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1077 if (ret < 0)
1078 return ret;
1079#endif /* HAVE_IPV6 */
1080
1081 return 0;
1082}
1083
1084/* Routing table read function using netlink interface. Only called
1085 bootstrap time. */
1086int
paul6621ca82005-11-23 13:02:08 +00001087netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001088{
1089 int ret;
paul7021c422003-07-15 12:52:22 +00001090
paul718e3742002-12-13 20:15:29 +00001091 /* Get IPv4 routing table. */
1092 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1093 if (ret < 0)
1094 return ret;
1095 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1096 if (ret < 0)
1097 return ret;
1098
1099#ifdef HAVE_IPV6
1100 /* Get IPv6 routing table. */
1101 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1102 if (ret < 0)
1103 return ret;
1104 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1105 if (ret < 0)
1106 return ret;
1107#endif /* HAVE_IPV6 */
1108
1109 return 0;
1110}
1111
1112/* Utility function comes from iproute2.
1113 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001114static int
paul718e3742002-12-13 20:15:29 +00001115addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1116{
1117 int len;
1118 struct rtattr *rta;
1119
paul7021c422003-07-15 12:52:22 +00001120 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001121
paul7021c422003-07-15 12:52:22 +00001122 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001123 return -1;
1124
paul7021c422003-07-15 12:52:22 +00001125 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001126 rta->rta_type = type;
1127 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001128 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001129 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1130
1131 return 0;
1132}
1133
Stephen Hemminger6072b242008-08-14 16:52:26 +01001134static int
paul718e3742002-12-13 20:15:29 +00001135rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1136{
1137 int len;
1138 struct rtattr *subrta;
1139
paul7021c422003-07-15 12:52:22 +00001140 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001141
paul7021c422003-07-15 12:52:22 +00001142 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001143 return -1;
1144
paul7021c422003-07-15 12:52:22 +00001145 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001146 subrta->rta_type = type;
1147 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001148 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001149 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1150
1151 return 0;
1152}
1153
1154/* Utility function comes from iproute2.
1155 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001156static int
paul718e3742002-12-13 20:15:29 +00001157addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1158{
1159 int len;
1160 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001161
1162 len = RTA_LENGTH (4);
1163
paul718e3742002-12-13 20:15:29 +00001164 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1165 return -1;
1166
paul7021c422003-07-15 12:52:22 +00001167 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001168 rta->rta_type = type;
1169 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001170 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001171 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1172
1173 return 0;
1174}
1175
1176static int
1177netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1178{
hassob7ed1ec2005-03-31 20:13:49 +00001179 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001180 return 0;
1181}
1182
1183/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001184static int
paul718e3742002-12-13 20:15:29 +00001185netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1186{
1187 int status;
1188 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001189 struct iovec iov = { (void *) n, n->nlmsg_len };
1190 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001191 int save_errno;
paul7021c422003-07-15 12:52:22 +00001192
paul718e3742002-12-13 20:15:29 +00001193 memset (&snl, 0, sizeof snl);
1194 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001195
hassob7ed1ec2005-03-31 20:13:49 +00001196 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001197
1198 /* Request an acknowledgement by setting NLM_F_ACK */
1199 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001200
1201 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001202 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001203 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1204 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001205
1206 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001207 if (zserv_privs.change (ZPRIVS_RAISE))
1208 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001209 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001210 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001211 if (zserv_privs.change (ZPRIVS_LOWER))
1212 zlog (NULL, LOG_ERR, "Can't lower privileges");
1213
paul718e3742002-12-13 20:15:29 +00001214 if (status < 0)
1215 {
1216 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001217 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001218 return -1;
1219 }
paul7021c422003-07-15 12:52:22 +00001220
paul718e3742002-12-13 20:15:29 +00001221
1222 /*
1223 * Get reply from netlink socket.
1224 * The reply should either be an acknowlegement or an error.
1225 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001226 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001227}
1228
1229/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001230static int
paul718e3742002-12-13 20:15:29 +00001231netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001232 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001233{
1234 int ret;
1235 int bytelen;
1236 struct sockaddr_nl snl;
1237 int discard;
1238
paul7021c422003-07-15 12:52:22 +00001239 struct
paul718e3742002-12-13 20:15:29 +00001240 {
1241 struct nlmsghdr n;
1242 struct rtmsg r;
1243 char buf[1024];
1244 } req;
1245
1246 memset (&req, 0, sizeof req);
1247
1248 bytelen = (family == AF_INET ? 4 : 16);
1249
1250 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1251 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1252 req.n.nlmsg_type = cmd;
1253 req.r.rtm_family = family;
1254 req.r.rtm_table = table;
1255 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001256 req.r.rtm_protocol = RTPROT_ZEBRA;
1257 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001258
hasso81dfcaa2003-05-25 19:21:25 +00001259 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1260 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001261 discard = 1;
1262 else
1263 discard = 0;
1264
paul7021c422003-07-15 12:52:22 +00001265 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001266 {
paul7021c422003-07-15 12:52:22 +00001267 if (discard)
paul595db7f2003-05-25 21:35:06 +00001268 {
1269 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1270 req.r.rtm_type = RTN_BLACKHOLE;
1271 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1272 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001273 else
1274 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1275 }
paul595db7f2003-05-25 21:35:06 +00001276 else
paul7021c422003-07-15 12:52:22 +00001277 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001278 }
1279
1280 if (dest)
1281 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1282
paul7021c422003-07-15 12:52:22 +00001283 if (!discard)
paul718e3742002-12-13 20:15:29 +00001284 {
1285 if (gate)
paul7021c422003-07-15 12:52:22 +00001286 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001287 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001288 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001289 }
1290
1291 /* Destination netlink address. */
1292 memset (&snl, 0, sizeof snl);
1293 snl.nl_family = AF_NETLINK;
1294
1295 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001296 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001297 if (ret < 0)
1298 return -1;
1299
1300 return 0;
1301}
1302
1303/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001304static int
paul718e3742002-12-13 20:15:29 +00001305netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001306 int family)
paul718e3742002-12-13 20:15:29 +00001307{
1308 int bytelen;
1309 struct sockaddr_nl snl;
1310 struct nexthop *nexthop = NULL;
1311 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001312 int discard;
1313
paul7021c422003-07-15 12:52:22 +00001314 struct
paul718e3742002-12-13 20:15:29 +00001315 {
1316 struct nlmsghdr n;
1317 struct rtmsg r;
1318 char buf[1024];
1319 } req;
1320
1321 memset (&req, 0, sizeof req);
1322
1323 bytelen = (family == AF_INET ? 4 : 16);
1324
1325 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1326 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1327 req.n.nlmsg_type = cmd;
1328 req.r.rtm_family = family;
1329 req.r.rtm_table = rib->table;
1330 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001331 req.r.rtm_protocol = RTPROT_ZEBRA;
1332 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001333
paul7021c422003-07-15 12:52:22 +00001334 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001335 discard = 1;
1336 else
1337 discard = 0;
1338
paul7021c422003-07-15 12:52:22 +00001339 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001340 {
paul7021c422003-07-15 12:52:22 +00001341 if (discard)
paul595db7f2003-05-25 21:35:06 +00001342 {
1343 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1344 req.r.rtm_type = RTN_BLACKHOLE;
1345 else if (rib->flags & ZEBRA_FLAG_REJECT)
1346 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001347 else
1348 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1349 }
paul595db7f2003-05-25 21:35:06 +00001350 else
paul7021c422003-07-15 12:52:22 +00001351 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001352 }
1353
1354 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1355
1356 /* Metric. */
1357 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1358
1359 if (discard)
1360 {
1361 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001362 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1363 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001364 goto skip;
1365 }
1366
1367 /* Multipath case. */
1368 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1369 {
1370 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001371 {
paul5ec90d22003-06-19 01:41:37 +00001372
paul7021c422003-07-15 12:52:22 +00001373 if ((cmd == RTM_NEWROUTE
1374 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1375 || (cmd == RTM_DELROUTE
1376 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1377 {
paul5ec90d22003-06-19 01:41:37 +00001378
paul7021c422003-07-15 12:52:22 +00001379 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1380 {
1381 if (IS_ZEBRA_DEBUG_KERNEL)
1382 {
ajsb6178002004-12-07 21:12:56 +00001383 zlog_debug
paul7021c422003-07-15 12:52:22 +00001384 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001385 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001386#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001387 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001388 inet6_ntoa (p->u.prefix6),
1389#else
1390 inet_ntoa (p->u.prefix4),
1391#endif /* HAVE_IPV6 */
1392
1393 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001394 }
paul5ec90d22003-06-19 01:41:37 +00001395
paul7021c422003-07-15 12:52:22 +00001396 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1397 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001398 {
1399 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1400 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001401 if (nexthop->src.ipv4.s_addr)
1402 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1403 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001404 if (IS_ZEBRA_DEBUG_KERNEL)
1405 zlog_debug("netlink_route_multipath() (recursive, "
1406 "1 hop): nexthop via %s if %u",
1407 inet_ntoa (nexthop->rgate.ipv4),
1408 nexthop->rifindex);
1409 }
paul718e3742002-12-13 20:15:29 +00001410#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001411 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1412 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1413 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001414 {
1415 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1416 &nexthop->rgate.ipv6, bytelen);
1417
1418 if (IS_ZEBRA_DEBUG_KERNEL)
1419 zlog_debug("netlink_route_multipath() (recursive, "
1420 "1 hop): nexthop via %s if %u",
1421 inet6_ntoa (nexthop->rgate.ipv6),
1422 nexthop->rifindex);
1423 }
paul718e3742002-12-13 20:15:29 +00001424#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001425 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1426 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1427 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1428 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1429 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001430 {
1431 addattr32 (&req.n, sizeof req, RTA_OIF,
1432 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001433 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1434 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1435 && nexthop->src.ipv4.s_addr)
1436 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1437 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001438
1439 if (IS_ZEBRA_DEBUG_KERNEL)
1440 zlog_debug("netlink_route_multipath() (recursive, "
1441 "1 hop): nexthop via if %u",
1442 nexthop->rifindex);
1443 }
paul7021c422003-07-15 12:52:22 +00001444 }
1445 else
1446 {
1447 if (IS_ZEBRA_DEBUG_KERNEL)
1448 {
ajsb6178002004-12-07 21:12:56 +00001449 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001450 ("netlink_route_multipath() (single hop): "
1451 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001452#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001453 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001454 inet6_ntoa (p->u.prefix6),
1455#else
1456 inet_ntoa (p->u.prefix4),
1457#endif /* HAVE_IPV6 */
1458 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001459 }
paul5ec90d22003-06-19 01:41:37 +00001460
paul7021c422003-07-15 12:52:22 +00001461 if (nexthop->type == NEXTHOP_TYPE_IPV4
1462 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001463 {
1464 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1465 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001466 if (nexthop->src.ipv4.s_addr)
1467 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1468 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001469
1470 if (IS_ZEBRA_DEBUG_KERNEL)
1471 zlog_debug("netlink_route_multipath() (single hop): "
1472 "nexthop via %s if %u",
1473 inet_ntoa (nexthop->gate.ipv4),
1474 nexthop->ifindex);
1475 }
paul718e3742002-12-13 20:15:29 +00001476#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001477 if (nexthop->type == NEXTHOP_TYPE_IPV6
1478 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1479 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001480 {
1481 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1482 &nexthop->gate.ipv6, bytelen);
1483
1484 if (IS_ZEBRA_DEBUG_KERNEL)
1485 zlog_debug("netlink_route_multipath() (single hop): "
1486 "nexthop via %s if %u",
1487 inet6_ntoa (nexthop->gate.ipv6),
1488 nexthop->ifindex);
1489 }
paul718e3742002-12-13 20:15:29 +00001490#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001491 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1492 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001493 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1494 {
1495 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1496
1497 if (nexthop->src.ipv4.s_addr)
1498 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1499 &nexthop->src.ipv4, bytelen);
1500
1501 if (IS_ZEBRA_DEBUG_KERNEL)
1502 zlog_debug("netlink_route_multipath() (single hop): "
1503 "nexthop via if %u", nexthop->ifindex);
1504 }
1505 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001506 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001507 {
1508 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1509
1510 if (IS_ZEBRA_DEBUG_KERNEL)
1511 zlog_debug("netlink_route_multipath() (single hop): "
1512 "nexthop via if %u", nexthop->ifindex);
1513 }
paul7021c422003-07-15 12:52:22 +00001514 }
paul718e3742002-12-13 20:15:29 +00001515
paul7021c422003-07-15 12:52:22 +00001516 if (cmd == RTM_NEWROUTE)
1517 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001518
paul7021c422003-07-15 12:52:22 +00001519 nexthop_num++;
1520 break;
1521 }
1522 }
paul718e3742002-12-13 20:15:29 +00001523 }
1524 else
1525 {
1526 char buf[1024];
1527 struct rtattr *rta = (void *) buf;
1528 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001529 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001530
1531 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001532 rta->rta_len = RTA_LENGTH (0);
1533 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001534
1535 nexthop_num = 0;
1536 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001537 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1538 nexthop = nexthop->next)
1539 {
1540 if ((cmd == RTM_NEWROUTE
1541 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1542 || (cmd == RTM_DELROUTE
1543 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1544 {
1545 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001546
paul7021c422003-07-15 12:52:22 +00001547 rtnh->rtnh_len = sizeof (*rtnh);
1548 rtnh->rtnh_flags = 0;
1549 rtnh->rtnh_hops = 0;
1550 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001551
paul7021c422003-07-15 12:52:22 +00001552 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1553 {
1554 if (IS_ZEBRA_DEBUG_KERNEL)
1555 {
ajsb6178002004-12-07 21:12:56 +00001556 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001557 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001558 lookup (nlmsg_str, cmd),
1559#ifdef HAVE_IPV6
1560 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1561 inet6_ntoa (p->u.prefix6),
1562#else
1563 inet_ntoa (p->u.prefix4),
1564#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001565 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001566 }
1567 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1568 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1569 {
1570 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1571 &nexthop->rgate.ipv4, bytelen);
1572 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001573
Paul Jakma7514fb72007-05-02 16:05:35 +00001574 if (nexthop->src.ipv4.s_addr)
1575 src = &nexthop->src;
1576
hasso206d8052005-04-09 16:38:51 +00001577 if (IS_ZEBRA_DEBUG_KERNEL)
1578 zlog_debug("netlink_route_multipath() (recursive, "
1579 "multihop): nexthop via %s if %u",
1580 inet_ntoa (nexthop->rgate.ipv4),
1581 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001582 }
paul718e3742002-12-13 20:15:29 +00001583#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001584 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1585 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1586 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001587 {
1588 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1589 &nexthop->rgate.ipv6, bytelen);
1590
1591 if (IS_ZEBRA_DEBUG_KERNEL)
1592 zlog_debug("netlink_route_multipath() (recursive, "
1593 "multihop): nexthop via %s if %u",
1594 inet6_ntoa (nexthop->rgate.ipv6),
1595 nexthop->rifindex);
1596 }
paul718e3742002-12-13 20:15:29 +00001597#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001598 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001599 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1600 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1601 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1602 {
1603 rtnh->rtnh_ifindex = nexthop->rifindex;
1604 if (nexthop->src.ipv4.s_addr)
1605 src = &nexthop->src;
1606
1607 if (IS_ZEBRA_DEBUG_KERNEL)
1608 zlog_debug("netlink_route_multipath() (recursive, "
1609 "multihop): nexthop via if %u",
1610 nexthop->rifindex);
1611 }
1612 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001613 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001614 {
1615 rtnh->rtnh_ifindex = nexthop->rifindex;
1616
1617 if (IS_ZEBRA_DEBUG_KERNEL)
1618 zlog_debug("netlink_route_multipath() (recursive, "
1619 "multihop): nexthop via if %u",
1620 nexthop->rifindex);
1621 }
paul7021c422003-07-15 12:52:22 +00001622 else
hasso206d8052005-04-09 16:38:51 +00001623 {
1624 rtnh->rtnh_ifindex = 0;
1625 }
paul7021c422003-07-15 12:52:22 +00001626 }
1627 else
1628 {
1629 if (IS_ZEBRA_DEBUG_KERNEL)
1630 {
hasso206d8052005-04-09 16:38:51 +00001631 zlog_debug ("netlink_route_multipath() (multihop): "
1632 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001633#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001634 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001635 inet6_ntoa (p->u.prefix6),
1636#else
1637 inet_ntoa (p->u.prefix4),
1638#endif /* HAVE_IPV6 */
1639 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001640 }
1641 if (nexthop->type == NEXTHOP_TYPE_IPV4
1642 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1643 {
hasso206d8052005-04-09 16:38:51 +00001644 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1645 &nexthop->gate.ipv4, bytelen);
1646 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1647
Paul Jakma7514fb72007-05-02 16:05:35 +00001648 if (nexthop->src.ipv4.s_addr)
1649 src = &nexthop->src;
1650
hasso206d8052005-04-09 16:38:51 +00001651 if (IS_ZEBRA_DEBUG_KERNEL)
1652 zlog_debug("netlink_route_multipath() (multihop): "
1653 "nexthop via %s if %u",
1654 inet_ntoa (nexthop->gate.ipv4),
1655 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001656 }
paul718e3742002-12-13 20:15:29 +00001657#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001658 if (nexthop->type == NEXTHOP_TYPE_IPV6
1659 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1660 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001661 {
1662 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1663 &nexthop->gate.ipv6, bytelen);
1664
1665 if (IS_ZEBRA_DEBUG_KERNEL)
1666 zlog_debug("netlink_route_multipath() (multihop): "
1667 "nexthop via %s if %u",
1668 inet6_ntoa (nexthop->gate.ipv6),
1669 nexthop->ifindex);
1670 }
paul718e3742002-12-13 20:15:29 +00001671#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001672 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001673 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1674 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1675 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1676 {
1677 rtnh->rtnh_ifindex = nexthop->ifindex;
1678 if (nexthop->src.ipv4.s_addr)
1679 src = &nexthop->src;
1680 if (IS_ZEBRA_DEBUG_KERNEL)
1681 zlog_debug("netlink_route_multipath() (multihop): "
1682 "nexthop via if %u", nexthop->ifindex);
1683 }
1684 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001685 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001686 {
1687 rtnh->rtnh_ifindex = nexthop->ifindex;
1688
1689 if (IS_ZEBRA_DEBUG_KERNEL)
1690 zlog_debug("netlink_route_multipath() (multihop): "
1691 "nexthop via if %u", nexthop->ifindex);
1692 }
paul7021c422003-07-15 12:52:22 +00001693 else
hasso206d8052005-04-09 16:38:51 +00001694 {
1695 rtnh->rtnh_ifindex = 0;
1696 }
paul7021c422003-07-15 12:52:22 +00001697 }
1698 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001699
paul7021c422003-07-15 12:52:22 +00001700 if (cmd == RTM_NEWROUTE)
1701 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1702 }
1703 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001704 if (src)
1705 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001706
1707 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001708 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1709 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001710 }
1711
1712 /* If there is no useful nexthop then return. */
1713 if (nexthop_num == 0)
1714 {
1715 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001716 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001717 return 0;
1718 }
1719
paul7021c422003-07-15 12:52:22 +00001720skip:
paul718e3742002-12-13 20:15:29 +00001721
1722 /* Destination netlink address. */
1723 memset (&snl, 0, sizeof snl);
1724 snl.nl_family = AF_NETLINK;
1725
paul718e3742002-12-13 20:15:29 +00001726 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001727 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001728}
1729
1730int
1731kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1732{
1733 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1734}
1735
1736int
1737kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1738{
1739 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1740}
1741
1742#ifdef HAVE_IPV6
1743int
1744kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1745{
1746 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1747}
1748
1749int
1750kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1751{
1752 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1753}
1754
1755/* Delete IPv6 route from the kernel. */
1756int
1757kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001758 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001759{
paul7021c422003-07-15 12:52:22 +00001760 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1761 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001762}
1763#endif /* HAVE_IPV6 */
1764
1765/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001766static int
paul718e3742002-12-13 20:15:29 +00001767netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001768 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001769{
1770 int bytelen;
1771 struct prefix *p;
1772
paul7021c422003-07-15 12:52:22 +00001773 struct
paul718e3742002-12-13 20:15:29 +00001774 {
1775 struct nlmsghdr n;
1776 struct ifaddrmsg ifa;
1777 char buf[1024];
1778 } req;
1779
1780 p = ifc->address;
1781 memset (&req, 0, sizeof req);
1782
1783 bytelen = (family == AF_INET ? 4 : 16);
1784
paul7021c422003-07-15 12:52:22 +00001785 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001786 req.n.nlmsg_flags = NLM_F_REQUEST;
1787 req.n.nlmsg_type = cmd;
1788 req.ifa.ifa_family = family;
1789
1790 req.ifa.ifa_index = ifp->ifindex;
1791 req.ifa.ifa_prefixlen = p->prefixlen;
1792
1793 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1794
1795 if (family == AF_INET && cmd == RTM_NEWADDR)
1796 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001797 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001798 {
1799 p = ifc->destination;
1800 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1801 bytelen);
1802 }
paul718e3742002-12-13 20:15:29 +00001803 }
1804
1805 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1806 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001807
paul718e3742002-12-13 20:15:29 +00001808 if (ifc->label)
1809 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001810 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001811
1812 return netlink_talk (&req.n, &netlink_cmd);
1813}
1814
1815int
1816kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1817{
1818 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1819}
1820
1821int
1822kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1823{
1824 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1825}
1826
paul718e3742002-12-13 20:15:29 +00001827
1828extern struct thread_master *master;
1829
1830/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001831static int
paul718e3742002-12-13 20:15:29 +00001832kernel_read (struct thread *thread)
1833{
1834 int ret;
1835 int sock;
1836
1837 sock = THREAD_FD (thread);
1838 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001839 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001840
1841 return 0;
1842}
1843
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001844/* Filter out messages from self that occur on listener socket,
1845 caused by our actions on the command socket
1846 */
1847static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001848{
Paul Jakma768a27e2008-05-29 18:23:08 +00001849 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001850 /* 0: ldh [4] */
1851 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1852 /* 1: jeq 0x18 jt 3 jf 6 */
1853 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1854 /* 2: jeq 0x19 jt 3 jf 6 */
1855 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1856 /* 3: ldw [12] */
1857 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1858 /* 4: jeq XX jt 5 jf 6 */
1859 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1860 /* 5: ret 0 (skip) */
1861 BPF_STMT(BPF_RET|BPF_K, 0),
1862 /* 6: ret 0xffff (keep) */
1863 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001864 };
1865
1866 struct sock_fprog prog = {
1867 .len = sizeof(filter) / sizeof(filter[0]),
1868 .filter = filter,
1869 };
1870
1871 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1872 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1873}
1874
paul718e3742002-12-13 20:15:29 +00001875/* Exported interface function. This function simply calls
1876 netlink_socket (). */
1877void
paul6621ca82005-11-23 13:02:08 +00001878kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001879{
1880 unsigned long groups;
1881
paul7021c422003-07-15 12:52:22 +00001882 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001883#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001884 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001885#endif /* HAVE_IPV6 */
1886 netlink_socket (&netlink, groups);
1887 netlink_socket (&netlink_cmd, 0);
1888
1889 /* Register kernel socket. */
1890 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001891 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001892 /* Only want non-blocking on the netlink event socket */
1893 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1894 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1895 safe_strerror (errno));
1896
Stephen Hemminger30afea32008-08-16 18:25:47 +01001897 /* Set receive buffer size if it's set from command line */
1898 if (nl_rcvbufsize)
1899 netlink_recvbuf (&netlink, nl_rcvbufsize);
1900
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001901 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001902 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1903 }
paul718e3742002-12-13 20:15:29 +00001904}