blob: 12dbd1ad5f198740f572de98541a28ed00db0a55 [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"
paul718e3742002-12-13 20:15:29 +000039
40#include "zebra/zserv.h"
paul6621ca82005-11-23 13:02:08 +000041#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000042#include "zebra/redistribute.h"
43#include "zebra/interface.h"
44#include "zebra/debug.h"
45
Avneesh Sachdev78deec42012-11-13 22:48:56 +000046#include "rt_netlink.h"
JR Rivers3cadc0c2012-04-01 12:16:31 -070047
paul718e3742002-12-13 20:15:29 +000048/* Socket interface to kernel */
49struct nlsock
50{
51 int sock;
52 int seq;
53 struct sockaddr_nl snl;
hassofce954f2004-10-07 20:29:24 +000054 const char *name;
paul7021c422003-07-15 12:52:22 +000055} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
hasso1ada8192005-06-12 11:28:18 +000056 netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
paul718e3742002-12-13 20:15:29 +000057
Stephen Hemminger1423c802008-08-14 17:59:25 +010058static const struct message nlmsg_str[] = {
paul718e3742002-12-13 20:15:29 +000059 {RTM_NEWROUTE, "RTM_NEWROUTE"},
60 {RTM_DELROUTE, "RTM_DELROUTE"},
61 {RTM_GETROUTE, "RTM_GETROUTE"},
62 {RTM_NEWLINK, "RTM_NEWLINK"},
63 {RTM_DELLINK, "RTM_DELLINK"},
64 {RTM_GETLINK, "RTM_GETLINK"},
65 {RTM_NEWADDR, "RTM_NEWADDR"},
66 {RTM_DELADDR, "RTM_DELADDR"},
67 {RTM_GETADDR, "RTM_GETADDR"},
paul7021c422003-07-15 12:52:22 +000068 {0, NULL}
paul718e3742002-12-13 20:15:29 +000069};
70
paulb21b19c2003-06-15 01:28:29 +000071extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000072
pauledd7c242003-06-04 13:59:38 +000073extern struct zebra_privs_t zserv_privs;
74
hassoc34b6b52004-08-31 13:41:49 +000075extern u_int32_t nl_rcvbufsize;
76
ajsd2fc8892005-04-02 18:38:43 +000077/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
78 names and ifindex values. */
79static void
80set_ifindex(struct interface *ifp, unsigned int ifi_index)
81{
82 struct interface *oifp;
83
84 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
85 {
86 if (ifi_index == IFINDEX_INTERNAL)
87 zlog_err("Netlink is setting interface %s ifindex to reserved "
88 "internal value %u", ifp->name, ifi_index);
89 else
90 {
91 if (IS_ZEBRA_DEBUG_KERNEL)
92 zlog_debug("interface index %d was renamed from %s to %s",
93 ifi_index, oifp->name, ifp->name);
94 if (if_is_up(oifp))
95 zlog_err("interface rename detected on up interface: index %d "
96 "was renamed from %s to %s, results are uncertain!",
97 ifi_index, oifp->name, ifp->name);
98 if_delete_update(oifp);
99 }
100 }
101 ifp->ifindex = ifi_index;
102}
103
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000104#ifndef SO_RCVBUFFORCE
105#define SO_RCVBUFFORCE (33)
106#endif
107
Stephen Hemminger30afea32008-08-16 18:25:47 +0100108static int
109netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
110{
111 u_int32_t oldsize;
112 socklen_t newlen = sizeof(newsize);
113 socklen_t oldlen = sizeof(oldsize);
114 int ret;
115
116 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
117 if (ret < 0)
118 {
119 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
120 safe_strerror (errno));
121 return -1;
122 }
123
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000124 /* Try force option (linux >= 2.6.14) and fall back to normal set */
125 if ( zserv_privs.change (ZPRIVS_RAISE) )
126 zlog_err ("routing_socket: Can't raise privileges");
127 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize,
Stephen Hemminger30afea32008-08-16 18:25:47 +0100128 sizeof(nl_rcvbufsize));
Ulrich Weberf1ef81b2013-01-22 10:39:18 +0000129 if ( zserv_privs.change (ZPRIVS_LOWER) )
130 zlog_err ("routing_socket: Can't lower privileges");
131 if (ret < 0)
132 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
133 sizeof(nl_rcvbufsize));
Stephen Hemminger30afea32008-08-16 18:25:47 +0100134 if (ret < 0)
135 {
136 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
137 safe_strerror (errno));
138 return -1;
139 }
140
141 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
142 if (ret < 0)
143 {
144 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
145 safe_strerror (errno));
146 return -1;
147 }
148
149 zlog (NULL, LOG_INFO,
150 "Setting netlink socket receive buffer size: %u -> %u",
151 oldsize, newsize);
152 return 0;
153}
154
paul718e3742002-12-13 20:15:29 +0000155/* Make socket for Linux netlink interface. */
156static int
157netlink_socket (struct nlsock *nl, unsigned long groups)
158{
159 int ret;
160 struct sockaddr_nl snl;
161 int sock;
162 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000163 int save_errno;
paul718e3742002-12-13 20:15:29 +0000164
Michal Sekletar8e998b12014-05-16 14:13:43 +0000165 if (zserv_privs.change (ZPRIVS_RAISE))
166 {
167 zlog (NULL, LOG_ERR, "Can't raise privileges");
168 return -1;
169 }
170
paul718e3742002-12-13 20:15:29 +0000171 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
172 if (sock < 0)
173 {
174 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000175 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000176 return -1;
177 }
178
paul718e3742002-12-13 20:15:29 +0000179 memset (&snl, 0, sizeof snl);
180 snl.nl_family = AF_NETLINK;
181 snl.nl_groups = groups;
182
183 /* Bind the socket to the netlink structure for anything. */
184 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000185 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000186 if (zserv_privs.change (ZPRIVS_LOWER))
187 zlog (NULL, LOG_ERR, "Can't lower privileges");
188
paul718e3742002-12-13 20:15:29 +0000189 if (ret < 0)
190 {
paul7021c422003-07-15 12:52:22 +0000191 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000192 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000193 close (sock);
194 return -1;
195 }
paul7021c422003-07-15 12:52:22 +0000196
paul718e3742002-12-13 20:15:29 +0000197 /* multiple netlink sockets will have different nl_pid */
198 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000199 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000200 if (ret < 0 || namelen != sizeof snl)
201 {
202 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000203 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000204 close (sock);
205 return -1;
206 }
207
208 nl->snl = snl;
209 nl->sock = sock;
210 return ret;
211}
212
213/* Get type specified information from netlink. */
214static int
215netlink_request (int family, int type, struct nlsock *nl)
216{
217 int ret;
218 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000219 int save_errno;
paul718e3742002-12-13 20:15:29 +0000220
221 struct
222 {
223 struct nlmsghdr nlh;
224 struct rtgenmsg g;
225 } req;
226
227
228 /* Check netlink socket. */
229 if (nl->sock < 0)
230 {
231 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
232 return -1;
233 }
234
235 memset (&snl, 0, sizeof snl);
236 snl.nl_family = AF_NETLINK;
237
ajsc05612b2005-10-01 16:36:54 +0000238 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000239 req.nlh.nlmsg_len = sizeof req;
240 req.nlh.nlmsg_type = type;
241 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100242 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000243 req.nlh.nlmsg_seq = ++nl->seq;
244 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000245
246 /* linux appears to check capabilities on every message
247 * have to raise caps for every message sent
248 */
paul7021c422003-07-15 12:52:22 +0000249 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000250 {
251 zlog (NULL, LOG_ERR, "Can't raise privileges");
252 return -1;
253 }
paul7021c422003-07-15 12:52:22 +0000254
255 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
256 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000257 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000258
259 if (zserv_privs.change (ZPRIVS_LOWER))
260 zlog (NULL, LOG_ERR, "Can't lower privileges");
261
paul718e3742002-12-13 20:15:29 +0000262 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000263 {
264 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000265 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000266 return -1;
267 }
pauledd7c242003-06-04 13:59:38 +0000268
paul718e3742002-12-13 20:15:29 +0000269 return 0;
270}
271
272/* Receive message from netlink interface and pass those information
273 to the given function. */
274static int
275netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000276 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000277{
278 int status;
279 int ret = 0;
280 int error;
281
282 while (1)
283 {
JR Rivers3cadc0c2012-04-01 12:16:31 -0700284 char buf[NL_PKT_BUF_SIZE];
Timo Teräsc299ed72014-07-29 09:41:55 +0000285 struct iovec iov = {
286 .iov_base = buf,
287 .iov_len = sizeof buf
288 };
paul718e3742002-12-13 20:15:29 +0000289 struct sockaddr_nl snl;
Timo Teräsc299ed72014-07-29 09:41:55 +0000290 struct msghdr msg = {
291 .msg_name = (void *) &snl,
292 .msg_namelen = sizeof snl,
293 .msg_iov = &iov,
294 .msg_iovlen = 1
295 };
paul718e3742002-12-13 20:15:29 +0000296 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000297
paul718e3742002-12-13 20:15:29 +0000298 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000299 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000300 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100301 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000302 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100303 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000304 break;
ajs4be019d2005-01-29 16:12:41 +0000305 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100306 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000307 continue;
308 }
paul718e3742002-12-13 20:15:29 +0000309
310 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000311 {
312 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
313 return -1;
314 }
paul718e3742002-12-13 20:15:29 +0000315
316 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000317 {
318 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
319 nl->name, msg.msg_namelen);
320 return -1;
321 }
paulb84d3a12003-11-17 10:31:01 +0000322
hasso206d8052005-04-09 16:38:51 +0000323 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000324 h = NLMSG_NEXT (h, status))
325 {
326 /* Finish of reading. */
327 if (h->nlmsg_type == NLMSG_DONE)
328 return ret;
paul718e3742002-12-13 20:15:29 +0000329
paul7021c422003-07-15 12:52:22 +0000330 /* Error handling. */
331 if (h->nlmsg_type == NLMSG_ERROR)
332 {
333 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100334 int errnum = err->error;
335 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000336
paul718e3742002-12-13 20:15:29 +0000337 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000338 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000339 {
paul7021c422003-07-15 12:52:22 +0000340 if (IS_ZEBRA_DEBUG_KERNEL)
341 {
hasso1ada8192005-06-12 11:28:18 +0000342 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000343 __FUNCTION__, nl->name,
344 lookup (nlmsg_str, err->msg.nlmsg_type),
345 err->msg.nlmsg_type, err->msg.nlmsg_seq,
346 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000347 }
paul7021c422003-07-15 12:52:22 +0000348
349 /* return if not a multipart message, otherwise continue */
350 if (!(h->nlmsg_flags & NLM_F_MULTI))
351 {
352 return 0;
paul718e3742002-12-13 20:15:29 +0000353 }
paul7021c422003-07-15 12:52:22 +0000354 continue;
paul718e3742002-12-13 20:15:29 +0000355 }
paul7021c422003-07-15 12:52:22 +0000356
paul718e3742002-12-13 20:15:29 +0000357 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000358 {
359 zlog (NULL, LOG_ERR, "%s error: message truncated",
360 nl->name);
361 return -1;
362 }
pauld753e9e2003-01-22 19:45:50 +0000363
Stephen Hemminger898987e2008-08-17 16:56:15 +0100364 /* Deal with errors that occur because of races in link handling */
365 if (nl == &netlink_cmd
366 && ((msg_type == RTM_DELROUTE &&
367 (-errnum == ENODEV || -errnum == ESRCH))
368 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
369 {
370 if (IS_ZEBRA_DEBUG_KERNEL)
371 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
372 nl->name, safe_strerror (-errnum),
373 lookup (nlmsg_str, msg_type),
374 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
375 return 0;
376 }
paul718e3742002-12-13 20:15:29 +0000377
Stephen Hemminger898987e2008-08-17 16:56:15 +0100378 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
379 nl->name, safe_strerror (-errnum),
380 lookup (nlmsg_str, msg_type),
381 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000382 return -1;
383 }
paul718e3742002-12-13 20:15:29 +0000384
paul7021c422003-07-15 12:52:22 +0000385 /* OK we got netlink message. */
386 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000387 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000388 nl->name,
389 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
390 h->nlmsg_seq, h->nlmsg_pid);
391
Christian Franke599da952013-01-24 14:04:43 +0000392 /* skip unsolicited messages originating from command socket
393 * linux sets the originators port-id for {NEW|DEL}ADDR messages,
394 * so this has to be checked here. */
395 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid
396 && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
paul7021c422003-07-15 12:52:22 +0000397 {
398 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000399 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000400 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000401 continue;
402 }
403
404 error = (*filter) (&snl, h);
405 if (error < 0)
406 {
407 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
408 ret = error;
409 }
410 }
paul718e3742002-12-13 20:15:29 +0000411
412 /* After error care. */
413 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000414 {
415 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
416 continue;
417 }
paul718e3742002-12-13 20:15:29 +0000418 if (status)
paul7021c422003-07-15 12:52:22 +0000419 {
420 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
421 status);
422 return -1;
423 }
paul718e3742002-12-13 20:15:29 +0000424 }
425 return ret;
426}
427
428/* Utility function for parse rtattr. */
429static void
paul7021c422003-07-15 12:52:22 +0000430netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
431 int len)
paul718e3742002-12-13 20:15:29 +0000432{
paul7021c422003-07-15 12:52:22 +0000433 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000434 {
435 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000436 tb[rta->rta_type] = rta;
437 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000438 }
439}
440
Josh Bailey26e2ae32012-03-22 01:09:21 -0700441/* Utility function to parse hardware link-layer address and update ifp */
442static void
443netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
444{
445 int i;
446
447 if (tb[IFLA_ADDRESS])
448 {
449 int hw_addr_len;
450
451 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
452
453 if (hw_addr_len > INTERFACE_HWADDR_MAX)
454 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
455 else
456 {
457 ifp->hw_addr_len = hw_addr_len;
458 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
459
460 for (i = 0; i < hw_addr_len; i++)
461 if (ifp->hw_addr[i] != 0)
462 break;
463
464 if (i == hw_addr_len)
465 ifp->hw_addr_len = 0;
466 else
467 ifp->hw_addr_len = hw_addr_len;
468 }
469 }
470}
471
paul718e3742002-12-13 20:15:29 +0000472/* Called from interface_lookup_netlink(). This function is only used
473 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100474static int
paul718e3742002-12-13 20:15:29 +0000475netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
476{
477 int len;
478 struct ifinfomsg *ifi;
479 struct rtattr *tb[IFLA_MAX + 1];
480 struct interface *ifp;
481 char *name;
paul718e3742002-12-13 20:15:29 +0000482
483 ifi = NLMSG_DATA (h);
484
485 if (h->nlmsg_type != RTM_NEWLINK)
486 return 0;
487
488 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
489 if (len < 0)
490 return -1;
491
492 /* Looking up interface name. */
493 memset (tb, 0, sizeof tb);
494 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000495
paul1e193152005-02-14 23:53:05 +0000496#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000497 /* check for wireless messages to ignore */
498 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
499 {
500 if (IS_ZEBRA_DEBUG_KERNEL)
501 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
502 return 0;
503 }
paul1e193152005-02-14 23:53:05 +0000504#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000505
paul718e3742002-12-13 20:15:29 +0000506 if (tb[IFLA_IFNAME] == NULL)
507 return -1;
paul7021c422003-07-15 12:52:22 +0000508 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000509
510 /* Add interface. */
511 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000512 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000513 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800514 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +0000515 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +0000516
517 /* Hardware type and address. */
518 ifp->hw_type = ifi->ifi_type;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700519 netlink_interface_update_hw_addr (tb, ifp);
paul718e3742002-12-13 20:15:29 +0000520
521 if_add_update (ifp);
522
523 return 0;
524}
525
526/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100527static int
paul718e3742002-12-13 20:15:29 +0000528netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
529{
530 int len;
531 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000532 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000533 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000534 void *addr;
535 void *broad;
paul718e3742002-12-13 20:15:29 +0000536 u_char flags = 0;
537 char *label = NULL;
538
539 ifa = NLMSG_DATA (h);
540
paul7021c422003-07-15 12:52:22 +0000541 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000542#ifdef HAVE_IPV6
543 && ifa->ifa_family != AF_INET6
544#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000545 )
paul718e3742002-12-13 20:15:29 +0000546 return 0;
547
548 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
549 return 0;
550
paul7021c422003-07-15 12:52:22 +0000551 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000552 if (len < 0)
553 return -1;
554
555 memset (tb, 0, sizeof tb);
556 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
557
558 ifp = if_lookup_by_index (ifa->ifa_index);
559 if (ifp == NULL)
560 {
561 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000562 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000563 return -1;
564 }
565
paul7021c422003-07-15 12:52:22 +0000566 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000567 {
paul00df0c12002-12-13 21:07:36 +0000568 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000569 zlog_debug ("netlink_interface_addr %s %s:",
570 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000571 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000572 zlog_debug (" IFA_LOCAL %s/%d",
573 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
574 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000575 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000576 zlog_debug (" IFA_ADDRESS %s/%d",
577 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
578 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000579 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000580 zlog_debug (" IFA_BROADCAST %s/%d",
581 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
582 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000583 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000584 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000585
586 if (tb[IFA_CACHEINFO])
587 {
588 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
589 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
590 ci->ifa_prefered, ci->ifa_valid);
591 }
paul718e3742002-12-13 20:15:29 +0000592 }
paul31a476c2003-09-29 19:54:53 +0000593
Andrew J. Schorre4529632006-12-12 19:18:21 +0000594 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
595 if (tb[IFA_LOCAL] == NULL)
596 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000597 if (tb[IFA_ADDRESS] == NULL)
598 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
599
Andrew J. Schorre4529632006-12-12 19:18:21 +0000600 /* local interface address */
601 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
602
603 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000604 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000605 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000606 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000607 broad = RTA_DATA(tb[IFA_ADDRESS]);
608 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000609 }
paul31a476c2003-09-29 19:54:53 +0000610 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000611 /* seeking a broadcast address */
612 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000613
Paul Jakma27b47252006-07-02 16:38:54 +0000614 /* addr is primary key, SOL if we don't have one */
615 if (addr == NULL)
616 {
617 zlog_debug ("%s: NULL address", __func__);
618 return -1;
619 }
620
paul718e3742002-12-13 20:15:29 +0000621 /* Flags. */
622 if (ifa->ifa_flags & IFA_F_SECONDARY)
623 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
624
625 /* Label */
626 if (tb[IFA_LABEL])
627 label = (char *) RTA_DATA (tb[IFA_LABEL]);
628
629 if (ifp && label && strcmp (ifp->name, label) == 0)
630 label = NULL;
631
632 /* Register interface address to the interface. */
633 if (ifa->ifa_family == AF_INET)
634 {
paul7021c422003-07-15 12:52:22 +0000635 if (h->nlmsg_type == RTM_NEWADDR)
636 connected_add_ipv4 (ifp, flags,
637 (struct in_addr *) addr, ifa->ifa_prefixlen,
638 (struct in_addr *) broad, label);
639 else
640 connected_delete_ipv4 (ifp, flags,
641 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000642 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000643 }
644#ifdef HAVE_IPV6
645 if (ifa->ifa_family == AF_INET6)
646 {
647 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000648 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000649 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000650 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000651 else
paul7021c422003-07-15 12:52:22 +0000652 connected_delete_ipv6 (ifp,
653 (struct in6_addr *) addr, ifa->ifa_prefixlen,
654 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000655 }
paul7021c422003-07-15 12:52:22 +0000656#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000657
658 return 0;
659}
660
661/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100662static int
paul718e3742002-12-13 20:15:29 +0000663netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
664{
665 int len;
666 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000667 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000668 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000669
670 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000671
672 int index;
673 int table;
hasso34195bf2004-04-06 12:07:06 +0000674 int metric;
675
paul718e3742002-12-13 20:15:29 +0000676 void *dest;
677 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000678 void *src;
paul718e3742002-12-13 20:15:29 +0000679
680 rtm = NLMSG_DATA (h);
681
682 if (h->nlmsg_type != RTM_NEWROUTE)
683 return 0;
684 if (rtm->rtm_type != RTN_UNICAST)
685 return 0;
686
687 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000688#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000689 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000690 return 0;
691#endif
692
paul7021c422003-07-15 12:52:22 +0000693 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000694 if (len < 0)
695 return -1;
696
697 memset (tb, 0, sizeof tb);
698 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
699
700 if (rtm->rtm_flags & RTM_F_CLONED)
701 return 0;
702 if (rtm->rtm_protocol == RTPROT_REDIRECT)
703 return 0;
704 if (rtm->rtm_protocol == RTPROT_KERNEL)
705 return 0;
706
707 if (rtm->rtm_src_len != 0)
708 return 0;
709
710 /* Route which inserted by Zebra. */
711 if (rtm->rtm_protocol == RTPROT_ZEBRA)
712 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000713
paul718e3742002-12-13 20:15:29 +0000714 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000715 metric = 0;
paul718e3742002-12-13 20:15:29 +0000716 dest = NULL;
717 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000718 src = NULL;
paul718e3742002-12-13 20:15:29 +0000719
720 if (tb[RTA_OIF])
721 index = *(int *) RTA_DATA (tb[RTA_OIF]);
722
723 if (tb[RTA_DST])
724 dest = RTA_DATA (tb[RTA_DST]);
725 else
726 dest = anyaddr;
727
Paul Jakma7514fb72007-05-02 16:05:35 +0000728 if (tb[RTA_PREFSRC])
729 src = RTA_DATA (tb[RTA_PREFSRC]);
730
paul718e3742002-12-13 20:15:29 +0000731 if (tb[RTA_GATEWAY])
732 gate = RTA_DATA (tb[RTA_GATEWAY]);
733
hasso34195bf2004-04-06 12:07:06 +0000734 if (tb[RTA_PRIORITY])
735 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
736
paul718e3742002-12-13 20:15:29 +0000737 if (rtm->rtm_family == AF_INET)
738 {
739 struct prefix_ipv4 p;
740 p.family = AF_INET;
741 memcpy (&p.prefix, dest, 4);
742 p.prefixlen = rtm->rtm_dst_len;
743
Josh Bailey26e2ae32012-03-22 01:09:21 -0700744 if (!tb[RTA_MULTIPATH])
745 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700746 table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700747 else
748 {
749 /* This is a multipath route */
750
751 struct rib *rib;
752 struct rtnexthop *rtnh =
753 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
754
755 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
756
757 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
758 rib->type = ZEBRA_ROUTE_KERNEL;
759 rib->distance = 0;
760 rib->flags = flags;
761 rib->metric = metric;
762 rib->table = table;
763 rib->nexthop_num = 0;
764 rib->uptime = time (NULL);
765
766 for (;;)
767 {
768 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
769 break;
770
771 rib->nexthop_num++;
772 index = rtnh->rtnh_ifindex;
773 gate = 0;
774 if (rtnh->rtnh_len > sizeof (*rtnh))
775 {
776 memset (tb, 0, sizeof (tb));
777 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
778 rtnh->rtnh_len - sizeof (*rtnh));
779 if (tb[RTA_GATEWAY])
780 gate = RTA_DATA (tb[RTA_GATEWAY]);
781 }
782
783 if (gate)
784 {
785 if (index)
786 nexthop_ipv4_ifindex_add (rib, gate, src, index);
787 else
788 nexthop_ipv4_add (rib, gate, src);
789 }
790 else
791 nexthop_ifindex_add (rib, index);
792
793 len -= NLMSG_ALIGN(rtnh->rtnh_len);
794 rtnh = RTNH_NEXT(rtnh);
795 }
796
797 if (rib->nexthop_num == 0)
798 XFREE (MTYPE_RIB, rib);
799 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700800 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700801 }
paul718e3742002-12-13 20:15:29 +0000802 }
803#ifdef HAVE_IPV6
804 if (rtm->rtm_family == AF_INET6)
805 {
806 struct prefix_ipv6 p;
807 p.family = AF_INET6;
808 memcpy (&p.prefix, dest, 16);
809 p.prefixlen = rtm->rtm_dst_len;
810
hassobe61c4e2005-08-27 06:05:47 +0000811 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
G.Balajif768f362011-11-26 22:10:39 +0400812 metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000813 }
814#endif /* HAVE_IPV6 */
815
816 return 0;
817}
818
Stephen Hemminger1423c802008-08-14 17:59:25 +0100819static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000820 {RTPROT_REDIRECT, "redirect"},
821 {RTPROT_KERNEL, "kernel"},
822 {RTPROT_BOOT, "boot"},
823 {RTPROT_STATIC, "static"},
824 {RTPROT_GATED, "GateD"},
825 {RTPROT_RA, "router advertisement"},
826 {RTPROT_MRT, "MRT"},
827 {RTPROT_ZEBRA, "Zebra"},
828#ifdef RTPROT_BIRD
829 {RTPROT_BIRD, "BIRD"},
830#endif /* RTPROT_BIRD */
831 {0, NULL}
832};
833
834/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100835static int
paul718e3742002-12-13 20:15:29 +0000836netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
837{
838 int len;
839 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000840 struct rtattr *tb[RTA_MAX + 1];
841
842 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000843
844 int index;
845 int table;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700846 int metric;
Dmitry Popov83d16142011-09-11 13:48:25 +0400847
paul718e3742002-12-13 20:15:29 +0000848 void *dest;
849 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000850 void *src;
paul718e3742002-12-13 20:15:29 +0000851
852 rtm = NLMSG_DATA (h);
853
paul7021c422003-07-15 12:52:22 +0000854 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000855 {
856 /* If this is not route add/delete message print warning. */
857 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
858 return 0;
859 }
860
861 /* Connected route. */
862 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000863 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000864 h->nlmsg_type ==
865 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
866 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
867 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
868 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000869
870 if (rtm->rtm_type != RTN_UNICAST)
871 {
872 return 0;
873 }
874
875 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000876 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000877 {
878 return 0;
879 }
880
paul7021c422003-07-15 12:52:22 +0000881 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000882 if (len < 0)
883 return -1;
884
885 memset (tb, 0, sizeof tb);
886 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
887
888 if (rtm->rtm_flags & RTM_F_CLONED)
889 return 0;
890 if (rtm->rtm_protocol == RTPROT_REDIRECT)
891 return 0;
892 if (rtm->rtm_protocol == RTPROT_KERNEL)
893 return 0;
894
895 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
896 return 0;
897
898 if (rtm->rtm_src_len != 0)
899 {
900 zlog_warn ("netlink_route_change(): no src len");
901 return 0;
902 }
paul7021c422003-07-15 12:52:22 +0000903
paul718e3742002-12-13 20:15:29 +0000904 index = 0;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700905 metric = 0;
paul718e3742002-12-13 20:15:29 +0000906 dest = NULL;
907 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000908 src = NULL;
paul718e3742002-12-13 20:15:29 +0000909
910 if (tb[RTA_OIF])
911 index = *(int *) RTA_DATA (tb[RTA_OIF]);
912
913 if (tb[RTA_DST])
914 dest = RTA_DATA (tb[RTA_DST]);
915 else
916 dest = anyaddr;
917
918 if (tb[RTA_GATEWAY])
919 gate = RTA_DATA (tb[RTA_GATEWAY]);
920
Paul Jakma7514fb72007-05-02 16:05:35 +0000921 if (tb[RTA_PREFSRC])
922 src = RTA_DATA (tb[RTA_PREFSRC]);
923
Dmitry Popov83d16142011-09-11 13:48:25 +0400924 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
Josh Bailey26e2ae32012-03-22 01:09:21 -0700925 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
926
paul718e3742002-12-13 20:15:29 +0000927 if (rtm->rtm_family == AF_INET)
928 {
929 struct prefix_ipv4 p;
930 p.family = AF_INET;
931 memcpy (&p.prefix, dest, 4);
932 p.prefixlen = rtm->rtm_dst_len;
933
934 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000935 {
936 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000937 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000938 inet_ntoa (p.prefix), p.prefixlen);
939 else
ajsb6178002004-12-07 21:12:56 +0000940 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000941 inet_ntoa (p.prefix), p.prefixlen);
942 }
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])
947 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700948 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;
964 rib->table = table;
965 rib->nexthop_num = 0;
966 rib->uptime = time (NULL);
967
968 for (;;)
969 {
970 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
971 break;
972
973 rib->nexthop_num++;
974 index = rtnh->rtnh_ifindex;
975 gate = 0;
976 if (rtnh->rtnh_len > sizeof (*rtnh))
977 {
978 memset (tb, 0, sizeof (tb));
979 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
980 rtnh->rtnh_len - sizeof (*rtnh));
981 if (tb[RTA_GATEWAY])
982 gate = RTA_DATA (tb[RTA_GATEWAY]);
983 }
984
985 if (gate)
986 {
987 if (index)
988 nexthop_ipv4_ifindex_add (rib, gate, src, index);
989 else
990 nexthop_ipv4_add (rib, gate, src);
991 }
992 else
993 nexthop_ifindex_add (rib, index);
994
995 len -= NLMSG_ALIGN(rtnh->rtnh_len);
996 rtnh = RTNH_NEXT(rtnh);
997 }
998
999 if (rib->nexthop_num == 0)
1000 XFREE (MTYPE_RIB, rib);
1001 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -07001002 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -07001003 }
1004 }
paul718e3742002-12-13 20:15:29 +00001005 else
G.Balajicddf3912011-11-26 21:59:32 +04001006 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001007 }
1008
1009#ifdef HAVE_IPV6
1010 if (rtm->rtm_family == AF_INET6)
1011 {
1012 struct prefix_ipv6 p;
1013 char buf[BUFSIZ];
1014
1015 p.family = AF_INET6;
1016 memcpy (&p.prefix, dest, 16);
1017 p.prefixlen = rtm->rtm_dst_len;
1018
1019 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001020 {
1021 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +00001022 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001023 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1024 p.prefixlen);
1025 else
ajsb6178002004-12-07 21:12:56 +00001026 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001027 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1028 p.prefixlen);
1029 }
paul718e3742002-12-13 20:15:29 +00001030
1031 if (h->nlmsg_type == RTM_NEWROUTE)
G.Balajif768f362011-11-26 22:10:39 +04001032 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001033 else
G.Balajif768f362011-11-26 22:10:39 +04001034 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001035 }
1036#endif /* HAVE_IPV6 */
1037
1038 return 0;
1039}
1040
Stephen Hemminger6072b242008-08-14 16:52:26 +01001041static int
paul718e3742002-12-13 20:15:29 +00001042netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
1043{
1044 int len;
1045 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +00001046 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +00001047 struct interface *ifp;
1048 char *name;
1049
1050 ifi = NLMSG_DATA (h);
1051
paul7021c422003-07-15 12:52:22 +00001052 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +00001053 {
1054 /* If this is not link add/delete message so print warning. */
1055 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +00001056 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001057 return 0;
1058 }
1059
1060 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1061 if (len < 0)
1062 return -1;
1063
1064 /* Looking up interface name. */
1065 memset (tb, 0, sizeof tb);
1066 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +00001067
paul1e193152005-02-14 23:53:05 +00001068#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +00001069 /* check for wireless messages to ignore */
1070 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1071 {
1072 if (IS_ZEBRA_DEBUG_KERNEL)
1073 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
1074 return 0;
1075 }
paul1e193152005-02-14 23:53:05 +00001076#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001077
paul718e3742002-12-13 20:15:29 +00001078 if (tb[IFLA_IFNAME] == NULL)
1079 return -1;
paul7021c422003-07-15 12:52:22 +00001080 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001081
1082 /* Add interface. */
1083 if (h->nlmsg_type == RTM_NEWLINK)
1084 {
1085 ifp = if_lookup_by_name (name);
1086
paul7021c422003-07-15 12:52:22 +00001087 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1088 {
1089 if (ifp == NULL)
1090 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001091
ajsd2fc8892005-04-02 18:38:43 +00001092 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001093 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001094 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +00001095 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +00001096
Josh Bailey26e2ae32012-03-22 01:09:21 -07001097 netlink_interface_update_hw_addr (tb, ifp);
1098
paul7021c422003-07-15 12:52:22 +00001099 /* If new link is added. */
1100 if_add_update (ifp);
1101 }
paul718e3742002-12-13 20:15:29 +00001102 else
paul7021c422003-07-15 12:52:22 +00001103 {
1104 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001105 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001106 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
Brett Cipherydb19c852013-10-03 13:48:54 +00001107 ifp->metric = 0;
paul718e3742002-12-13 20:15:29 +00001108
Josh Bailey26e2ae32012-03-22 01:09:21 -07001109 netlink_interface_update_hw_addr (tb, ifp);
1110
paul7021c422003-07-15 12:52:22 +00001111 if (if_is_operative (ifp))
1112 {
1113 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1114 if (!if_is_operative (ifp))
1115 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001116 else
1117 /* Must notify client daemons of new interface status. */
1118 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001119 }
1120 else
1121 {
1122 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1123 if (if_is_operative (ifp))
1124 if_up (ifp);
1125 }
1126 }
paul718e3742002-12-13 20:15:29 +00001127 }
1128 else
1129 {
1130 /* RTM_DELLINK. */
1131 ifp = if_lookup_by_name (name);
1132
1133 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001134 {
1135 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001136 name);
paul7021c422003-07-15 12:52:22 +00001137 return 0;
1138 }
1139
paul718e3742002-12-13 20:15:29 +00001140 if_delete_update (ifp);
1141 }
1142
1143 return 0;
1144}
1145
Stephen Hemminger6072b242008-08-14 16:52:26 +01001146static int
paul718e3742002-12-13 20:15:29 +00001147netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1148{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001149 /* JF: Ignore messages that aren't from the kernel */
1150 if ( snl->nl_pid != 0 )
1151 {
1152 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1153 return 0;
1154 }
1155
paul718e3742002-12-13 20:15:29 +00001156 switch (h->nlmsg_type)
1157 {
1158 case RTM_NEWROUTE:
1159 return netlink_route_change (snl, h);
1160 break;
1161 case RTM_DELROUTE:
1162 return netlink_route_change (snl, h);
1163 break;
1164 case RTM_NEWLINK:
1165 return netlink_link_change (snl, h);
1166 break;
1167 case RTM_DELLINK:
1168 return netlink_link_change (snl, h);
1169 break;
1170 case RTM_NEWADDR:
1171 return netlink_interface_addr (snl, h);
1172 break;
1173 case RTM_DELADDR:
1174 return netlink_interface_addr (snl, h);
1175 break;
1176 default:
1177 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1178 break;
1179 }
1180 return 0;
1181}
1182
1183/* Interface lookup by netlink socket. */
1184int
paul6621ca82005-11-23 13:02:08 +00001185interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001186{
1187 int ret;
paul7021c422003-07-15 12:52:22 +00001188
paul718e3742002-12-13 20:15:29 +00001189 /* Get interface information. */
1190 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1191 if (ret < 0)
1192 return ret;
1193 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1194 if (ret < 0)
1195 return ret;
1196
1197 /* Get IPv4 address of the interfaces. */
1198 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1199 if (ret < 0)
1200 return ret;
1201 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1202 if (ret < 0)
1203 return ret;
1204
1205#ifdef HAVE_IPV6
1206 /* Get IPv6 address of the interfaces. */
1207 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1208 if (ret < 0)
1209 return ret;
1210 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1211 if (ret < 0)
1212 return ret;
1213#endif /* HAVE_IPV6 */
1214
1215 return 0;
1216}
1217
1218/* Routing table read function using netlink interface. Only called
1219 bootstrap time. */
1220int
paul6621ca82005-11-23 13:02:08 +00001221netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001222{
1223 int ret;
paul7021c422003-07-15 12:52:22 +00001224
paul718e3742002-12-13 20:15:29 +00001225 /* Get IPv4 routing table. */
1226 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1227 if (ret < 0)
1228 return ret;
1229 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1230 if (ret < 0)
1231 return ret;
1232
1233#ifdef HAVE_IPV6
1234 /* Get IPv6 routing table. */
1235 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1236 if (ret < 0)
1237 return ret;
1238 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1239 if (ret < 0)
1240 return ret;
1241#endif /* HAVE_IPV6 */
1242
1243 return 0;
1244}
1245
1246/* Utility function comes from iproute2.
1247 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001248int
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001249addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen)
paul718e3742002-12-13 20:15:29 +00001250{
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001251 size_t len;
paul718e3742002-12-13 20:15:29 +00001252 struct rtattr *rta;
1253
paul7021c422003-07-15 12:52:22 +00001254 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001255
paul7021c422003-07-15 12:52:22 +00001256 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001257 return -1;
1258
paul7021c422003-07-15 12:52:22 +00001259 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001260 rta->rta_type = type;
1261 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001262 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001263 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1264
1265 return 0;
1266}
1267
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001268int
paul718e3742002-12-13 20:15:29 +00001269rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1270{
1271 int len;
1272 struct rtattr *subrta;
1273
paul7021c422003-07-15 12:52:22 +00001274 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001275
paul7021c422003-07-15 12:52:22 +00001276 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001277 return -1;
1278
paul7021c422003-07-15 12:52:22 +00001279 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001280 subrta->rta_type = type;
1281 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001282 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001283 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1284
1285 return 0;
1286}
1287
1288/* Utility function comes from iproute2.
1289 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001290int
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001291addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data)
paul718e3742002-12-13 20:15:29 +00001292{
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001293 size_t len;
paul718e3742002-12-13 20:15:29 +00001294 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001295
1296 len = RTA_LENGTH (4);
1297
paul718e3742002-12-13 20:15:29 +00001298 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1299 return -1;
1300
paul7021c422003-07-15 12:52:22 +00001301 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001302 rta->rta_type = type;
1303 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001304 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001305 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1306
1307 return 0;
1308}
1309
1310static int
1311netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1312{
hassob7ed1ec2005-03-31 20:13:49 +00001313 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001314 return 0;
1315}
1316
1317/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001318static int
paul718e3742002-12-13 20:15:29 +00001319netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1320{
1321 int status;
1322 struct sockaddr_nl snl;
Timo Teräsc299ed72014-07-29 09:41:55 +00001323 struct iovec iov = {
1324 .iov_base = (void *) n,
1325 .iov_len = n->nlmsg_len
1326 };
1327 struct msghdr msg = {
1328 .msg_name = (void *) &snl,
1329 .msg_namelen = sizeof snl,
1330 .msg_iov = &iov,
1331 .msg_iovlen = 1,
1332 };
ajs4be019d2005-01-29 16:12:41 +00001333 int save_errno;
paul7021c422003-07-15 12:52:22 +00001334
paul718e3742002-12-13 20:15:29 +00001335 memset (&snl, 0, sizeof snl);
1336 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001337
hassob7ed1ec2005-03-31 20:13:49 +00001338 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001339
1340 /* Request an acknowledgement by setting NLM_F_ACK */
1341 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001342
1343 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001344 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001345 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1346 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001347
1348 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001349 if (zserv_privs.change (ZPRIVS_RAISE))
1350 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001351 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001352 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001353 if (zserv_privs.change (ZPRIVS_LOWER))
1354 zlog (NULL, LOG_ERR, "Can't lower privileges");
1355
paul718e3742002-12-13 20:15:29 +00001356 if (status < 0)
1357 {
1358 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001359 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001360 return -1;
1361 }
paul7021c422003-07-15 12:52:22 +00001362
paul718e3742002-12-13 20:15:29 +00001363
1364 /*
1365 * Get reply from netlink socket.
1366 * The reply should either be an acknowlegement or an error.
1367 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001368 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001369}
1370
1371/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001372static int
paul718e3742002-12-13 20:15:29 +00001373netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001374 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001375{
1376 int ret;
1377 int bytelen;
1378 struct sockaddr_nl snl;
1379 int discard;
1380
paul7021c422003-07-15 12:52:22 +00001381 struct
paul718e3742002-12-13 20:15:29 +00001382 {
1383 struct nlmsghdr n;
1384 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001385 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001386 } req;
1387
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001388 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001389
1390 bytelen = (family == AF_INET ? 4 : 16);
1391
1392 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1393 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1394 req.n.nlmsg_type = cmd;
1395 req.r.rtm_family = family;
1396 req.r.rtm_table = table;
1397 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001398 req.r.rtm_protocol = RTPROT_ZEBRA;
1399 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001400
hasso81dfcaa2003-05-25 19:21:25 +00001401 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1402 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001403 discard = 1;
1404 else
1405 discard = 0;
1406
paul7021c422003-07-15 12:52:22 +00001407 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001408 {
paul7021c422003-07-15 12:52:22 +00001409 if (discard)
paul595db7f2003-05-25 21:35:06 +00001410 {
1411 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1412 req.r.rtm_type = RTN_BLACKHOLE;
1413 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1414 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001415 else
1416 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1417 }
paul595db7f2003-05-25 21:35:06 +00001418 else
paul7021c422003-07-15 12:52:22 +00001419 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001420 }
1421
1422 if (dest)
1423 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1424
paul7021c422003-07-15 12:52:22 +00001425 if (!discard)
paul718e3742002-12-13 20:15:29 +00001426 {
1427 if (gate)
paul7021c422003-07-15 12:52:22 +00001428 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001429 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001430 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001431 }
1432
1433 /* Destination netlink address. */
1434 memset (&snl, 0, sizeof snl);
1435 snl.nl_family = AF_NETLINK;
1436
1437 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001438 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001439 if (ret < 0)
1440 return -1;
1441
1442 return 0;
1443}
1444
Christian Frankefa713d92013-07-05 15:35:37 +00001445/* This function takes a nexthop as argument and adds
1446 * the appropriate netlink attributes to an existing
1447 * netlink message.
1448 *
1449 * @param routedesc: Human readable description of route type
1450 * (direct/recursive, single-/multipath)
1451 * @param bytelen: Length of addresses in bytes.
1452 * @param nexthop: Nexthop information
1453 * @param nlmsg: nlmsghdr structure to fill in.
1454 * @param req_size: The size allocated for the message.
1455 */
1456static void
1457_netlink_route_build_singlepath(
1458 const char *routedesc,
1459 int bytelen,
1460 struct nexthop *nexthop,
1461 struct nlmsghdr *nlmsg,
Christian Frankee8d3d292013-07-05 15:35:39 +00001462 struct rtmsg *rtmsg,
Christian Frankefa713d92013-07-05 15:35:37 +00001463 size_t req_size)
1464{
Christian Frankee8d3d292013-07-05 15:35:39 +00001465 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1466 rtmsg->rtm_flags |= RTNH_F_ONLINK;
Christian Frankefa713d92013-07-05 15:35:37 +00001467 if (nexthop->type == NEXTHOP_TYPE_IPV4
1468 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1469 {
1470 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1471 &nexthop->gate.ipv4, bytelen);
1472 if (nexthop->src.ipv4.s_addr)
1473 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1474 &nexthop->src.ipv4, bytelen);
1475
1476 if (IS_ZEBRA_DEBUG_KERNEL)
1477 zlog_debug("netlink_route_multipath() (%s): "
1478 "nexthop via %s if %u",
1479 routedesc,
1480 inet_ntoa (nexthop->gate.ipv4),
1481 nexthop->ifindex);
1482 }
1483#ifdef HAVE_IPV6
1484 if (nexthop->type == NEXTHOP_TYPE_IPV6
1485 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1486 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1487 {
1488 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1489 &nexthop->gate.ipv6, bytelen);
1490
1491 if (IS_ZEBRA_DEBUG_KERNEL)
1492 zlog_debug("netlink_route_multipath() (%s): "
1493 "nexthop via %s if %u",
1494 routedesc,
1495 inet6_ntoa (nexthop->gate.ipv6),
1496 nexthop->ifindex);
1497 }
1498#endif /* HAVE_IPV6 */
1499 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1500 || nexthop->type == NEXTHOP_TYPE_IFNAME
1501 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1502 {
1503 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1504
1505 if (nexthop->src.ipv4.s_addr)
1506 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1507 &nexthop->src.ipv4, bytelen);
1508
1509 if (IS_ZEBRA_DEBUG_KERNEL)
1510 zlog_debug("netlink_route_multipath() (%s): "
1511 "nexthop via if %u", routedesc, nexthop->ifindex);
1512 }
1513
1514 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1515 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1516 {
1517 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1518
1519 if (IS_ZEBRA_DEBUG_KERNEL)
1520 zlog_debug("netlink_route_multipath() (%s): "
1521 "nexthop via if %u", routedesc, nexthop->ifindex);
1522 }
1523}
1524
1525/* This function takes a nexthop as argument and
1526 * appends to the given rtattr/rtnexthop pair the
1527 * representation of the nexthop. If the nexthop
1528 * defines a preferred source, the src parameter
1529 * will be modified to point to that src, otherwise
1530 * it will be kept unmodified.
1531 *
1532 * @param routedesc: Human readable description of route type
1533 * (direct/recursive, single-/multipath)
1534 * @param bytelen: Length of addresses in bytes.
1535 * @param nexthop: Nexthop information
1536 * @param rta: rtnetlink attribute structure
1537 * @param rtnh: pointer to an rtnetlink nexthop structure
1538 * @param src: pointer pointing to a location where
1539 * the prefsrc should be stored.
1540 */
1541static void
1542_netlink_route_build_multipath(
1543 const char *routedesc,
1544 int bytelen,
1545 struct nexthop *nexthop,
1546 struct rtattr *rta,
1547 struct rtnexthop *rtnh,
1548 union g_addr **src
1549 )
1550{
1551 rtnh->rtnh_len = sizeof (*rtnh);
1552 rtnh->rtnh_flags = 0;
1553 rtnh->rtnh_hops = 0;
1554 rta->rta_len += rtnh->rtnh_len;
1555
Christian Frankee8d3d292013-07-05 15:35:39 +00001556 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1557 rtnh->rtnh_flags |= RTNH_F_ONLINK;
1558
Christian Frankefa713d92013-07-05 15:35:37 +00001559 if (nexthop->type == NEXTHOP_TYPE_IPV4
1560 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1561 {
1562 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1563 &nexthop->gate.ipv4, bytelen);
Lu Feng621e2aa2014-07-11 07:52:15 +00001564 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
Christian Frankefa713d92013-07-05 15:35:37 +00001565
1566 if (nexthop->src.ipv4.s_addr)
1567 *src = &nexthop->src;
1568
1569 if (IS_ZEBRA_DEBUG_KERNEL)
1570 zlog_debug("netlink_route_multipath() (%s): "
1571 "nexthop via %s if %u",
1572 routedesc,
1573 inet_ntoa (nexthop->gate.ipv4),
1574 nexthop->ifindex);
1575 }
1576#ifdef HAVE_IPV6
1577 if (nexthop->type == NEXTHOP_TYPE_IPV6
1578 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1579 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1580 {
1581 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1582 &nexthop->gate.ipv6, bytelen);
Lu Feng621e2aa2014-07-11 07:52:15 +00001583 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
Christian Frankefa713d92013-07-05 15:35:37 +00001584
1585 if (IS_ZEBRA_DEBUG_KERNEL)
1586 zlog_debug("netlink_route_multipath() (%s): "
1587 "nexthop via %s if %u",
1588 routedesc,
1589 inet6_ntoa (nexthop->gate.ipv6),
1590 nexthop->ifindex);
1591 }
1592#endif /* HAVE_IPV6 */
1593 /* ifindex */
1594 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1595 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1596 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1597 {
1598 rtnh->rtnh_ifindex = nexthop->ifindex;
1599 if (nexthop->src.ipv4.s_addr)
1600 *src = &nexthop->src;
1601 if (IS_ZEBRA_DEBUG_KERNEL)
1602 zlog_debug("netlink_route_multipath() (%s): "
1603 "nexthop via if %u", routedesc, nexthop->ifindex);
1604 }
1605 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1606 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1607 {
1608 rtnh->rtnh_ifindex = nexthop->ifindex;
1609
1610 if (IS_ZEBRA_DEBUG_KERNEL)
1611 zlog_debug("netlink_route_multipath() (%s): "
1612 "nexthop via if %u", routedesc, nexthop->ifindex);
1613 }
1614 else
1615 {
1616 rtnh->rtnh_ifindex = 0;
1617 }
1618}
1619
1620/* Log debug information for netlink_route_multipath
1621 * if debug logging is enabled.
1622 *
1623 * @param cmd: Netlink command which is to be processed
1624 * @param p: Prefix for which the change is due
1625 * @param nexthop: Nexthop which is currently processed
1626 * @param routedesc: Semantic annotation for nexthop
1627 * (recursive, multipath, etc.)
1628 * @param family: Address family which the change concerns
1629 */
1630static void
1631_netlink_route_debug(
1632 int cmd,
1633 struct prefix *p,
1634 struct nexthop *nexthop,
1635 const char *routedesc,
1636 int family)
1637{
1638 if (IS_ZEBRA_DEBUG_KERNEL)
1639 {
1640 zlog_debug ("netlink_route_multipath() (%s): %s %s/%d type %s",
1641 routedesc,
1642 lookup (nlmsg_str, cmd),
1643#ifdef HAVE_IPV6
1644 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1645 inet6_ntoa (p->u.prefix6),
1646#else
1647 inet_ntoa (p->u.prefix4),
1648#endif /* HAVE_IPV6 */
1649 p->prefixlen, nexthop_type_to_str (nexthop->type));
1650 }
1651}
1652
paul718e3742002-12-13 20:15:29 +00001653/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001654static int
paul718e3742002-12-13 20:15:29 +00001655netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001656 int family)
paul718e3742002-12-13 20:15:29 +00001657{
1658 int bytelen;
1659 struct sockaddr_nl snl;
Christian Frankefa713d92013-07-05 15:35:37 +00001660 struct nexthop *nexthop = NULL, *tnexthop;
1661 int recursing;
1662 int nexthop_num;
paul718e3742002-12-13 20:15:29 +00001663 int discard;
Christian Frankefa713d92013-07-05 15:35:37 +00001664 const char *routedesc;
paul718e3742002-12-13 20:15:29 +00001665
paul7021c422003-07-15 12:52:22 +00001666 struct
paul718e3742002-12-13 20:15:29 +00001667 {
1668 struct nlmsghdr n;
1669 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001670 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001671 } req;
1672
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001673 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001674
1675 bytelen = (family == AF_INET ? 4 : 16);
1676
1677 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1678 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1679 req.n.nlmsg_type = cmd;
1680 req.r.rtm_family = family;
1681 req.r.rtm_table = rib->table;
1682 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001683 req.r.rtm_protocol = RTPROT_ZEBRA;
1684 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001685
paul7021c422003-07-15 12:52:22 +00001686 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001687 discard = 1;
1688 else
1689 discard = 0;
1690
paul7021c422003-07-15 12:52:22 +00001691 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001692 {
paul7021c422003-07-15 12:52:22 +00001693 if (discard)
paul595db7f2003-05-25 21:35:06 +00001694 {
1695 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1696 req.r.rtm_type = RTN_BLACKHOLE;
1697 else if (rib->flags & ZEBRA_FLAG_REJECT)
1698 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001699 else
1700 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1701 }
paul595db7f2003-05-25 21:35:06 +00001702 else
paul7021c422003-07-15 12:52:22 +00001703 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001704 }
1705
1706 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1707
1708 /* Metric. */
1709 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1710
1711 if (discard)
1712 {
1713 if (cmd == RTM_NEWROUTE)
Christian Frankefa713d92013-07-05 15:35:37 +00001714 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1715 {
1716 /* We shouldn't encounter recursive nexthops on discard routes,
1717 * but it is probably better to handle that case correctly anyway.
1718 */
1719 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1720 continue;
1721 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1722 }
paul718e3742002-12-13 20:15:29 +00001723 goto skip;
1724 }
1725
Christian Frankefa713d92013-07-05 15:35:37 +00001726 /* Count overall nexthops so we can decide whether to use singlepath
1727 * or multipath case. */
1728 nexthop_num = 0;
1729 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul718e3742002-12-13 20:15:29 +00001730 {
Christian Frankefa713d92013-07-05 15:35:37 +00001731 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1732 continue;
1733 if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1734 continue;
1735 if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
1736 continue;
1737
1738 nexthop_num++;
1739 }
1740
1741 /* Singlepath case. */
1742 if (nexthop_num == 1 || MULTIPATH_NUM == 1)
1743 {
1744 nexthop_num = 0;
1745 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001746 {
Christian Frankefa713d92013-07-05 15:35:37 +00001747 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1748 continue;
paul5ec90d22003-06-19 01:41:37 +00001749
paul7021c422003-07-15 12:52:22 +00001750 if ((cmd == RTM_NEWROUTE
1751 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1752 || (cmd == RTM_DELROUTE
1753 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1754 {
Christian Frankefa713d92013-07-05 15:35:37 +00001755 routedesc = recursing ? "recursive, 1 hop" : "single hop";
paul5ec90d22003-06-19 01:41:37 +00001756
Christian Frankefa713d92013-07-05 15:35:37 +00001757 _netlink_route_debug(cmd, p, nexthop, routedesc, family);
1758 _netlink_route_build_singlepath(routedesc, bytelen,
Christian Frankee8d3d292013-07-05 15:35:39 +00001759 nexthop, &req.n, &req.r,
1760 sizeof req);
paul718e3742002-12-13 20:15:29 +00001761
paul7021c422003-07-15 12:52:22 +00001762 if (cmd == RTM_NEWROUTE)
1763 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001764
paul7021c422003-07-15 12:52:22 +00001765 nexthop_num++;
1766 break;
1767 }
1768 }
paul718e3742002-12-13 20:15:29 +00001769 }
1770 else
1771 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001772 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001773 struct rtattr *rta = (void *) buf;
1774 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001775 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001776
1777 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001778 rta->rta_len = RTA_LENGTH (0);
1779 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001780
1781 nexthop_num = 0;
Christian Frankefa713d92013-07-05 15:35:37 +00001782 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001783 {
Christian Frankefa713d92013-07-05 15:35:37 +00001784 if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
1785 break;
1786
1787 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1788 continue;
1789
paul7021c422003-07-15 12:52:22 +00001790 if ((cmd == RTM_NEWROUTE
1791 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1792 || (cmd == RTM_DELROUTE
1793 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1794 {
Christian Frankefa713d92013-07-05 15:35:37 +00001795 routedesc = recursing ? "recursive, multihop" : "multihop";
paul7021c422003-07-15 12:52:22 +00001796 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001797
Christian Frankefa713d92013-07-05 15:35:37 +00001798 _netlink_route_debug(cmd, p, nexthop,
1799 routedesc, family);
1800 _netlink_route_build_multipath(routedesc, bytelen,
1801 nexthop, rta, rtnh, &src);
paul7021c422003-07-15 12:52:22 +00001802 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001803
paul7021c422003-07-15 12:52:22 +00001804 if (cmd == RTM_NEWROUTE)
1805 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1806 }
1807 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001808 if (src)
1809 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001810
1811 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001812 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001813 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001814 }
1815
1816 /* If there is no useful nexthop then return. */
1817 if (nexthop_num == 0)
1818 {
1819 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001820 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001821 return 0;
1822 }
1823
paul7021c422003-07-15 12:52:22 +00001824skip:
paul718e3742002-12-13 20:15:29 +00001825
1826 /* Destination netlink address. */
1827 memset (&snl, 0, sizeof snl);
1828 snl.nl_family = AF_NETLINK;
1829
paul718e3742002-12-13 20:15:29 +00001830 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001831 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001832}
1833
1834int
1835kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1836{
1837 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1838}
1839
1840int
1841kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1842{
1843 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1844}
1845
1846#ifdef HAVE_IPV6
1847int
1848kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1849{
1850 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1851}
1852
1853int
1854kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1855{
1856 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1857}
1858
1859/* Delete IPv6 route from the kernel. */
1860int
1861kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001862 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001863{
paul7021c422003-07-15 12:52:22 +00001864 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1865 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001866}
1867#endif /* HAVE_IPV6 */
David Lamparter6b0655a2014-06-04 06:53:35 +02001868
paul718e3742002-12-13 20:15:29 +00001869/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001870static int
paul718e3742002-12-13 20:15:29 +00001871netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001872 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001873{
1874 int bytelen;
1875 struct prefix *p;
1876
paul7021c422003-07-15 12:52:22 +00001877 struct
paul718e3742002-12-13 20:15:29 +00001878 {
1879 struct nlmsghdr n;
1880 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001881 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001882 } req;
1883
1884 p = ifc->address;
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001885 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001886
1887 bytelen = (family == AF_INET ? 4 : 16);
1888
paul7021c422003-07-15 12:52:22 +00001889 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001890 req.n.nlmsg_flags = NLM_F_REQUEST;
1891 req.n.nlmsg_type = cmd;
1892 req.ifa.ifa_family = family;
1893
1894 req.ifa.ifa_index = ifp->ifindex;
1895 req.ifa.ifa_prefixlen = p->prefixlen;
1896
1897 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1898
1899 if (family == AF_INET && cmd == RTM_NEWADDR)
1900 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001901 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001902 {
1903 p = ifc->destination;
1904 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1905 bytelen);
1906 }
paul718e3742002-12-13 20:15:29 +00001907 }
1908
1909 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1910 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001911
paul718e3742002-12-13 20:15:29 +00001912 if (ifc->label)
1913 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001914 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001915
1916 return netlink_talk (&req.n, &netlink_cmd);
1917}
1918
1919int
1920kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1921{
1922 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1923}
1924
1925int
1926kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1927{
1928 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1929}
1930
paul718e3742002-12-13 20:15:29 +00001931
1932extern struct thread_master *master;
1933
1934/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001935static int
paul718e3742002-12-13 20:15:29 +00001936kernel_read (struct thread *thread)
1937{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001938 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001939 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001940
1941 return 0;
1942}
1943
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001944/* Filter out messages from self that occur on listener socket,
1945 caused by our actions on the command socket
1946 */
1947static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001948{
Paul Jakma768a27e2008-05-29 18:23:08 +00001949 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001950 /* 0: ldh [4] */
1951 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1952 /* 1: jeq 0x18 jt 3 jf 6 */
1953 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1954 /* 2: jeq 0x19 jt 3 jf 6 */
1955 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1956 /* 3: ldw [12] */
1957 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1958 /* 4: jeq XX jt 5 jf 6 */
1959 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1960 /* 5: ret 0 (skip) */
1961 BPF_STMT(BPF_RET|BPF_K, 0),
1962 /* 6: ret 0xffff (keep) */
1963 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001964 };
1965
1966 struct sock_fprog prog = {
Balaji.G837d16c2012-09-26 14:09:10 +05301967 .len = array_size(filter),
Paul Jakma768a27e2008-05-29 18:23:08 +00001968 .filter = filter,
1969 };
1970
1971 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1972 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1973}
1974
paul718e3742002-12-13 20:15:29 +00001975/* Exported interface function. This function simply calls
1976 netlink_socket (). */
1977void
paul6621ca82005-11-23 13:02:08 +00001978kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001979{
1980 unsigned long groups;
1981
paul7021c422003-07-15 12:52:22 +00001982 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001983#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001984 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001985#endif /* HAVE_IPV6 */
1986 netlink_socket (&netlink, groups);
1987 netlink_socket (&netlink_cmd, 0);
1988
1989 /* Register kernel socket. */
1990 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001991 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001992 /* Only want non-blocking on the netlink event socket */
1993 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1994 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1995 safe_strerror (errno));
1996
Stephen Hemminger30afea32008-08-16 18:25:47 +01001997 /* Set receive buffer size if it's set from command line */
1998 if (nl_rcvbufsize)
1999 netlink_recvbuf (&netlink, nl_rcvbufsize);
2000
Stephen Hemminger3d265b42008-08-16 17:30:39 +01002001 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00002002 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
2003 }
paul718e3742002-12-13 20:15:29 +00002004}
Avneesh Sachdev78deec42012-11-13 22:48:56 +00002005
2006/*
2007 * nl_msg_type_to_str
2008 */
2009const char *
2010nl_msg_type_to_str (uint16_t msg_type)
2011{
2012 return lookup (nlmsg_str, msg_type);
2013}
2014
2015/*
2016 * nl_rtproto_to_str
2017 */
2018const char *
2019nl_rtproto_to_str (u_char rtproto)
2020{
2021 return lookup (rtproto_str, rtproto);
2022}