blob: cf6ce0cdeb42461d9b855236e33a105afa6a46b8 [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"
Josh Bailey26e2ae32012-03-22 01:09:21 -070035#include "memory.h"
paul718e3742002-12-13 20:15:29 +000036#include "rib.h"
paule04ab742003-01-17 23:47:00 +000037#include "thread.h"
pauledd7c242003-06-04 13:59:38 +000038#include "privs.h"
Feng Lu0d0686f2015-05-22 11:40:02 +020039#include "vrf.h"
paul718e3742002-12-13 20:15:29 +000040
41#include "zebra/zserv.h"
paul6621ca82005-11-23 13:02:08 +000042#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000043#include "zebra/redistribute.h"
44#include "zebra/interface.h"
45#include "zebra/debug.h"
46
Avneesh Sachdev78deec42012-11-13 22:48:56 +000047#include "rt_netlink.h"
JR Rivers3cadc0c2012-04-01 12:16:31 -070048
paul718e3742002-12-13 20:15:29 +000049/* Socket interface to kernel */
50struct nlsock
51{
52 int sock;
53 int seq;
54 struct sockaddr_nl snl;
hassofce954f2004-10-07 20:29:24 +000055 const char *name;
paul7021c422003-07-15 12:52:22 +000056} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
hasso1ada8192005-06-12 11:28:18 +000057 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
paul718e3742002-12-13 20:15:29 +000058
Stephen Hemminger1423c802008-08-14 17:59:25 +010059static const struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000060 {RTM_NEWROUTE, "RTM_NEWROUTE"},
61 {RTM_DELROUTE, "RTM_DELROUTE"},
62 {RTM_GETROUTE, "RTM_GETROUTE"},
63 {RTM_NEWLINK, "RTM_NEWLINK"},
64 {RTM_DELLINK, "RTM_DELLINK"},
65 {RTM_GETLINK, "RTM_GETLINK"},
66 {RTM_NEWADDR, "RTM_NEWADDR"},
67 {RTM_DELADDR, "RTM_DELADDR"},
68 {RTM_GETADDR, "RTM_GETADDR"},
paul7021c422003-07-15 12:52:22 +000069 {0, NULL}
paul718e3742002-12-13 20:15:29 +000070};
71
paulb21b19c2003-06-15 01:28:29 +000072extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000073
pauledd7c242003-06-04 13:59:38 +000074extern struct zebra_privs_t zserv_privs;
75
hassoc34b6b52004-08-31 13:41:49 +000076extern u_int32_t nl_rcvbufsize;
77
ajsd2fc8892005-04-02 18:38:43 +000078/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
79 names and ifindex values. */
80static void
81set_ifindex(struct interface *ifp, unsigned int ifi_index)
82{
83 struct interface *oifp;
84
85 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
86 {
87 if (ifi_index == IFINDEX_INTERNAL)
88 zlog_err("Netlink is setting interface %s ifindex to reserved "
89 "internal value %u", ifp->name, ifi_index);
90 else
91 {
92 if (IS_ZEBRA_DEBUG_KERNEL)
93 zlog_debug("interface index %d was renamed from %s to %s",
94 ifi_index, oifp->name, ifp->name);
95 if (if_is_up(oifp))
96 zlog_err("interface rename detected on up interface: index %d "
97 "was renamed from %s to %s, results are uncertain!",
98 ifi_index, oifp->name, ifp->name);
99 if_delete_update(oifp);
100 }
101 }
102 ifp->ifindex = ifi_index;
103}
104
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000105#ifndef SO_RCVBUFFORCE
106#define SO_RCVBUFFORCE (33)
107#endif
108
Stephen Hemminger30afea32008-08-16 18:25:47 +0100109static int
110netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
111{
112 u_int32_t oldsize;
113 socklen_t newlen = sizeof(newsize);
114 socklen_t oldlen = sizeof(oldsize);
115 int ret;
116
117 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
118 if (ret < 0)
119 {
120 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
121 safe_strerror (errno));
122 return -1;
123 }
124
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000125 /* Try force option (linux >= 2.6.14) and fall back to normal set */
126 if ( zserv_privs.change (ZPRIVS_RAISE) )
127 zlog_err ("routing_socket: Can't raise privileges");
128 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize,
Stephen Hemminger30afea32008-08-16 18:25:47 +0100129 sizeof(nl_rcvbufsize));
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000130 if ( zserv_privs.change (ZPRIVS_LOWER) )
131 zlog_err ("routing_socket: Can't lower privileges");
132 if (ret < 0)
133 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
134 sizeof(nl_rcvbufsize));
Stephen Hemminger30afea32008-08-16 18:25:47 +0100135 if (ret < 0)
136 {
137 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
138 safe_strerror (errno));
139 return -1;
140 }
141
142 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
143 if (ret < 0)
144 {
145 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
146 safe_strerror (errno));
147 return -1;
148 }
149
150 zlog (NULL, LOG_INFO,
151 "Setting netlink socket receive buffer size: %u -> %u",
152 oldsize, newsize);
153 return 0;
154}
155
paul718e3742002-12-13 20:15:29 +0000156/* Make socket for Linux netlink interface. */
157static int
158netlink_socket (struct nlsock *nl, unsigned long groups)
159{
160 int ret;
161 struct sockaddr_nl snl;
162 int sock;
163 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000164 int save_errno;
paul718e3742002-12-13 20:15:29 +0000165
Michal Sekletar8e998b12014-05-16 14:13:43 +0000166 if (zserv_privs.change (ZPRIVS_RAISE))
167 {
168 zlog (NULL, LOG_ERR, "Can't raise privileges");
169 return -1;
170 }
171
paul718e3742002-12-13 20:15:29 +0000172 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
173 if (sock < 0)
174 {
175 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000176 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000177 return -1;
178 }
179
paul718e3742002-12-13 20:15:29 +0000180 memset (&snl, 0, sizeof snl);
181 snl.nl_family = AF_NETLINK;
182 snl.nl_groups = groups;
183
184 /* Bind the socket to the netlink structure for anything. */
185 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000186 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000187 if (zserv_privs.change (ZPRIVS_LOWER))
188 zlog (NULL, LOG_ERR, "Can't lower privileges");
189
paul718e3742002-12-13 20:15:29 +0000190 if (ret < 0)
191 {
paul7021c422003-07-15 12:52:22 +0000192 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000193 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000194 close (sock);
195 return -1;
196 }
paul7021c422003-07-15 12:52:22 +0000197
paul718e3742002-12-13 20:15:29 +0000198 /* multiple netlink sockets will have different nl_pid */
199 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000200 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000201 if (ret < 0 || namelen != sizeof snl)
202 {
203 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000204 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000205 close (sock);
206 return -1;
207 }
208
209 nl->snl = snl;
210 nl->sock = sock;
211 return ret;
212}
213
214/* Get type specified information from netlink. */
215static int
216netlink_request (int family, int type, struct nlsock *nl)
217{
218 int ret;
219 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000220 int save_errno;
paul718e3742002-12-13 20:15:29 +0000221
222 struct
223 {
224 struct nlmsghdr nlh;
225 struct rtgenmsg g;
226 } req;
227
228
229 /* Check netlink socket. */
230 if (nl->sock < 0)
231 {
232 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
233 return -1;
234 }
235
236 memset (&snl, 0, sizeof snl);
237 snl.nl_family = AF_NETLINK;
238
ajsc05612b2005-10-01 16:36:54 +0000239 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000240 req.nlh.nlmsg_len = sizeof req;
241 req.nlh.nlmsg_type = type;
242 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100243 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000244 req.nlh.nlmsg_seq = ++nl->seq;
245 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000246
247 /* linux appears to check capabilities on every message
248 * have to raise caps for every message sent
249 */
paul7021c422003-07-15 12:52:22 +0000250 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000251 {
252 zlog (NULL, LOG_ERR, "Can't raise privileges");
253 return -1;
254 }
paul7021c422003-07-15 12:52:22 +0000255
256 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
257 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000258 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000259
260 if (zserv_privs.change (ZPRIVS_LOWER))
261 zlog (NULL, LOG_ERR, "Can't lower privileges");
262
paul718e3742002-12-13 20:15:29 +0000263 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000264 {
265 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000266 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000267 return -1;
268 }
pauledd7c242003-06-04 13:59:38 +0000269
paul718e3742002-12-13 20:15:29 +0000270 return 0;
271}
272
273/* Receive message from netlink interface and pass those information
274 to the given function. */
275static int
276netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000277 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000278{
279 int status;
280 int ret = 0;
281 int error;
282
283 while (1)
284 {
JR Rivers3cadc0c2012-04-01 12:16:31 -0700285 char buf[NL_PKT_BUF_SIZE];
Timo Teräsc299ed72014-07-29 09:41:55 +0000286 struct iovec iov = {
287 .iov_base = buf,
288 .iov_len = sizeof buf
289 };
paul718e3742002-12-13 20:15:29 +0000290 struct sockaddr_nl snl;
Timo Teräsc299ed72014-07-29 09:41:55 +0000291 struct msghdr msg = {
292 .msg_name = (void *) &snl,
293 .msg_namelen = sizeof snl,
294 .msg_iov = &iov,
295 .msg_iovlen = 1
296 };
paul718e3742002-12-13 20:15:29 +0000297 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000298
paul718e3742002-12-13 20:15:29 +0000299 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000300 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000301 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100302 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000303 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100304 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000305 break;
ajs4be019d2005-01-29 16:12:41 +0000306 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100307 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000308 continue;
309 }
paul718e3742002-12-13 20:15:29 +0000310
311 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000312 {
313 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
314 return -1;
315 }
paul718e3742002-12-13 20:15:29 +0000316
317 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000318 {
319 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
320 nl->name, msg.msg_namelen);
321 return -1;
322 }
paulb84d3a12003-11-17 10:31:01 +0000323
hasso206d8052005-04-09 16:38:51 +0000324 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000325 h = NLMSG_NEXT (h, status))
326 {
327 /* Finish of reading. */
328 if (h->nlmsg_type == NLMSG_DONE)
329 return ret;
paul718e3742002-12-13 20:15:29 +0000330
paul7021c422003-07-15 12:52:22 +0000331 /* Error handling. */
332 if (h->nlmsg_type == NLMSG_ERROR)
333 {
334 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100335 int errnum = err->error;
336 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000337
paul718e3742002-12-13 20:15:29 +0000338 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000339 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000340 {
paul7021c422003-07-15 12:52:22 +0000341 if (IS_ZEBRA_DEBUG_KERNEL)
342 {
hasso1ada8192005-06-12 11:28:18 +0000343 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000344 __FUNCTION__, nl->name,
345 lookup (nlmsg_str, err->msg.nlmsg_type),
346 err->msg.nlmsg_type, err->msg.nlmsg_seq,
347 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000348 }
paul7021c422003-07-15 12:52:22 +0000349
350 /* return if not a multipart message, otherwise continue */
351 if (!(h->nlmsg_flags & NLM_F_MULTI))
352 {
353 return 0;
paul718e3742002-12-13 20:15:29 +0000354 }
paul7021c422003-07-15 12:52:22 +0000355 continue;
paul718e3742002-12-13 20:15:29 +0000356 }
paul7021c422003-07-15 12:52:22 +0000357
paul718e3742002-12-13 20:15:29 +0000358 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000359 {
360 zlog (NULL, LOG_ERR, "%s error: message truncated",
361 nl->name);
362 return -1;
363 }
pauld753e9e2003-01-22 19:45:50 +0000364
Stephen Hemminger898987e2008-08-17 16:56:15 +0100365 /* Deal with errors that occur because of races in link handling */
366 if (nl == &netlink_cmd
367 && ((msg_type == RTM_DELROUTE &&
368 (-errnum == ENODEV || -errnum == ESRCH))
369 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
370 {
371 if (IS_ZEBRA_DEBUG_KERNEL)
372 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
373 nl->name, safe_strerror (-errnum),
374 lookup (nlmsg_str, msg_type),
375 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
376 return 0;
377 }
paul718e3742002-12-13 20:15:29 +0000378
Stephen Hemminger898987e2008-08-17 16:56:15 +0100379 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
380 nl->name, safe_strerror (-errnum),
381 lookup (nlmsg_str, msg_type),
382 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000383 return -1;
384 }
paul718e3742002-12-13 20:15:29 +0000385
paul7021c422003-07-15 12:52:22 +0000386 /* OK we got netlink message. */
387 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000388 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000389 nl->name,
390 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
391 h->nlmsg_seq, h->nlmsg_pid);
392
Christian Franke599da952013-01-24 14:04:43 +0000393 /* skip unsolicited messages originating from command socket
394 * linux sets the originators port-id for {NEW|DEL}ADDR messages,
395 * so this has to be checked here. */
396 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid
397 && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
paul7021c422003-07-15 12:52:22 +0000398 {
399 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000400 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000401 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000402 continue;
403 }
404
405 error = (*filter) (&snl, h);
406 if (error < 0)
407 {
408 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
409 ret = error;
410 }
411 }
paul718e3742002-12-13 20:15:29 +0000412
413 /* After error care. */
414 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000415 {
416 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
417 continue;
418 }
paul718e3742002-12-13 20:15:29 +0000419 if (status)
paul7021c422003-07-15 12:52:22 +0000420 {
421 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
422 status);
423 return -1;
424 }
paul718e3742002-12-13 20:15:29 +0000425 }
426 return ret;
427}
428
429/* Utility function for parse rtattr. */
430static void
paul7021c422003-07-15 12:52:22 +0000431netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
432 int len)
paul718e3742002-12-13 20:15:29 +0000433{
paul7021c422003-07-15 12:52:22 +0000434 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000435 {
436 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000437 tb[rta->rta_type] = rta;
438 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000439 }
440}
441
Josh Bailey26e2ae32012-03-22 01:09:21 -0700442/* Utility function to parse hardware link-layer address and update ifp */
443static void
444netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
445{
446 int i;
447
448 if (tb[IFLA_ADDRESS])
449 {
450 int hw_addr_len;
451
452 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
453
454 if (hw_addr_len > INTERFACE_HWADDR_MAX)
455 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
456 else
457 {
458 ifp->hw_addr_len = hw_addr_len;
459 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
460
461 for (i = 0; i < hw_addr_len; i++)
462 if (ifp->hw_addr[i] != 0)
463 break;
464
465 if (i == hw_addr_len)
466 ifp->hw_addr_len = 0;
467 else
468 ifp->hw_addr_len = hw_addr_len;
469 }
470 }
471}
472
paul718e3742002-12-13 20:15:29 +0000473/* Called from interface_lookup_netlink(). This function is only used
474 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100475static int
paul718e3742002-12-13 20:15:29 +0000476netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
477{
478 int len;
479 struct ifinfomsg *ifi;
480 struct rtattr *tb[IFLA_MAX + 1];
481 struct interface *ifp;
482 char *name;
paul718e3742002-12-13 20:15:29 +0000483
484 ifi = NLMSG_DATA (h);
485
486 if (h->nlmsg_type != RTM_NEWLINK)
487 return 0;
488
489 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
490 if (len < 0)
491 return -1;
492
493 /* Looking up interface name. */
494 memset (tb, 0, sizeof tb);
495 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000496
paul1e193152005-02-14 23:53:05 +0000497#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000498 /* check for wireless messages to ignore */
499 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
500 {
501 if (IS_ZEBRA_DEBUG_KERNEL)
502 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
503 return 0;
504 }
paul1e193152005-02-14 23:53:05 +0000505#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000506
paul718e3742002-12-13 20:15:29 +0000507 if (tb[IFLA_IFNAME] == NULL)
508 return -1;
paul7021c422003-07-15 12:52:22 +0000509 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000510
511 /* Add interface. */
512 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000513 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000514 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800515 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +0000516 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +0000517
518 /* Hardware type and address. */
519 ifp->hw_type = ifi->ifi_type;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700520 netlink_interface_update_hw_addr (tb, ifp);
paul718e3742002-12-13 20:15:29 +0000521
522 if_add_update (ifp);
523
524 return 0;
525}
526
527/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100528static int
paul718e3742002-12-13 20:15:29 +0000529netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
530{
531 int len;
532 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000533 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000534 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000535 void *addr;
536 void *broad;
paul718e3742002-12-13 20:15:29 +0000537 u_char flags = 0;
538 char *label = NULL;
539
540 ifa = NLMSG_DATA (h);
541
paul7021c422003-07-15 12:52:22 +0000542 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000543#ifdef HAVE_IPV6
544 && ifa->ifa_family != AF_INET6
545#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000546 )
paul718e3742002-12-13 20:15:29 +0000547 return 0;
548
549 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
550 return 0;
551
paul7021c422003-07-15 12:52:22 +0000552 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000553 if (len < 0)
554 return -1;
555
556 memset (tb, 0, sizeof tb);
557 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
558
559 ifp = if_lookup_by_index (ifa->ifa_index);
560 if (ifp == NULL)
561 {
562 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000563 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000564 return -1;
565 }
566
paul7021c422003-07-15 12:52:22 +0000567 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000568 {
paul00df0c12002-12-13 21:07:36 +0000569 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000570 zlog_debug ("netlink_interface_addr %s %s:",
571 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000572 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000573 zlog_debug (" IFA_LOCAL %s/%d",
574 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
575 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000576 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000577 zlog_debug (" IFA_ADDRESS %s/%d",
578 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
579 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000580 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000581 zlog_debug (" IFA_BROADCAST %s/%d",
582 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
583 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000584 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000585 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000586
587 if (tb[IFA_CACHEINFO])
588 {
589 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
590 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
591 ci->ifa_prefered, ci->ifa_valid);
592 }
paul718e3742002-12-13 20:15:29 +0000593 }
paul31a476c2003-09-29 19:54:53 +0000594
Andrew J. Schorre4529632006-12-12 19:18:21 +0000595 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
596 if (tb[IFA_LOCAL] == NULL)
597 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000598 if (tb[IFA_ADDRESS] == NULL)
599 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
600
Andrew J. Schorre4529632006-12-12 19:18:21 +0000601 /* local interface address */
602 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
603
604 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000605 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000606 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000607 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000608 broad = RTA_DATA(tb[IFA_ADDRESS]);
609 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000610 }
paul31a476c2003-09-29 19:54:53 +0000611 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000612 /* seeking a broadcast address */
613 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000614
Paul Jakma27b47252006-07-02 16:38:54 +0000615 /* addr is primary key, SOL if we don't have one */
616 if (addr == NULL)
617 {
618 zlog_debug ("%s: NULL address", __func__);
619 return -1;
620 }
621
paul718e3742002-12-13 20:15:29 +0000622 /* Flags. */
623 if (ifa->ifa_flags & IFA_F_SECONDARY)
624 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
625
626 /* Label */
627 if (tb[IFA_LABEL])
628 label = (char *) RTA_DATA (tb[IFA_LABEL]);
629
630 if (ifp && label && strcmp (ifp->name, label) == 0)
631 label = NULL;
632
633 /* Register interface address to the interface. */
634 if (ifa->ifa_family == AF_INET)
635 {
paul7021c422003-07-15 12:52:22 +0000636 if (h->nlmsg_type == RTM_NEWADDR)
637 connected_add_ipv4 (ifp, flags,
638 (struct in_addr *) addr, ifa->ifa_prefixlen,
639 (struct in_addr *) broad, label);
640 else
641 connected_delete_ipv4 (ifp, flags,
642 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000643 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000644 }
645#ifdef HAVE_IPV6
646 if (ifa->ifa_family == AF_INET6)
647 {
648 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000649 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000650 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000651 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000652 else
paul7021c422003-07-15 12:52:22 +0000653 connected_delete_ipv6 (ifp,
654 (struct in6_addr *) addr, ifa->ifa_prefixlen,
655 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000656 }
paul7021c422003-07-15 12:52:22 +0000657#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000658
659 return 0;
660}
661
662/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100663static int
paul718e3742002-12-13 20:15:29 +0000664netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
665{
666 int len;
667 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000668 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000669 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000670
671 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000672
673 int index;
674 int table;
hasso34195bf2004-04-06 12:07:06 +0000675 int metric;
676
paul718e3742002-12-13 20:15:29 +0000677 void *dest;
678 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000679 void *src;
paul718e3742002-12-13 20:15:29 +0000680
681 rtm = NLMSG_DATA (h);
682
683 if (h->nlmsg_type != RTM_NEWROUTE)
684 return 0;
685 if (rtm->rtm_type != RTN_UNICAST)
686 return 0;
687
688 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000689#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000690 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000691 return 0;
692#endif
693
paul7021c422003-07-15 12:52:22 +0000694 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000695 if (len < 0)
696 return -1;
697
698 memset (tb, 0, sizeof tb);
699 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
700
701 if (rtm->rtm_flags & RTM_F_CLONED)
702 return 0;
703 if (rtm->rtm_protocol == RTPROT_REDIRECT)
704 return 0;
705 if (rtm->rtm_protocol == RTPROT_KERNEL)
706 return 0;
707
708 if (rtm->rtm_src_len != 0)
709 return 0;
710
711 /* Route which inserted by Zebra. */
712 if (rtm->rtm_protocol == RTPROT_ZEBRA)
713 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000714
paul718e3742002-12-13 20:15:29 +0000715 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000716 metric = 0;
paul718e3742002-12-13 20:15:29 +0000717 dest = NULL;
718 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000719 src = NULL;
paul718e3742002-12-13 20:15:29 +0000720
721 if (tb[RTA_OIF])
722 index = *(int *) RTA_DATA (tb[RTA_OIF]);
723
724 if (tb[RTA_DST])
725 dest = RTA_DATA (tb[RTA_DST]);
726 else
727 dest = anyaddr;
728
Paul Jakma7514fb72007-05-02 16:05:35 +0000729 if (tb[RTA_PREFSRC])
730 src = RTA_DATA (tb[RTA_PREFSRC]);
731
paul718e3742002-12-13 20:15:29 +0000732 if (tb[RTA_GATEWAY])
733 gate = RTA_DATA (tb[RTA_GATEWAY]);
734
hasso34195bf2004-04-06 12:07:06 +0000735 if (tb[RTA_PRIORITY])
736 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
737
paul718e3742002-12-13 20:15:29 +0000738 if (rtm->rtm_family == AF_INET)
739 {
740 struct prefix_ipv4 p;
741 p.family = AF_INET;
742 memcpy (&p.prefix, dest, 4);
743 p.prefixlen = rtm->rtm_dst_len;
744
Josh Bailey26e2ae32012-03-22 01:09:21 -0700745 if (!tb[RTA_MULTIPATH])
746 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
Feng Lu0d0686f2015-05-22 11:40:02 +0200747 VRF_DEFAULT, table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700748 else
749 {
750 /* This is a multipath route */
751
752 struct rib *rib;
753 struct rtnexthop *rtnh =
754 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
755
756 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
757
758 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
759 rib->type = ZEBRA_ROUTE_KERNEL;
760 rib->distance = 0;
761 rib->flags = flags;
762 rib->metric = metric;
Feng Lu0d0686f2015-05-22 11:40:02 +0200763 rib->vrf_id = VRF_DEFAULT;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700764 rib->table = table;
765 rib->nexthop_num = 0;
766 rib->uptime = time (NULL);
767
768 for (;;)
769 {
770 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
771 break;
772
773 rib->nexthop_num++;
774 index = rtnh->rtnh_ifindex;
775 gate = 0;
776 if (rtnh->rtnh_len > sizeof (*rtnh))
777 {
778 memset (tb, 0, sizeof (tb));
779 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
780 rtnh->rtnh_len - sizeof (*rtnh));
781 if (tb[RTA_GATEWAY])
782 gate = RTA_DATA (tb[RTA_GATEWAY]);
783 }
784
785 if (gate)
786 {
787 if (index)
788 nexthop_ipv4_ifindex_add (rib, gate, src, index);
789 else
790 nexthop_ipv4_add (rib, gate, src);
791 }
792 else
793 nexthop_ifindex_add (rib, index);
794
795 len -= NLMSG_ALIGN(rtnh->rtnh_len);
796 rtnh = RTNH_NEXT(rtnh);
797 }
798
799 if (rib->nexthop_num == 0)
800 XFREE (MTYPE_RIB, rib);
801 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700802 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700803 }
paul718e3742002-12-13 20:15:29 +0000804 }
805#ifdef HAVE_IPV6
806 if (rtm->rtm_family == AF_INET6)
807 {
808 struct prefix_ipv6 p;
809 p.family = AF_INET6;
810 memcpy (&p.prefix, dest, 16);
811 p.prefixlen = rtm->rtm_dst_len;
812
Feng Lu0d0686f2015-05-22 11:40:02 +0200813 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, VRF_DEFAULT,
814 table, metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000815 }
816#endif /* HAVE_IPV6 */
817
818 return 0;
819}
820
Stephen Hemminger1423c802008-08-14 17:59:25 +0100821static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000822 {RTPROT_REDIRECT, "redirect"},
823 {RTPROT_KERNEL, "kernel"},
824 {RTPROT_BOOT, "boot"},
825 {RTPROT_STATIC, "static"},
826 {RTPROT_GATED, "GateD"},
827 {RTPROT_RA, "router advertisement"},
828 {RTPROT_MRT, "MRT"},
829 {RTPROT_ZEBRA, "Zebra"},
830#ifdef RTPROT_BIRD
831 {RTPROT_BIRD, "BIRD"},
832#endif /* RTPROT_BIRD */
833 {0, NULL}
834};
835
836/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100837static int
paul718e3742002-12-13 20:15:29 +0000838netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
839{
840 int len;
841 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000842 struct rtattr *tb[RTA_MAX + 1];
843
844 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000845
846 int index;
847 int table;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700848 int metric;
Dmitry Popov83d16142011-09-11 13:48:25 +0400849
paul718e3742002-12-13 20:15:29 +0000850 void *dest;
851 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000852 void *src;
paul718e3742002-12-13 20:15:29 +0000853
854 rtm = NLMSG_DATA (h);
855
paul7021c422003-07-15 12:52:22 +0000856 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000857 {
858 /* If this is not route add/delete message print warning. */
859 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
860 return 0;
861 }
862
863 /* Connected route. */
864 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000865 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000866 h->nlmsg_type ==
867 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
868 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
869 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
870 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000871
872 if (rtm->rtm_type != RTN_UNICAST)
873 {
874 return 0;
875 }
876
877 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000878 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000879 {
880 return 0;
881 }
882
paul7021c422003-07-15 12:52:22 +0000883 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000884 if (len < 0)
885 return -1;
886
887 memset (tb, 0, sizeof tb);
888 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
889
890 if (rtm->rtm_flags & RTM_F_CLONED)
891 return 0;
892 if (rtm->rtm_protocol == RTPROT_REDIRECT)
893 return 0;
894 if (rtm->rtm_protocol == RTPROT_KERNEL)
895 return 0;
896
897 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
898 return 0;
899
900 if (rtm->rtm_src_len != 0)
901 {
902 zlog_warn ("netlink_route_change(): no src len");
903 return 0;
904 }
paul7021c422003-07-15 12:52:22 +0000905
paul718e3742002-12-13 20:15:29 +0000906 index = 0;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700907 metric = 0;
paul718e3742002-12-13 20:15:29 +0000908 dest = NULL;
909 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000910 src = NULL;
paul718e3742002-12-13 20:15:29 +0000911
912 if (tb[RTA_OIF])
913 index = *(int *) RTA_DATA (tb[RTA_OIF]);
914
915 if (tb[RTA_DST])
916 dest = RTA_DATA (tb[RTA_DST]);
917 else
918 dest = anyaddr;
919
920 if (tb[RTA_GATEWAY])
921 gate = RTA_DATA (tb[RTA_GATEWAY]);
922
Paul Jakma7514fb72007-05-02 16:05:35 +0000923 if (tb[RTA_PREFSRC])
924 src = RTA_DATA (tb[RTA_PREFSRC]);
925
Dmitry Popov83d16142011-09-11 13:48:25 +0400926 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
Josh Bailey26e2ae32012-03-22 01:09:21 -0700927 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
928
paul718e3742002-12-13 20:15:29 +0000929 if (rtm->rtm_family == AF_INET)
930 {
931 struct prefix_ipv4 p;
932 p.family = AF_INET;
933 memcpy (&p.prefix, dest, 4);
934 p.prefixlen = rtm->rtm_dst_len;
935
936 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000937 {
Timo Teräsbe6335d2015-05-23 11:08:41 +0300938 char buf[PREFIX_STRLEN];
939 zlog_debug ("%s %s",
940 h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
941 prefix2str (&p, buf, sizeof(buf)));
paul7021c422003-07-15 12:52:22 +0000942 }
paul718e3742002-12-13 20:15:29 +0000943
944 if (h->nlmsg_type == RTM_NEWROUTE)
Josh Bailey26e2ae32012-03-22 01:09:21 -0700945 {
946 if (!tb[RTA_MULTIPATH])
Feng Lu0d0686f2015-05-22 11:40:02 +0200947 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, VRF_DEFAULT,
948 table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700949 else
950 {
951 /* This is a multipath route */
952
953 struct rib *rib;
954 struct rtnexthop *rtnh =
955 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
956
957 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
958
959 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
960 rib->type = ZEBRA_ROUTE_KERNEL;
961 rib->distance = 0;
962 rib->flags = 0;
963 rib->metric = metric;
Feng Lu0d0686f2015-05-22 11:40:02 +0200964 rib->vrf_id = VRF_DEFAULT;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700965 rib->table = table;
966 rib->nexthop_num = 0;
967 rib->uptime = time (NULL);
968
969 for (;;)
970 {
971 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
972 break;
973
974 rib->nexthop_num++;
975 index = rtnh->rtnh_ifindex;
976 gate = 0;
977 if (rtnh->rtnh_len > sizeof (*rtnh))
978 {
979 memset (tb, 0, sizeof (tb));
980 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
981 rtnh->rtnh_len - sizeof (*rtnh));
982 if (tb[RTA_GATEWAY])
983 gate = RTA_DATA (tb[RTA_GATEWAY]);
984 }
985
986 if (gate)
987 {
988 if (index)
989 nexthop_ipv4_ifindex_add (rib, gate, src, index);
990 else
991 nexthop_ipv4_add (rib, gate, src);
992 }
993 else
994 nexthop_ifindex_add (rib, index);
995
996 len -= NLMSG_ALIGN(rtnh->rtnh_len);
997 rtnh = RTNH_NEXT(rtnh);
998 }
999
1000 if (rib->nexthop_num == 0)
1001 XFREE (MTYPE_RIB, rib);
1002 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -07001003 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -07001004 }
1005 }
paul718e3742002-12-13 20:15:29 +00001006 else
Feng Lu0d0686f2015-05-22 11:40:02 +02001007 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT,
1008 SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001009 }
1010
1011#ifdef HAVE_IPV6
1012 if (rtm->rtm_family == AF_INET6)
1013 {
1014 struct prefix_ipv6 p;
paul718e3742002-12-13 20:15:29 +00001015
1016 p.family = AF_INET6;
1017 memcpy (&p.prefix, dest, 16);
1018 p.prefixlen = rtm->rtm_dst_len;
1019
1020 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001021 {
Timo Teräsbe6335d2015-05-23 11:08:41 +03001022 char buf[PREFIX_STRLEN];
1023 zlog_debug ("%s %s",
1024 h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
1025 prefix2str (&p, buf, sizeof(buf)));
paul7021c422003-07-15 12:52:22 +00001026 }
paul718e3742002-12-13 20:15:29 +00001027
1028 if (h->nlmsg_type == RTM_NEWROUTE)
Feng Lu0d0686f2015-05-22 11:40:02 +02001029 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, table,
1030 metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001031 else
Feng Lu0d0686f2015-05-22 11:40:02 +02001032 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT,
1033 SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001034 }
1035#endif /* HAVE_IPV6 */
1036
1037 return 0;
1038}
1039
Stephen Hemminger6072b242008-08-14 16:52:26 +01001040static int
paul718e3742002-12-13 20:15:29 +00001041netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
1042{
1043 int len;
1044 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +00001045 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +00001046 struct interface *ifp;
1047 char *name;
1048
1049 ifi = NLMSG_DATA (h);
1050
paul7021c422003-07-15 12:52:22 +00001051 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +00001052 {
1053 /* If this is not link add/delete message so print warning. */
1054 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +00001055 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001056 return 0;
1057 }
1058
1059 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1060 if (len < 0)
1061 return -1;
1062
1063 /* Looking up interface name. */
1064 memset (tb, 0, sizeof tb);
1065 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +00001066
paul1e193152005-02-14 23:53:05 +00001067#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +00001068 /* check for wireless messages to ignore */
1069 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1070 {
1071 if (IS_ZEBRA_DEBUG_KERNEL)
1072 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
1073 return 0;
1074 }
paul1e193152005-02-14 23:53:05 +00001075#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001076
paul718e3742002-12-13 20:15:29 +00001077 if (tb[IFLA_IFNAME] == NULL)
1078 return -1;
paul7021c422003-07-15 12:52:22 +00001079 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001080
1081 /* Add interface. */
1082 if (h->nlmsg_type == RTM_NEWLINK)
1083 {
1084 ifp = if_lookup_by_name (name);
1085
paul7021c422003-07-15 12:52:22 +00001086 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1087 {
1088 if (ifp == NULL)
1089 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001090
ajsd2fc8892005-04-02 18:38:43 +00001091 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001092 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001093 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +00001094 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +00001095
Josh Bailey26e2ae32012-03-22 01:09:21 -07001096 netlink_interface_update_hw_addr (tb, ifp);
1097
paul7021c422003-07-15 12:52:22 +00001098 /* If new link is added. */
1099 if_add_update (ifp);
1100 }
paul718e3742002-12-13 20:15:29 +00001101 else
paul7021c422003-07-15 12:52:22 +00001102 {
1103 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001104 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001105 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +00001106 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +00001107
Josh Bailey26e2ae32012-03-22 01:09:21 -07001108 netlink_interface_update_hw_addr (tb, ifp);
1109
paul7021c422003-07-15 12:52:22 +00001110 if (if_is_operative (ifp))
1111 {
1112 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1113 if (!if_is_operative (ifp))
1114 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001115 else
1116 /* Must notify client daemons of new interface status. */
1117 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001118 }
1119 else
1120 {
1121 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1122 if (if_is_operative (ifp))
1123 if_up (ifp);
1124 }
1125 }
paul718e3742002-12-13 20:15:29 +00001126 }
1127 else
1128 {
1129 /* RTM_DELLINK. */
1130 ifp = if_lookup_by_name (name);
1131
1132 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001133 {
1134 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001135 name);
paul7021c422003-07-15 12:52:22 +00001136 return 0;
1137 }
1138
paul718e3742002-12-13 20:15:29 +00001139 if_delete_update (ifp);
1140 }
1141
1142 return 0;
1143}
1144
Stephen Hemminger6072b242008-08-14 16:52:26 +01001145static int
paul718e3742002-12-13 20:15:29 +00001146netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1147{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001148 /* JF: Ignore messages that aren't from the kernel */
1149 if ( snl->nl_pid != 0 )
1150 {
1151 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1152 return 0;
1153 }
1154
paul718e3742002-12-13 20:15:29 +00001155 switch (h->nlmsg_type)
1156 {
1157 case RTM_NEWROUTE:
1158 return netlink_route_change (snl, h);
1159 break;
1160 case RTM_DELROUTE:
1161 return netlink_route_change (snl, h);
1162 break;
1163 case RTM_NEWLINK:
1164 return netlink_link_change (snl, h);
1165 break;
1166 case RTM_DELLINK:
1167 return netlink_link_change (snl, h);
1168 break;
1169 case RTM_NEWADDR:
1170 return netlink_interface_addr (snl, h);
1171 break;
1172 case RTM_DELADDR:
1173 return netlink_interface_addr (snl, h);
1174 break;
1175 default:
1176 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1177 break;
1178 }
1179 return 0;
1180}
1181
1182/* Interface lookup by netlink socket. */
1183int
paul6621ca82005-11-23 13:02:08 +00001184interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001185{
1186 int ret;
paul7021c422003-07-15 12:52:22 +00001187
paul718e3742002-12-13 20:15:29 +00001188 /* Get interface information. */
1189 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1190 if (ret < 0)
1191 return ret;
1192 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1193 if (ret < 0)
1194 return ret;
1195
1196 /* Get IPv4 address of the interfaces. */
1197 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1198 if (ret < 0)
1199 return ret;
1200 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1201 if (ret < 0)
1202 return ret;
1203
1204#ifdef HAVE_IPV6
1205 /* Get IPv6 address of the interfaces. */
1206 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1207 if (ret < 0)
1208 return ret;
1209 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1210 if (ret < 0)
1211 return ret;
1212#endif /* HAVE_IPV6 */
1213
1214 return 0;
1215}
1216
1217/* Routing table read function using netlink interface. Only called
1218 bootstrap time. */
1219int
paul6621ca82005-11-23 13:02:08 +00001220netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001221{
1222 int ret;
paul7021c422003-07-15 12:52:22 +00001223
paul718e3742002-12-13 20:15:29 +00001224 /* Get IPv4 routing table. */
1225 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1226 if (ret < 0)
1227 return ret;
1228 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1229 if (ret < 0)
1230 return ret;
1231
1232#ifdef HAVE_IPV6
1233 /* Get IPv6 routing table. */
1234 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1235 if (ret < 0)
1236 return ret;
1237 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1238 if (ret < 0)
1239 return ret;
1240#endif /* HAVE_IPV6 */
1241
1242 return 0;
1243}
1244
1245/* Utility function comes from iproute2.
1246 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001247int
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001248addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen)
paul718e3742002-12-13 20:15:29 +00001249{
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001250 size_t len;
paul718e3742002-12-13 20:15:29 +00001251 struct rtattr *rta;
1252
paul7021c422003-07-15 12:52:22 +00001253 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001254
paul7021c422003-07-15 12:52:22 +00001255 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001256 return -1;
1257
paul7021c422003-07-15 12:52:22 +00001258 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001259 rta->rta_type = type;
1260 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001261 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001262 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1263
1264 return 0;
1265}
1266
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001267int
paul718e3742002-12-13 20:15:29 +00001268rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1269{
1270 int len;
1271 struct rtattr *subrta;
1272
paul7021c422003-07-15 12:52:22 +00001273 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001274
paul7021c422003-07-15 12:52:22 +00001275 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001276 return -1;
1277
paul7021c422003-07-15 12:52:22 +00001278 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001279 subrta->rta_type = type;
1280 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001281 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001282 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1283
1284 return 0;
1285}
1286
1287/* Utility function comes from iproute2.
1288 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001289int
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001290addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data)
paul718e3742002-12-13 20:15:29 +00001291{
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001292 size_t len;
paul718e3742002-12-13 20:15:29 +00001293 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001294
1295 len = RTA_LENGTH (4);
1296
paul718e3742002-12-13 20:15:29 +00001297 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1298 return -1;
1299
paul7021c422003-07-15 12:52:22 +00001300 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001301 rta->rta_type = type;
1302 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001303 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001304 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1305
1306 return 0;
1307}
1308
1309static int
1310netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1311{
hassob7ed1ec2005-03-31 20:13:49 +00001312 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001313 return 0;
1314}
1315
1316/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001317static int
paul718e3742002-12-13 20:15:29 +00001318netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1319{
1320 int status;
1321 struct sockaddr_nl snl;
Timo Teräsc299ed72014-07-29 09:41:55 +00001322 struct iovec iov = {
1323 .iov_base = (void *) n,
1324 .iov_len = n->nlmsg_len
1325 };
1326 struct msghdr msg = {
1327 .msg_name = (void *) &snl,
1328 .msg_namelen = sizeof snl,
1329 .msg_iov = &iov,
1330 .msg_iovlen = 1,
1331 };
ajs4be019d2005-01-29 16:12:41 +00001332 int save_errno;
paul7021c422003-07-15 12:52:22 +00001333
paul718e3742002-12-13 20:15:29 +00001334 memset (&snl, 0, sizeof snl);
1335 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001336
hassob7ed1ec2005-03-31 20:13:49 +00001337 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001338
1339 /* Request an acknowledgement by setting NLM_F_ACK */
1340 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001341
1342 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001343 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001344 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1345 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001346
1347 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001348 if (zserv_privs.change (ZPRIVS_RAISE))
1349 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001350 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001351 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001352 if (zserv_privs.change (ZPRIVS_LOWER))
1353 zlog (NULL, LOG_ERR, "Can't lower privileges");
1354
paul718e3742002-12-13 20:15:29 +00001355 if (status < 0)
1356 {
1357 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001358 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001359 return -1;
1360 }
paul7021c422003-07-15 12:52:22 +00001361
paul718e3742002-12-13 20:15:29 +00001362
1363 /*
1364 * Get reply from netlink socket.
1365 * The reply should either be an acknowlegement or an error.
1366 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001367 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001368}
1369
Christian Frankefa713d92013-07-05 15:35:37 +00001370/* This function takes a nexthop as argument and adds
1371 * the appropriate netlink attributes to an existing
1372 * netlink message.
1373 *
1374 * @param routedesc: Human readable description of route type
1375 * (direct/recursive, single-/multipath)
1376 * @param bytelen: Length of addresses in bytes.
1377 * @param nexthop: Nexthop information
1378 * @param nlmsg: nlmsghdr structure to fill in.
1379 * @param req_size: The size allocated for the message.
1380 */
1381static void
1382_netlink_route_build_singlepath(
1383 const char *routedesc,
1384 int bytelen,
1385 struct nexthop *nexthop,
1386 struct nlmsghdr *nlmsg,
Christian Frankee8d3d292013-07-05 15:35:39 +00001387 struct rtmsg *rtmsg,
Christian Frankefa713d92013-07-05 15:35:37 +00001388 size_t req_size)
1389{
Christian Frankee8d3d292013-07-05 15:35:39 +00001390 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1391 rtmsg->rtm_flags |= RTNH_F_ONLINK;
Christian Frankefa713d92013-07-05 15:35:37 +00001392 if (nexthop->type == NEXTHOP_TYPE_IPV4
1393 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1394 {
1395 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1396 &nexthop->gate.ipv4, bytelen);
1397 if (nexthop->src.ipv4.s_addr)
1398 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1399 &nexthop->src.ipv4, bytelen);
1400
1401 if (IS_ZEBRA_DEBUG_KERNEL)
1402 zlog_debug("netlink_route_multipath() (%s): "
1403 "nexthop via %s if %u",
1404 routedesc,
1405 inet_ntoa (nexthop->gate.ipv4),
1406 nexthop->ifindex);
1407 }
1408#ifdef HAVE_IPV6
1409 if (nexthop->type == NEXTHOP_TYPE_IPV6
1410 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1411 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1412 {
1413 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1414 &nexthop->gate.ipv6, bytelen);
1415
1416 if (IS_ZEBRA_DEBUG_KERNEL)
1417 zlog_debug("netlink_route_multipath() (%s): "
1418 "nexthop via %s if %u",
1419 routedesc,
1420 inet6_ntoa (nexthop->gate.ipv6),
1421 nexthop->ifindex);
1422 }
1423#endif /* HAVE_IPV6 */
1424 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1425 || nexthop->type == NEXTHOP_TYPE_IFNAME
1426 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1427 {
1428 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1429
1430 if (nexthop->src.ipv4.s_addr)
1431 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1432 &nexthop->src.ipv4, bytelen);
1433
1434 if (IS_ZEBRA_DEBUG_KERNEL)
1435 zlog_debug("netlink_route_multipath() (%s): "
1436 "nexthop via if %u", routedesc, nexthop->ifindex);
1437 }
1438
1439 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1440 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1441 {
1442 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1443
1444 if (IS_ZEBRA_DEBUG_KERNEL)
1445 zlog_debug("netlink_route_multipath() (%s): "
1446 "nexthop via if %u", routedesc, nexthop->ifindex);
1447 }
1448}
1449
1450/* This function takes a nexthop as argument and
1451 * appends to the given rtattr/rtnexthop pair the
1452 * representation of the nexthop. If the nexthop
1453 * defines a preferred source, the src parameter
1454 * will be modified to point to that src, otherwise
1455 * it will be kept unmodified.
1456 *
1457 * @param routedesc: Human readable description of route type
1458 * (direct/recursive, single-/multipath)
1459 * @param bytelen: Length of addresses in bytes.
1460 * @param nexthop: Nexthop information
1461 * @param rta: rtnetlink attribute structure
1462 * @param rtnh: pointer to an rtnetlink nexthop structure
1463 * @param src: pointer pointing to a location where
1464 * the prefsrc should be stored.
1465 */
1466static void
1467_netlink_route_build_multipath(
1468 const char *routedesc,
1469 int bytelen,
1470 struct nexthop *nexthop,
1471 struct rtattr *rta,
1472 struct rtnexthop *rtnh,
1473 union g_addr **src
1474 )
1475{
1476 rtnh->rtnh_len = sizeof (*rtnh);
1477 rtnh->rtnh_flags = 0;
1478 rtnh->rtnh_hops = 0;
1479 rta->rta_len += rtnh->rtnh_len;
1480
Christian Frankee8d3d292013-07-05 15:35:39 +00001481 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1482 rtnh->rtnh_flags |= RTNH_F_ONLINK;
1483
Christian Frankefa713d92013-07-05 15:35:37 +00001484 if (nexthop->type == NEXTHOP_TYPE_IPV4
1485 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1486 {
1487 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1488 &nexthop->gate.ipv4, bytelen);
Lu Feng621e2aa2014-07-11 07:52:15 +00001489 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
Christian Frankefa713d92013-07-05 15:35:37 +00001490
1491 if (nexthop->src.ipv4.s_addr)
1492 *src = &nexthop->src;
1493
1494 if (IS_ZEBRA_DEBUG_KERNEL)
1495 zlog_debug("netlink_route_multipath() (%s): "
1496 "nexthop via %s if %u",
1497 routedesc,
1498 inet_ntoa (nexthop->gate.ipv4),
1499 nexthop->ifindex);
1500 }
1501#ifdef HAVE_IPV6
1502 if (nexthop->type == NEXTHOP_TYPE_IPV6
1503 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1504 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1505 {
1506 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1507 &nexthop->gate.ipv6, bytelen);
Lu Feng621e2aa2014-07-11 07:52:15 +00001508 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
Christian Frankefa713d92013-07-05 15:35:37 +00001509
1510 if (IS_ZEBRA_DEBUG_KERNEL)
1511 zlog_debug("netlink_route_multipath() (%s): "
1512 "nexthop via %s if %u",
1513 routedesc,
1514 inet6_ntoa (nexthop->gate.ipv6),
1515 nexthop->ifindex);
1516 }
1517#endif /* HAVE_IPV6 */
1518 /* ifindex */
1519 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1520 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1521 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1522 {
1523 rtnh->rtnh_ifindex = nexthop->ifindex;
1524 if (nexthop->src.ipv4.s_addr)
1525 *src = &nexthop->src;
1526 if (IS_ZEBRA_DEBUG_KERNEL)
1527 zlog_debug("netlink_route_multipath() (%s): "
1528 "nexthop via if %u", routedesc, nexthop->ifindex);
1529 }
1530 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1531 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1532 {
1533 rtnh->rtnh_ifindex = nexthop->ifindex;
1534
1535 if (IS_ZEBRA_DEBUG_KERNEL)
1536 zlog_debug("netlink_route_multipath() (%s): "
1537 "nexthop via if %u", routedesc, nexthop->ifindex);
1538 }
1539 else
1540 {
1541 rtnh->rtnh_ifindex = 0;
1542 }
1543}
1544
1545/* Log debug information for netlink_route_multipath
1546 * if debug logging is enabled.
1547 *
1548 * @param cmd: Netlink command which is to be processed
1549 * @param p: Prefix for which the change is due
1550 * @param nexthop: Nexthop which is currently processed
1551 * @param routedesc: Semantic annotation for nexthop
1552 * (recursive, multipath, etc.)
1553 * @param family: Address family which the change concerns
1554 */
1555static void
1556_netlink_route_debug(
1557 int cmd,
1558 struct prefix *p,
1559 struct nexthop *nexthop,
1560 const char *routedesc,
1561 int family)
1562{
1563 if (IS_ZEBRA_DEBUG_KERNEL)
1564 {
Timo Teräsbe6335d2015-05-23 11:08:41 +03001565 char buf[PREFIX_STRLEN];
1566 zlog_debug ("netlink_route_multipath() (%s): %s %s type %s",
Christian Frankefa713d92013-07-05 15:35:37 +00001567 routedesc,
1568 lookup (nlmsg_str, cmd),
Timo Teräsbe6335d2015-05-23 11:08:41 +03001569 prefix2str (p, buf, sizeof(buf)),
1570 nexthop_type_to_str (nexthop->type));
Christian Frankefa713d92013-07-05 15:35:37 +00001571 }
1572}
1573
paul718e3742002-12-13 20:15:29 +00001574/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001575static int
paul718e3742002-12-13 20:15:29 +00001576netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001577 int family)
paul718e3742002-12-13 20:15:29 +00001578{
1579 int bytelen;
1580 struct sockaddr_nl snl;
Christian Frankefa713d92013-07-05 15:35:37 +00001581 struct nexthop *nexthop = NULL, *tnexthop;
1582 int recursing;
1583 int nexthop_num;
paul718e3742002-12-13 20:15:29 +00001584 int discard;
Christian Frankefa713d92013-07-05 15:35:37 +00001585 const char *routedesc;
paul718e3742002-12-13 20:15:29 +00001586
paul7021c422003-07-15 12:52:22 +00001587 struct
paul718e3742002-12-13 20:15:29 +00001588 {
1589 struct nlmsghdr n;
1590 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001591 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001592 } req;
1593
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001594 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001595
1596 bytelen = (family == AF_INET ? 4 : 16);
1597
1598 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1599 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1600 req.n.nlmsg_type = cmd;
1601 req.r.rtm_family = family;
1602 req.r.rtm_table = rib->table;
1603 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001604 req.r.rtm_protocol = RTPROT_ZEBRA;
1605 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001606
paul7021c422003-07-15 12:52:22 +00001607 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001608 discard = 1;
1609 else
1610 discard = 0;
1611
paul7021c422003-07-15 12:52:22 +00001612 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001613 {
paul7021c422003-07-15 12:52:22 +00001614 if (discard)
paul595db7f2003-05-25 21:35:06 +00001615 {
1616 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1617 req.r.rtm_type = RTN_BLACKHOLE;
1618 else if (rib->flags & ZEBRA_FLAG_REJECT)
1619 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001620 else
1621 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1622 }
paul595db7f2003-05-25 21:35:06 +00001623 else
paul7021c422003-07-15 12:52:22 +00001624 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001625 }
1626
1627 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1628
1629 /* Metric. */
1630 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1631
1632 if (discard)
1633 {
1634 if (cmd == RTM_NEWROUTE)
Christian Frankefa713d92013-07-05 15:35:37 +00001635 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1636 {
1637 /* We shouldn't encounter recursive nexthops on discard routes,
1638 * but it is probably better to handle that case correctly anyway.
1639 */
1640 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1641 continue;
1642 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1643 }
paul718e3742002-12-13 20:15:29 +00001644 goto skip;
1645 }
1646
Christian Frankefa713d92013-07-05 15:35:37 +00001647 /* Count overall nexthops so we can decide whether to use singlepath
1648 * or multipath case. */
1649 nexthop_num = 0;
1650 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul718e3742002-12-13 20:15:29 +00001651 {
Christian Frankefa713d92013-07-05 15:35:37 +00001652 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1653 continue;
1654 if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1655 continue;
1656 if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
1657 continue;
1658
1659 nexthop_num++;
1660 }
1661
1662 /* Singlepath case. */
1663 if (nexthop_num == 1 || MULTIPATH_NUM == 1)
1664 {
1665 nexthop_num = 0;
1666 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001667 {
Christian Frankefa713d92013-07-05 15:35:37 +00001668 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1669 continue;
paul5ec90d22003-06-19 01:41:37 +00001670
paul7021c422003-07-15 12:52:22 +00001671 if ((cmd == RTM_NEWROUTE
1672 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1673 || (cmd == RTM_DELROUTE
1674 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1675 {
Christian Frankefa713d92013-07-05 15:35:37 +00001676 routedesc = recursing ? "recursive, 1 hop" : "single hop";
paul5ec90d22003-06-19 01:41:37 +00001677
Christian Frankefa713d92013-07-05 15:35:37 +00001678 _netlink_route_debug(cmd, p, nexthop, routedesc, family);
1679 _netlink_route_build_singlepath(routedesc, bytelen,
Christian Frankee8d3d292013-07-05 15:35:39 +00001680 nexthop, &req.n, &req.r,
1681 sizeof req);
paul718e3742002-12-13 20:15:29 +00001682
paul7021c422003-07-15 12:52:22 +00001683 if (cmd == RTM_NEWROUTE)
1684 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001685
paul7021c422003-07-15 12:52:22 +00001686 nexthop_num++;
1687 break;
1688 }
1689 }
paul718e3742002-12-13 20:15:29 +00001690 }
1691 else
1692 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001693 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001694 struct rtattr *rta = (void *) buf;
1695 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001696 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001697
1698 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001699 rta->rta_len = RTA_LENGTH (0);
1700 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001701
1702 nexthop_num = 0;
Christian Frankefa713d92013-07-05 15:35:37 +00001703 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001704 {
Christian Frankefa713d92013-07-05 15:35:37 +00001705 if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
1706 break;
1707
1708 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1709 continue;
1710
paul7021c422003-07-15 12:52:22 +00001711 if ((cmd == RTM_NEWROUTE
1712 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1713 || (cmd == RTM_DELROUTE
1714 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1715 {
Christian Frankefa713d92013-07-05 15:35:37 +00001716 routedesc = recursing ? "recursive, multihop" : "multihop";
paul7021c422003-07-15 12:52:22 +00001717 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001718
Christian Frankefa713d92013-07-05 15:35:37 +00001719 _netlink_route_debug(cmd, p, nexthop,
1720 routedesc, family);
1721 _netlink_route_build_multipath(routedesc, bytelen,
1722 nexthop, rta, rtnh, &src);
paul7021c422003-07-15 12:52:22 +00001723 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001724
paul7021c422003-07-15 12:52:22 +00001725 if (cmd == RTM_NEWROUTE)
1726 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1727 }
1728 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001729 if (src)
1730 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001731
1732 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001733 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001734 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001735 }
1736
1737 /* If there is no useful nexthop then return. */
1738 if (nexthop_num == 0)
1739 {
1740 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001741 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001742 return 0;
1743 }
1744
paul7021c422003-07-15 12:52:22 +00001745skip:
paul718e3742002-12-13 20:15:29 +00001746
1747 /* Destination netlink address. */
1748 memset (&snl, 0, sizeof snl);
1749 snl.nl_family = AF_NETLINK;
1750
paul718e3742002-12-13 20:15:29 +00001751 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001752 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001753}
1754
1755int
1756kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1757{
1758 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1759}
1760
1761int
1762kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1763{
1764 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1765}
1766
1767#ifdef HAVE_IPV6
1768int
1769kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1770{
1771 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1772}
1773
1774int
1775kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1776{
1777 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1778}
paul718e3742002-12-13 20:15:29 +00001779#endif /* HAVE_IPV6 */
David Lamparter6b0655a2014-06-04 06:53:35 +02001780
paul718e3742002-12-13 20:15:29 +00001781/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001782static int
paul718e3742002-12-13 20:15:29 +00001783netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001784 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001785{
1786 int bytelen;
1787 struct prefix *p;
1788
paul7021c422003-07-15 12:52:22 +00001789 struct
paul718e3742002-12-13 20:15:29 +00001790 {
1791 struct nlmsghdr n;
1792 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001793 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001794 } req;
1795
1796 p = ifc->address;
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001797 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001798
1799 bytelen = (family == AF_INET ? 4 : 16);
1800
paul7021c422003-07-15 12:52:22 +00001801 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001802 req.n.nlmsg_flags = NLM_F_REQUEST;
1803 req.n.nlmsg_type = cmd;
1804 req.ifa.ifa_family = family;
1805
1806 req.ifa.ifa_index = ifp->ifindex;
1807 req.ifa.ifa_prefixlen = p->prefixlen;
1808
1809 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1810
1811 if (family == AF_INET && cmd == RTM_NEWADDR)
1812 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001813 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001814 {
1815 p = ifc->destination;
1816 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1817 bytelen);
1818 }
paul718e3742002-12-13 20:15:29 +00001819 }
1820
1821 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1822 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001823
paul718e3742002-12-13 20:15:29 +00001824 if (ifc->label)
1825 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001826 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001827
1828 return netlink_talk (&req.n, &netlink_cmd);
1829}
1830
1831int
1832kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1833{
1834 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1835}
1836
1837int
1838kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1839{
1840 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1841}
1842
paul718e3742002-12-13 20:15:29 +00001843
1844extern struct thread_master *master;
1845
1846/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001847static int
paul718e3742002-12-13 20:15:29 +00001848kernel_read (struct thread *thread)
1849{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001850 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001851 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001852
1853 return 0;
1854}
1855
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001856/* Filter out messages from self that occur on listener socket,
1857 caused by our actions on the command socket
1858 */
1859static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001860{
Paul Jakma768a27e2008-05-29 18:23:08 +00001861 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001862 /* 0: ldh [4] */
1863 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1864 /* 1: jeq 0x18 jt 3 jf 6 */
1865 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1866 /* 2: jeq 0x19 jt 3 jf 6 */
1867 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1868 /* 3: ldw [12] */
1869 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1870 /* 4: jeq XX jt 5 jf 6 */
1871 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1872 /* 5: ret 0 (skip) */
1873 BPF_STMT(BPF_RET|BPF_K, 0),
1874 /* 6: ret 0xffff (keep) */
1875 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001876 };
1877
1878 struct sock_fprog prog = {
Balaji.G837d16c2012-09-26 14:09:10 +05301879 .len = array_size(filter),
Paul Jakma768a27e2008-05-29 18:23:08 +00001880 .filter = filter,
1881 };
1882
1883 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1884 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1885}
1886
paul718e3742002-12-13 20:15:29 +00001887/* Exported interface function. This function simply calls
1888 netlink_socket (). */
1889void
paul6621ca82005-11-23 13:02:08 +00001890kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001891{
1892 unsigned long groups;
1893
paul7021c422003-07-15 12:52:22 +00001894 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001895#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001896 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001897#endif /* HAVE_IPV6 */
1898 netlink_socket (&netlink, groups);
1899 netlink_socket (&netlink_cmd, 0);
1900
1901 /* Register kernel socket. */
1902 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001903 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001904 /* Only want non-blocking on the netlink event socket */
1905 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1906 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1907 safe_strerror (errno));
1908
Stephen Hemminger30afea32008-08-16 18:25:47 +01001909 /* Set receive buffer size if it's set from command line */
1910 if (nl_rcvbufsize)
1911 netlink_recvbuf (&netlink, nl_rcvbufsize);
1912
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001913 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001914 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1915 }
paul718e3742002-12-13 20:15:29 +00001916}
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001917
1918/*
1919 * nl_msg_type_to_str
1920 */
1921const char *
1922nl_msg_type_to_str (uint16_t msg_type)
1923{
1924 return lookup (nlmsg_str, msg_type);
1925}
1926
1927/*
1928 * nl_rtproto_to_str
1929 */
1930const char *
1931nl_rtproto_to_str (u_char rtproto)
1932{
1933 return lookup (rtproto_str, rtproto);
1934}