blob: fe55d43ecaaa155791485384e98f0207c649a445 [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
paul718e3742002-12-13 20:15:29 +0000115/* Make socket for Linux netlink interface. */
116static int
117netlink_socket (struct nlsock *nl, unsigned long groups)
118{
119 int ret;
120 struct sockaddr_nl snl;
121 int sock;
122 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000123 int save_errno;
paul718e3742002-12-13 20:15:29 +0000124
125 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
126 if (sock < 0)
127 {
128 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000129 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000130 return -1;
131 }
132
paul7021c422003-07-15 12:52:22 +0000133
hassoc34b6b52004-08-31 13:41:49 +0000134 /* Set receive buffer size if it's set from command line */
135 if (nl_rcvbufsize)
136 {
137 u_int32_t oldsize, oldlen;
138 u_int32_t newsize, newlen;
139
140 oldlen = sizeof(oldsize);
141 newlen = sizeof(newsize);
142
143 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
144 if (ret < 0)
145 {
146 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000147 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000148 close (sock);
149 return -1;
150 }
151
152 ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
153 sizeof(nl_rcvbufsize));
154 if (ret < 0)
155 {
156 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000157 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000158 close (sock);
159 return -1;
160 }
161
162 ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
163 if (ret < 0)
164 {
165 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000166 safe_strerror (errno));
hassoc34b6b52004-08-31 13:41:49 +0000167 close (sock);
168 return -1;
169 }
170
171 zlog (NULL, LOG_INFO,
172 "Setting netlink socket receive buffer size: %u -> %u",
173 oldsize, newsize);
174 }
175
paul718e3742002-12-13 20:15:29 +0000176 memset (&snl, 0, sizeof snl);
177 snl.nl_family = AF_NETLINK;
178 snl.nl_groups = groups;
179
180 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000181 if (zserv_privs.change (ZPRIVS_RAISE))
182 {
183 zlog (NULL, LOG_ERR, "Can't raise privileges");
184 return -1;
185 }
pauledd7c242003-06-04 13:59:38 +0000186
paul718e3742002-12-13 20:15:29 +0000187 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000188 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000189 if (zserv_privs.change (ZPRIVS_LOWER))
190 zlog (NULL, LOG_ERR, "Can't lower privileges");
191
paul718e3742002-12-13 20:15:29 +0000192 if (ret < 0)
193 {
paul7021c422003-07-15 12:52:22 +0000194 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000195 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000196 close (sock);
197 return -1;
198 }
paul7021c422003-07-15 12:52:22 +0000199
paul718e3742002-12-13 20:15:29 +0000200 /* multiple netlink sockets will have different nl_pid */
201 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000202 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000203 if (ret < 0 || namelen != sizeof snl)
204 {
205 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000206 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000207 close (sock);
208 return -1;
209 }
210
211 nl->snl = snl;
212 nl->sock = sock;
213 return ret;
214}
215
216/* Get type specified information from netlink. */
217static int
218netlink_request (int family, int type, struct nlsock *nl)
219{
220 int ret;
221 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000222 int save_errno;
paul718e3742002-12-13 20:15:29 +0000223
224 struct
225 {
226 struct nlmsghdr nlh;
227 struct rtgenmsg g;
228 } req;
229
230
231 /* Check netlink socket. */
232 if (nl->sock < 0)
233 {
234 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
235 return -1;
236 }
237
238 memset (&snl, 0, sizeof snl);
239 snl.nl_family = AF_NETLINK;
240
ajsc05612b2005-10-01 16:36:54 +0000241 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000242 req.nlh.nlmsg_len = sizeof req;
243 req.nlh.nlmsg_type = type;
244 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100245 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000246 req.nlh.nlmsg_seq = ++nl->seq;
247 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000248
249 /* linux appears to check capabilities on every message
250 * have to raise caps for every message sent
251 */
paul7021c422003-07-15 12:52:22 +0000252 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000253 {
254 zlog (NULL, LOG_ERR, "Can't raise privileges");
255 return -1;
256 }
paul7021c422003-07-15 12:52:22 +0000257
258 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
259 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000260 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000261
262 if (zserv_privs.change (ZPRIVS_LOWER))
263 zlog (NULL, LOG_ERR, "Can't lower privileges");
264
paul718e3742002-12-13 20:15:29 +0000265 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000266 {
267 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000268 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000269 return -1;
270 }
pauledd7c242003-06-04 13:59:38 +0000271
paul718e3742002-12-13 20:15:29 +0000272 return 0;
273}
274
275/* Receive message from netlink interface and pass those information
276 to the given function. */
277static int
278netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000279 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000280{
281 int status;
282 int ret = 0;
283 int error;
284
285 while (1)
286 {
287 char buf[4096];
288 struct iovec iov = { buf, sizeof buf };
289 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000290 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000291 struct nlmsghdr *h;
ajs4be019d2005-01-29 16:12:41 +0000292 int save_errno;
paul718e3742002-12-13 20:15:29 +0000293
paul7021c422003-07-15 12:52:22 +0000294 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000295 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul7021c422003-07-15 12:52:22 +0000296
paul718e3742002-12-13 20:15:29 +0000297 status = recvmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +0000298 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000299
300 if (zserv_privs.change (ZPRIVS_LOWER))
pauledd7c242003-06-04 13:59:38 +0000301 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +0000302
303 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000304 {
ajs4be019d2005-01-29 16:12:41 +0000305 if (save_errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000306 continue;
ajs4be019d2005-01-29 16:12:41 +0000307 if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000308 break;
ajs4be019d2005-01-29 16:12:41 +0000309 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
310 nl->name, safe_strerror(save_errno));
paul7021c422003-07-15 12:52:22 +0000311 continue;
312 }
paul718e3742002-12-13 20:15:29 +0000313
314 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000315 {
316 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
317 return -1;
318 }
paul718e3742002-12-13 20:15:29 +0000319
320 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000321 {
322 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
323 nl->name, msg.msg_namelen);
324 return -1;
325 }
paulb84d3a12003-11-17 10:31:01 +0000326
hasso206d8052005-04-09 16:38:51 +0000327 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000328 h = NLMSG_NEXT (h, status))
329 {
330 /* Finish of reading. */
331 if (h->nlmsg_type == NLMSG_DONE)
332 return ret;
paul718e3742002-12-13 20:15:29 +0000333
paul7021c422003-07-15 12:52:22 +0000334 /* Error handling. */
335 if (h->nlmsg_type == NLMSG_ERROR)
336 {
337 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
338
paul718e3742002-12-13 20:15:29 +0000339 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000340 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000341 {
paul7021c422003-07-15 12:52:22 +0000342 if (IS_ZEBRA_DEBUG_KERNEL)
343 {
hasso1ada8192005-06-12 11:28:18 +0000344 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000345 __FUNCTION__, nl->name,
346 lookup (nlmsg_str, err->msg.nlmsg_type),
347 err->msg.nlmsg_type, err->msg.nlmsg_seq,
348 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000349 }
paul7021c422003-07-15 12:52:22 +0000350
351 /* return if not a multipart message, otherwise continue */
352 if (!(h->nlmsg_flags & NLM_F_MULTI))
353 {
354 return 0;
paul718e3742002-12-13 20:15:29 +0000355 }
paul7021c422003-07-15 12:52:22 +0000356 continue;
paul718e3742002-12-13 20:15:29 +0000357 }
paul7021c422003-07-15 12:52:22 +0000358
paul718e3742002-12-13 20:15:29 +0000359 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000360 {
361 zlog (NULL, LOG_ERR, "%s error: message truncated",
362 nl->name);
363 return -1;
364 }
pauld753e9e2003-01-22 19:45:50 +0000365
paul7021c422003-07-15 12:52:22 +0000366 /* Deal with Error Noise - MAG */
367 {
368 int loglvl = LOG_ERR;
369 int errnum = err->error;
370 int msg_type = err->msg.nlmsg_type;
paul718e3742002-12-13 20:15:29 +0000371
paul7021c422003-07-15 12:52:22 +0000372 if (nl == &netlink_cmd
373 && (-errnum == ENODEV || -errnum == ESRCH)
374 && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
375 loglvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +0000376
paul7021c422003-07-15 12:52:22 +0000377 zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
hasso1ada8192005-06-12 11:28:18 +0000378 "seq=%u, pid=%u",
ajs6099b3b2004-11-20 02:06:59 +0000379 nl->name, safe_strerror (-errnum),
paul7021c422003-07-15 12:52:22 +0000380 lookup (nlmsg_str, msg_type),
381 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
382 }
383 /*
384 ret = -1;
385 continue;
386 */
387 return -1;
388 }
paul718e3742002-12-13 20:15:29 +0000389
paul7021c422003-07-15 12:52:22 +0000390 /* OK we got netlink message. */
391 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000392 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000393 nl->name,
394 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
395 h->nlmsg_seq, h->nlmsg_pid);
396
397 /* skip unsolicited messages originating from command socket */
398 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
399 {
400 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000401 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000402 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000403 continue;
404 }
405
406 error = (*filter) (&snl, h);
407 if (error < 0)
408 {
409 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
410 ret = error;
411 }
412 }
paul718e3742002-12-13 20:15:29 +0000413
414 /* After error care. */
415 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000416 {
417 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
418 continue;
419 }
paul718e3742002-12-13 20:15:29 +0000420 if (status)
paul7021c422003-07-15 12:52:22 +0000421 {
422 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
423 status);
424 return -1;
425 }
paul718e3742002-12-13 20:15:29 +0000426 }
427 return ret;
428}
429
430/* Utility function for parse rtattr. */
431static void
paul7021c422003-07-15 12:52:22 +0000432netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
433 int len)
paul718e3742002-12-13 20:15:29 +0000434{
paul7021c422003-07-15 12:52:22 +0000435 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000436 {
437 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000438 tb[rta->rta_type] = rta;
439 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000440 }
441}
442
443/* Called from interface_lookup_netlink(). This function is only used
444 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100445static int
paul718e3742002-12-13 20:15:29 +0000446netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
447{
448 int len;
449 struct ifinfomsg *ifi;
450 struct rtattr *tb[IFLA_MAX + 1];
451 struct interface *ifp;
452 char *name;
453 int i;
454
455 ifi = NLMSG_DATA (h);
456
457 if (h->nlmsg_type != RTM_NEWLINK)
458 return 0;
459
460 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
461 if (len < 0)
462 return -1;
463
464 /* Looking up interface name. */
465 memset (tb, 0, sizeof tb);
466 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000467
paul1e193152005-02-14 23:53:05 +0000468#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000469 /* check for wireless messages to ignore */
470 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
471 {
472 if (IS_ZEBRA_DEBUG_KERNEL)
473 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
474 return 0;
475 }
paul1e193152005-02-14 23:53:05 +0000476#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000477
paul718e3742002-12-13 20:15:29 +0000478 if (tb[IFLA_IFNAME] == NULL)
479 return -1;
paul7021c422003-07-15 12:52:22 +0000480 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000481
482 /* Add interface. */
483 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000484 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000485 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000486 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000487 ifp->metric = 1;
488
489 /* Hardware type and address. */
490 ifp->hw_type = ifi->ifi_type;
491
492 if (tb[IFLA_ADDRESS])
493 {
494 int hw_addr_len;
495
paul7021c422003-07-15 12:52:22 +0000496 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
paul718e3742002-12-13 20:15:29 +0000497
498 if (hw_addr_len > INTERFACE_HWADDR_MAX)
paul7021c422003-07-15 12:52:22 +0000499 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000500 else
paul7021c422003-07-15 12:52:22 +0000501 {
502 ifp->hw_addr_len = hw_addr_len;
503 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
paul718e3742002-12-13 20:15:29 +0000504
paul7021c422003-07-15 12:52:22 +0000505 for (i = 0; i < hw_addr_len; i++)
506 if (ifp->hw_addr[i] != 0)
507 break;
paul718e3742002-12-13 20:15:29 +0000508
paul7021c422003-07-15 12:52:22 +0000509 if (i == hw_addr_len)
510 ifp->hw_addr_len = 0;
511 else
512 ifp->hw_addr_len = hw_addr_len;
513 }
paul718e3742002-12-13 20:15:29 +0000514 }
515
516 if_add_update (ifp);
517
518 return 0;
519}
520
521/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100522static int
paul718e3742002-12-13 20:15:29 +0000523netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
524{
525 int len;
526 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000527 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000528 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000529 void *addr;
530 void *broad;
paul718e3742002-12-13 20:15:29 +0000531 u_char flags = 0;
532 char *label = NULL;
533
534 ifa = NLMSG_DATA (h);
535
paul7021c422003-07-15 12:52:22 +0000536 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000537#ifdef HAVE_IPV6
538 && ifa->ifa_family != AF_INET6
539#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000540 )
paul718e3742002-12-13 20:15:29 +0000541 return 0;
542
543 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
544 return 0;
545
paul7021c422003-07-15 12:52:22 +0000546 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000547 if (len < 0)
548 return -1;
549
550 memset (tb, 0, sizeof tb);
551 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
552
553 ifp = if_lookup_by_index (ifa->ifa_index);
554 if (ifp == NULL)
555 {
556 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000557 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000558 return -1;
559 }
560
paul7021c422003-07-15 12:52:22 +0000561 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000562 {
paul00df0c12002-12-13 21:07:36 +0000563 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000564 zlog_debug ("netlink_interface_addr %s %s:",
565 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000566 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000567 zlog_debug (" IFA_LOCAL %s/%d",
568 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
569 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000570 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000571 zlog_debug (" IFA_ADDRESS %s/%d",
572 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
573 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000574 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000575 zlog_debug (" IFA_BROADCAST %s/%d",
576 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
577 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000578 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000579 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000580
581 if (tb[IFA_CACHEINFO])
582 {
583 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
584 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
585 ci->ifa_prefered, ci->ifa_valid);
586 }
paul718e3742002-12-13 20:15:29 +0000587 }
paul31a476c2003-09-29 19:54:53 +0000588
Andrew J. Schorre4529632006-12-12 19:18:21 +0000589 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
590 if (tb[IFA_LOCAL] == NULL)
591 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000592 if (tb[IFA_ADDRESS] == NULL)
593 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
594
Andrew J. Schorre4529632006-12-12 19:18:21 +0000595 /* local interface address */
596 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
597
598 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000599 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000600 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000601 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000602 broad = RTA_DATA(tb[IFA_ADDRESS]);
603 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000604 }
paul31a476c2003-09-29 19:54:53 +0000605 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000606 /* seeking a broadcast address */
607 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000608
Paul Jakma27b47252006-07-02 16:38:54 +0000609 /* addr is primary key, SOL if we don't have one */
610 if (addr == NULL)
611 {
612 zlog_debug ("%s: NULL address", __func__);
613 return -1;
614 }
615
paul718e3742002-12-13 20:15:29 +0000616 /* Flags. */
617 if (ifa->ifa_flags & IFA_F_SECONDARY)
618 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
619
620 /* Label */
621 if (tb[IFA_LABEL])
622 label = (char *) RTA_DATA (tb[IFA_LABEL]);
623
624 if (ifp && label && strcmp (ifp->name, label) == 0)
625 label = NULL;
626
627 /* Register interface address to the interface. */
628 if (ifa->ifa_family == AF_INET)
629 {
paul7021c422003-07-15 12:52:22 +0000630 if (h->nlmsg_type == RTM_NEWADDR)
631 connected_add_ipv4 (ifp, flags,
632 (struct in_addr *) addr, ifa->ifa_prefixlen,
633 (struct in_addr *) broad, label);
634 else
635 connected_delete_ipv4 (ifp, flags,
636 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000637 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000638 }
639#ifdef HAVE_IPV6
640 if (ifa->ifa_family == AF_INET6)
641 {
642 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000643 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000644 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000645 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000646 else
paul7021c422003-07-15 12:52:22 +0000647 connected_delete_ipv6 (ifp,
648 (struct in6_addr *) addr, ifa->ifa_prefixlen,
649 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000650 }
paul7021c422003-07-15 12:52:22 +0000651#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000652
653 return 0;
654}
655
656/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100657static int
paul718e3742002-12-13 20:15:29 +0000658netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
659{
660 int len;
661 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000662 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000663 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000664
665 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000666
667 int index;
668 int table;
hasso34195bf2004-04-06 12:07:06 +0000669 int metric;
670
paul718e3742002-12-13 20:15:29 +0000671 void *dest;
672 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000673 void *src;
paul718e3742002-12-13 20:15:29 +0000674
675 rtm = NLMSG_DATA (h);
676
677 if (h->nlmsg_type != RTM_NEWROUTE)
678 return 0;
679 if (rtm->rtm_type != RTN_UNICAST)
680 return 0;
681
682 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000683#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000684 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000685 return 0;
686#endif
687
paul7021c422003-07-15 12:52:22 +0000688 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000689 if (len < 0)
690 return -1;
691
692 memset (tb, 0, sizeof tb);
693 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
694
695 if (rtm->rtm_flags & RTM_F_CLONED)
696 return 0;
697 if (rtm->rtm_protocol == RTPROT_REDIRECT)
698 return 0;
699 if (rtm->rtm_protocol == RTPROT_KERNEL)
700 return 0;
701
702 if (rtm->rtm_src_len != 0)
703 return 0;
704
705 /* Route which inserted by Zebra. */
706 if (rtm->rtm_protocol == RTPROT_ZEBRA)
707 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000708
paul718e3742002-12-13 20:15:29 +0000709 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000710 metric = 0;
paul718e3742002-12-13 20:15:29 +0000711 dest = NULL;
712 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000713 src = NULL;
paul718e3742002-12-13 20:15:29 +0000714
715 if (tb[RTA_OIF])
716 index = *(int *) RTA_DATA (tb[RTA_OIF]);
717
718 if (tb[RTA_DST])
719 dest = RTA_DATA (tb[RTA_DST]);
720 else
721 dest = anyaddr;
722
Paul Jakma7514fb72007-05-02 16:05:35 +0000723 if (tb[RTA_PREFSRC])
724 src = RTA_DATA (tb[RTA_PREFSRC]);
725
paul718e3742002-12-13 20:15:29 +0000726 /* Multipath treatment is needed. */
727 if (tb[RTA_GATEWAY])
728 gate = RTA_DATA (tb[RTA_GATEWAY]);
729
hasso34195bf2004-04-06 12:07:06 +0000730 if (tb[RTA_PRIORITY])
731 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
732
paul718e3742002-12-13 20:15:29 +0000733 if (rtm->rtm_family == AF_INET)
734 {
735 struct prefix_ipv4 p;
736 p.family = AF_INET;
737 memcpy (&p.prefix, dest, 4);
738 p.prefixlen = rtm->rtm_dst_len;
739
Paul Jakma7514fb72007-05-02 16:05:35 +0000740 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
paul718e3742002-12-13 20:15:29 +0000741 }
742#ifdef HAVE_IPV6
743 if (rtm->rtm_family == AF_INET6)
744 {
745 struct prefix_ipv6 p;
746 p.family = AF_INET6;
747 memcpy (&p.prefix, dest, 16);
748 p.prefixlen = rtm->rtm_dst_len;
749
hassobe61c4e2005-08-27 06:05:47 +0000750 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
751 metric, 0);
paul718e3742002-12-13 20:15:29 +0000752 }
753#endif /* HAVE_IPV6 */
754
755 return 0;
756}
757
Stephen Hemminger1423c802008-08-14 17:59:25 +0100758static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000759 {RTPROT_REDIRECT, "redirect"},
760 {RTPROT_KERNEL, "kernel"},
761 {RTPROT_BOOT, "boot"},
762 {RTPROT_STATIC, "static"},
763 {RTPROT_GATED, "GateD"},
764 {RTPROT_RA, "router advertisement"},
765 {RTPROT_MRT, "MRT"},
766 {RTPROT_ZEBRA, "Zebra"},
767#ifdef RTPROT_BIRD
768 {RTPROT_BIRD, "BIRD"},
769#endif /* RTPROT_BIRD */
770 {0, NULL}
771};
772
773/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100774static int
paul718e3742002-12-13 20:15:29 +0000775netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
776{
777 int len;
778 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000779 struct rtattr *tb[RTA_MAX + 1];
780
781 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000782
783 int index;
784 int table;
785 void *dest;
786 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000787 void *src;
paul718e3742002-12-13 20:15:29 +0000788
789 rtm = NLMSG_DATA (h);
790
paul7021c422003-07-15 12:52:22 +0000791 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000792 {
793 /* If this is not route add/delete message print warning. */
794 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
795 return 0;
796 }
797
798 /* Connected route. */
799 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000800 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000801 h->nlmsg_type ==
802 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
803 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
804 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
805 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000806
807 if (rtm->rtm_type != RTN_UNICAST)
808 {
809 return 0;
810 }
811
812 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000813 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000814 {
815 return 0;
816 }
817
paul7021c422003-07-15 12:52:22 +0000818 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000819 if (len < 0)
820 return -1;
821
822 memset (tb, 0, sizeof tb);
823 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
824
825 if (rtm->rtm_flags & RTM_F_CLONED)
826 return 0;
827 if (rtm->rtm_protocol == RTPROT_REDIRECT)
828 return 0;
829 if (rtm->rtm_protocol == RTPROT_KERNEL)
830 return 0;
831
832 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
833 return 0;
834
835 if (rtm->rtm_src_len != 0)
836 {
837 zlog_warn ("netlink_route_change(): no src len");
838 return 0;
839 }
paul7021c422003-07-15 12:52:22 +0000840
paul718e3742002-12-13 20:15:29 +0000841 index = 0;
842 dest = NULL;
843 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000844 src = NULL;
paul718e3742002-12-13 20:15:29 +0000845
846 if (tb[RTA_OIF])
847 index = *(int *) RTA_DATA (tb[RTA_OIF]);
848
849 if (tb[RTA_DST])
850 dest = RTA_DATA (tb[RTA_DST]);
851 else
852 dest = anyaddr;
853
854 if (tb[RTA_GATEWAY])
855 gate = RTA_DATA (tb[RTA_GATEWAY]);
856
Paul Jakma7514fb72007-05-02 16:05:35 +0000857 if (tb[RTA_PREFSRC])
858 src = RTA_DATA (tb[RTA_PREFSRC]);
859
paul718e3742002-12-13 20:15:29 +0000860 if (rtm->rtm_family == AF_INET)
861 {
862 struct prefix_ipv4 p;
863 p.family = AF_INET;
864 memcpy (&p.prefix, dest, 4);
865 p.prefixlen = rtm->rtm_dst_len;
866
867 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000868 {
869 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000870 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000871 inet_ntoa (p.prefix), p.prefixlen);
872 else
ajsb6178002004-12-07 21:12:56 +0000873 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000874 inet_ntoa (p.prefix), p.prefixlen);
875 }
paul718e3742002-12-13 20:15:29 +0000876
877 if (h->nlmsg_type == RTM_NEWROUTE)
Paul Jakma7514fb72007-05-02 16:05:35 +0000878 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
paul718e3742002-12-13 20:15:29 +0000879 else
paul7021c422003-07-15 12:52:22 +0000880 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
paul718e3742002-12-13 20:15:29 +0000881 }
882
883#ifdef HAVE_IPV6
884 if (rtm->rtm_family == AF_INET6)
885 {
886 struct prefix_ipv6 p;
887 char buf[BUFSIZ];
888
889 p.family = AF_INET6;
890 memcpy (&p.prefix, dest, 16);
891 p.prefixlen = rtm->rtm_dst_len;
892
893 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000894 {
895 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000896 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000897 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
898 p.prefixlen);
899 else
ajsb6178002004-12-07 21:12:56 +0000900 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000901 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
902 p.prefixlen);
903 }
paul718e3742002-12-13 20:15:29 +0000904
905 if (h->nlmsg_type == RTM_NEWROUTE)
hassobe61c4e2005-08-27 06:05:47 +0000906 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000907 else
paul7021c422003-07-15 12:52:22 +0000908 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
paul718e3742002-12-13 20:15:29 +0000909 }
910#endif /* HAVE_IPV6 */
911
912 return 0;
913}
914
Stephen Hemminger6072b242008-08-14 16:52:26 +0100915static int
paul718e3742002-12-13 20:15:29 +0000916netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
917{
918 int len;
919 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +0000920 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000921 struct interface *ifp;
922 char *name;
923
924 ifi = NLMSG_DATA (h);
925
paul7021c422003-07-15 12:52:22 +0000926 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +0000927 {
928 /* If this is not link add/delete message so print warning. */
929 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +0000930 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +0000931 return 0;
932 }
933
934 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
935 if (len < 0)
936 return -1;
937
938 /* Looking up interface name. */
939 memset (tb, 0, sizeof tb);
940 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000941
paul1e193152005-02-14 23:53:05 +0000942#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000943 /* check for wireless messages to ignore */
944 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
945 {
946 if (IS_ZEBRA_DEBUG_KERNEL)
947 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
948 return 0;
949 }
paul1e193152005-02-14 23:53:05 +0000950#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000951
paul718e3742002-12-13 20:15:29 +0000952 if (tb[IFLA_IFNAME] == NULL)
953 return -1;
paul7021c422003-07-15 12:52:22 +0000954 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000955
956 /* Add interface. */
957 if (h->nlmsg_type == RTM_NEWLINK)
958 {
959 ifp = if_lookup_by_name (name);
960
paul7021c422003-07-15 12:52:22 +0000961 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
962 {
963 if (ifp == NULL)
964 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +0000965
ajsd2fc8892005-04-02 18:38:43 +0000966 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +0000967 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +0000968 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000969 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000970
paul7021c422003-07-15 12:52:22 +0000971 /* If new link is added. */
972 if_add_update (ifp);
973 }
paul718e3742002-12-13 20:15:29 +0000974 else
paul7021c422003-07-15 12:52:22 +0000975 {
976 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +0000977 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +0000978 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +0000979 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +0000980
paul7021c422003-07-15 12:52:22 +0000981 if (if_is_operative (ifp))
982 {
983 ifp->flags = ifi->ifi_flags & 0x0000fffff;
984 if (!if_is_operative (ifp))
985 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +0000986 else
987 /* Must notify client daemons of new interface status. */
988 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +0000989 }
990 else
991 {
992 ifp->flags = ifi->ifi_flags & 0x0000fffff;
993 if (if_is_operative (ifp))
994 if_up (ifp);
995 }
996 }
paul718e3742002-12-13 20:15:29 +0000997 }
998 else
999 {
1000 /* RTM_DELLINK. */
1001 ifp = if_lookup_by_name (name);
1002
1003 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001004 {
1005 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001006 name);
paul7021c422003-07-15 12:52:22 +00001007 return 0;
1008 }
1009
paul718e3742002-12-13 20:15:29 +00001010 if_delete_update (ifp);
1011 }
1012
1013 return 0;
1014}
1015
Stephen Hemminger6072b242008-08-14 16:52:26 +01001016static int
paul718e3742002-12-13 20:15:29 +00001017netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1018{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001019 /* JF: Ignore messages that aren't from the kernel */
1020 if ( snl->nl_pid != 0 )
1021 {
1022 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1023 return 0;
1024 }
1025
paul718e3742002-12-13 20:15:29 +00001026 switch (h->nlmsg_type)
1027 {
1028 case RTM_NEWROUTE:
1029 return netlink_route_change (snl, h);
1030 break;
1031 case RTM_DELROUTE:
1032 return netlink_route_change (snl, h);
1033 break;
1034 case RTM_NEWLINK:
1035 return netlink_link_change (snl, h);
1036 break;
1037 case RTM_DELLINK:
1038 return netlink_link_change (snl, h);
1039 break;
1040 case RTM_NEWADDR:
1041 return netlink_interface_addr (snl, h);
1042 break;
1043 case RTM_DELADDR:
1044 return netlink_interface_addr (snl, h);
1045 break;
1046 default:
1047 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1048 break;
1049 }
1050 return 0;
1051}
1052
1053/* Interface lookup by netlink socket. */
1054int
paul6621ca82005-11-23 13:02:08 +00001055interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001056{
1057 int ret;
paul7021c422003-07-15 12:52:22 +00001058
paul718e3742002-12-13 20:15:29 +00001059 /* Get interface information. */
1060 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1061 if (ret < 0)
1062 return ret;
1063 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1064 if (ret < 0)
1065 return ret;
1066
1067 /* Get IPv4 address of the interfaces. */
1068 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1069 if (ret < 0)
1070 return ret;
1071 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1072 if (ret < 0)
1073 return ret;
1074
1075#ifdef HAVE_IPV6
1076 /* Get IPv6 address of the interfaces. */
1077 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1078 if (ret < 0)
1079 return ret;
1080 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1081 if (ret < 0)
1082 return ret;
1083#endif /* HAVE_IPV6 */
1084
1085 return 0;
1086}
1087
1088/* Routing table read function using netlink interface. Only called
1089 bootstrap time. */
1090int
paul6621ca82005-11-23 13:02:08 +00001091netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001092{
1093 int ret;
paul7021c422003-07-15 12:52:22 +00001094
paul718e3742002-12-13 20:15:29 +00001095 /* Get IPv4 routing table. */
1096 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1097 if (ret < 0)
1098 return ret;
1099 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1100 if (ret < 0)
1101 return ret;
1102
1103#ifdef HAVE_IPV6
1104 /* Get IPv6 routing table. */
1105 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1106 if (ret < 0)
1107 return ret;
1108 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1109 if (ret < 0)
1110 return ret;
1111#endif /* HAVE_IPV6 */
1112
1113 return 0;
1114}
1115
1116/* Utility function comes from iproute2.
1117 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001118static int
paul718e3742002-12-13 20:15:29 +00001119addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1120{
1121 int len;
1122 struct rtattr *rta;
1123
paul7021c422003-07-15 12:52:22 +00001124 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001125
paul7021c422003-07-15 12:52:22 +00001126 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001127 return -1;
1128
paul7021c422003-07-15 12:52:22 +00001129 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001130 rta->rta_type = type;
1131 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001132 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001133 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1134
1135 return 0;
1136}
1137
Stephen Hemminger6072b242008-08-14 16:52:26 +01001138static int
paul718e3742002-12-13 20:15:29 +00001139rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1140{
1141 int len;
1142 struct rtattr *subrta;
1143
paul7021c422003-07-15 12:52:22 +00001144 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001145
paul7021c422003-07-15 12:52:22 +00001146 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001147 return -1;
1148
paul7021c422003-07-15 12:52:22 +00001149 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001150 subrta->rta_type = type;
1151 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001152 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001153 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1154
1155 return 0;
1156}
1157
1158/* Utility function comes from iproute2.
1159 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001160static int
paul718e3742002-12-13 20:15:29 +00001161addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1162{
1163 int len;
1164 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001165
1166 len = RTA_LENGTH (4);
1167
paul718e3742002-12-13 20:15:29 +00001168 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1169 return -1;
1170
paul7021c422003-07-15 12:52:22 +00001171 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001172 rta->rta_type = type;
1173 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001174 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001175 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1176
1177 return 0;
1178}
1179
1180static int
1181netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1182{
hassob7ed1ec2005-03-31 20:13:49 +00001183 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001184 return 0;
1185}
1186
1187/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001188static int
paul718e3742002-12-13 20:15:29 +00001189netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1190{
1191 int status;
1192 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001193 struct iovec iov = { (void *) n, n->nlmsg_len };
1194 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001195 int save_errno;
paul7021c422003-07-15 12:52:22 +00001196
paul718e3742002-12-13 20:15:29 +00001197 memset (&snl, 0, sizeof snl);
1198 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001199
hassob7ed1ec2005-03-31 20:13:49 +00001200 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001201
1202 /* Request an acknowledgement by setting NLM_F_ACK */
1203 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001204
1205 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001206 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001207 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1208 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001209
1210 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001211 if (zserv_privs.change (ZPRIVS_RAISE))
1212 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001213 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001214 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001215 if (zserv_privs.change (ZPRIVS_LOWER))
1216 zlog (NULL, LOG_ERR, "Can't lower privileges");
1217
paul718e3742002-12-13 20:15:29 +00001218 if (status < 0)
1219 {
1220 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001221 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001222 return -1;
1223 }
paul7021c422003-07-15 12:52:22 +00001224
paul718e3742002-12-13 20:15:29 +00001225
1226 /*
1227 * Get reply from netlink socket.
1228 * The reply should either be an acknowlegement or an error.
1229 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001230 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001231}
1232
1233/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001234static int
paul718e3742002-12-13 20:15:29 +00001235netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001236 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001237{
1238 int ret;
1239 int bytelen;
1240 struct sockaddr_nl snl;
1241 int discard;
1242
paul7021c422003-07-15 12:52:22 +00001243 struct
paul718e3742002-12-13 20:15:29 +00001244 {
1245 struct nlmsghdr n;
1246 struct rtmsg r;
1247 char buf[1024];
1248 } req;
1249
1250 memset (&req, 0, sizeof req);
1251
1252 bytelen = (family == AF_INET ? 4 : 16);
1253
1254 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1255 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1256 req.n.nlmsg_type = cmd;
1257 req.r.rtm_family = family;
1258 req.r.rtm_table = table;
1259 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001260 req.r.rtm_protocol = RTPROT_ZEBRA;
1261 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001262
hasso81dfcaa2003-05-25 19:21:25 +00001263 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1264 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001265 discard = 1;
1266 else
1267 discard = 0;
1268
paul7021c422003-07-15 12:52:22 +00001269 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001270 {
paul7021c422003-07-15 12:52:22 +00001271 if (discard)
paul595db7f2003-05-25 21:35:06 +00001272 {
1273 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1274 req.r.rtm_type = RTN_BLACKHOLE;
1275 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1276 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001277 else
1278 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1279 }
paul595db7f2003-05-25 21:35:06 +00001280 else
paul7021c422003-07-15 12:52:22 +00001281 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001282 }
1283
1284 if (dest)
1285 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1286
paul7021c422003-07-15 12:52:22 +00001287 if (!discard)
paul718e3742002-12-13 20:15:29 +00001288 {
1289 if (gate)
paul7021c422003-07-15 12:52:22 +00001290 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001291 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001292 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001293 }
1294
1295 /* Destination netlink address. */
1296 memset (&snl, 0, sizeof snl);
1297 snl.nl_family = AF_NETLINK;
1298
1299 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001300 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001301 if (ret < 0)
1302 return -1;
1303
1304 return 0;
1305}
1306
1307/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001308static int
paul718e3742002-12-13 20:15:29 +00001309netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001310 int family)
paul718e3742002-12-13 20:15:29 +00001311{
1312 int bytelen;
1313 struct sockaddr_nl snl;
1314 struct nexthop *nexthop = NULL;
1315 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001316 int discard;
1317
paul7021c422003-07-15 12:52:22 +00001318 struct
paul718e3742002-12-13 20:15:29 +00001319 {
1320 struct nlmsghdr n;
1321 struct rtmsg r;
1322 char buf[1024];
1323 } req;
1324
1325 memset (&req, 0, sizeof req);
1326
1327 bytelen = (family == AF_INET ? 4 : 16);
1328
1329 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1330 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1331 req.n.nlmsg_type = cmd;
1332 req.r.rtm_family = family;
1333 req.r.rtm_table = rib->table;
1334 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001335 req.r.rtm_protocol = RTPROT_ZEBRA;
1336 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001337
paul7021c422003-07-15 12:52:22 +00001338 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001339 discard = 1;
1340 else
1341 discard = 0;
1342
paul7021c422003-07-15 12:52:22 +00001343 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001344 {
paul7021c422003-07-15 12:52:22 +00001345 if (discard)
paul595db7f2003-05-25 21:35:06 +00001346 {
1347 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1348 req.r.rtm_type = RTN_BLACKHOLE;
1349 else if (rib->flags & ZEBRA_FLAG_REJECT)
1350 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001351 else
1352 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1353 }
paul595db7f2003-05-25 21:35:06 +00001354 else
paul7021c422003-07-15 12:52:22 +00001355 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001356 }
1357
1358 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1359
1360 /* Metric. */
1361 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1362
1363 if (discard)
1364 {
1365 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001366 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1367 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001368 goto skip;
1369 }
1370
1371 /* Multipath case. */
1372 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1373 {
1374 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001375 {
paul5ec90d22003-06-19 01:41:37 +00001376
paul7021c422003-07-15 12:52:22 +00001377 if ((cmd == RTM_NEWROUTE
1378 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1379 || (cmd == RTM_DELROUTE
1380 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1381 {
paul5ec90d22003-06-19 01:41:37 +00001382
paul7021c422003-07-15 12:52:22 +00001383 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1384 {
1385 if (IS_ZEBRA_DEBUG_KERNEL)
1386 {
ajsb6178002004-12-07 21:12:56 +00001387 zlog_debug
paul7021c422003-07-15 12:52:22 +00001388 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001389 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001390#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001391 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001392 inet6_ntoa (p->u.prefix6),
1393#else
1394 inet_ntoa (p->u.prefix4),
1395#endif /* HAVE_IPV6 */
1396
1397 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001398 }
paul5ec90d22003-06-19 01:41:37 +00001399
paul7021c422003-07-15 12:52:22 +00001400 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1401 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001402 {
1403 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1404 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001405 if (nexthop->src.ipv4.s_addr)
1406 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1407 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001408 if (IS_ZEBRA_DEBUG_KERNEL)
1409 zlog_debug("netlink_route_multipath() (recursive, "
1410 "1 hop): nexthop via %s if %u",
1411 inet_ntoa (nexthop->rgate.ipv4),
1412 nexthop->rifindex);
1413 }
paul718e3742002-12-13 20:15:29 +00001414#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001415 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1416 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1417 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001418 {
1419 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1420 &nexthop->rgate.ipv6, bytelen);
1421
1422 if (IS_ZEBRA_DEBUG_KERNEL)
1423 zlog_debug("netlink_route_multipath() (recursive, "
1424 "1 hop): nexthop via %s if %u",
1425 inet6_ntoa (nexthop->rgate.ipv6),
1426 nexthop->rifindex);
1427 }
paul718e3742002-12-13 20:15:29 +00001428#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001429 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1430 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1431 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1432 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1433 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001434 {
1435 addattr32 (&req.n, sizeof req, RTA_OIF,
1436 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001437 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1438 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1439 && nexthop->src.ipv4.s_addr)
1440 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1441 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001442
1443 if (IS_ZEBRA_DEBUG_KERNEL)
1444 zlog_debug("netlink_route_multipath() (recursive, "
1445 "1 hop): nexthop via if %u",
1446 nexthop->rifindex);
1447 }
paul7021c422003-07-15 12:52:22 +00001448 }
1449 else
1450 {
1451 if (IS_ZEBRA_DEBUG_KERNEL)
1452 {
ajsb6178002004-12-07 21:12:56 +00001453 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001454 ("netlink_route_multipath() (single hop): "
1455 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001456#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001457 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001458 inet6_ntoa (p->u.prefix6),
1459#else
1460 inet_ntoa (p->u.prefix4),
1461#endif /* HAVE_IPV6 */
1462 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001463 }
paul5ec90d22003-06-19 01:41:37 +00001464
paul7021c422003-07-15 12:52:22 +00001465 if (nexthop->type == NEXTHOP_TYPE_IPV4
1466 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001467 {
1468 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1469 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001470 if (nexthop->src.ipv4.s_addr)
1471 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1472 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001473
1474 if (IS_ZEBRA_DEBUG_KERNEL)
1475 zlog_debug("netlink_route_multipath() (single hop): "
1476 "nexthop via %s if %u",
1477 inet_ntoa (nexthop->gate.ipv4),
1478 nexthop->ifindex);
1479 }
paul718e3742002-12-13 20:15:29 +00001480#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001481 if (nexthop->type == NEXTHOP_TYPE_IPV6
1482 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1483 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001484 {
1485 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1486 &nexthop->gate.ipv6, bytelen);
1487
1488 if (IS_ZEBRA_DEBUG_KERNEL)
1489 zlog_debug("netlink_route_multipath() (single hop): "
1490 "nexthop via %s if %u",
1491 inet6_ntoa (nexthop->gate.ipv6),
1492 nexthop->ifindex);
1493 }
paul718e3742002-12-13 20:15:29 +00001494#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001495 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1496 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001497 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1498 {
1499 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1500
1501 if (nexthop->src.ipv4.s_addr)
1502 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1503 &nexthop->src.ipv4, bytelen);
1504
1505 if (IS_ZEBRA_DEBUG_KERNEL)
1506 zlog_debug("netlink_route_multipath() (single hop): "
1507 "nexthop via if %u", nexthop->ifindex);
1508 }
1509 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001510 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001511 {
1512 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1513
1514 if (IS_ZEBRA_DEBUG_KERNEL)
1515 zlog_debug("netlink_route_multipath() (single hop): "
1516 "nexthop via if %u", nexthop->ifindex);
1517 }
paul7021c422003-07-15 12:52:22 +00001518 }
paul718e3742002-12-13 20:15:29 +00001519
paul7021c422003-07-15 12:52:22 +00001520 if (cmd == RTM_NEWROUTE)
1521 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001522
paul7021c422003-07-15 12:52:22 +00001523 nexthop_num++;
1524 break;
1525 }
1526 }
paul718e3742002-12-13 20:15:29 +00001527 }
1528 else
1529 {
1530 char buf[1024];
1531 struct rtattr *rta = (void *) buf;
1532 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001533 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001534
1535 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001536 rta->rta_len = RTA_LENGTH (0);
1537 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001538
1539 nexthop_num = 0;
1540 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001541 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1542 nexthop = nexthop->next)
1543 {
1544 if ((cmd == RTM_NEWROUTE
1545 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1546 || (cmd == RTM_DELROUTE
1547 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1548 {
1549 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001550
paul7021c422003-07-15 12:52:22 +00001551 rtnh->rtnh_len = sizeof (*rtnh);
1552 rtnh->rtnh_flags = 0;
1553 rtnh->rtnh_hops = 0;
1554 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001555
paul7021c422003-07-15 12:52:22 +00001556 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1557 {
1558 if (IS_ZEBRA_DEBUG_KERNEL)
1559 {
ajsb6178002004-12-07 21:12:56 +00001560 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001561 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001562 lookup (nlmsg_str, cmd),
1563#ifdef HAVE_IPV6
1564 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1565 inet6_ntoa (p->u.prefix6),
1566#else
1567 inet_ntoa (p->u.prefix4),
1568#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001569 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001570 }
1571 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1572 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1573 {
1574 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1575 &nexthop->rgate.ipv4, bytelen);
1576 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001577
Paul Jakma7514fb72007-05-02 16:05:35 +00001578 if (nexthop->src.ipv4.s_addr)
1579 src = &nexthop->src;
1580
hasso206d8052005-04-09 16:38:51 +00001581 if (IS_ZEBRA_DEBUG_KERNEL)
1582 zlog_debug("netlink_route_multipath() (recursive, "
1583 "multihop): nexthop via %s if %u",
1584 inet_ntoa (nexthop->rgate.ipv4),
1585 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001586 }
paul718e3742002-12-13 20:15:29 +00001587#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001588 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1589 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1590 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001591 {
1592 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1593 &nexthop->rgate.ipv6, bytelen);
1594
1595 if (IS_ZEBRA_DEBUG_KERNEL)
1596 zlog_debug("netlink_route_multipath() (recursive, "
1597 "multihop): nexthop via %s if %u",
1598 inet6_ntoa (nexthop->rgate.ipv6),
1599 nexthop->rifindex);
1600 }
paul718e3742002-12-13 20:15:29 +00001601#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001602 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001603 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1604 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1605 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1606 {
1607 rtnh->rtnh_ifindex = nexthop->rifindex;
1608 if (nexthop->src.ipv4.s_addr)
1609 src = &nexthop->src;
1610
1611 if (IS_ZEBRA_DEBUG_KERNEL)
1612 zlog_debug("netlink_route_multipath() (recursive, "
1613 "multihop): nexthop via if %u",
1614 nexthop->rifindex);
1615 }
1616 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001617 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001618 {
1619 rtnh->rtnh_ifindex = nexthop->rifindex;
1620
1621 if (IS_ZEBRA_DEBUG_KERNEL)
1622 zlog_debug("netlink_route_multipath() (recursive, "
1623 "multihop): nexthop via if %u",
1624 nexthop->rifindex);
1625 }
paul7021c422003-07-15 12:52:22 +00001626 else
hasso206d8052005-04-09 16:38:51 +00001627 {
1628 rtnh->rtnh_ifindex = 0;
1629 }
paul7021c422003-07-15 12:52:22 +00001630 }
1631 else
1632 {
1633 if (IS_ZEBRA_DEBUG_KERNEL)
1634 {
hasso206d8052005-04-09 16:38:51 +00001635 zlog_debug ("netlink_route_multipath() (multihop): "
1636 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001637#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001638 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001639 inet6_ntoa (p->u.prefix6),
1640#else
1641 inet_ntoa (p->u.prefix4),
1642#endif /* HAVE_IPV6 */
1643 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001644 }
1645 if (nexthop->type == NEXTHOP_TYPE_IPV4
1646 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1647 {
hasso206d8052005-04-09 16:38:51 +00001648 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1649 &nexthop->gate.ipv4, bytelen);
1650 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1651
Paul Jakma7514fb72007-05-02 16:05:35 +00001652 if (nexthop->src.ipv4.s_addr)
1653 src = &nexthop->src;
1654
hasso206d8052005-04-09 16:38:51 +00001655 if (IS_ZEBRA_DEBUG_KERNEL)
1656 zlog_debug("netlink_route_multipath() (multihop): "
1657 "nexthop via %s if %u",
1658 inet_ntoa (nexthop->gate.ipv4),
1659 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001660 }
paul718e3742002-12-13 20:15:29 +00001661#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001662 if (nexthop->type == NEXTHOP_TYPE_IPV6
1663 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1664 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001665 {
1666 rta_addattr_l (rta, 4096, RTA_GATEWAY,
1667 &nexthop->gate.ipv6, bytelen);
1668
1669 if (IS_ZEBRA_DEBUG_KERNEL)
1670 zlog_debug("netlink_route_multipath() (multihop): "
1671 "nexthop via %s if %u",
1672 inet6_ntoa (nexthop->gate.ipv6),
1673 nexthop->ifindex);
1674 }
paul718e3742002-12-13 20:15:29 +00001675#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001676 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001677 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1678 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1679 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1680 {
1681 rtnh->rtnh_ifindex = nexthop->ifindex;
1682 if (nexthop->src.ipv4.s_addr)
1683 src = &nexthop->src;
1684 if (IS_ZEBRA_DEBUG_KERNEL)
1685 zlog_debug("netlink_route_multipath() (multihop): "
1686 "nexthop via if %u", nexthop->ifindex);
1687 }
1688 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001689 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001690 {
1691 rtnh->rtnh_ifindex = nexthop->ifindex;
1692
1693 if (IS_ZEBRA_DEBUG_KERNEL)
1694 zlog_debug("netlink_route_multipath() (multihop): "
1695 "nexthop via if %u", nexthop->ifindex);
1696 }
paul7021c422003-07-15 12:52:22 +00001697 else
hasso206d8052005-04-09 16:38:51 +00001698 {
1699 rtnh->rtnh_ifindex = 0;
1700 }
paul7021c422003-07-15 12:52:22 +00001701 }
1702 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001703
paul7021c422003-07-15 12:52:22 +00001704 if (cmd == RTM_NEWROUTE)
1705 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1706 }
1707 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001708 if (src)
1709 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001710
1711 if (rta->rta_len > RTA_LENGTH (0))
paul7021c422003-07-15 12:52:22 +00001712 addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
1713 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001714 }
1715
1716 /* If there is no useful nexthop then return. */
1717 if (nexthop_num == 0)
1718 {
1719 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001720 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001721 return 0;
1722 }
1723
paul7021c422003-07-15 12:52:22 +00001724skip:
paul718e3742002-12-13 20:15:29 +00001725
1726 /* Destination netlink address. */
1727 memset (&snl, 0, sizeof snl);
1728 snl.nl_family = AF_NETLINK;
1729
paul718e3742002-12-13 20:15:29 +00001730 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001731 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001732}
1733
1734int
1735kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1736{
1737 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1738}
1739
1740int
1741kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1742{
1743 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1744}
1745
1746#ifdef HAVE_IPV6
1747int
1748kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1749{
1750 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1751}
1752
1753int
1754kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1755{
1756 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1757}
1758
1759/* Delete IPv6 route from the kernel. */
1760int
1761kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001762 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001763{
paul7021c422003-07-15 12:52:22 +00001764 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1765 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001766}
1767#endif /* HAVE_IPV6 */
1768
1769/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001770static int
paul718e3742002-12-13 20:15:29 +00001771netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001772 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001773{
1774 int bytelen;
1775 struct prefix *p;
1776
paul7021c422003-07-15 12:52:22 +00001777 struct
paul718e3742002-12-13 20:15:29 +00001778 {
1779 struct nlmsghdr n;
1780 struct ifaddrmsg ifa;
1781 char buf[1024];
1782 } req;
1783
1784 p = ifc->address;
1785 memset (&req, 0, sizeof req);
1786
1787 bytelen = (family == AF_INET ? 4 : 16);
1788
paul7021c422003-07-15 12:52:22 +00001789 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001790 req.n.nlmsg_flags = NLM_F_REQUEST;
1791 req.n.nlmsg_type = cmd;
1792 req.ifa.ifa_family = family;
1793
1794 req.ifa.ifa_index = ifp->ifindex;
1795 req.ifa.ifa_prefixlen = p->prefixlen;
1796
1797 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1798
1799 if (family == AF_INET && cmd == RTM_NEWADDR)
1800 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001801 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001802 {
1803 p = ifc->destination;
1804 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1805 bytelen);
1806 }
paul718e3742002-12-13 20:15:29 +00001807 }
1808
1809 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1810 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001811
paul718e3742002-12-13 20:15:29 +00001812 if (ifc->label)
1813 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001814 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001815
1816 return netlink_talk (&req.n, &netlink_cmd);
1817}
1818
1819int
1820kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1821{
1822 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1823}
1824
1825int
1826kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1827{
1828 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1829}
1830
paul718e3742002-12-13 20:15:29 +00001831
1832extern struct thread_master *master;
1833
1834/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001835static int
paul718e3742002-12-13 20:15:29 +00001836kernel_read (struct thread *thread)
1837{
1838 int ret;
1839 int sock;
1840
1841 sock = THREAD_FD (thread);
1842 ret = netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001843 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001844
1845 return 0;
1846}
1847
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001848/* Filter out messages from self that occur on listener socket,
1849 caused by our actions on the command socket
1850 */
1851static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001852{
Paul Jakma768a27e2008-05-29 18:23:08 +00001853 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001854 /* 0: ldh [4] */
1855 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1856 /* 1: jeq 0x18 jt 3 jf 6 */
1857 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1858 /* 2: jeq 0x19 jt 3 jf 6 */
1859 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1860 /* 3: ldw [12] */
1861 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1862 /* 4: jeq XX jt 5 jf 6 */
1863 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1864 /* 5: ret 0 (skip) */
1865 BPF_STMT(BPF_RET|BPF_K, 0),
1866 /* 6: ret 0xffff (keep) */
1867 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001868 };
1869
1870 struct sock_fprog prog = {
1871 .len = sizeof(filter) / sizeof(filter[0]),
1872 .filter = filter,
1873 };
1874
1875 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1876 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1877}
1878
paul718e3742002-12-13 20:15:29 +00001879/* Exported interface function. This function simply calls
1880 netlink_socket (). */
1881void
paul6621ca82005-11-23 13:02:08 +00001882kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001883{
1884 unsigned long groups;
1885
paul7021c422003-07-15 12:52:22 +00001886 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001887#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001888 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001889#endif /* HAVE_IPV6 */
1890 netlink_socket (&netlink, groups);
1891 netlink_socket (&netlink_cmd, 0);
1892
1893 /* Register kernel socket. */
1894 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001895 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001896 /* Only want non-blocking on the netlink event socket */
1897 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1898 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1899 safe_strerror (errno));
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}