blob: 86e02efb88fa9739cde51129a7c83133f897c008 [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
1429/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001430static int
paul718e3742002-12-13 20:15:29 +00001431netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001432 int family)
paul718e3742002-12-13 20:15:29 +00001433{
1434 int bytelen;
1435 struct sockaddr_nl snl;
1436 struct nexthop *nexthop = NULL;
1437 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001438 int discard;
1439
paul7021c422003-07-15 12:52:22 +00001440 struct
paul718e3742002-12-13 20:15:29 +00001441 {
1442 struct nlmsghdr n;
1443 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001444 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001445 } req;
1446
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001447 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001448
1449 bytelen = (family == AF_INET ? 4 : 16);
1450
1451 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1452 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1453 req.n.nlmsg_type = cmd;
1454 req.r.rtm_family = family;
1455 req.r.rtm_table = rib->table;
1456 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001457 req.r.rtm_protocol = RTPROT_ZEBRA;
1458 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001459
paul7021c422003-07-15 12:52:22 +00001460 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001461 discard = 1;
1462 else
1463 discard = 0;
1464
paul7021c422003-07-15 12:52:22 +00001465 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001466 {
paul7021c422003-07-15 12:52:22 +00001467 if (discard)
paul595db7f2003-05-25 21:35:06 +00001468 {
1469 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1470 req.r.rtm_type = RTN_BLACKHOLE;
1471 else if (rib->flags & ZEBRA_FLAG_REJECT)
1472 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001473 else
1474 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1475 }
paul595db7f2003-05-25 21:35:06 +00001476 else
paul7021c422003-07-15 12:52:22 +00001477 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001478 }
1479
1480 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1481
1482 /* Metric. */
1483 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1484
1485 if (discard)
1486 {
1487 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001488 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1489 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001490 goto skip;
1491 }
1492
1493 /* Multipath case. */
1494 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1495 {
1496 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001497 {
paul5ec90d22003-06-19 01:41:37 +00001498
paul7021c422003-07-15 12:52:22 +00001499 if ((cmd == RTM_NEWROUTE
1500 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1501 || (cmd == RTM_DELROUTE
1502 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1503 {
paul5ec90d22003-06-19 01:41:37 +00001504
paul7021c422003-07-15 12:52:22 +00001505 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1506 {
1507 if (IS_ZEBRA_DEBUG_KERNEL)
1508 {
ajsb6178002004-12-07 21:12:56 +00001509 zlog_debug
paul7021c422003-07-15 12:52:22 +00001510 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001511 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001512#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001513 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001514 inet6_ntoa (p->u.prefix6),
1515#else
1516 inet_ntoa (p->u.prefix4),
1517#endif /* HAVE_IPV6 */
1518
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001519 p->prefixlen, nexthop_type_to_str (nexthop->rtype));
paul7021c422003-07-15 12:52:22 +00001520 }
paul5ec90d22003-06-19 01:41:37 +00001521
paul7021c422003-07-15 12:52:22 +00001522 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1523 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001524 {
1525 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1526 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001527 if (nexthop->src.ipv4.s_addr)
1528 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1529 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001530 if (IS_ZEBRA_DEBUG_KERNEL)
1531 zlog_debug("netlink_route_multipath() (recursive, "
1532 "1 hop): nexthop via %s if %u",
1533 inet_ntoa (nexthop->rgate.ipv4),
1534 nexthop->rifindex);
1535 }
paul718e3742002-12-13 20:15:29 +00001536#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001537 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1538 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1539 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001540 {
1541 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1542 &nexthop->rgate.ipv6, bytelen);
1543
1544 if (IS_ZEBRA_DEBUG_KERNEL)
1545 zlog_debug("netlink_route_multipath() (recursive, "
1546 "1 hop): nexthop via %s if %u",
1547 inet6_ntoa (nexthop->rgate.ipv6),
1548 nexthop->rifindex);
1549 }
paul718e3742002-12-13 20:15:29 +00001550#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001551 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1552 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1553 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1554 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1555 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001556 {
1557 addattr32 (&req.n, sizeof req, RTA_OIF,
1558 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001559 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1560 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1561 && nexthop->src.ipv4.s_addr)
1562 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1563 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001564
1565 if (IS_ZEBRA_DEBUG_KERNEL)
1566 zlog_debug("netlink_route_multipath() (recursive, "
1567 "1 hop): nexthop via if %u",
1568 nexthop->rifindex);
1569 }
paul7021c422003-07-15 12:52:22 +00001570 }
1571 else
1572 {
1573 if (IS_ZEBRA_DEBUG_KERNEL)
1574 {
ajsb6178002004-12-07 21:12:56 +00001575 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001576 ("netlink_route_multipath() (single hop): "
1577 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001578#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001579 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001580 inet6_ntoa (p->u.prefix6),
1581#else
1582 inet_ntoa (p->u.prefix4),
1583#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001584 p->prefixlen, nexthop_type_to_str (nexthop->type));
paul7021c422003-07-15 12:52:22 +00001585 }
paul5ec90d22003-06-19 01:41:37 +00001586
paul7021c422003-07-15 12:52:22 +00001587 if (nexthop->type == NEXTHOP_TYPE_IPV4
1588 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001589 {
1590 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1591 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001592 if (nexthop->src.ipv4.s_addr)
1593 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1594 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001595
1596 if (IS_ZEBRA_DEBUG_KERNEL)
1597 zlog_debug("netlink_route_multipath() (single hop): "
1598 "nexthop via %s if %u",
1599 inet_ntoa (nexthop->gate.ipv4),
1600 nexthop->ifindex);
1601 }
paul718e3742002-12-13 20:15:29 +00001602#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001603 if (nexthop->type == NEXTHOP_TYPE_IPV6
1604 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1605 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001606 {
1607 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1608 &nexthop->gate.ipv6, bytelen);
1609
1610 if (IS_ZEBRA_DEBUG_KERNEL)
1611 zlog_debug("netlink_route_multipath() (single hop): "
1612 "nexthop via %s if %u",
1613 inet6_ntoa (nexthop->gate.ipv6),
1614 nexthop->ifindex);
1615 }
paul718e3742002-12-13 20:15:29 +00001616#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001617 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1618 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001619 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1620 {
1621 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1622
1623 if (nexthop->src.ipv4.s_addr)
1624 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1625 &nexthop->src.ipv4, bytelen);
1626
1627 if (IS_ZEBRA_DEBUG_KERNEL)
1628 zlog_debug("netlink_route_multipath() (single hop): "
1629 "nexthop via if %u", nexthop->ifindex);
1630 }
1631 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001632 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001633 {
1634 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1635
1636 if (IS_ZEBRA_DEBUG_KERNEL)
1637 zlog_debug("netlink_route_multipath() (single hop): "
1638 "nexthop via if %u", nexthop->ifindex);
1639 }
paul7021c422003-07-15 12:52:22 +00001640 }
paul718e3742002-12-13 20:15:29 +00001641
paul7021c422003-07-15 12:52:22 +00001642 if (cmd == RTM_NEWROUTE)
1643 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001644
paul7021c422003-07-15 12:52:22 +00001645 nexthop_num++;
1646 break;
1647 }
1648 }
paul718e3742002-12-13 20:15:29 +00001649 }
1650 else
1651 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001652 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001653 struct rtattr *rta = (void *) buf;
1654 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001655 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001656
1657 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001658 rta->rta_len = RTA_LENGTH (0);
1659 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001660
1661 nexthop_num = 0;
1662 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001663 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1664 nexthop = nexthop->next)
1665 {
1666 if ((cmd == RTM_NEWROUTE
1667 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1668 || (cmd == RTM_DELROUTE
1669 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1670 {
1671 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001672
paul7021c422003-07-15 12:52:22 +00001673 rtnh->rtnh_len = sizeof (*rtnh);
1674 rtnh->rtnh_flags = 0;
1675 rtnh->rtnh_hops = 0;
1676 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001677
paul7021c422003-07-15 12:52:22 +00001678 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1679 {
1680 if (IS_ZEBRA_DEBUG_KERNEL)
1681 {
ajsb6178002004-12-07 21:12:56 +00001682 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001683 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001684 lookup (nlmsg_str, cmd),
1685#ifdef HAVE_IPV6
1686 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1687 inet6_ntoa (p->u.prefix6),
1688#else
1689 inet_ntoa (p->u.prefix4),
1690#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001691 p->prefixlen, nexthop_type_to_str (nexthop->rtype));
paul7021c422003-07-15 12:52:22 +00001692 }
1693 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1694 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1695 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001696 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
paul7021c422003-07-15 12:52:22 +00001697 &nexthop->rgate.ipv4, bytelen);
1698 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001699
Paul Jakma7514fb72007-05-02 16:05:35 +00001700 if (nexthop->src.ipv4.s_addr)
1701 src = &nexthop->src;
1702
hasso206d8052005-04-09 16:38:51 +00001703 if (IS_ZEBRA_DEBUG_KERNEL)
1704 zlog_debug("netlink_route_multipath() (recursive, "
1705 "multihop): nexthop via %s if %u",
1706 inet_ntoa (nexthop->rgate.ipv4),
1707 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001708 }
paul718e3742002-12-13 20:15:29 +00001709#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001710 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1711 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1712 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001713 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001714 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001715 &nexthop->rgate.ipv6, bytelen);
1716
1717 if (IS_ZEBRA_DEBUG_KERNEL)
1718 zlog_debug("netlink_route_multipath() (recursive, "
1719 "multihop): nexthop via %s if %u",
1720 inet6_ntoa (nexthop->rgate.ipv6),
1721 nexthop->rifindex);
1722 }
paul718e3742002-12-13 20:15:29 +00001723#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001724 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001725 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1726 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1727 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1728 {
1729 rtnh->rtnh_ifindex = nexthop->rifindex;
1730 if (nexthop->src.ipv4.s_addr)
1731 src = &nexthop->src;
1732
1733 if (IS_ZEBRA_DEBUG_KERNEL)
1734 zlog_debug("netlink_route_multipath() (recursive, "
1735 "multihop): nexthop via if %u",
1736 nexthop->rifindex);
1737 }
1738 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001739 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001740 {
1741 rtnh->rtnh_ifindex = nexthop->rifindex;
1742
1743 if (IS_ZEBRA_DEBUG_KERNEL)
1744 zlog_debug("netlink_route_multipath() (recursive, "
1745 "multihop): nexthop via if %u",
1746 nexthop->rifindex);
1747 }
paul7021c422003-07-15 12:52:22 +00001748 else
hasso206d8052005-04-09 16:38:51 +00001749 {
1750 rtnh->rtnh_ifindex = 0;
1751 }
paul7021c422003-07-15 12:52:22 +00001752 }
1753 else
1754 {
1755 if (IS_ZEBRA_DEBUG_KERNEL)
1756 {
hasso206d8052005-04-09 16:38:51 +00001757 zlog_debug ("netlink_route_multipath() (multihop): "
1758 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001759#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001760 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001761 inet6_ntoa (p->u.prefix6),
1762#else
1763 inet_ntoa (p->u.prefix4),
1764#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001765 p->prefixlen, nexthop_type_to_str (nexthop->type));
paul7021c422003-07-15 12:52:22 +00001766 }
1767 if (nexthop->type == NEXTHOP_TYPE_IPV4
1768 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1769 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001770 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001771 &nexthop->gate.ipv4, bytelen);
1772 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1773
Paul Jakma7514fb72007-05-02 16:05:35 +00001774 if (nexthop->src.ipv4.s_addr)
1775 src = &nexthop->src;
1776
hasso206d8052005-04-09 16:38:51 +00001777 if (IS_ZEBRA_DEBUG_KERNEL)
1778 zlog_debug("netlink_route_multipath() (multihop): "
1779 "nexthop via %s if %u",
1780 inet_ntoa (nexthop->gate.ipv4),
1781 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001782 }
paul718e3742002-12-13 20:15:29 +00001783#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001784 if (nexthop->type == NEXTHOP_TYPE_IPV6
1785 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1786 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001787 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001788 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001789 &nexthop->gate.ipv6, bytelen);
1790
1791 if (IS_ZEBRA_DEBUG_KERNEL)
1792 zlog_debug("netlink_route_multipath() (multihop): "
1793 "nexthop via %s if %u",
1794 inet6_ntoa (nexthop->gate.ipv6),
1795 nexthop->ifindex);
1796 }
paul718e3742002-12-13 20:15:29 +00001797#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001798 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001799 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1800 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1801 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1802 {
1803 rtnh->rtnh_ifindex = nexthop->ifindex;
1804 if (nexthop->src.ipv4.s_addr)
1805 src = &nexthop->src;
1806 if (IS_ZEBRA_DEBUG_KERNEL)
1807 zlog_debug("netlink_route_multipath() (multihop): "
1808 "nexthop via if %u", nexthop->ifindex);
1809 }
1810 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001811 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001812 {
1813 rtnh->rtnh_ifindex = nexthop->ifindex;
1814
1815 if (IS_ZEBRA_DEBUG_KERNEL)
1816 zlog_debug("netlink_route_multipath() (multihop): "
1817 "nexthop via if %u", nexthop->ifindex);
1818 }
paul7021c422003-07-15 12:52:22 +00001819 else
hasso206d8052005-04-09 16:38:51 +00001820 {
1821 rtnh->rtnh_ifindex = 0;
1822 }
paul7021c422003-07-15 12:52:22 +00001823 }
1824 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001825
paul7021c422003-07-15 12:52:22 +00001826 if (cmd == RTM_NEWROUTE)
1827 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1828 }
1829 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001830 if (src)
1831 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001832
1833 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001834 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001835 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001836 }
1837
1838 /* If there is no useful nexthop then return. */
1839 if (nexthop_num == 0)
1840 {
1841 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001842 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001843 return 0;
1844 }
1845
paul7021c422003-07-15 12:52:22 +00001846skip:
paul718e3742002-12-13 20:15:29 +00001847
1848 /* Destination netlink address. */
1849 memset (&snl, 0, sizeof snl);
1850 snl.nl_family = AF_NETLINK;
1851
paul718e3742002-12-13 20:15:29 +00001852 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001853 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001854}
1855
1856int
1857kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1858{
1859 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1860}
1861
1862int
1863kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1864{
1865 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1866}
1867
1868#ifdef HAVE_IPV6
1869int
1870kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1871{
1872 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1873}
1874
1875int
1876kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1877{
1878 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1879}
1880
1881/* Delete IPv6 route from the kernel. */
1882int
1883kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001884 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001885{
paul7021c422003-07-15 12:52:22 +00001886 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1887 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001888}
1889#endif /* HAVE_IPV6 */
1890
1891/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001892static int
paul718e3742002-12-13 20:15:29 +00001893netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001894 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001895{
1896 int bytelen;
1897 struct prefix *p;
1898
paul7021c422003-07-15 12:52:22 +00001899 struct
paul718e3742002-12-13 20:15:29 +00001900 {
1901 struct nlmsghdr n;
1902 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001903 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001904 } req;
1905
1906 p = ifc->address;
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001907 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001908
1909 bytelen = (family == AF_INET ? 4 : 16);
1910
paul7021c422003-07-15 12:52:22 +00001911 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001912 req.n.nlmsg_flags = NLM_F_REQUEST;
1913 req.n.nlmsg_type = cmd;
1914 req.ifa.ifa_family = family;
1915
1916 req.ifa.ifa_index = ifp->ifindex;
1917 req.ifa.ifa_prefixlen = p->prefixlen;
1918
1919 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1920
1921 if (family == AF_INET && cmd == RTM_NEWADDR)
1922 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001923 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001924 {
1925 p = ifc->destination;
1926 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1927 bytelen);
1928 }
paul718e3742002-12-13 20:15:29 +00001929 }
1930
1931 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1932 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001933
paul718e3742002-12-13 20:15:29 +00001934 if (ifc->label)
1935 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001936 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001937
1938 return netlink_talk (&req.n, &netlink_cmd);
1939}
1940
1941int
1942kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1943{
1944 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1945}
1946
1947int
1948kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1949{
1950 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1951}
1952
paul718e3742002-12-13 20:15:29 +00001953
1954extern struct thread_master *master;
1955
1956/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001957static int
paul718e3742002-12-13 20:15:29 +00001958kernel_read (struct thread *thread)
1959{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001960 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001961 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001962
1963 return 0;
1964}
1965
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001966/* Filter out messages from self that occur on listener socket,
1967 caused by our actions on the command socket
1968 */
1969static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001970{
Paul Jakma768a27e2008-05-29 18:23:08 +00001971 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001972 /* 0: ldh [4] */
1973 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1974 /* 1: jeq 0x18 jt 3 jf 6 */
1975 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1976 /* 2: jeq 0x19 jt 3 jf 6 */
1977 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1978 /* 3: ldw [12] */
1979 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1980 /* 4: jeq XX jt 5 jf 6 */
1981 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1982 /* 5: ret 0 (skip) */
1983 BPF_STMT(BPF_RET|BPF_K, 0),
1984 /* 6: ret 0xffff (keep) */
1985 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001986 };
1987
1988 struct sock_fprog prog = {
Balaji.G837d16c2012-09-26 14:09:10 +05301989 .len = array_size(filter),
Paul Jakma768a27e2008-05-29 18:23:08 +00001990 .filter = filter,
1991 };
1992
1993 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1994 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1995}
1996
paul718e3742002-12-13 20:15:29 +00001997/* Exported interface function. This function simply calls
1998 netlink_socket (). */
1999void
paul6621ca82005-11-23 13:02:08 +00002000kernel_init (void)
paul718e3742002-12-13 20:15:29 +00002001{
2002 unsigned long groups;
2003
paul7021c422003-07-15 12:52:22 +00002004 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00002005#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00002006 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00002007#endif /* HAVE_IPV6 */
2008 netlink_socket (&netlink, groups);
2009 netlink_socket (&netlink_cmd, 0);
2010
2011 /* Register kernel socket. */
2012 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00002013 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01002014 /* Only want non-blocking on the netlink event socket */
2015 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
2016 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
2017 safe_strerror (errno));
2018
Stephen Hemminger30afea32008-08-16 18:25:47 +01002019 /* Set receive buffer size if it's set from command line */
2020 if (nl_rcvbufsize)
2021 netlink_recvbuf (&netlink, nl_rcvbufsize);
2022
Stephen Hemminger3d265b42008-08-16 17:30:39 +01002023 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00002024 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
2025 }
paul718e3742002-12-13 20:15:29 +00002026}
Avneesh Sachdev78deec42012-11-13 22:48:56 +00002027
2028/*
2029 * nl_msg_type_to_str
2030 */
2031const char *
2032nl_msg_type_to_str (uint16_t msg_type)
2033{
2034 return lookup (nlmsg_str, msg_type);
2035}
2036
2037/*
2038 * nl_rtproto_to_str
2039 */
2040const char *
2041nl_rtproto_to_str (u_char rtproto)
2042{
2043 return lookup (rtproto_str, rtproto);
2044}