blob: 904367e0d5b311b3d0411eb0ccc31fd036b77b0c [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);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100334 int errnum = err->error;
335 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000336
paul718e3742002-12-13 20:15:29 +0000337 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000338 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000339 {
paul7021c422003-07-15 12:52:22 +0000340 if (IS_ZEBRA_DEBUG_KERNEL)
341 {
hasso1ada8192005-06-12 11:28:18 +0000342 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000343 __FUNCTION__, nl->name,
344 lookup (nlmsg_str, err->msg.nlmsg_type),
345 err->msg.nlmsg_type, err->msg.nlmsg_seq,
346 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000347 }
paul7021c422003-07-15 12:52:22 +0000348
349 /* return if not a multipart message, otherwise continue */
350 if (!(h->nlmsg_flags & NLM_F_MULTI))
351 {
352 return 0;
paul718e3742002-12-13 20:15:29 +0000353 }
paul7021c422003-07-15 12:52:22 +0000354 continue;
paul718e3742002-12-13 20:15:29 +0000355 }
paul7021c422003-07-15 12:52:22 +0000356
paul718e3742002-12-13 20:15:29 +0000357 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000358 {
359 zlog (NULL, LOG_ERR, "%s error: message truncated",
360 nl->name);
361 return -1;
362 }
pauld753e9e2003-01-22 19:45:50 +0000363
Stephen Hemminger898987e2008-08-17 16:56:15 +0100364 /* Deal with errors that occur because of races in link handling */
365 if (nl == &netlink_cmd
366 && ((msg_type == RTM_DELROUTE &&
367 (-errnum == ENODEV || -errnum == ESRCH))
368 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
369 {
370 if (IS_ZEBRA_DEBUG_KERNEL)
371 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
372 nl->name, safe_strerror (-errnum),
373 lookup (nlmsg_str, msg_type),
374 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
375 return 0;
376 }
paul718e3742002-12-13 20:15:29 +0000377
Stephen Hemminger898987e2008-08-17 16:56:15 +0100378 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
379 nl->name, safe_strerror (-errnum),
380 lookup (nlmsg_str, msg_type),
381 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000382 return -1;
383 }
paul718e3742002-12-13 20:15:29 +0000384
paul7021c422003-07-15 12:52:22 +0000385 /* OK we got netlink message. */
386 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000387 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000388 nl->name,
389 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
390 h->nlmsg_seq, h->nlmsg_pid);
391
392 /* skip unsolicited messages originating from command socket */
393 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
394 {
395 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000396 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000397 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000398 continue;
399 }
400
401 error = (*filter) (&snl, h);
402 if (error < 0)
403 {
404 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
405 ret = error;
406 }
407 }
paul718e3742002-12-13 20:15:29 +0000408
409 /* After error care. */
410 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000411 {
412 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
413 continue;
414 }
paul718e3742002-12-13 20:15:29 +0000415 if (status)
paul7021c422003-07-15 12:52:22 +0000416 {
417 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
418 status);
419 return -1;
420 }
paul718e3742002-12-13 20:15:29 +0000421 }
422 return ret;
423}
424
425/* Utility function for parse rtattr. */
426static void
paul7021c422003-07-15 12:52:22 +0000427netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
428 int len)
paul718e3742002-12-13 20:15:29 +0000429{
paul7021c422003-07-15 12:52:22 +0000430 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000431 {
432 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000433 tb[rta->rta_type] = rta;
434 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000435 }
436}
437
438/* Called from interface_lookup_netlink(). This function is only used
439 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100440static int
paul718e3742002-12-13 20:15:29 +0000441netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
442{
443 int len;
444 struct ifinfomsg *ifi;
445 struct rtattr *tb[IFLA_MAX + 1];
446 struct interface *ifp;
447 char *name;
448 int i;
449
450 ifi = NLMSG_DATA (h);
451
452 if (h->nlmsg_type != RTM_NEWLINK)
453 return 0;
454
455 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
456 if (len < 0)
457 return -1;
458
459 /* Looking up interface name. */
460 memset (tb, 0, sizeof tb);
461 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000462
paul1e193152005-02-14 23:53:05 +0000463#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000464 /* check for wireless messages to ignore */
465 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
466 {
467 if (IS_ZEBRA_DEBUG_KERNEL)
468 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
469 return 0;
470 }
paul1e193152005-02-14 23:53:05 +0000471#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000472
paul718e3742002-12-13 20:15:29 +0000473 if (tb[IFLA_IFNAME] == NULL)
474 return -1;
paul7021c422003-07-15 12:52:22 +0000475 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000476
477 /* Add interface. */
478 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000479 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000480 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000481 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000482 ifp->metric = 1;
483
484 /* Hardware type and address. */
485 ifp->hw_type = ifi->ifi_type;
486
487 if (tb[IFLA_ADDRESS])
488 {
489 int hw_addr_len;
490
paul7021c422003-07-15 12:52:22 +0000491 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000492
493 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000494 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000495 else
paul7021c422003-07-15 12:52:22 +0000496 {
497 ifp->hw_addr_len = hw_addr_len;
498 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000499
paul7021c422003-07-15 12:52:22 +0000500 for (i = 0; i < hw_addr_len; i++)
501 if (ifp->hw_addr[i] != 0)
502 break;
paul718e3742002-12-13 20:15:29 +0000503
paul7021c422003-07-15 12:52:22 +0000504 if (i == hw_addr_len)
505 ifp->hw_addr_len = 0;
506 else
507 ifp->hw_addr_len = hw_addr_len;
508 }
paul718e3742002-12-13 20:15:29 +0000509 }
510
511 if_add_update (ifp);
512
513 return 0;
514}
515
516/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100517static int
paul718e3742002-12-13 20:15:29 +0000518netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
519{
520 int len;
521 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000522 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000523 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000524 void *addr;
525 void *broad;
paul718e3742002-12-13 20:15:29 +0000526 u_char flags = 0;
527 char *label = NULL;
528
529 ifa = NLMSG_DATA (h);
530
paul7021c422003-07-15 12:52:22 +0000531 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000532#ifdef HAVE_IPV6
533 && ifa->ifa_family != AF_INET6
534#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000535 )
paul718e3742002-12-13 20:15:29 +0000536 return 0;
537
538 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
539 return 0;
540
paul7021c422003-07-15 12:52:22 +0000541 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000542 if (len < 0)
543 return -1;
544
545 memset (tb, 0, sizeof tb);
546 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
547
548 ifp = if_lookup_by_index (ifa->ifa_index);
549 if (ifp == NULL)
550 {
551 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000552 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000553 return -1;
554 }
555
paul7021c422003-07-15 12:52:22 +0000556 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000557 {
paul00df0c12002-12-13 21:07:36 +0000558 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000559 zlog_debug ("netlink_interface_addr %s %s:",
560 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000561 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000562 zlog_debug (" IFA_LOCAL %s/%d",
563 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
564 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000565 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000566 zlog_debug (" IFA_ADDRESS %s/%d",
567 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
568 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000569 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000570 zlog_debug (" IFA_BROADCAST %s/%d",
571 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
572 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000573 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000574 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000575
576 if (tb[IFA_CACHEINFO])
577 {
578 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
579 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
580 ci->ifa_prefered, ci->ifa_valid);
581 }
paul718e3742002-12-13 20:15:29 +0000582 }
paul31a476c2003-09-29 19:54:53 +0000583
Andrew J. Schorre4529632006-12-12 19:18:21 +0000584 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
585 if (tb[IFA_LOCAL] == NULL)
586 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000587 if (tb[IFA_ADDRESS] == NULL)
588 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
589
Andrew J. Schorre4529632006-12-12 19:18:21 +0000590 /* local interface address */
591 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
592
593 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000594 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000595 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000596 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000597 broad = RTA_DATA(tb[IFA_ADDRESS]);
598 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000599 }
paul31a476c2003-09-29 19:54:53 +0000600 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000601 /* seeking a broadcast address */
602 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000603
Paul Jakma27b47252006-07-02 16:38:54 +0000604 /* addr is primary key, SOL if we don't have one */
605 if (addr == NULL)
606 {
607 zlog_debug ("%s: NULL address", __func__);
608 return -1;
609 }
610
paul718e3742002-12-13 20:15:29 +0000611 /* Flags. */
612 if (ifa->ifa_flags & IFA_F_SECONDARY)
613 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
614
615 /* Label */
616 if (tb[IFA_LABEL])
617 label = (char *) RTA_DATA (tb[IFA_LABEL]);
618
619 if (ifp && label && strcmp (ifp->name, label) == 0)
620 label = NULL;
621
622 /* Register interface address to the interface. */
623 if (ifa->ifa_family == AF_INET)
624 {
paul7021c422003-07-15 12:52:22 +0000625 if (h->nlmsg_type == RTM_NEWADDR)
626 connected_add_ipv4 (ifp, flags,
627 (struct in_addr *) addr, ifa->ifa_prefixlen,
628 (struct in_addr *) broad, label);
629 else
630 connected_delete_ipv4 (ifp, flags,
631 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000632 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000633 }
634#ifdef HAVE_IPV6
635 if (ifa->ifa_family == AF_INET6)
636 {
637 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000638 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000639 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000640 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000641 else
paul7021c422003-07-15 12:52:22 +0000642 connected_delete_ipv6 (ifp,
643 (struct in6_addr *) addr, ifa->ifa_prefixlen,
644 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000645 }
paul7021c422003-07-15 12:52:22 +0000646#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000647
648 return 0;
649}
650
651/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100652static int
paul718e3742002-12-13 20:15:29 +0000653netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
654{
655 int len;
656 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000657 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000658 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000659
660 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000661
662 int index;
663 int table;
hasso34195bf2004-04-06 12:07:06 +0000664 int metric;
665
paul718e3742002-12-13 20:15:29 +0000666 void *dest;
667 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000668 void *src;
paul718e3742002-12-13 20:15:29 +0000669
670 rtm = NLMSG_DATA (h);
671
672 if (h->nlmsg_type != RTM_NEWROUTE)
673 return 0;
674 if (rtm->rtm_type != RTN_UNICAST)
675 return 0;
676
677 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000678#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000679 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000680 return 0;
681#endif
682
paul7021c422003-07-15 12:52:22 +0000683 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000684 if (len < 0)
685 return -1;
686
687 memset (tb, 0, sizeof tb);
688 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
689
690 if (rtm->rtm_flags & RTM_F_CLONED)
691 return 0;
692 if (rtm->rtm_protocol == RTPROT_REDIRECT)
693 return 0;
694 if (rtm->rtm_protocol == RTPROT_KERNEL)
695 return 0;
696
697 if (rtm->rtm_src_len != 0)
698 return 0;
699
700 /* Route which inserted by Zebra. */
701 if (rtm->rtm_protocol == RTPROT_ZEBRA)
702 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000703
paul718e3742002-12-13 20:15:29 +0000704 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000705 metric = 0;
paul718e3742002-12-13 20:15:29 +0000706 dest = NULL;
707 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000708 src = NULL;
paul718e3742002-12-13 20:15:29 +0000709
710 if (tb[RTA_OIF])
711 index = *(int *) RTA_DATA (tb[RTA_OIF]);
712
713 if (tb[RTA_DST])
714 dest = RTA_DATA (tb[RTA_DST]);
715 else
716 dest = anyaddr;
717
Paul Jakma7514fb72007-05-02 16:05:35 +0000718 if (tb[RTA_PREFSRC])
719 src = RTA_DATA (tb[RTA_PREFSRC]);
720
paul718e3742002-12-13 20:15:29 +0000721 /* Multipath treatment is needed. */
722 if (tb[RTA_GATEWAY])
723 gate = RTA_DATA (tb[RTA_GATEWAY]);
724
hasso34195bf2004-04-06 12:07:06 +0000725 if (tb[RTA_PRIORITY])
726 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
727
paul718e3742002-12-13 20:15:29 +0000728 if (rtm->rtm_family == AF_INET)
729 {
730 struct prefix_ipv4 p;
731 p.family = AF_INET;
732 memcpy (&p.prefix, dest, 4);
733 p.prefixlen = rtm->rtm_dst_len;
734
Paul Jakma7514fb72007-05-02 16:05:35 +0000735 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000736 }
737#ifdef HAVE_IPV6
738 if (rtm->rtm_family == AF_INET6)
739 {
740 struct prefix_ipv6 p;
741 p.family = AF_INET6;
742 memcpy (&p.prefix, dest, 16);
743 p.prefixlen = rtm->rtm_dst_len;
744
hassobe61c4e2005-08-27 06:05:47 +0000745 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
746 metric, 0);
paul718e3742002-12-13 20:15:29 +0000747 }
748#endif /* HAVE_IPV6 */
749
750 return 0;
751}
752
Stephen Hemminger1423c802008-08-14 17:59:25 +0100753static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000754 {RTPROT_REDIRECT, "redirect"},
755 {RTPROT_KERNEL, "kernel"},
756 {RTPROT_BOOT, "boot"},
757 {RTPROT_STATIC, "static"},
758 {RTPROT_GATED, "GateD"},
759 {RTPROT_RA, "router advertisement"},
760 {RTPROT_MRT, "MRT"},
761 {RTPROT_ZEBRA, "Zebra"},
762#ifdef RTPROT_BIRD
763 {RTPROT_BIRD, "BIRD"},
764#endif /* RTPROT_BIRD */
765 {0, NULL}
766};
767
768/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100769static int
paul718e3742002-12-13 20:15:29 +0000770netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
771{
772 int len;
773 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000774 struct rtattr *tb[RTA_MAX + 1];
775
776 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000777
778 int index;
779 int table;
780 void *dest;
781 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000782 void *src;
paul718e3742002-12-13 20:15:29 +0000783
784 rtm = NLMSG_DATA (h);
785
paul7021c422003-07-15 12:52:22 +0000786 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000787 {
788 /* If this is not route add/delete message print warning. */
789 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
790 return 0;
791 }
792
793 /* Connected route. */
794 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000795 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000796 h->nlmsg_type ==
797 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
798 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
799 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
800 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000801
802 if (rtm->rtm_type != RTN_UNICAST)
803 {
804 return 0;
805 }
806
807 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000808 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000809 {
810 return 0;
811 }
812
paul7021c422003-07-15 12:52:22 +0000813 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000814 if (len < 0)
815 return -1;
816
817 memset (tb, 0, sizeof tb);
818 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
819
820 if (rtm->rtm_flags & RTM_F_CLONED)
821 return 0;
822 if (rtm->rtm_protocol == RTPROT_REDIRECT)
823 return 0;
824 if (rtm->rtm_protocol == RTPROT_KERNEL)
825 return 0;
826
827 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
828 return 0;
829
830 if (rtm->rtm_src_len != 0)
831 {
832 zlog_warn ("netlink_route_change(): no src len");
833 return 0;
834 }
paul7021c422003-07-15 12:52:22 +0000835
paul718e3742002-12-13 20:15:29 +0000836 index = 0;
837 dest = NULL;
838 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000839 src = NULL;
paul718e3742002-12-13 20:15:29 +0000840
841 if (tb[RTA_OIF])
842 index = *(int *) RTA_DATA (tb[RTA_OIF]);
843
844 if (tb[RTA_DST])
845 dest = RTA_DATA (tb[RTA_DST]);
846 else
847 dest = anyaddr;
848
849 if (tb[RTA_GATEWAY])
850 gate = RTA_DATA (tb[RTA_GATEWAY]);
851
Paul Jakma7514fb72007-05-02 16:05:35 +0000852 if (tb[RTA_PREFSRC])
853 src = RTA_DATA (tb[RTA_PREFSRC]);
854
paul718e3742002-12-13 20:15:29 +0000855 if (rtm->rtm_family == AF_INET)
856 {
857 struct prefix_ipv4 p;
858 p.family = AF_INET;
859 memcpy (&p.prefix, dest, 4);
860 p.prefixlen = rtm->rtm_dst_len;
861
862 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000863 {
864 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000865 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000866 inet_ntoa (p.prefix), p.prefixlen);
867 else
ajsb6178002004-12-07 21:12:56 +0000868 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000869 inet_ntoa (p.prefix), p.prefixlen);
870 }
paul718e3742002-12-13 20:15:29 +0000871
872 if (h->nlmsg_type == RTM_NEWROUTE)
Paul Jakma7514fb72007-05-02 16:05:35 +0000873 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000874 else
paul7021c422003-07-15 12:52:22 +0000875 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000876 }
877
878#ifdef HAVE_IPV6
879 if (rtm->rtm_family == AF_INET6)
880 {
881 struct prefix_ipv6 p;
882 char buf[BUFSIZ];
883
884 p.family = AF_INET6;
885 memcpy (&p.prefix, dest, 16);
886 p.prefixlen = rtm->rtm_dst_len;
887
888 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000889 {
890 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000891 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000892 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
893 p.prefixlen);
894 else
ajsb6178002004-12-07 21:12:56 +0000895 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000896 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
897 p.prefixlen);
898 }
paul718e3742002-12-13 20:15:29 +0000899
900 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000901 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000902 else
paul7021c422003-07-15 12:52:22 +0000903 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000904 }
905#endif /* HAVE_IPV6 */
906
907 return 0;
908}
909
Stephen Hemminger6072b242008-08-14 16:52:26 +0100910static int
paul718e3742002-12-13 20:15:29 +0000911netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
912{
913 int len;
914 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000915 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000916 struct interface *ifp;
917 char *name;
918
919 ifi = NLMSG_DATA (h);
920
paul7021c422003-07-15 12:52:22 +0000921 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000922 {
923 /* If this is not link add/delete message so print warning. */
924 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000925 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000926 return 0;
927 }
928
929 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
930 if (len < 0)
931 return -1;
932
933 /* Looking up interface name. */
934 memset (tb, 0, sizeof tb);
935 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000936
paul1e193152005-02-14 23:53:05 +0000937#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000938 /* check for wireless messages to ignore */
939 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
940 {
941 if (IS_ZEBRA_DEBUG_KERNEL)
942 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
943 return 0;
944 }
paul1e193152005-02-14 23:53:05 +0000945#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000946
paul718e3742002-12-13 20:15:29 +0000947 if (tb[IFLA_IFNAME] == NULL)
948 return -1;
paul7021c422003-07-15 12:52:22 +0000949 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000950
951 /* Add interface. */
952 if (h->nlmsg_type == RTM_NEWLINK)
953 {
954 ifp = if_lookup_by_name (name);
955
paul7021c422003-07-15 12:52:22 +0000956 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
957 {
958 if (ifp == NULL)
959 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000960
ajsd2fc8892005-04-02 18:38:43 +0000961 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +0000962 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000963 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000964 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000965
paul7021c422003-07-15 12:52:22 +0000966 /* If new link is added. */
967 if_add_update (ifp);
968 }
paul718e3742002-12-13 20:15:29 +0000969 else
paul7021c422003-07-15 12:52:22 +0000970 {
971 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +0000972 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +0000973 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000974 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000975
paul7021c422003-07-15 12:52:22 +0000976 if (if_is_operative (ifp))
977 {
978 ifp->flags = ifi->ifi_flags & 0x0000fffff;
979 if (!if_is_operative (ifp))
980 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +0000981 else
982 /* Must notify client daemons of new interface status. */
983 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +0000984 }
985 else
986 {
987 ifp->flags = ifi->ifi_flags & 0x0000fffff;
988 if (if_is_operative (ifp))
989 if_up (ifp);
990 }
991 }
paul718e3742002-12-13 20:15:29 +0000992 }
993 else
994 {
995 /* RTM_DELLINK. */
996 ifp = if_lookup_by_name (name);
997
998 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +0000999 {
1000 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001001 name);
paul7021c422003-07-15 12:52:22 +00001002 return 0;
1003 }
1004
paul718e3742002-12-13 20:15:29 +00001005 if_delete_update (ifp);
1006 }
1007
1008 return 0;
1009}
1010
Stephen Hemminger6072b242008-08-14 16:52:26 +01001011static int
paul718e3742002-12-13 20:15:29 +00001012netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1013{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001014 /* JF: Ignore messages that aren't from the kernel */
1015 if ( snl->nl_pid != 0 )
1016 {
1017 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1018 return 0;
1019 }
1020
paul718e3742002-12-13 20:15:29 +00001021 switch (h->nlmsg_type)
1022 {
1023 case RTM_NEWROUTE:
1024 return netlink_route_change (snl, h);
1025 break;
1026 case RTM_DELROUTE:
1027 return netlink_route_change (snl, h);
1028 break;
1029 case RTM_NEWLINK:
1030 return netlink_link_change (snl, h);
1031 break;
1032 case RTM_DELLINK:
1033 return netlink_link_change (snl, h);
1034 break;
1035 case RTM_NEWADDR:
1036 return netlink_interface_addr (snl, h);
1037 break;
1038 case RTM_DELADDR:
1039 return netlink_interface_addr (snl, h);
1040 break;
1041 default:
1042 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1043 break;
1044 }
1045 return 0;
1046}
1047
1048/* Interface lookup by netlink socket. */
1049int
paul6621ca82005-11-23 13:02:08 +00001050interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001051{
1052 int ret;
paul7021c422003-07-15 12:52:22 +00001053
paul718e3742002-12-13 20:15:29 +00001054 /* Get interface information. */
1055 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1056 if (ret < 0)
1057 return ret;
1058 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1059 if (ret < 0)
1060 return ret;
1061
1062 /* Get IPv4 address of the interfaces. */
1063 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1064 if (ret < 0)
1065 return ret;
1066 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1067 if (ret < 0)
1068 return ret;
1069
1070#ifdef HAVE_IPV6
1071 /* Get IPv6 address of the interfaces. */
1072 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1073 if (ret < 0)
1074 return ret;
1075 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1076 if (ret < 0)
1077 return ret;
1078#endif /* HAVE_IPV6 */
1079
1080 return 0;
1081}
1082
1083/* Routing table read function using netlink interface. Only called
1084 bootstrap time. */
1085int
paul6621ca82005-11-23 13:02:08 +00001086netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001087{
1088 int ret;
paul7021c422003-07-15 12:52:22 +00001089
paul718e3742002-12-13 20:15:29 +00001090 /* Get IPv4 routing table. */
1091 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1092 if (ret < 0)
1093 return ret;
1094 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1095 if (ret < 0)
1096 return ret;
1097
1098#ifdef HAVE_IPV6
1099 /* Get IPv6 routing table. */
1100 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1101 if (ret < 0)
1102 return ret;
1103 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1104 if (ret < 0)
1105 return ret;
1106#endif /* HAVE_IPV6 */
1107
1108 return 0;
1109}
1110
1111/* Utility function comes from iproute2.
1112 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001113static int
paul718e3742002-12-13 20:15:29 +00001114addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1115{
1116 int len;
1117 struct rtattr *rta;
1118
paul7021c422003-07-15 12:52:22 +00001119 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001120
paul7021c422003-07-15 12:52:22 +00001121 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001122 return -1;
1123
paul7021c422003-07-15 12:52:22 +00001124 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001125 rta->rta_type = type;
1126 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001127 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001128 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1129
1130 return 0;
1131}
1132
Stephen Hemminger6072b242008-08-14 16:52:26 +01001133static int
paul718e3742002-12-13 20:15:29 +00001134rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1135{
1136 int len;
1137 struct rtattr *subrta;
1138
paul7021c422003-07-15 12:52:22 +00001139 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001140
paul7021c422003-07-15 12:52:22 +00001141 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001142 return -1;
1143
paul7021c422003-07-15 12:52:22 +00001144 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001145 subrta->rta_type = type;
1146 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001147 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001148 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1149
1150 return 0;
1151}
1152
1153/* Utility function comes from iproute2.
1154 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001155static int
paul718e3742002-12-13 20:15:29 +00001156addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1157{
1158 int len;
1159 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001160
1161 len = RTA_LENGTH (4);
1162
paul718e3742002-12-13 20:15:29 +00001163 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1164 return -1;
1165
paul7021c422003-07-15 12:52:22 +00001166 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001167 rta->rta_type = type;
1168 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001169 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001170 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1171
1172 return 0;
1173}
1174
1175static int
1176netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1177{
hassob7ed1ec2005-03-31 20:13:49 +00001178 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001179 return 0;
1180}
1181
1182/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001183static int
paul718e3742002-12-13 20:15:29 +00001184netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1185{
1186 int status;
1187 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001188 struct iovec iov = { (void *) n, n->nlmsg_len };
1189 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001190 int save_errno;
paul7021c422003-07-15 12:52:22 +00001191
paul718e3742002-12-13 20:15:29 +00001192 memset (&snl, 0, sizeof snl);
1193 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001194
hassob7ed1ec2005-03-31 20:13:49 +00001195 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001196
1197 /* Request an acknowledgement by setting NLM_F_ACK */
1198 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001199
1200 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001201 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001202 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1203 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001204
1205 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001206 if (zserv_privs.change (ZPRIVS_RAISE))
1207 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001208 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001209 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001210 if (zserv_privs.change (ZPRIVS_LOWER))
1211 zlog (NULL, LOG_ERR, "Can't lower privileges");
1212
paul718e3742002-12-13 20:15:29 +00001213 if (status < 0)
1214 {
1215 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001216 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001217 return -1;
1218 }
paul7021c422003-07-15 12:52:22 +00001219
paul718e3742002-12-13 20:15:29 +00001220
1221 /*
1222 * Get reply from netlink socket.
1223 * The reply should either be an acknowlegement or an error.
1224 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001225 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001226}
1227
1228/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001229static int
paul718e3742002-12-13 20:15:29 +00001230netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001231 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001232{
1233 int ret;
1234 int bytelen;
1235 struct sockaddr_nl snl;
1236 int discard;
1237
paul7021c422003-07-15 12:52:22 +00001238 struct
paul718e3742002-12-13 20:15:29 +00001239 {
1240 struct nlmsghdr n;
1241 struct rtmsg r;
1242 char buf[1024];
1243 } req;
1244
1245 memset (&req, 0, sizeof req);
1246
1247 bytelen = (family == AF_INET ? 4 : 16);
1248
1249 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1250 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1251 req.n.nlmsg_type = cmd;
1252 req.r.rtm_family = family;
1253 req.r.rtm_table = table;
1254 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001255 req.r.rtm_protocol = RTPROT_ZEBRA;
1256 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001257
hasso81dfcaa2003-05-25 19:21:25 +00001258 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1259 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001260 discard = 1;
1261 else
1262 discard = 0;
1263
paul7021c422003-07-15 12:52:22 +00001264 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001265 {
paul7021c422003-07-15 12:52:22 +00001266 if (discard)
paul595db7f2003-05-25 21:35:06 +00001267 {
1268 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1269 req.r.rtm_type = RTN_BLACKHOLE;
1270 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1271 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001272 else
1273 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1274 }
paul595db7f2003-05-25 21:35:06 +00001275 else
paul7021c422003-07-15 12:52:22 +00001276 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001277 }
1278
1279 if (dest)
1280 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1281
paul7021c422003-07-15 12:52:22 +00001282 if (!discard)
paul718e3742002-12-13 20:15:29 +00001283 {
1284 if (gate)
paul7021c422003-07-15 12:52:22 +00001285 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001286 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001287 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001288 }
1289
1290 /* Destination netlink address. */
1291 memset (&snl, 0, sizeof snl);
1292 snl.nl_family = AF_NETLINK;
1293
1294 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001295 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001296 if (ret < 0)
1297 return -1;
1298
1299 return 0;
1300}
1301
1302/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001303static int
paul718e3742002-12-13 20:15:29 +00001304netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001305 int family)
paul718e3742002-12-13 20:15:29 +00001306{
1307 int bytelen;
1308 struct sockaddr_nl snl;
1309 struct nexthop *nexthop = NULL;
1310 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001311 int discard;
1312
paul7021c422003-07-15 12:52:22 +00001313 struct
paul718e3742002-12-13 20:15:29 +00001314 {
1315 struct nlmsghdr n;
1316 struct rtmsg r;
1317 char buf[1024];
1318 } req;
1319
1320 memset (&req, 0, sizeof req);
1321
1322 bytelen = (family == AF_INET ? 4 : 16);
1323
1324 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1325 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1326 req.n.nlmsg_type = cmd;
1327 req.r.rtm_family = family;
1328 req.r.rtm_table = rib->table;
1329 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001330 req.r.rtm_protocol = RTPROT_ZEBRA;
1331 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001332
paul7021c422003-07-15 12:52:22 +00001333 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001334 discard = 1;
1335 else
1336 discard = 0;
1337
paul7021c422003-07-15 12:52:22 +00001338 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001339 {
paul7021c422003-07-15 12:52:22 +00001340 if (discard)
paul595db7f2003-05-25 21:35:06 +00001341 {
1342 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1343 req.r.rtm_type = RTN_BLACKHOLE;
1344 else if (rib->flags & ZEBRA_FLAG_REJECT)
1345 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001346 else
1347 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1348 }
paul595db7f2003-05-25 21:35:06 +00001349 else
paul7021c422003-07-15 12:52:22 +00001350 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001351 }
1352
1353 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1354
1355 /* Metric. */
1356 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1357
1358 if (discard)
1359 {
1360 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001361 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1362 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001363 goto skip;
1364 }
1365
1366 /* Multipath case. */
1367 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1368 {
1369 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001370 {
paul5ec90d22003-06-19 01:41:37 +00001371
paul7021c422003-07-15 12:52:22 +00001372 if ((cmd == RTM_NEWROUTE
1373 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1374 || (cmd == RTM_DELROUTE
1375 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1376 {
paul5ec90d22003-06-19 01:41:37 +00001377
paul7021c422003-07-15 12:52:22 +00001378 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1379 {
1380 if (IS_ZEBRA_DEBUG_KERNEL)
1381 {
ajsb6178002004-12-07 21:12:56 +00001382 zlog_debug
paul7021c422003-07-15 12:52:22 +00001383 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001384 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001385#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001386 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001387 inet6_ntoa (p->u.prefix6),
1388#else
1389 inet_ntoa (p->u.prefix4),
1390#endif /* HAVE_IPV6 */
1391
1392 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001393 }
paul5ec90d22003-06-19 01:41:37 +00001394
paul7021c422003-07-15 12:52:22 +00001395 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1396 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001397 {
1398 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1399 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001400 if (nexthop->src.ipv4.s_addr)
1401 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1402 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001403 if (IS_ZEBRA_DEBUG_KERNEL)
1404 zlog_debug("netlink_route_multipath() (recursive, "
1405 "1 hop): nexthop via %s if %u",
1406 inet_ntoa (nexthop->rgate.ipv4),
1407 nexthop->rifindex);
1408 }
paul718e3742002-12-13 20:15:29 +00001409#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001410 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1411 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1412 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001413 {
1414 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1415 &nexthop->rgate.ipv6, bytelen);
1416
1417 if (IS_ZEBRA_DEBUG_KERNEL)
1418 zlog_debug("netlink_route_multipath() (recursive, "
1419 "1 hop): nexthop via %s if %u",
1420 inet6_ntoa (nexthop->rgate.ipv6),
1421 nexthop->rifindex);
1422 }
paul718e3742002-12-13 20:15:29 +00001423#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001424 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1425 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1426 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1427 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1428 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001429 {
1430 addattr32 (&req.n, sizeof req, RTA_OIF,
1431 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001432 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1433 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1434 && nexthop->src.ipv4.s_addr)
1435 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1436 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001437
1438 if (IS_ZEBRA_DEBUG_KERNEL)
1439 zlog_debug("netlink_route_multipath() (recursive, "
1440 "1 hop): nexthop via if %u",
1441 nexthop->rifindex);
1442 }
paul7021c422003-07-15 12:52:22 +00001443 }
1444 else
1445 {
1446 if (IS_ZEBRA_DEBUG_KERNEL)
1447 {
ajsb6178002004-12-07 21:12:56 +00001448 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001449 ("netlink_route_multipath() (single hop): "
1450 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001451#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001452 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001453 inet6_ntoa (p->u.prefix6),
1454#else
1455 inet_ntoa (p->u.prefix4),
1456#endif /* HAVE_IPV6 */
1457 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001458 }
paul5ec90d22003-06-19 01:41:37 +00001459
paul7021c422003-07-15 12:52:22 +00001460 if (nexthop->type == NEXTHOP_TYPE_IPV4
1461 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001462 {
1463 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1464 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001465 if (nexthop->src.ipv4.s_addr)
1466 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1467 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001468
1469 if (IS_ZEBRA_DEBUG_KERNEL)
1470 zlog_debug("netlink_route_multipath() (single hop): "
1471 "nexthop via %s if %u",
1472 inet_ntoa (nexthop->gate.ipv4),
1473 nexthop->ifindex);
1474 }
paul718e3742002-12-13 20:15:29 +00001475#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001476 if (nexthop->type == NEXTHOP_TYPE_IPV6
1477 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1478 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001479 {
1480 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1481 &nexthop->gate.ipv6, bytelen);
1482
1483 if (IS_ZEBRA_DEBUG_KERNEL)
1484 zlog_debug("netlink_route_multipath() (single hop): "
1485 "nexthop via %s if %u",
1486 inet6_ntoa (nexthop->gate.ipv6),
1487 nexthop->ifindex);
1488 }
paul718e3742002-12-13 20:15:29 +00001489#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001490 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1491 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001492 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1493 {
1494 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1495
1496 if (nexthop->src.ipv4.s_addr)
1497 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1498 &nexthop->src.ipv4, bytelen);
1499
1500 if (IS_ZEBRA_DEBUG_KERNEL)
1501 zlog_debug("netlink_route_multipath() (single hop): "
1502 "nexthop via if %u", nexthop->ifindex);
1503 }
1504 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001505 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001506 {
1507 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1508
1509 if (IS_ZEBRA_DEBUG_KERNEL)
1510 zlog_debug("netlink_route_multipath() (single hop): "
1511 "nexthop via if %u", nexthop->ifindex);
1512 }
paul7021c422003-07-15 12:52:22 +00001513 }
paul718e3742002-12-13 20:15:29 +00001514
paul7021c422003-07-15 12:52:22 +00001515 if (cmd == RTM_NEWROUTE)
1516 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001517
paul7021c422003-07-15 12:52:22 +00001518 nexthop_num++;
1519 break;
1520 }
1521 }
paul718e3742002-12-13 20:15:29 +00001522 }
1523 else
1524 {
1525 char buf[1024];
1526 struct rtattr *rta = (void *) buf;
1527 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001528 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001529
1530 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001531 rta->rta_len = RTA_LENGTH (0);
1532 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001533
1534 nexthop_num = 0;
1535 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001536 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1537 nexthop = nexthop->next)
1538 {
1539 if ((cmd == RTM_NEWROUTE
1540 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1541 || (cmd == RTM_DELROUTE
1542 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1543 {
1544 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001545
paul7021c422003-07-15 12:52:22 +00001546 rtnh->rtnh_len = sizeof (*rtnh);
1547 rtnh->rtnh_flags = 0;
1548 rtnh->rtnh_hops = 0;
1549 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001550
paul7021c422003-07-15 12:52:22 +00001551 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1552 {
1553 if (IS_ZEBRA_DEBUG_KERNEL)
1554 {
ajsb6178002004-12-07 21:12:56 +00001555 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001556 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001557 lookup (nlmsg_str, cmd),
1558#ifdef HAVE_IPV6
1559 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1560 inet6_ntoa (p->u.prefix6),
1561#else
1562 inet_ntoa (p->u.prefix4),
1563#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001564 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001565 }
1566 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1567 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1568 {
1569 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1570 &nexthop->rgate.ipv4, bytelen);
1571 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001572
Paul Jakma7514fb72007-05-02 16:05:35 +00001573 if (nexthop->src.ipv4.s_addr)
1574 src = &nexthop->src;
1575
hasso206d8052005-04-09 16:38:51 +00001576 if (IS_ZEBRA_DEBUG_KERNEL)
1577 zlog_debug("netlink_route_multipath() (recursive, "
1578 "multihop): nexthop via %s if %u",
1579 inet_ntoa (nexthop->rgate.ipv4),
1580 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001581 }
paul718e3742002-12-13 20:15:29 +00001582#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001583 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1584 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1585 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001586 {
1587 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1588 &nexthop->rgate.ipv6, bytelen);
1589
1590 if (IS_ZEBRA_DEBUG_KERNEL)
1591 zlog_debug("netlink_route_multipath() (recursive, "
1592 "multihop): nexthop via %s if %u",
1593 inet6_ntoa (nexthop->rgate.ipv6),
1594 nexthop->rifindex);
1595 }
paul718e3742002-12-13 20:15:29 +00001596#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001597 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001598 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1599 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1600 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1601 {
1602 rtnh->rtnh_ifindex = nexthop->rifindex;
1603 if (nexthop->src.ipv4.s_addr)
1604 src = &nexthop->src;
1605
1606 if (IS_ZEBRA_DEBUG_KERNEL)
1607 zlog_debug("netlink_route_multipath() (recursive, "
1608 "multihop): nexthop via if %u",
1609 nexthop->rifindex);
1610 }
1611 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001612 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001613 {
1614 rtnh->rtnh_ifindex = nexthop->rifindex;
1615
1616 if (IS_ZEBRA_DEBUG_KERNEL)
1617 zlog_debug("netlink_route_multipath() (recursive, "
1618 "multihop): nexthop via if %u",
1619 nexthop->rifindex);
1620 }
paul7021c422003-07-15 12:52:22 +00001621 else
hasso206d8052005-04-09 16:38:51 +00001622 {
1623 rtnh->rtnh_ifindex = 0;
1624 }
paul7021c422003-07-15 12:52:22 +00001625 }
1626 else
1627 {
1628 if (IS_ZEBRA_DEBUG_KERNEL)
1629 {
hasso206d8052005-04-09 16:38:51 +00001630 zlog_debug ("netlink_route_multipath() (multihop): "
1631 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001632#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001633 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001634 inet6_ntoa (p->u.prefix6),
1635#else
1636 inet_ntoa (p->u.prefix4),
1637#endif /* HAVE_IPV6 */
1638 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001639 }
1640 if (nexthop->type == NEXTHOP_TYPE_IPV4
1641 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1642 {
hasso206d8052005-04-09 16:38:51 +00001643 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1644 &nexthop->gate.ipv4, bytelen);
1645 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1646
Paul Jakma7514fb72007-05-02 16:05:35 +00001647 if (nexthop->src.ipv4.s_addr)
1648 src = &nexthop->src;
1649
hasso206d8052005-04-09 16:38:51 +00001650 if (IS_ZEBRA_DEBUG_KERNEL)
1651 zlog_debug("netlink_route_multipath() (multihop): "
1652 "nexthop via %s if %u",
1653 inet_ntoa (nexthop->gate.ipv4),
1654 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001655 }
paul718e3742002-12-13 20:15:29 +00001656#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001657 if (nexthop->type == NEXTHOP_TYPE_IPV6
1658 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1659 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001660 {
1661 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1662 &nexthop->gate.ipv6, bytelen);
1663
1664 if (IS_ZEBRA_DEBUG_KERNEL)
1665 zlog_debug("netlink_route_multipath() (multihop): "
1666 "nexthop via %s if %u",
1667 inet6_ntoa (nexthop->gate.ipv6),
1668 nexthop->ifindex);
1669 }
paul718e3742002-12-13 20:15:29 +00001670#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001671 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001672 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1673 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1674 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1675 {
1676 rtnh->rtnh_ifindex = nexthop->ifindex;
1677 if (nexthop->src.ipv4.s_addr)
1678 src = &nexthop->src;
1679 if (IS_ZEBRA_DEBUG_KERNEL)
1680 zlog_debug("netlink_route_multipath() (multihop): "
1681 "nexthop via if %u", nexthop->ifindex);
1682 }
1683 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001684 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001685 {
1686 rtnh->rtnh_ifindex = nexthop->ifindex;
1687
1688 if (IS_ZEBRA_DEBUG_KERNEL)
1689 zlog_debug("netlink_route_multipath() (multihop): "
1690 "nexthop via if %u", nexthop->ifindex);
1691 }
paul7021c422003-07-15 12:52:22 +00001692 else
hasso206d8052005-04-09 16:38:51 +00001693 {
1694 rtnh->rtnh_ifindex = 0;
1695 }
paul7021c422003-07-15 12:52:22 +00001696 }
1697 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001698
paul7021c422003-07-15 12:52:22 +00001699 if (cmd == RTM_NEWROUTE)
1700 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1701 }
1702 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001703 if (src)
1704 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001705
1706 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001707 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1708 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001709 }
1710
1711 /* If there is no useful nexthop then return. */
1712 if (nexthop_num == 0)
1713 {
1714 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001715 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001716 return 0;
1717 }
1718
paul7021c422003-07-15 12:52:22 +00001719skip:
paul718e3742002-12-13 20:15:29 +00001720
1721 /* Destination netlink address. */
1722 memset (&snl, 0, sizeof snl);
1723 snl.nl_family = AF_NETLINK;
1724
paul718e3742002-12-13 20:15:29 +00001725 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001726 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001727}
1728
1729int
1730kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1731{
1732 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1733}
1734
1735int
1736kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1737{
1738 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1739}
1740
1741#ifdef HAVE_IPV6
1742int
1743kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1744{
1745 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1746}
1747
1748int
1749kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1750{
1751 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1752}
1753
1754/* Delete IPv6 route from the kernel. */
1755int
1756kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001757 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001758{
paul7021c422003-07-15 12:52:22 +00001759 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1760 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001761}
1762#endif /* HAVE_IPV6 */
1763
1764/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001765static int
paul718e3742002-12-13 20:15:29 +00001766netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001767 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001768{
1769 int bytelen;
1770 struct prefix *p;
1771
paul7021c422003-07-15 12:52:22 +00001772 struct
paul718e3742002-12-13 20:15:29 +00001773 {
1774 struct nlmsghdr n;
1775 struct ifaddrmsg ifa;
1776 char buf[1024];
1777 } req;
1778
1779 p = ifc->address;
1780 memset (&req, 0, sizeof req);
1781
1782 bytelen = (family == AF_INET ? 4 : 16);
1783
paul7021c422003-07-15 12:52:22 +00001784 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001785 req.n.nlmsg_flags = NLM_F_REQUEST;
1786 req.n.nlmsg_type = cmd;
1787 req.ifa.ifa_family = family;
1788
1789 req.ifa.ifa_index = ifp->ifindex;
1790 req.ifa.ifa_prefixlen = p->prefixlen;
1791
1792 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1793
1794 if (family == AF_INET && cmd == RTM_NEWADDR)
1795 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001796 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001797 {
1798 p = ifc->destination;
1799 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1800 bytelen);
1801 }
paul718e3742002-12-13 20:15:29 +00001802 }
1803
1804 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1805 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001806
paul718e3742002-12-13 20:15:29 +00001807 if (ifc->label)
1808 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001809 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001810
1811 return netlink_talk (&req.n, &netlink_cmd);
1812}
1813
1814int
1815kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1816{
1817 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1818}
1819
1820int
1821kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1822{
1823 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1824}
1825
paul718e3742002-12-13 20:15:29 +00001826
1827extern struct thread_master *master;
1828
1829/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001830static int
paul718e3742002-12-13 20:15:29 +00001831kernel_read (struct thread *thread)
1832{
1833 int ret;
1834 int sock;
1835
1836 sock = THREAD_FD (thread);
1837 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001838 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001839
1840 return 0;
1841}
1842
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001843/* Filter out messages from self that occur on listener socket,
1844 caused by our actions on the command socket
1845 */
1846static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001847{
Paul Jakma768a27e2008-05-29 18:23:08 +00001848 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001849 /* 0: ldh [4] */
1850 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1851 /* 1: jeq 0x18 jt 3 jf 6 */
1852 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1853 /* 2: jeq 0x19 jt 3 jf 6 */
1854 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1855 /* 3: ldw [12] */
1856 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1857 /* 4: jeq XX jt 5 jf 6 */
1858 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1859 /* 5: ret 0 (skip) */
1860 BPF_STMT(BPF_RET|BPF_K, 0),
1861 /* 6: ret 0xffff (keep) */
1862 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001863 };
1864
1865 struct sock_fprog prog = {
1866 .len = sizeof(filter) / sizeof(filter[0]),
1867 .filter = filter,
1868 };
1869
1870 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1871 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1872}
1873
paul718e3742002-12-13 20:15:29 +00001874/* Exported interface function. This function simply calls
1875 netlink_socket (). */
1876void
paul6621ca82005-11-23 13:02:08 +00001877kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001878{
1879 unsigned long groups;
1880
paul7021c422003-07-15 12:52:22 +00001881 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001882#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001883 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001884#endif /* HAVE_IPV6 */
1885 netlink_socket (&netlink, groups);
1886 netlink_socket (&netlink_cmd, 0);
1887
1888 /* Register kernel socket. */
1889 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001890 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001891 /* Only want non-blocking on the netlink event socket */
1892 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1893 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1894 safe_strerror (errno));
1895
Stephen Hemminger30afea32008-08-16 18:25:47 +01001896 /* Set receive buffer size if it's set from command line */
1897 if (nl_rcvbufsize)
1898 netlink_recvbuf (&netlink, nl_rcvbufsize);
1899
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001900 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001901 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1902 }
paul718e3742002-12-13 20:15:29 +00001903}