blob: 7a820bfd1413343d055d32a2ef67cac330391236 [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
165 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
166 if (sock < 0)
167 {
168 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000169 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000170 return -1;
171 }
172
paul718e3742002-12-13 20:15:29 +0000173 memset (&snl, 0, sizeof snl);
174 snl.nl_family = AF_NETLINK;
175 snl.nl_groups = groups;
176
177 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000178 if (zserv_privs.change (ZPRIVS_RAISE))
179 {
180 zlog (NULL, LOG_ERR, "Can't raise privileges");
181 return -1;
182 }
pauledd7c242003-06-04 13:59:38 +0000183
paul718e3742002-12-13 20:15:29 +0000184 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];
paul718e3742002-12-13 20:15:29 +0000285 struct iovec iov = { buf, sizeof buf };
286 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000287 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000288 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000289
paul718e3742002-12-13 20:15:29 +0000290 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000291 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000292 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100293 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000294 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100295 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000296 break;
ajs4be019d2005-01-29 16:12:41 +0000297 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100298 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000299 continue;
300 }
paul718e3742002-12-13 20:15:29 +0000301
302 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000303 {
304 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
305 return -1;
306 }
paul718e3742002-12-13 20:15:29 +0000307
308 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000309 {
310 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
311 nl->name, msg.msg_namelen);
312 return -1;
313 }
paulb84d3a12003-11-17 10:31:01 +0000314
hasso206d8052005-04-09 16:38:51 +0000315 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000316 h = NLMSG_NEXT (h, status))
317 {
318 /* Finish of reading. */
319 if (h->nlmsg_type == NLMSG_DONE)
320 return ret;
paul718e3742002-12-13 20:15:29 +0000321
paul7021c422003-07-15 12:52:22 +0000322 /* Error handling. */
323 if (h->nlmsg_type == NLMSG_ERROR)
324 {
325 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100326 int errnum = err->error;
327 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000328
paul718e3742002-12-13 20:15:29 +0000329 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000330 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000331 {
paul7021c422003-07-15 12:52:22 +0000332 if (IS_ZEBRA_DEBUG_KERNEL)
333 {
hasso1ada8192005-06-12 11:28:18 +0000334 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000335 __FUNCTION__, nl->name,
336 lookup (nlmsg_str, err->msg.nlmsg_type),
337 err->msg.nlmsg_type, err->msg.nlmsg_seq,
338 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000339 }
paul7021c422003-07-15 12:52:22 +0000340
341 /* return if not a multipart message, otherwise continue */
342 if (!(h->nlmsg_flags & NLM_F_MULTI))
343 {
344 return 0;
paul718e3742002-12-13 20:15:29 +0000345 }
paul7021c422003-07-15 12:52:22 +0000346 continue;
paul718e3742002-12-13 20:15:29 +0000347 }
paul7021c422003-07-15 12:52:22 +0000348
paul718e3742002-12-13 20:15:29 +0000349 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000350 {
351 zlog (NULL, LOG_ERR, "%s error: message truncated",
352 nl->name);
353 return -1;
354 }
pauld753e9e2003-01-22 19:45:50 +0000355
Stephen Hemminger898987e2008-08-17 16:56:15 +0100356 /* Deal with errors that occur because of races in link handling */
357 if (nl == &netlink_cmd
358 && ((msg_type == RTM_DELROUTE &&
359 (-errnum == ENODEV || -errnum == ESRCH))
360 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
361 {
362 if (IS_ZEBRA_DEBUG_KERNEL)
363 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
364 nl->name, safe_strerror (-errnum),
365 lookup (nlmsg_str, msg_type),
366 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
367 return 0;
368 }
paul718e3742002-12-13 20:15:29 +0000369
Stephen Hemminger898987e2008-08-17 16:56:15 +0100370 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
371 nl->name, safe_strerror (-errnum),
372 lookup (nlmsg_str, msg_type),
373 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000374 return -1;
375 }
paul718e3742002-12-13 20:15:29 +0000376
paul7021c422003-07-15 12:52:22 +0000377 /* OK we got netlink message. */
378 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000379 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000380 nl->name,
381 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
382 h->nlmsg_seq, h->nlmsg_pid);
383
Christian Franke599da952013-01-24 14:04:43 +0000384 /* skip unsolicited messages originating from command socket
385 * linux sets the originators port-id for {NEW|DEL}ADDR messages,
386 * so this has to be checked here. */
387 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid
388 && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
paul7021c422003-07-15 12:52:22 +0000389 {
390 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000391 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000392 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000393 continue;
394 }
395
396 error = (*filter) (&snl, h);
397 if (error < 0)
398 {
399 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
400 ret = error;
401 }
402 }
paul718e3742002-12-13 20:15:29 +0000403
404 /* After error care. */
405 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000406 {
407 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
408 continue;
409 }
paul718e3742002-12-13 20:15:29 +0000410 if (status)
paul7021c422003-07-15 12:52:22 +0000411 {
412 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
413 status);
414 return -1;
415 }
paul718e3742002-12-13 20:15:29 +0000416 }
417 return ret;
418}
419
420/* Utility function for parse rtattr. */
421static void
paul7021c422003-07-15 12:52:22 +0000422netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
423 int len)
paul718e3742002-12-13 20:15:29 +0000424{
paul7021c422003-07-15 12:52:22 +0000425 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000426 {
427 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000428 tb[rta->rta_type] = rta;
429 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000430 }
431}
432
Josh Bailey26e2ae32012-03-22 01:09:21 -0700433/* Utility function to parse hardware link-layer address and update ifp */
434static void
435netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
436{
437 int i;
438
439 if (tb[IFLA_ADDRESS])
440 {
441 int hw_addr_len;
442
443 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
444
445 if (hw_addr_len > INTERFACE_HWADDR_MAX)
446 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
447 else
448 {
449 ifp->hw_addr_len = hw_addr_len;
450 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
451
452 for (i = 0; i < hw_addr_len; i++)
453 if (ifp->hw_addr[i] != 0)
454 break;
455
456 if (i == hw_addr_len)
457 ifp->hw_addr_len = 0;
458 else
459 ifp->hw_addr_len = hw_addr_len;
460 }
461 }
462}
463
paul718e3742002-12-13 20:15:29 +0000464/* Called from interface_lookup_netlink(). This function is only used
465 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100466static int
paul718e3742002-12-13 20:15:29 +0000467netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
468{
469 int len;
470 struct ifinfomsg *ifi;
471 struct rtattr *tb[IFLA_MAX + 1];
472 struct interface *ifp;
473 char *name;
paul718e3742002-12-13 20:15:29 +0000474
475 ifi = NLMSG_DATA (h);
476
477 if (h->nlmsg_type != RTM_NEWLINK)
478 return 0;
479
480 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
481 if (len < 0)
482 return -1;
483
484 /* Looking up interface name. */
485 memset (tb, 0, sizeof tb);
486 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000487
paul1e193152005-02-14 23:53:05 +0000488#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000489 /* check for wireless messages to ignore */
490 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
491 {
492 if (IS_ZEBRA_DEBUG_KERNEL)
493 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
494 return 0;
495 }
paul1e193152005-02-14 23:53:05 +0000496#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000497
paul718e3742002-12-13 20:15:29 +0000498 if (tb[IFLA_IFNAME] == NULL)
499 return -1;
paul7021c422003-07-15 12:52:22 +0000500 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000501
502 /* Add interface. */
503 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000504 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000505 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800506 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000507 ifp->metric = 1;
508
509 /* Hardware type and address. */
510 ifp->hw_type = ifi->ifi_type;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700511 netlink_interface_update_hw_addr (tb, ifp);
paul718e3742002-12-13 20:15:29 +0000512
513 if_add_update (ifp);
514
515 return 0;
516}
517
518/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100519static int
paul718e3742002-12-13 20:15:29 +0000520netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
521{
522 int len;
523 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000524 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000525 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000526 void *addr;
527 void *broad;
paul718e3742002-12-13 20:15:29 +0000528 u_char flags = 0;
529 char *label = NULL;
530
531 ifa = NLMSG_DATA (h);
532
paul7021c422003-07-15 12:52:22 +0000533 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000534#ifdef HAVE_IPV6
535 && ifa->ifa_family != AF_INET6
536#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000537 )
paul718e3742002-12-13 20:15:29 +0000538 return 0;
539
540 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
541 return 0;
542
paul7021c422003-07-15 12:52:22 +0000543 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000544 if (len < 0)
545 return -1;
546
547 memset (tb, 0, sizeof tb);
548 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
549
550 ifp = if_lookup_by_index (ifa->ifa_index);
551 if (ifp == NULL)
552 {
553 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000554 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000555 return -1;
556 }
557
paul7021c422003-07-15 12:52:22 +0000558 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000559 {
paul00df0c12002-12-13 21:07:36 +0000560 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000561 zlog_debug ("netlink_interface_addr %s %s:",
562 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000563 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000564 zlog_debug (" IFA_LOCAL %s/%d",
565 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
566 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000567 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000568 zlog_debug (" IFA_ADDRESS %s/%d",
569 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
570 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000571 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000572 zlog_debug (" IFA_BROADCAST %s/%d",
573 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
574 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000575 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000576 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000577
578 if (tb[IFA_CACHEINFO])
579 {
580 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
581 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
582 ci->ifa_prefered, ci->ifa_valid);
583 }
paul718e3742002-12-13 20:15:29 +0000584 }
paul31a476c2003-09-29 19:54:53 +0000585
Andrew J. Schorre4529632006-12-12 19:18:21 +0000586 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
587 if (tb[IFA_LOCAL] == NULL)
588 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000589 if (tb[IFA_ADDRESS] == NULL)
590 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
591
Andrew J. Schorre4529632006-12-12 19:18:21 +0000592 /* local interface address */
593 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
594
595 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000596 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000597 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000598 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000599 broad = RTA_DATA(tb[IFA_ADDRESS]);
600 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000601 }
paul31a476c2003-09-29 19:54:53 +0000602 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000603 /* seeking a broadcast address */
604 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000605
Paul Jakma27b47252006-07-02 16:38:54 +0000606 /* addr is primary key, SOL if we don't have one */
607 if (addr == NULL)
608 {
609 zlog_debug ("%s: NULL address", __func__);
610 return -1;
611 }
612
paul718e3742002-12-13 20:15:29 +0000613 /* Flags. */
614 if (ifa->ifa_flags & IFA_F_SECONDARY)
615 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
616
617 /* Label */
618 if (tb[IFA_LABEL])
619 label = (char *) RTA_DATA (tb[IFA_LABEL]);
620
621 if (ifp && label && strcmp (ifp->name, label) == 0)
622 label = NULL;
623
624 /* Register interface address to the interface. */
625 if (ifa->ifa_family == AF_INET)
626 {
paul7021c422003-07-15 12:52:22 +0000627 if (h->nlmsg_type == RTM_NEWADDR)
628 connected_add_ipv4 (ifp, flags,
629 (struct in_addr *) addr, ifa->ifa_prefixlen,
630 (struct in_addr *) broad, label);
631 else
632 connected_delete_ipv4 (ifp, flags,
633 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000634 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000635 }
636#ifdef HAVE_IPV6
637 if (ifa->ifa_family == AF_INET6)
638 {
639 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000640 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000641 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000642 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000643 else
paul7021c422003-07-15 12:52:22 +0000644 connected_delete_ipv6 (ifp,
645 (struct in6_addr *) addr, ifa->ifa_prefixlen,
646 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000647 }
paul7021c422003-07-15 12:52:22 +0000648#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000649
650 return 0;
651}
652
653/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100654static int
paul718e3742002-12-13 20:15:29 +0000655netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
656{
657 int len;
658 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000659 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000660 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000661
662 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000663
664 int index;
665 int table;
hasso34195bf2004-04-06 12:07:06 +0000666 int metric;
667
paul718e3742002-12-13 20:15:29 +0000668 void *dest;
669 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000670 void *src;
paul718e3742002-12-13 20:15:29 +0000671
672 rtm = NLMSG_DATA (h);
673
674 if (h->nlmsg_type != RTM_NEWROUTE)
675 return 0;
676 if (rtm->rtm_type != RTN_UNICAST)
677 return 0;
678
679 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000680#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000681 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000682 return 0;
683#endif
684
paul7021c422003-07-15 12:52:22 +0000685 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000686 if (len < 0)
687 return -1;
688
689 memset (tb, 0, sizeof tb);
690 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
691
692 if (rtm->rtm_flags & RTM_F_CLONED)
693 return 0;
694 if (rtm->rtm_protocol == RTPROT_REDIRECT)
695 return 0;
696 if (rtm->rtm_protocol == RTPROT_KERNEL)
697 return 0;
698
699 if (rtm->rtm_src_len != 0)
700 return 0;
701
702 /* Route which inserted by Zebra. */
703 if (rtm->rtm_protocol == RTPROT_ZEBRA)
704 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000705
paul718e3742002-12-13 20:15:29 +0000706 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000707 metric = 0;
paul718e3742002-12-13 20:15:29 +0000708 dest = NULL;
709 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000710 src = NULL;
paul718e3742002-12-13 20:15:29 +0000711
712 if (tb[RTA_OIF])
713 index = *(int *) RTA_DATA (tb[RTA_OIF]);
714
715 if (tb[RTA_DST])
716 dest = RTA_DATA (tb[RTA_DST]);
717 else
718 dest = anyaddr;
719
Paul Jakma7514fb72007-05-02 16:05:35 +0000720 if (tb[RTA_PREFSRC])
721 src = RTA_DATA (tb[RTA_PREFSRC]);
722
paul718e3742002-12-13 20:15:29 +0000723 if (tb[RTA_GATEWAY])
724 gate = RTA_DATA (tb[RTA_GATEWAY]);
725
hasso34195bf2004-04-06 12:07:06 +0000726 if (tb[RTA_PRIORITY])
727 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
728
paul718e3742002-12-13 20:15:29 +0000729 if (rtm->rtm_family == AF_INET)
730 {
731 struct prefix_ipv4 p;
732 p.family = AF_INET;
733 memcpy (&p.prefix, dest, 4);
734 p.prefixlen = rtm->rtm_dst_len;
735
Josh Bailey26e2ae32012-03-22 01:09:21 -0700736 if (!tb[RTA_MULTIPATH])
737 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700738 table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700739 else
740 {
741 /* This is a multipath route */
742
743 struct rib *rib;
744 struct rtnexthop *rtnh =
745 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
746
747 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
748
749 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
750 rib->type = ZEBRA_ROUTE_KERNEL;
751 rib->distance = 0;
752 rib->flags = flags;
753 rib->metric = metric;
754 rib->table = table;
755 rib->nexthop_num = 0;
756 rib->uptime = time (NULL);
757
758 for (;;)
759 {
760 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
761 break;
762
763 rib->nexthop_num++;
764 index = rtnh->rtnh_ifindex;
765 gate = 0;
766 if (rtnh->rtnh_len > sizeof (*rtnh))
767 {
768 memset (tb, 0, sizeof (tb));
769 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
770 rtnh->rtnh_len - sizeof (*rtnh));
771 if (tb[RTA_GATEWAY])
772 gate = RTA_DATA (tb[RTA_GATEWAY]);
773 }
774
775 if (gate)
776 {
777 if (index)
778 nexthop_ipv4_ifindex_add (rib, gate, src, index);
779 else
780 nexthop_ipv4_add (rib, gate, src);
781 }
782 else
783 nexthop_ifindex_add (rib, index);
784
785 len -= NLMSG_ALIGN(rtnh->rtnh_len);
786 rtnh = RTNH_NEXT(rtnh);
787 }
788
789 if (rib->nexthop_num == 0)
790 XFREE (MTYPE_RIB, rib);
791 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700792 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700793 }
paul718e3742002-12-13 20:15:29 +0000794 }
795#ifdef HAVE_IPV6
796 if (rtm->rtm_family == AF_INET6)
797 {
798 struct prefix_ipv6 p;
799 p.family = AF_INET6;
800 memcpy (&p.prefix, dest, 16);
801 p.prefixlen = rtm->rtm_dst_len;
802
hassobe61c4e2005-08-27 06:05:47 +0000803 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
G.Balajif768f362011-11-26 22:10:39 +0400804 metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000805 }
806#endif /* HAVE_IPV6 */
807
808 return 0;
809}
810
Stephen Hemminger1423c802008-08-14 17:59:25 +0100811static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000812 {RTPROT_REDIRECT, "redirect"},
813 {RTPROT_KERNEL, "kernel"},
814 {RTPROT_BOOT, "boot"},
815 {RTPROT_STATIC, "static"},
816 {RTPROT_GATED, "GateD"},
817 {RTPROT_RA, "router advertisement"},
818 {RTPROT_MRT, "MRT"},
819 {RTPROT_ZEBRA, "Zebra"},
820#ifdef RTPROT_BIRD
821 {RTPROT_BIRD, "BIRD"},
822#endif /* RTPROT_BIRD */
823 {0, NULL}
824};
825
826/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100827static int
paul718e3742002-12-13 20:15:29 +0000828netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
829{
830 int len;
831 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000832 struct rtattr *tb[RTA_MAX + 1];
833
834 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000835
836 int index;
837 int table;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700838 int metric;
Dmitry Popov83d16142011-09-11 13:48:25 +0400839
paul718e3742002-12-13 20:15:29 +0000840 void *dest;
841 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000842 void *src;
paul718e3742002-12-13 20:15:29 +0000843
844 rtm = NLMSG_DATA (h);
845
paul7021c422003-07-15 12:52:22 +0000846 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000847 {
848 /* If this is not route add/delete message print warning. */
849 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
850 return 0;
851 }
852
853 /* Connected route. */
854 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000855 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000856 h->nlmsg_type ==
857 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
858 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
859 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
860 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000861
862 if (rtm->rtm_type != RTN_UNICAST)
863 {
864 return 0;
865 }
866
867 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000868 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000869 {
870 return 0;
871 }
872
paul7021c422003-07-15 12:52:22 +0000873 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000874 if (len < 0)
875 return -1;
876
877 memset (tb, 0, sizeof tb);
878 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
879
880 if (rtm->rtm_flags & RTM_F_CLONED)
881 return 0;
882 if (rtm->rtm_protocol == RTPROT_REDIRECT)
883 return 0;
884 if (rtm->rtm_protocol == RTPROT_KERNEL)
885 return 0;
886
887 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
888 return 0;
889
890 if (rtm->rtm_src_len != 0)
891 {
892 zlog_warn ("netlink_route_change(): no src len");
893 return 0;
894 }
paul7021c422003-07-15 12:52:22 +0000895
paul718e3742002-12-13 20:15:29 +0000896 index = 0;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700897 metric = 0;
paul718e3742002-12-13 20:15:29 +0000898 dest = NULL;
899 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000900 src = NULL;
paul718e3742002-12-13 20:15:29 +0000901
902 if (tb[RTA_OIF])
903 index = *(int *) RTA_DATA (tb[RTA_OIF]);
904
905 if (tb[RTA_DST])
906 dest = RTA_DATA (tb[RTA_DST]);
907 else
908 dest = anyaddr;
909
910 if (tb[RTA_GATEWAY])
911 gate = RTA_DATA (tb[RTA_GATEWAY]);
912
Paul Jakma7514fb72007-05-02 16:05:35 +0000913 if (tb[RTA_PREFSRC])
914 src = RTA_DATA (tb[RTA_PREFSRC]);
915
Dmitry Popov83d16142011-09-11 13:48:25 +0400916 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
Josh Bailey26e2ae32012-03-22 01:09:21 -0700917 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
918
paul718e3742002-12-13 20:15:29 +0000919 if (rtm->rtm_family == AF_INET)
920 {
921 struct prefix_ipv4 p;
922 p.family = AF_INET;
923 memcpy (&p.prefix, dest, 4);
924 p.prefixlen = rtm->rtm_dst_len;
925
926 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000927 {
928 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000929 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000930 inet_ntoa (p.prefix), p.prefixlen);
931 else
ajsb6178002004-12-07 21:12:56 +0000932 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000933 inet_ntoa (p.prefix), p.prefixlen);
934 }
paul718e3742002-12-13 20:15:29 +0000935
936 if (h->nlmsg_type == RTM_NEWROUTE)
Josh Bailey26e2ae32012-03-22 01:09:21 -0700937 {
938 if (!tb[RTA_MULTIPATH])
939 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700940 metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700941 else
942 {
943 /* This is a multipath route */
944
945 struct rib *rib;
946 struct rtnexthop *rtnh =
947 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
948
949 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
950
951 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
952 rib->type = ZEBRA_ROUTE_KERNEL;
953 rib->distance = 0;
954 rib->flags = 0;
955 rib->metric = metric;
956 rib->table = table;
957 rib->nexthop_num = 0;
958 rib->uptime = time (NULL);
959
960 for (;;)
961 {
962 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
963 break;
964
965 rib->nexthop_num++;
966 index = rtnh->rtnh_ifindex;
967 gate = 0;
968 if (rtnh->rtnh_len > sizeof (*rtnh))
969 {
970 memset (tb, 0, sizeof (tb));
971 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
972 rtnh->rtnh_len - sizeof (*rtnh));
973 if (tb[RTA_GATEWAY])
974 gate = RTA_DATA (tb[RTA_GATEWAY]);
975 }
976
977 if (gate)
978 {
979 if (index)
980 nexthop_ipv4_ifindex_add (rib, gate, src, index);
981 else
982 nexthop_ipv4_add (rib, gate, src);
983 }
984 else
985 nexthop_ifindex_add (rib, index);
986
987 len -= NLMSG_ALIGN(rtnh->rtnh_len);
988 rtnh = RTNH_NEXT(rtnh);
989 }
990
991 if (rib->nexthop_num == 0)
992 XFREE (MTYPE_RIB, rib);
993 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700994 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700995 }
996 }
paul718e3742002-12-13 20:15:29 +0000997 else
G.Balajicddf3912011-11-26 21:59:32 +0400998 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000999 }
1000
1001#ifdef HAVE_IPV6
1002 if (rtm->rtm_family == AF_INET6)
1003 {
1004 struct prefix_ipv6 p;
1005 char buf[BUFSIZ];
1006
1007 p.family = AF_INET6;
1008 memcpy (&p.prefix, dest, 16);
1009 p.prefixlen = rtm->rtm_dst_len;
1010
1011 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001012 {
1013 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +00001014 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001015 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1016 p.prefixlen);
1017 else
ajsb6178002004-12-07 21:12:56 +00001018 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001019 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1020 p.prefixlen);
1021 }
paul718e3742002-12-13 20:15:29 +00001022
1023 if (h->nlmsg_type == RTM_NEWROUTE)
G.Balajif768f362011-11-26 22:10:39 +04001024 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001025 else
G.Balajif768f362011-11-26 22:10:39 +04001026 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001027 }
1028#endif /* HAVE_IPV6 */
1029
1030 return 0;
1031}
1032
Stephen Hemminger6072b242008-08-14 16:52:26 +01001033static int
paul718e3742002-12-13 20:15:29 +00001034netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
1035{
1036 int len;
1037 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +00001038 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +00001039 struct interface *ifp;
1040 char *name;
1041
1042 ifi = NLMSG_DATA (h);
1043
paul7021c422003-07-15 12:52:22 +00001044 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +00001045 {
1046 /* If this is not link add/delete message so print warning. */
1047 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +00001048 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001049 return 0;
1050 }
1051
1052 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1053 if (len < 0)
1054 return -1;
1055
1056 /* Looking up interface name. */
1057 memset (tb, 0, sizeof tb);
1058 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +00001059
paul1e193152005-02-14 23:53:05 +00001060#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +00001061 /* check for wireless messages to ignore */
1062 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1063 {
1064 if (IS_ZEBRA_DEBUG_KERNEL)
1065 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
1066 return 0;
1067 }
paul1e193152005-02-14 23:53:05 +00001068#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001069
paul718e3742002-12-13 20:15:29 +00001070 if (tb[IFLA_IFNAME] == NULL)
1071 return -1;
paul7021c422003-07-15 12:52:22 +00001072 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001073
1074 /* Add interface. */
1075 if (h->nlmsg_type == RTM_NEWLINK)
1076 {
1077 ifp = if_lookup_by_name (name);
1078
paul7021c422003-07-15 12:52:22 +00001079 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1080 {
1081 if (ifp == NULL)
1082 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001083
ajsd2fc8892005-04-02 18:38:43 +00001084 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001085 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001086 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001087 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001088
Josh Bailey26e2ae32012-03-22 01:09:21 -07001089 netlink_interface_update_hw_addr (tb, ifp);
1090
paul7021c422003-07-15 12:52:22 +00001091 /* If new link is added. */
1092 if_add_update (ifp);
1093 }
paul718e3742002-12-13 20:15:29 +00001094 else
paul7021c422003-07-15 12:52:22 +00001095 {
1096 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001097 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001098 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001099 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001100
Josh Bailey26e2ae32012-03-22 01:09:21 -07001101 netlink_interface_update_hw_addr (tb, ifp);
1102
paul7021c422003-07-15 12:52:22 +00001103 if (if_is_operative (ifp))
1104 {
1105 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1106 if (!if_is_operative (ifp))
1107 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001108 else
1109 /* Must notify client daemons of new interface status. */
1110 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001111 }
1112 else
1113 {
1114 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1115 if (if_is_operative (ifp))
1116 if_up (ifp);
1117 }
1118 }
paul718e3742002-12-13 20:15:29 +00001119 }
1120 else
1121 {
1122 /* RTM_DELLINK. */
1123 ifp = if_lookup_by_name (name);
1124
1125 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001126 {
1127 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001128 name);
paul7021c422003-07-15 12:52:22 +00001129 return 0;
1130 }
1131
paul718e3742002-12-13 20:15:29 +00001132 if_delete_update (ifp);
1133 }
1134
1135 return 0;
1136}
1137
Stephen Hemminger6072b242008-08-14 16:52:26 +01001138static int
paul718e3742002-12-13 20:15:29 +00001139netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1140{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001141 /* JF: Ignore messages that aren't from the kernel */
1142 if ( snl->nl_pid != 0 )
1143 {
1144 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1145 return 0;
1146 }
1147
paul718e3742002-12-13 20:15:29 +00001148 switch (h->nlmsg_type)
1149 {
1150 case RTM_NEWROUTE:
1151 return netlink_route_change (snl, h);
1152 break;
1153 case RTM_DELROUTE:
1154 return netlink_route_change (snl, h);
1155 break;
1156 case RTM_NEWLINK:
1157 return netlink_link_change (snl, h);
1158 break;
1159 case RTM_DELLINK:
1160 return netlink_link_change (snl, h);
1161 break;
1162 case RTM_NEWADDR:
1163 return netlink_interface_addr (snl, h);
1164 break;
1165 case RTM_DELADDR:
1166 return netlink_interface_addr (snl, h);
1167 break;
1168 default:
1169 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1170 break;
1171 }
1172 return 0;
1173}
1174
1175/* Interface lookup by netlink socket. */
1176int
paul6621ca82005-11-23 13:02:08 +00001177interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001178{
1179 int ret;
paul7021c422003-07-15 12:52:22 +00001180
paul718e3742002-12-13 20:15:29 +00001181 /* Get interface information. */
1182 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1183 if (ret < 0)
1184 return ret;
1185 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1186 if (ret < 0)
1187 return ret;
1188
1189 /* Get IPv4 address of the interfaces. */
1190 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1191 if (ret < 0)
1192 return ret;
1193 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1194 if (ret < 0)
1195 return ret;
1196
1197#ifdef HAVE_IPV6
1198 /* Get IPv6 address of the interfaces. */
1199 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1200 if (ret < 0)
1201 return ret;
1202 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1203 if (ret < 0)
1204 return ret;
1205#endif /* HAVE_IPV6 */
1206
1207 return 0;
1208}
1209
1210/* Routing table read function using netlink interface. Only called
1211 bootstrap time. */
1212int
paul6621ca82005-11-23 13:02:08 +00001213netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001214{
1215 int ret;
paul7021c422003-07-15 12:52:22 +00001216
paul718e3742002-12-13 20:15:29 +00001217 /* Get IPv4 routing table. */
1218 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1219 if (ret < 0)
1220 return ret;
1221 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1222 if (ret < 0)
1223 return ret;
1224
1225#ifdef HAVE_IPV6
1226 /* Get IPv6 routing table. */
1227 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1228 if (ret < 0)
1229 return ret;
1230 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1231 if (ret < 0)
1232 return ret;
1233#endif /* HAVE_IPV6 */
1234
1235 return 0;
1236}
1237
1238/* Utility function comes from iproute2.
1239 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001240int
paul718e3742002-12-13 20:15:29 +00001241addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1242{
1243 int len;
1244 struct rtattr *rta;
1245
paul7021c422003-07-15 12:52:22 +00001246 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001247
paul7021c422003-07-15 12:52:22 +00001248 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001249 return -1;
1250
paul7021c422003-07-15 12:52:22 +00001251 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001252 rta->rta_type = type;
1253 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001254 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001255 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1256
1257 return 0;
1258}
1259
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001260int
paul718e3742002-12-13 20:15:29 +00001261rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1262{
1263 int len;
1264 struct rtattr *subrta;
1265
paul7021c422003-07-15 12:52:22 +00001266 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001267
paul7021c422003-07-15 12:52:22 +00001268 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001269 return -1;
1270
paul7021c422003-07-15 12:52:22 +00001271 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001272 subrta->rta_type = type;
1273 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001274 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001275 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1276
1277 return 0;
1278}
1279
1280/* Utility function comes from iproute2.
1281 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001282int
paul718e3742002-12-13 20:15:29 +00001283addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1284{
1285 int len;
1286 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001287
1288 len = RTA_LENGTH (4);
1289
paul718e3742002-12-13 20:15:29 +00001290 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1291 return -1;
1292
paul7021c422003-07-15 12:52:22 +00001293 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001294 rta->rta_type = type;
1295 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001296 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001297 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1298
1299 return 0;
1300}
1301
1302static int
1303netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1304{
hassob7ed1ec2005-03-31 20:13:49 +00001305 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001306 return 0;
1307}
1308
1309/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001310static int
paul718e3742002-12-13 20:15:29 +00001311netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1312{
1313 int status;
1314 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001315 struct iovec iov = { (void *) n, n->nlmsg_len };
1316 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001317 int save_errno;
paul7021c422003-07-15 12:52:22 +00001318
paul718e3742002-12-13 20:15:29 +00001319 memset (&snl, 0, sizeof snl);
1320 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001321
hassob7ed1ec2005-03-31 20:13:49 +00001322 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001323
1324 /* Request an acknowledgement by setting NLM_F_ACK */
1325 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001326
1327 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001328 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001329 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1330 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001331
1332 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001333 if (zserv_privs.change (ZPRIVS_RAISE))
1334 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001335 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001336 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001337 if (zserv_privs.change (ZPRIVS_LOWER))
1338 zlog (NULL, LOG_ERR, "Can't lower privileges");
1339
paul718e3742002-12-13 20:15:29 +00001340 if (status < 0)
1341 {
1342 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001343 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001344 return -1;
1345 }
paul7021c422003-07-15 12:52:22 +00001346
paul718e3742002-12-13 20:15:29 +00001347
1348 /*
1349 * Get reply from netlink socket.
1350 * The reply should either be an acknowlegement or an error.
1351 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001352 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001353}
1354
1355/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001356static int
paul718e3742002-12-13 20:15:29 +00001357netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001358 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001359{
1360 int ret;
1361 int bytelen;
1362 struct sockaddr_nl snl;
1363 int discard;
1364
paul7021c422003-07-15 12:52:22 +00001365 struct
paul718e3742002-12-13 20:15:29 +00001366 {
1367 struct nlmsghdr n;
1368 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001369 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001370 } req;
1371
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001372 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001373
1374 bytelen = (family == AF_INET ? 4 : 16);
1375
1376 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1377 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1378 req.n.nlmsg_type = cmd;
1379 req.r.rtm_family = family;
1380 req.r.rtm_table = table;
1381 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001382 req.r.rtm_protocol = RTPROT_ZEBRA;
1383 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001384
hasso81dfcaa2003-05-25 19:21:25 +00001385 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1386 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001387 discard = 1;
1388 else
1389 discard = 0;
1390
paul7021c422003-07-15 12:52:22 +00001391 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001392 {
paul7021c422003-07-15 12:52:22 +00001393 if (discard)
paul595db7f2003-05-25 21:35:06 +00001394 {
1395 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1396 req.r.rtm_type = RTN_BLACKHOLE;
1397 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1398 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001399 else
1400 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1401 }
paul595db7f2003-05-25 21:35:06 +00001402 else
paul7021c422003-07-15 12:52:22 +00001403 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001404 }
1405
1406 if (dest)
1407 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1408
paul7021c422003-07-15 12:52:22 +00001409 if (!discard)
paul718e3742002-12-13 20:15:29 +00001410 {
1411 if (gate)
paul7021c422003-07-15 12:52:22 +00001412 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001413 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001414 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001415 }
1416
1417 /* Destination netlink address. */
1418 memset (&snl, 0, sizeof snl);
1419 snl.nl_family = AF_NETLINK;
1420
1421 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001422 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001423 if (ret < 0)
1424 return -1;
1425
1426 return 0;
1427}
1428
Christian Frankefa713d92013-07-05 15:35:37 +00001429/* This function takes a nexthop as argument and adds
1430 * the appropriate netlink attributes to an existing
1431 * netlink message.
1432 *
1433 * @param routedesc: Human readable description of route type
1434 * (direct/recursive, single-/multipath)
1435 * @param bytelen: Length of addresses in bytes.
1436 * @param nexthop: Nexthop information
1437 * @param nlmsg: nlmsghdr structure to fill in.
1438 * @param req_size: The size allocated for the message.
1439 */
1440static void
1441_netlink_route_build_singlepath(
1442 const char *routedesc,
1443 int bytelen,
1444 struct nexthop *nexthop,
1445 struct nlmsghdr *nlmsg,
Christian Frankee8d3d292013-07-05 15:35:39 +00001446 struct rtmsg *rtmsg,
Christian Frankefa713d92013-07-05 15:35:37 +00001447 size_t req_size)
1448{
Christian Frankee8d3d292013-07-05 15:35:39 +00001449 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1450 rtmsg->rtm_flags |= RTNH_F_ONLINK;
Christian Frankefa713d92013-07-05 15:35:37 +00001451 if (nexthop->type == NEXTHOP_TYPE_IPV4
1452 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1453 {
1454 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1455 &nexthop->gate.ipv4, bytelen);
1456 if (nexthop->src.ipv4.s_addr)
1457 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1458 &nexthop->src.ipv4, bytelen);
1459
1460 if (IS_ZEBRA_DEBUG_KERNEL)
1461 zlog_debug("netlink_route_multipath() (%s): "
1462 "nexthop via %s if %u",
1463 routedesc,
1464 inet_ntoa (nexthop->gate.ipv4),
1465 nexthop->ifindex);
1466 }
1467#ifdef HAVE_IPV6
1468 if (nexthop->type == NEXTHOP_TYPE_IPV6
1469 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1470 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1471 {
1472 addattr_l (nlmsg, req_size, RTA_GATEWAY,
1473 &nexthop->gate.ipv6, bytelen);
1474
1475 if (IS_ZEBRA_DEBUG_KERNEL)
1476 zlog_debug("netlink_route_multipath() (%s): "
1477 "nexthop via %s if %u",
1478 routedesc,
1479 inet6_ntoa (nexthop->gate.ipv6),
1480 nexthop->ifindex);
1481 }
1482#endif /* HAVE_IPV6 */
1483 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1484 || nexthop->type == NEXTHOP_TYPE_IFNAME
1485 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1486 {
1487 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1488
1489 if (nexthop->src.ipv4.s_addr)
1490 addattr_l (nlmsg, req_size, RTA_PREFSRC,
1491 &nexthop->src.ipv4, bytelen);
1492
1493 if (IS_ZEBRA_DEBUG_KERNEL)
1494 zlog_debug("netlink_route_multipath() (%s): "
1495 "nexthop via if %u", routedesc, nexthop->ifindex);
1496 }
1497
1498 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
1499 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
1500 {
1501 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
1502
1503 if (IS_ZEBRA_DEBUG_KERNEL)
1504 zlog_debug("netlink_route_multipath() (%s): "
1505 "nexthop via if %u", routedesc, nexthop->ifindex);
1506 }
1507}
1508
1509/* This function takes a nexthop as argument and
1510 * appends to the given rtattr/rtnexthop pair the
1511 * representation of the nexthop. If the nexthop
1512 * defines a preferred source, the src parameter
1513 * will be modified to point to that src, otherwise
1514 * it will be kept unmodified.
1515 *
1516 * @param routedesc: Human readable description of route type
1517 * (direct/recursive, single-/multipath)
1518 * @param bytelen: Length of addresses in bytes.
1519 * @param nexthop: Nexthop information
1520 * @param rta: rtnetlink attribute structure
1521 * @param rtnh: pointer to an rtnetlink nexthop structure
1522 * @param src: pointer pointing to a location where
1523 * the prefsrc should be stored.
1524 */
1525static void
1526_netlink_route_build_multipath(
1527 const char *routedesc,
1528 int bytelen,
1529 struct nexthop *nexthop,
1530 struct rtattr *rta,
1531 struct rtnexthop *rtnh,
1532 union g_addr **src
1533 )
1534{
1535 rtnh->rtnh_len = sizeof (*rtnh);
1536 rtnh->rtnh_flags = 0;
1537 rtnh->rtnh_hops = 0;
1538 rta->rta_len += rtnh->rtnh_len;
1539
Christian Frankee8d3d292013-07-05 15:35:39 +00001540 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
1541 rtnh->rtnh_flags |= RTNH_F_ONLINK;
1542
Christian Frankefa713d92013-07-05 15:35:37 +00001543 if (nexthop->type == NEXTHOP_TYPE_IPV4
1544 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1545 {
1546 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1547 &nexthop->gate.ipv4, bytelen);
1548 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1549
1550 if (nexthop->src.ipv4.s_addr)
1551 *src = &nexthop->src;
1552
1553 if (IS_ZEBRA_DEBUG_KERNEL)
1554 zlog_debug("netlink_route_multipath() (%s): "
1555 "nexthop via %s if %u",
1556 routedesc,
1557 inet_ntoa (nexthop->gate.ipv4),
1558 nexthop->ifindex);
1559 }
1560#ifdef HAVE_IPV6
1561 if (nexthop->type == NEXTHOP_TYPE_IPV6
1562 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1563 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1564 {
1565 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
1566 &nexthop->gate.ipv6, bytelen);
1567
1568 if (IS_ZEBRA_DEBUG_KERNEL)
1569 zlog_debug("netlink_route_multipath() (%s): "
1570 "nexthop via %s if %u",
1571 routedesc,
1572 inet6_ntoa (nexthop->gate.ipv6),
1573 nexthop->ifindex);
1574 }
1575#endif /* HAVE_IPV6 */
1576 /* ifindex */
1577 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1578 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1579 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1580 {
1581 rtnh->rtnh_ifindex = nexthop->ifindex;
1582 if (nexthop->src.ipv4.s_addr)
1583 *src = &nexthop->src;
1584 if (IS_ZEBRA_DEBUG_KERNEL)
1585 zlog_debug("netlink_route_multipath() (%s): "
1586 "nexthop via if %u", routedesc, nexthop->ifindex);
1587 }
1588 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1589 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1590 {
1591 rtnh->rtnh_ifindex = nexthop->ifindex;
1592
1593 if (IS_ZEBRA_DEBUG_KERNEL)
1594 zlog_debug("netlink_route_multipath() (%s): "
1595 "nexthop via if %u", routedesc, nexthop->ifindex);
1596 }
1597 else
1598 {
1599 rtnh->rtnh_ifindex = 0;
1600 }
1601}
1602
1603/* Log debug information for netlink_route_multipath
1604 * if debug logging is enabled.
1605 *
1606 * @param cmd: Netlink command which is to be processed
1607 * @param p: Prefix for which the change is due
1608 * @param nexthop: Nexthop which is currently processed
1609 * @param routedesc: Semantic annotation for nexthop
1610 * (recursive, multipath, etc.)
1611 * @param family: Address family which the change concerns
1612 */
1613static void
1614_netlink_route_debug(
1615 int cmd,
1616 struct prefix *p,
1617 struct nexthop *nexthop,
1618 const char *routedesc,
1619 int family)
1620{
1621 if (IS_ZEBRA_DEBUG_KERNEL)
1622 {
1623 zlog_debug ("netlink_route_multipath() (%s): %s %s/%d type %s",
1624 routedesc,
1625 lookup (nlmsg_str, cmd),
1626#ifdef HAVE_IPV6
1627 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1628 inet6_ntoa (p->u.prefix6),
1629#else
1630 inet_ntoa (p->u.prefix4),
1631#endif /* HAVE_IPV6 */
1632 p->prefixlen, nexthop_type_to_str (nexthop->type));
1633 }
1634}
1635
paul718e3742002-12-13 20:15:29 +00001636/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001637static int
paul718e3742002-12-13 20:15:29 +00001638netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001639 int family)
paul718e3742002-12-13 20:15:29 +00001640{
1641 int bytelen;
1642 struct sockaddr_nl snl;
Christian Frankefa713d92013-07-05 15:35:37 +00001643 struct nexthop *nexthop = NULL, *tnexthop;
1644 int recursing;
1645 int nexthop_num;
paul718e3742002-12-13 20:15:29 +00001646 int discard;
Christian Frankefa713d92013-07-05 15:35:37 +00001647 const char *routedesc;
paul718e3742002-12-13 20:15:29 +00001648
paul7021c422003-07-15 12:52:22 +00001649 struct
paul718e3742002-12-13 20:15:29 +00001650 {
1651 struct nlmsghdr n;
1652 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001653 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001654 } req;
1655
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001656 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001657
1658 bytelen = (family == AF_INET ? 4 : 16);
1659
1660 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1661 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1662 req.n.nlmsg_type = cmd;
1663 req.r.rtm_family = family;
1664 req.r.rtm_table = rib->table;
1665 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001666 req.r.rtm_protocol = RTPROT_ZEBRA;
1667 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001668
paul7021c422003-07-15 12:52:22 +00001669 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001670 discard = 1;
1671 else
1672 discard = 0;
1673
paul7021c422003-07-15 12:52:22 +00001674 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001675 {
paul7021c422003-07-15 12:52:22 +00001676 if (discard)
paul595db7f2003-05-25 21:35:06 +00001677 {
1678 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1679 req.r.rtm_type = RTN_BLACKHOLE;
1680 else if (rib->flags & ZEBRA_FLAG_REJECT)
1681 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001682 else
1683 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1684 }
paul595db7f2003-05-25 21:35:06 +00001685 else
paul7021c422003-07-15 12:52:22 +00001686 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001687 }
1688
1689 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1690
1691 /* Metric. */
1692 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1693
1694 if (discard)
1695 {
1696 if (cmd == RTM_NEWROUTE)
Christian Frankefa713d92013-07-05 15:35:37 +00001697 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1698 {
1699 /* We shouldn't encounter recursive nexthops on discard routes,
1700 * but it is probably better to handle that case correctly anyway.
1701 */
1702 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1703 continue;
1704 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1705 }
paul718e3742002-12-13 20:15:29 +00001706 goto skip;
1707 }
1708
Christian Frankefa713d92013-07-05 15:35:37 +00001709 /* Count overall nexthops so we can decide whether to use singlepath
1710 * or multipath case. */
1711 nexthop_num = 0;
1712 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul718e3742002-12-13 20:15:29 +00001713 {
Christian Frankefa713d92013-07-05 15:35:37 +00001714 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1715 continue;
1716 if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1717 continue;
1718 if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
1719 continue;
1720
1721 nexthop_num++;
1722 }
1723
1724 /* Singlepath case. */
1725 if (nexthop_num == 1 || MULTIPATH_NUM == 1)
1726 {
1727 nexthop_num = 0;
1728 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001729 {
Christian Frankefa713d92013-07-05 15:35:37 +00001730 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1731 continue;
paul5ec90d22003-06-19 01:41:37 +00001732
paul7021c422003-07-15 12:52:22 +00001733 if ((cmd == RTM_NEWROUTE
1734 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1735 || (cmd == RTM_DELROUTE
1736 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1737 {
Christian Frankefa713d92013-07-05 15:35:37 +00001738 routedesc = recursing ? "recursive, 1 hop" : "single hop";
paul5ec90d22003-06-19 01:41:37 +00001739
Christian Frankefa713d92013-07-05 15:35:37 +00001740 _netlink_route_debug(cmd, p, nexthop, routedesc, family);
1741 _netlink_route_build_singlepath(routedesc, bytelen,
Christian Frankee8d3d292013-07-05 15:35:39 +00001742 nexthop, &req.n, &req.r,
1743 sizeof req);
paul718e3742002-12-13 20:15:29 +00001744
paul7021c422003-07-15 12:52:22 +00001745 if (cmd == RTM_NEWROUTE)
1746 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001747
paul7021c422003-07-15 12:52:22 +00001748 nexthop_num++;
1749 break;
1750 }
1751 }
paul718e3742002-12-13 20:15:29 +00001752 }
1753 else
1754 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001755 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001756 struct rtattr *rta = (void *) buf;
1757 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001758 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001759
1760 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001761 rta->rta_len = RTA_LENGTH (0);
1762 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001763
1764 nexthop_num = 0;
Christian Frankefa713d92013-07-05 15:35:37 +00001765 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul7021c422003-07-15 12:52:22 +00001766 {
Christian Frankefa713d92013-07-05 15:35:37 +00001767 if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
1768 break;
1769
1770 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1771 continue;
1772
paul7021c422003-07-15 12:52:22 +00001773 if ((cmd == RTM_NEWROUTE
1774 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1775 || (cmd == RTM_DELROUTE
1776 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1777 {
Christian Frankefa713d92013-07-05 15:35:37 +00001778 routedesc = recursing ? "recursive, multihop" : "multihop";
paul7021c422003-07-15 12:52:22 +00001779 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001780
Christian Frankefa713d92013-07-05 15:35:37 +00001781 _netlink_route_debug(cmd, p, nexthop,
1782 routedesc, family);
1783 _netlink_route_build_multipath(routedesc, bytelen,
1784 nexthop, rta, rtnh, &src);
paul7021c422003-07-15 12:52:22 +00001785 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001786
paul7021c422003-07-15 12:52:22 +00001787 if (cmd == RTM_NEWROUTE)
1788 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1789 }
1790 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001791 if (src)
1792 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001793
1794 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001795 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001796 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001797 }
1798
1799 /* If there is no useful nexthop then return. */
1800 if (nexthop_num == 0)
1801 {
1802 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001803 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001804 return 0;
1805 }
1806
paul7021c422003-07-15 12:52:22 +00001807skip:
paul718e3742002-12-13 20:15:29 +00001808
1809 /* Destination netlink address. */
1810 memset (&snl, 0, sizeof snl);
1811 snl.nl_family = AF_NETLINK;
1812
paul718e3742002-12-13 20:15:29 +00001813 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001814 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001815}
1816
1817int
1818kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1819{
1820 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1821}
1822
1823int
1824kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1825{
1826 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1827}
1828
1829#ifdef HAVE_IPV6
1830int
1831kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1832{
1833 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1834}
1835
1836int
1837kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1838{
1839 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1840}
1841
1842/* Delete IPv6 route from the kernel. */
1843int
1844kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001845 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001846{
paul7021c422003-07-15 12:52:22 +00001847 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1848 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001849}
1850#endif /* HAVE_IPV6 */
1851
1852/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001853static int
paul718e3742002-12-13 20:15:29 +00001854netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001855 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001856{
1857 int bytelen;
1858 struct prefix *p;
1859
paul7021c422003-07-15 12:52:22 +00001860 struct
paul718e3742002-12-13 20:15:29 +00001861 {
1862 struct nlmsghdr n;
1863 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001864 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001865 } req;
1866
1867 p = ifc->address;
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001868 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001869
1870 bytelen = (family == AF_INET ? 4 : 16);
1871
paul7021c422003-07-15 12:52:22 +00001872 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001873 req.n.nlmsg_flags = NLM_F_REQUEST;
1874 req.n.nlmsg_type = cmd;
1875 req.ifa.ifa_family = family;
1876
1877 req.ifa.ifa_index = ifp->ifindex;
1878 req.ifa.ifa_prefixlen = p->prefixlen;
1879
1880 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1881
1882 if (family == AF_INET && cmd == RTM_NEWADDR)
1883 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001884 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001885 {
1886 p = ifc->destination;
1887 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1888 bytelen);
1889 }
paul718e3742002-12-13 20:15:29 +00001890 }
1891
1892 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1893 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001894
paul718e3742002-12-13 20:15:29 +00001895 if (ifc->label)
1896 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001897 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001898
1899 return netlink_talk (&req.n, &netlink_cmd);
1900}
1901
1902int
1903kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1904{
1905 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1906}
1907
1908int
1909kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1910{
1911 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1912}
1913
paul718e3742002-12-13 20:15:29 +00001914
1915extern struct thread_master *master;
1916
1917/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001918static int
paul718e3742002-12-13 20:15:29 +00001919kernel_read (struct thread *thread)
1920{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001921 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001922 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001923
1924 return 0;
1925}
1926
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001927/* Filter out messages from self that occur on listener socket,
1928 caused by our actions on the command socket
1929 */
1930static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001931{
Paul Jakma768a27e2008-05-29 18:23:08 +00001932 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001933 /* 0: ldh [4] */
1934 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1935 /* 1: jeq 0x18 jt 3 jf 6 */
1936 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1937 /* 2: jeq 0x19 jt 3 jf 6 */
1938 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1939 /* 3: ldw [12] */
1940 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1941 /* 4: jeq XX jt 5 jf 6 */
1942 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1943 /* 5: ret 0 (skip) */
1944 BPF_STMT(BPF_RET|BPF_K, 0),
1945 /* 6: ret 0xffff (keep) */
1946 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001947 };
1948
1949 struct sock_fprog prog = {
Balaji.G837d16c2012-09-26 14:09:10 +05301950 .len = array_size(filter),
Paul Jakma768a27e2008-05-29 18:23:08 +00001951 .filter = filter,
1952 };
1953
1954 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1955 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1956}
1957
paul718e3742002-12-13 20:15:29 +00001958/* Exported interface function. This function simply calls
1959 netlink_socket (). */
1960void
paul6621ca82005-11-23 13:02:08 +00001961kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001962{
1963 unsigned long groups;
1964
paul7021c422003-07-15 12:52:22 +00001965 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001966#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001967 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001968#endif /* HAVE_IPV6 */
1969 netlink_socket (&netlink, groups);
1970 netlink_socket (&netlink_cmd, 0);
1971
1972 /* Register kernel socket. */
1973 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001974 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001975 /* Only want non-blocking on the netlink event socket */
1976 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
1977 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
1978 safe_strerror (errno));
1979
Stephen Hemminger30afea32008-08-16 18:25:47 +01001980 /* Set receive buffer size if it's set from command line */
1981 if (nl_rcvbufsize)
1982 netlink_recvbuf (&netlink, nl_rcvbufsize);
1983
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001984 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00001985 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
1986 }
paul718e3742002-12-13 20:15:29 +00001987}
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001988
1989/*
1990 * nl_msg_type_to_str
1991 */
1992const char *
1993nl_msg_type_to_str (uint16_t msg_type)
1994{
1995 return lookup (nlmsg_str, msg_type);
1996}
1997
1998/*
1999 * nl_rtproto_to_str
2000 */
2001const char *
2002nl_rtproto_to_str (u_char rtproto)
2003{
2004 return lookup (rtproto_str, rtproto);
2005}