blob: 5909131ddbc2e55f3dcdf63e5e46b8b7134d4911 [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
JR Rivers3cadc0c2012-04-01 12:16:31 -070046#define NL_PKT_BUF_SIZE 4096
47
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
Stephen Hemminger6072b242008-08-14 16:52:26 +010071static const char *nexthop_types_desc[] =
paul7021c422003-07-15 12:52:22 +000072{
73 "none",
74 "Directly connected",
75 "Interface route",
76 "IPv4 nexthop",
77 "IPv4 nexthop with ifindex",
78 "IPv4 nexthop with ifname",
hassofa599802005-04-09 16:59:28 +000079 "IPv6 nexthop",
paul7021c422003-07-15 12:52:22 +000080 "IPv6 nexthop with ifindex",
81 "IPv6 nexthop with ifname",
82 "Null0 nexthop",
83};
84
paulb21b19c2003-06-15 01:28:29 +000085extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000086
pauledd7c242003-06-04 13:59:38 +000087extern struct zebra_privs_t zserv_privs;
88
hassoc34b6b52004-08-31 13:41:49 +000089extern u_int32_t nl_rcvbufsize;
90
ajsd2fc8892005-04-02 18:38:43 +000091/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
92 names and ifindex values. */
93static void
94set_ifindex(struct interface *ifp, unsigned int ifi_index)
95{
96 struct interface *oifp;
97
98 if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
99 {
100 if (ifi_index == IFINDEX_INTERNAL)
101 zlog_err("Netlink is setting interface %s ifindex to reserved "
102 "internal value %u", ifp->name, ifi_index);
103 else
104 {
105 if (IS_ZEBRA_DEBUG_KERNEL)
106 zlog_debug("interface index %d was renamed from %s to %s",
107 ifi_index, oifp->name, ifp->name);
108 if (if_is_up(oifp))
109 zlog_err("interface rename detected on up interface: index %d "
110 "was renamed from %s to %s, results are uncertain!",
111 ifi_index, oifp->name, ifp->name);
112 if_delete_update(oifp);
113 }
114 }
115 ifp->ifindex = ifi_index;
116}
117
Stephen Hemminger30afea32008-08-16 18:25:47 +0100118static int
119netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
120{
121 u_int32_t oldsize;
122 socklen_t newlen = sizeof(newsize);
123 socklen_t oldlen = sizeof(oldsize);
124 int ret;
125
126 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
127 if (ret < 0)
128 {
129 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
130 safe_strerror (errno));
131 return -1;
132 }
133
134 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
135 sizeof(nl_rcvbufsize));
136 if (ret < 0)
137 {
138 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
139 safe_strerror (errno));
140 return -1;
141 }
142
143 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
144 if (ret < 0)
145 {
146 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
147 safe_strerror (errno));
148 return -1;
149 }
150
151 zlog (NULL, LOG_INFO,
152 "Setting netlink socket receive buffer size: %u -> %u",
153 oldsize, newsize);
154 return 0;
155}
156
paul718e3742002-12-13 20:15:29 +0000157/* Make socket for Linux netlink interface. */
158static int
159netlink_socket (struct nlsock *nl, unsigned long groups)
160{
161 int ret;
162 struct sockaddr_nl snl;
163 int sock;
164 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000165 int save_errno;
paul718e3742002-12-13 20:15:29 +0000166
167 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
168 if (sock < 0)
169 {
170 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000171 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000172 return -1;
173 }
174
paul718e3742002-12-13 20:15:29 +0000175 memset (&snl, 0, sizeof snl);
176 snl.nl_family = AF_NETLINK;
177 snl.nl_groups = groups;
178
179 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000180 if (zserv_privs.change (ZPRIVS_RAISE))
181 {
182 zlog (NULL, LOG_ERR, "Can't raise privileges");
183 return -1;
184 }
pauledd7c242003-06-04 13:59:38 +0000185
paul718e3742002-12-13 20:15:29 +0000186 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000187 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000188 if (zserv_privs.change (ZPRIVS_LOWER))
189 zlog (NULL, LOG_ERR, "Can't lower privileges");
190
paul718e3742002-12-13 20:15:29 +0000191 if (ret < 0)
192 {
paul7021c422003-07-15 12:52:22 +0000193 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000194 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000195 close (sock);
196 return -1;
197 }
paul7021c422003-07-15 12:52:22 +0000198
paul718e3742002-12-13 20:15:29 +0000199 /* multiple netlink sockets will have different nl_pid */
200 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000201 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000202 if (ret < 0 || namelen != sizeof snl)
203 {
204 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000205 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000206 close (sock);
207 return -1;
208 }
209
210 nl->snl = snl;
211 nl->sock = sock;
212 return ret;
213}
214
215/* Get type specified information from netlink. */
216static int
217netlink_request (int family, int type, struct nlsock *nl)
218{
219 int ret;
220 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000221 int save_errno;
paul718e3742002-12-13 20:15:29 +0000222
223 struct
224 {
225 struct nlmsghdr nlh;
226 struct rtgenmsg g;
227 } req;
228
229
230 /* Check netlink socket. */
231 if (nl->sock < 0)
232 {
233 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
234 return -1;
235 }
236
237 memset (&snl, 0, sizeof snl);
238 snl.nl_family = AF_NETLINK;
239
ajsc05612b2005-10-01 16:36:54 +0000240 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000241 req.nlh.nlmsg_len = sizeof req;
242 req.nlh.nlmsg_type = type;
243 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100244 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000245 req.nlh.nlmsg_seq = ++nl->seq;
246 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000247
248 /* linux appears to check capabilities on every message
249 * have to raise caps for every message sent
250 */
paul7021c422003-07-15 12:52:22 +0000251 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000252 {
253 zlog (NULL, LOG_ERR, "Can't raise privileges");
254 return -1;
255 }
paul7021c422003-07-15 12:52:22 +0000256
257 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
258 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000259 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000260
261 if (zserv_privs.change (ZPRIVS_LOWER))
262 zlog (NULL, LOG_ERR, "Can't lower privileges");
263
paul718e3742002-12-13 20:15:29 +0000264 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000265 {
266 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000267 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000268 return -1;
269 }
pauledd7c242003-06-04 13:59:38 +0000270
paul718e3742002-12-13 20:15:29 +0000271 return 0;
272}
273
274/* Receive message from netlink interface and pass those information
275 to the given function. */
276static int
277netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000278 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000279{
280 int status;
281 int ret = 0;
282 int error;
283
284 while (1)
285 {
JR Rivers3cadc0c2012-04-01 12:16:31 -0700286 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +0000287 struct iovec iov = { buf, sizeof buf };
288 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000289 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000290 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000291
paul718e3742002-12-13 20:15:29 +0000292 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000293 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000294 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100295 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000296 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100297 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000298 break;
ajs4be019d2005-01-29 16:12:41 +0000299 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100300 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000301 continue;
302 }
paul718e3742002-12-13 20:15:29 +0000303
304 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000305 {
306 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
307 return -1;
308 }
paul718e3742002-12-13 20:15:29 +0000309
310 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000311 {
312 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
313 nl->name, msg.msg_namelen);
314 return -1;
315 }
paulb84d3a12003-11-17 10:31:01 +0000316
hasso206d8052005-04-09 16:38:51 +0000317 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000318 h = NLMSG_NEXT (h, status))
319 {
320 /* Finish of reading. */
321 if (h->nlmsg_type == NLMSG_DONE)
322 return ret;
paul718e3742002-12-13 20:15:29 +0000323
paul7021c422003-07-15 12:52:22 +0000324 /* Error handling. */
325 if (h->nlmsg_type == NLMSG_ERROR)
326 {
327 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100328 int errnum = err->error;
329 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000330
paul718e3742002-12-13 20:15:29 +0000331 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000332 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000333 {
paul7021c422003-07-15 12:52:22 +0000334 if (IS_ZEBRA_DEBUG_KERNEL)
335 {
hasso1ada8192005-06-12 11:28:18 +0000336 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000337 __FUNCTION__, nl->name,
338 lookup (nlmsg_str, err->msg.nlmsg_type),
339 err->msg.nlmsg_type, err->msg.nlmsg_seq,
340 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000341 }
paul7021c422003-07-15 12:52:22 +0000342
343 /* return if not a multipart message, otherwise continue */
344 if (!(h->nlmsg_flags & NLM_F_MULTI))
345 {
346 return 0;
paul718e3742002-12-13 20:15:29 +0000347 }
paul7021c422003-07-15 12:52:22 +0000348 continue;
paul718e3742002-12-13 20:15:29 +0000349 }
paul7021c422003-07-15 12:52:22 +0000350
paul718e3742002-12-13 20:15:29 +0000351 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000352 {
353 zlog (NULL, LOG_ERR, "%s error: message truncated",
354 nl->name);
355 return -1;
356 }
pauld753e9e2003-01-22 19:45:50 +0000357
Stephen Hemminger898987e2008-08-17 16:56:15 +0100358 /* Deal with errors that occur because of races in link handling */
359 if (nl == &netlink_cmd
360 && ((msg_type == RTM_DELROUTE &&
361 (-errnum == ENODEV || -errnum == ESRCH))
362 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
363 {
364 if (IS_ZEBRA_DEBUG_KERNEL)
365 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
366 nl->name, safe_strerror (-errnum),
367 lookup (nlmsg_str, msg_type),
368 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
369 return 0;
370 }
paul718e3742002-12-13 20:15:29 +0000371
Stephen Hemminger898987e2008-08-17 16:56:15 +0100372 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
373 nl->name, safe_strerror (-errnum),
374 lookup (nlmsg_str, msg_type),
375 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000376 return -1;
377 }
paul718e3742002-12-13 20:15:29 +0000378
paul7021c422003-07-15 12:52:22 +0000379 /* OK we got netlink message. */
380 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000381 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000382 nl->name,
383 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
384 h->nlmsg_seq, h->nlmsg_pid);
385
386 /* skip unsolicited messages originating from command socket */
387 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
388 {
389 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000390 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000391 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000392 continue;
393 }
394
395 error = (*filter) (&snl, h);
396 if (error < 0)
397 {
398 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
399 ret = error;
400 }
401 }
paul718e3742002-12-13 20:15:29 +0000402
403 /* After error care. */
404 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000405 {
406 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
407 continue;
408 }
paul718e3742002-12-13 20:15:29 +0000409 if (status)
paul7021c422003-07-15 12:52:22 +0000410 {
411 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
412 status);
413 return -1;
414 }
paul718e3742002-12-13 20:15:29 +0000415 }
416 return ret;
417}
418
419/* Utility function for parse rtattr. */
420static void
paul7021c422003-07-15 12:52:22 +0000421netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
422 int len)
paul718e3742002-12-13 20:15:29 +0000423{
paul7021c422003-07-15 12:52:22 +0000424 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000425 {
426 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000427 tb[rta->rta_type] = rta;
428 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000429 }
430}
431
Josh Bailey26e2ae32012-03-22 01:09:21 -0700432/* Utility function to parse hardware link-layer address and update ifp */
433static void
434netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
435{
436 int i;
437
438 if (tb[IFLA_ADDRESS])
439 {
440 int hw_addr_len;
441
442 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
443
444 if (hw_addr_len > INTERFACE_HWADDR_MAX)
445 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
446 else
447 {
448 ifp->hw_addr_len = hw_addr_len;
449 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
450
451 for (i = 0; i < hw_addr_len; i++)
452 if (ifp->hw_addr[i] != 0)
453 break;
454
455 if (i == hw_addr_len)
456 ifp->hw_addr_len = 0;
457 else
458 ifp->hw_addr_len = hw_addr_len;
459 }
460 }
461}
462
paul718e3742002-12-13 20:15:29 +0000463/* Called from interface_lookup_netlink(). This function is only used
464 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100465static int
paul718e3742002-12-13 20:15:29 +0000466netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
467{
468 int len;
469 struct ifinfomsg *ifi;
470 struct rtattr *tb[IFLA_MAX + 1];
471 struct interface *ifp;
472 char *name;
paul718e3742002-12-13 20:15:29 +0000473
474 ifi = NLMSG_DATA (h);
475
476 if (h->nlmsg_type != RTM_NEWLINK)
477 return 0;
478
479 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
480 if (len < 0)
481 return -1;
482
483 /* Looking up interface name. */
484 memset (tb, 0, sizeof tb);
485 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000486
paul1e193152005-02-14 23:53:05 +0000487#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000488 /* check for wireless messages to ignore */
489 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
490 {
491 if (IS_ZEBRA_DEBUG_KERNEL)
492 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
493 return 0;
494 }
paul1e193152005-02-14 23:53:05 +0000495#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000496
paul718e3742002-12-13 20:15:29 +0000497 if (tb[IFLA_IFNAME] == NULL)
498 return -1;
paul7021c422003-07-15 12:52:22 +0000499 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000500
501 /* Add interface. */
502 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000503 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000504 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800505 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000506 ifp->metric = 1;
507
508 /* Hardware type and address. */
509 ifp->hw_type = ifi->ifi_type;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700510 netlink_interface_update_hw_addr (tb, ifp);
paul718e3742002-12-13 20:15:29 +0000511
512 if_add_update (ifp);
513
514 return 0;
515}
516
517/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100518static int
paul718e3742002-12-13 20:15:29 +0000519netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
520{
521 int len;
522 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000523 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000524 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000525 void *addr;
526 void *broad;
paul718e3742002-12-13 20:15:29 +0000527 u_char flags = 0;
528 char *label = NULL;
529
530 ifa = NLMSG_DATA (h);
531
paul7021c422003-07-15 12:52:22 +0000532 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000533#ifdef HAVE_IPV6
534 && ifa->ifa_family != AF_INET6
535#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000536 )
paul718e3742002-12-13 20:15:29 +0000537 return 0;
538
539 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
540 return 0;
541
paul7021c422003-07-15 12:52:22 +0000542 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000543 if (len < 0)
544 return -1;
545
546 memset (tb, 0, sizeof tb);
547 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
548
549 ifp = if_lookup_by_index (ifa->ifa_index);
550 if (ifp == NULL)
551 {
552 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000553 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000554 return -1;
555 }
556
paul7021c422003-07-15 12:52:22 +0000557 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000558 {
paul00df0c12002-12-13 21:07:36 +0000559 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000560 zlog_debug ("netlink_interface_addr %s %s:",
561 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000562 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000563 zlog_debug (" IFA_LOCAL %s/%d",
564 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
565 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000566 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000567 zlog_debug (" IFA_ADDRESS %s/%d",
568 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
569 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000570 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000571 zlog_debug (" IFA_BROADCAST %s/%d",
572 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
573 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000574 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000575 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000576
577 if (tb[IFA_CACHEINFO])
578 {
579 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
580 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
581 ci->ifa_prefered, ci->ifa_valid);
582 }
paul718e3742002-12-13 20:15:29 +0000583 }
paul31a476c2003-09-29 19:54:53 +0000584
Andrew J. Schorre4529632006-12-12 19:18:21 +0000585 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
586 if (tb[IFA_LOCAL] == NULL)
587 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000588 if (tb[IFA_ADDRESS] == NULL)
589 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
590
Andrew J. Schorre4529632006-12-12 19:18:21 +0000591 /* local interface address */
592 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
593
594 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000595 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000596 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000597 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000598 broad = RTA_DATA(tb[IFA_ADDRESS]);
599 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000600 }
paul31a476c2003-09-29 19:54:53 +0000601 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000602 /* seeking a broadcast address */
603 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000604
Paul Jakma27b47252006-07-02 16:38:54 +0000605 /* addr is primary key, SOL if we don't have one */
606 if (addr == NULL)
607 {
608 zlog_debug ("%s: NULL address", __func__);
609 return -1;
610 }
611
paul718e3742002-12-13 20:15:29 +0000612 /* Flags. */
613 if (ifa->ifa_flags & IFA_F_SECONDARY)
614 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
615
616 /* Label */
617 if (tb[IFA_LABEL])
618 label = (char *) RTA_DATA (tb[IFA_LABEL]);
619
620 if (ifp && label && strcmp (ifp->name, label) == 0)
621 label = NULL;
622
623 /* Register interface address to the interface. */
624 if (ifa->ifa_family == AF_INET)
625 {
paul7021c422003-07-15 12:52:22 +0000626 if (h->nlmsg_type == RTM_NEWADDR)
627 connected_add_ipv4 (ifp, flags,
628 (struct in_addr *) addr, ifa->ifa_prefixlen,
629 (struct in_addr *) broad, label);
630 else
631 connected_delete_ipv4 (ifp, flags,
632 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000633 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000634 }
635#ifdef HAVE_IPV6
636 if (ifa->ifa_family == AF_INET6)
637 {
638 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000639 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000640 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000641 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000642 else
paul7021c422003-07-15 12:52:22 +0000643 connected_delete_ipv6 (ifp,
644 (struct in6_addr *) addr, ifa->ifa_prefixlen,
645 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000646 }
paul7021c422003-07-15 12:52:22 +0000647#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000648
649 return 0;
650}
651
652/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100653static int
paul718e3742002-12-13 20:15:29 +0000654netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
655{
656 int len;
657 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000658 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000659 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000660
661 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000662
663 int index;
664 int table;
hasso34195bf2004-04-06 12:07:06 +0000665 int metric;
666
paul718e3742002-12-13 20:15:29 +0000667 void *dest;
668 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000669 void *src;
paul718e3742002-12-13 20:15:29 +0000670
671 rtm = NLMSG_DATA (h);
672
673 if (h->nlmsg_type != RTM_NEWROUTE)
674 return 0;
675 if (rtm->rtm_type != RTN_UNICAST)
676 return 0;
677
678 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000679#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000680 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000681 return 0;
682#endif
683
paul7021c422003-07-15 12:52:22 +0000684 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000685 if (len < 0)
686 return -1;
687
688 memset (tb, 0, sizeof tb);
689 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
690
691 if (rtm->rtm_flags & RTM_F_CLONED)
692 return 0;
693 if (rtm->rtm_protocol == RTPROT_REDIRECT)
694 return 0;
695 if (rtm->rtm_protocol == RTPROT_KERNEL)
696 return 0;
697
698 if (rtm->rtm_src_len != 0)
699 return 0;
700
701 /* Route which inserted by Zebra. */
702 if (rtm->rtm_protocol == RTPROT_ZEBRA)
703 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000704
paul718e3742002-12-13 20:15:29 +0000705 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000706 metric = 0;
paul718e3742002-12-13 20:15:29 +0000707 dest = NULL;
708 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000709 src = NULL;
paul718e3742002-12-13 20:15:29 +0000710
711 if (tb[RTA_OIF])
712 index = *(int *) RTA_DATA (tb[RTA_OIF]);
713
714 if (tb[RTA_DST])
715 dest = RTA_DATA (tb[RTA_DST]);
716 else
717 dest = anyaddr;
718
Paul Jakma7514fb72007-05-02 16:05:35 +0000719 if (tb[RTA_PREFSRC])
720 src = RTA_DATA (tb[RTA_PREFSRC]);
721
paul718e3742002-12-13 20:15:29 +0000722 if (tb[RTA_GATEWAY])
723 gate = RTA_DATA (tb[RTA_GATEWAY]);
724
hasso34195bf2004-04-06 12:07:06 +0000725 if (tb[RTA_PRIORITY])
726 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
727
paul718e3742002-12-13 20:15:29 +0000728 if (rtm->rtm_family == AF_INET)
729 {
730 struct prefix_ipv4 p;
731 p.family = AF_INET;
732 memcpy (&p.prefix, dest, 4);
733 p.prefixlen = rtm->rtm_dst_len;
734
Josh Bailey26e2ae32012-03-22 01:09:21 -0700735 if (!tb[RTA_MULTIPATH])
736 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700737 table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700738 else
739 {
740 /* This is a multipath route */
741
742 struct rib *rib;
743 struct rtnexthop *rtnh =
744 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
745
746 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
747
748 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
749 rib->type = ZEBRA_ROUTE_KERNEL;
750 rib->distance = 0;
751 rib->flags = flags;
752 rib->metric = metric;
753 rib->table = table;
754 rib->nexthop_num = 0;
755 rib->uptime = time (NULL);
756
757 for (;;)
758 {
759 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
760 break;
761
762 rib->nexthop_num++;
763 index = rtnh->rtnh_ifindex;
764 gate = 0;
765 if (rtnh->rtnh_len > sizeof (*rtnh))
766 {
767 memset (tb, 0, sizeof (tb));
768 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
769 rtnh->rtnh_len - sizeof (*rtnh));
770 if (tb[RTA_GATEWAY])
771 gate = RTA_DATA (tb[RTA_GATEWAY]);
772 }
773
774 if (gate)
775 {
776 if (index)
777 nexthop_ipv4_ifindex_add (rib, gate, src, index);
778 else
779 nexthop_ipv4_add (rib, gate, src);
780 }
781 else
782 nexthop_ifindex_add (rib, index);
783
784 len -= NLMSG_ALIGN(rtnh->rtnh_len);
785 rtnh = RTNH_NEXT(rtnh);
786 }
787
788 if (rib->nexthop_num == 0)
789 XFREE (MTYPE_RIB, rib);
790 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700791 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700792 }
paul718e3742002-12-13 20:15:29 +0000793 }
794#ifdef HAVE_IPV6
795 if (rtm->rtm_family == AF_INET6)
796 {
797 struct prefix_ipv6 p;
798 p.family = AF_INET6;
799 memcpy (&p.prefix, dest, 16);
800 p.prefixlen = rtm->rtm_dst_len;
801
hassobe61c4e2005-08-27 06:05:47 +0000802 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
G.Balajif768f362011-11-26 22:10:39 +0400803 metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000804 }
805#endif /* HAVE_IPV6 */
806
807 return 0;
808}
809
Stephen Hemminger1423c802008-08-14 17:59:25 +0100810static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000811 {RTPROT_REDIRECT, "redirect"},
812 {RTPROT_KERNEL, "kernel"},
813 {RTPROT_BOOT, "boot"},
814 {RTPROT_STATIC, "static"},
815 {RTPROT_GATED, "GateD"},
816 {RTPROT_RA, "router advertisement"},
817 {RTPROT_MRT, "MRT"},
818 {RTPROT_ZEBRA, "Zebra"},
819#ifdef RTPROT_BIRD
820 {RTPROT_BIRD, "BIRD"},
821#endif /* RTPROT_BIRD */
822 {0, NULL}
823};
824
825/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100826static int
paul718e3742002-12-13 20:15:29 +0000827netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
828{
829 int len;
830 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000831 struct rtattr *tb[RTA_MAX + 1];
832
833 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000834
835 int index;
836 int table;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700837 int metric;
Dmitry Popov83d16142011-09-11 13:48:25 +0400838
paul718e3742002-12-13 20:15:29 +0000839 void *dest;
840 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000841 void *src;
paul718e3742002-12-13 20:15:29 +0000842
843 rtm = NLMSG_DATA (h);
844
paul7021c422003-07-15 12:52:22 +0000845 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000846 {
847 /* If this is not route add/delete message print warning. */
848 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
849 return 0;
850 }
851
852 /* Connected route. */
853 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000854 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000855 h->nlmsg_type ==
856 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
857 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
858 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
859 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000860
861 if (rtm->rtm_type != RTN_UNICAST)
862 {
863 return 0;
864 }
865
866 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000867 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000868 {
869 return 0;
870 }
871
paul7021c422003-07-15 12:52:22 +0000872 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000873 if (len < 0)
874 return -1;
875
876 memset (tb, 0, sizeof tb);
877 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
878
879 if (rtm->rtm_flags & RTM_F_CLONED)
880 return 0;
881 if (rtm->rtm_protocol == RTPROT_REDIRECT)
882 return 0;
883 if (rtm->rtm_protocol == RTPROT_KERNEL)
884 return 0;
885
886 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
887 return 0;
888
889 if (rtm->rtm_src_len != 0)
890 {
891 zlog_warn ("netlink_route_change(): no src len");
892 return 0;
893 }
paul7021c422003-07-15 12:52:22 +0000894
paul718e3742002-12-13 20:15:29 +0000895 index = 0;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700896 metric = 0;
paul718e3742002-12-13 20:15:29 +0000897 dest = NULL;
898 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000899 src = NULL;
paul718e3742002-12-13 20:15:29 +0000900
901 if (tb[RTA_OIF])
902 index = *(int *) RTA_DATA (tb[RTA_OIF]);
903
904 if (tb[RTA_DST])
905 dest = RTA_DATA (tb[RTA_DST]);
906 else
907 dest = anyaddr;
908
909 if (tb[RTA_GATEWAY])
910 gate = RTA_DATA (tb[RTA_GATEWAY]);
911
Paul Jakma7514fb72007-05-02 16:05:35 +0000912 if (tb[RTA_PREFSRC])
913 src = RTA_DATA (tb[RTA_PREFSRC]);
914
Dmitry Popov83d16142011-09-11 13:48:25 +0400915 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
Josh Bailey26e2ae32012-03-22 01:09:21 -0700916 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
917
paul718e3742002-12-13 20:15:29 +0000918 if (rtm->rtm_family == AF_INET)
919 {
920 struct prefix_ipv4 p;
921 p.family = AF_INET;
922 memcpy (&p.prefix, dest, 4);
923 p.prefixlen = rtm->rtm_dst_len;
924
925 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000926 {
927 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000928 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000929 inet_ntoa (p.prefix), p.prefixlen);
930 else
ajsb6178002004-12-07 21:12:56 +0000931 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000932 inet_ntoa (p.prefix), p.prefixlen);
933 }
paul718e3742002-12-13 20:15:29 +0000934
935 if (h->nlmsg_type == RTM_NEWROUTE)
Josh Bailey26e2ae32012-03-22 01:09:21 -0700936 {
937 if (!tb[RTA_MULTIPATH])
938 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700939 metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700940 else
941 {
942 /* This is a multipath route */
943
944 struct rib *rib;
945 struct rtnexthop *rtnh =
946 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
947
948 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
949
950 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
951 rib->type = ZEBRA_ROUTE_KERNEL;
952 rib->distance = 0;
953 rib->flags = 0;
954 rib->metric = metric;
955 rib->table = table;
956 rib->nexthop_num = 0;
957 rib->uptime = time (NULL);
958
959 for (;;)
960 {
961 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
962 break;
963
964 rib->nexthop_num++;
965 index = rtnh->rtnh_ifindex;
966 gate = 0;
967 if (rtnh->rtnh_len > sizeof (*rtnh))
968 {
969 memset (tb, 0, sizeof (tb));
970 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
971 rtnh->rtnh_len - sizeof (*rtnh));
972 if (tb[RTA_GATEWAY])
973 gate = RTA_DATA (tb[RTA_GATEWAY]);
974 }
975
976 if (gate)
977 {
978 if (index)
979 nexthop_ipv4_ifindex_add (rib, gate, src, index);
980 else
981 nexthop_ipv4_add (rib, gate, src);
982 }
983 else
984 nexthop_ifindex_add (rib, index);
985
986 len -= NLMSG_ALIGN(rtnh->rtnh_len);
987 rtnh = RTNH_NEXT(rtnh);
988 }
989
990 if (rib->nexthop_num == 0)
991 XFREE (MTYPE_RIB, rib);
992 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700993 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700994 }
995 }
paul718e3742002-12-13 20:15:29 +0000996 else
G.Balajicddf3912011-11-26 21:59:32 +0400997 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000998 }
999
1000#ifdef HAVE_IPV6
1001 if (rtm->rtm_family == AF_INET6)
1002 {
1003 struct prefix_ipv6 p;
1004 char buf[BUFSIZ];
1005
1006 p.family = AF_INET6;
1007 memcpy (&p.prefix, dest, 16);
1008 p.prefixlen = rtm->rtm_dst_len;
1009
1010 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +00001011 {
1012 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +00001013 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001014 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1015 p.prefixlen);
1016 else
ajsb6178002004-12-07 21:12:56 +00001017 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001018 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1019 p.prefixlen);
1020 }
paul718e3742002-12-13 20:15:29 +00001021
1022 if (h->nlmsg_type == RTM_NEWROUTE)
G.Balajif768f362011-11-26 22:10:39 +04001023 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001024 else
G.Balajif768f362011-11-26 22:10:39 +04001025 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001026 }
1027#endif /* HAVE_IPV6 */
1028
1029 return 0;
1030}
1031
Stephen Hemminger6072b242008-08-14 16:52:26 +01001032static int
paul718e3742002-12-13 20:15:29 +00001033netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
1034{
1035 int len;
1036 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +00001037 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +00001038 struct interface *ifp;
1039 char *name;
1040
1041 ifi = NLMSG_DATA (h);
1042
paul7021c422003-07-15 12:52:22 +00001043 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +00001044 {
1045 /* If this is not link add/delete message so print warning. */
1046 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +00001047 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001048 return 0;
1049 }
1050
1051 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1052 if (len < 0)
1053 return -1;
1054
1055 /* Looking up interface name. */
1056 memset (tb, 0, sizeof tb);
1057 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +00001058
paul1e193152005-02-14 23:53:05 +00001059#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +00001060 /* check for wireless messages to ignore */
1061 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1062 {
1063 if (IS_ZEBRA_DEBUG_KERNEL)
1064 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
1065 return 0;
1066 }
paul1e193152005-02-14 23:53:05 +00001067#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001068
paul718e3742002-12-13 20:15:29 +00001069 if (tb[IFLA_IFNAME] == NULL)
1070 return -1;
paul7021c422003-07-15 12:52:22 +00001071 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001072
1073 /* Add interface. */
1074 if (h->nlmsg_type == RTM_NEWLINK)
1075 {
1076 ifp = if_lookup_by_name (name);
1077
paul7021c422003-07-15 12:52:22 +00001078 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1079 {
1080 if (ifp == NULL)
1081 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001082
ajsd2fc8892005-04-02 18:38:43 +00001083 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001084 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001085 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001086 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001087
Josh Bailey26e2ae32012-03-22 01:09:21 -07001088 netlink_interface_update_hw_addr (tb, ifp);
1089
paul7021c422003-07-15 12:52:22 +00001090 /* If new link is added. */
1091 if_add_update (ifp);
1092 }
paul718e3742002-12-13 20:15:29 +00001093 else
paul7021c422003-07-15 12:52:22 +00001094 {
1095 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001096 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001097 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001098 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001099
Josh Bailey26e2ae32012-03-22 01:09:21 -07001100 netlink_interface_update_hw_addr (tb, ifp);
1101
paul7021c422003-07-15 12:52:22 +00001102 if (if_is_operative (ifp))
1103 {
1104 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1105 if (!if_is_operative (ifp))
1106 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001107 else
1108 /* Must notify client daemons of new interface status. */
1109 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001110 }
1111 else
1112 {
1113 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1114 if (if_is_operative (ifp))
1115 if_up (ifp);
1116 }
1117 }
paul718e3742002-12-13 20:15:29 +00001118 }
1119 else
1120 {
1121 /* RTM_DELLINK. */
1122 ifp = if_lookup_by_name (name);
1123
1124 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001125 {
1126 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001127 name);
paul7021c422003-07-15 12:52:22 +00001128 return 0;
1129 }
1130
paul718e3742002-12-13 20:15:29 +00001131 if_delete_update (ifp);
1132 }
1133
1134 return 0;
1135}
1136
Stephen Hemminger6072b242008-08-14 16:52:26 +01001137static int
paul718e3742002-12-13 20:15:29 +00001138netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1139{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001140 /* JF: Ignore messages that aren't from the kernel */
1141 if ( snl->nl_pid != 0 )
1142 {
1143 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1144 return 0;
1145 }
1146
paul718e3742002-12-13 20:15:29 +00001147 switch (h->nlmsg_type)
1148 {
1149 case RTM_NEWROUTE:
1150 return netlink_route_change (snl, h);
1151 break;
1152 case RTM_DELROUTE:
1153 return netlink_route_change (snl, h);
1154 break;
1155 case RTM_NEWLINK:
1156 return netlink_link_change (snl, h);
1157 break;
1158 case RTM_DELLINK:
1159 return netlink_link_change (snl, h);
1160 break;
1161 case RTM_NEWADDR:
1162 return netlink_interface_addr (snl, h);
1163 break;
1164 case RTM_DELADDR:
1165 return netlink_interface_addr (snl, h);
1166 break;
1167 default:
1168 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1169 break;
1170 }
1171 return 0;
1172}
1173
1174/* Interface lookup by netlink socket. */
1175int
paul6621ca82005-11-23 13:02:08 +00001176interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001177{
1178 int ret;
paul7021c422003-07-15 12:52:22 +00001179
paul718e3742002-12-13 20:15:29 +00001180 /* Get interface information. */
1181 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1182 if (ret < 0)
1183 return ret;
1184 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1185 if (ret < 0)
1186 return ret;
1187
1188 /* Get IPv4 address of the interfaces. */
1189 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1190 if (ret < 0)
1191 return ret;
1192 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1193 if (ret < 0)
1194 return ret;
1195
1196#ifdef HAVE_IPV6
1197 /* Get IPv6 address of the interfaces. */
1198 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1199 if (ret < 0)
1200 return ret;
1201 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1202 if (ret < 0)
1203 return ret;
1204#endif /* HAVE_IPV6 */
1205
1206 return 0;
1207}
1208
1209/* Routing table read function using netlink interface. Only called
1210 bootstrap time. */
1211int
paul6621ca82005-11-23 13:02:08 +00001212netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001213{
1214 int ret;
paul7021c422003-07-15 12:52:22 +00001215
paul718e3742002-12-13 20:15:29 +00001216 /* Get IPv4 routing table. */
1217 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1218 if (ret < 0)
1219 return ret;
1220 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1221 if (ret < 0)
1222 return ret;
1223
1224#ifdef HAVE_IPV6
1225 /* Get IPv6 routing table. */
1226 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1227 if (ret < 0)
1228 return ret;
1229 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1230 if (ret < 0)
1231 return ret;
1232#endif /* HAVE_IPV6 */
1233
1234 return 0;
1235}
1236
1237/* Utility function comes from iproute2.
1238 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001239static int
paul718e3742002-12-13 20:15:29 +00001240addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1241{
1242 int len;
1243 struct rtattr *rta;
1244
paul7021c422003-07-15 12:52:22 +00001245 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001246
paul7021c422003-07-15 12:52:22 +00001247 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001248 return -1;
1249
paul7021c422003-07-15 12:52:22 +00001250 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001251 rta->rta_type = type;
1252 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001253 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001254 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1255
1256 return 0;
1257}
1258
Stephen Hemminger6072b242008-08-14 16:52:26 +01001259static int
paul718e3742002-12-13 20:15:29 +00001260rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1261{
1262 int len;
1263 struct rtattr *subrta;
1264
paul7021c422003-07-15 12:52:22 +00001265 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001266
paul7021c422003-07-15 12:52:22 +00001267 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001268 return -1;
1269
paul7021c422003-07-15 12:52:22 +00001270 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001271 subrta->rta_type = type;
1272 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001273 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001274 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1275
1276 return 0;
1277}
1278
1279/* Utility function comes from iproute2.
1280 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001281static int
paul718e3742002-12-13 20:15:29 +00001282addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1283{
1284 int len;
1285 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001286
1287 len = RTA_LENGTH (4);
1288
paul718e3742002-12-13 20:15:29 +00001289 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1290 return -1;
1291
paul7021c422003-07-15 12:52:22 +00001292 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001293 rta->rta_type = type;
1294 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001295 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001296 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1297
1298 return 0;
1299}
1300
1301static int
1302netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1303{
hassob7ed1ec2005-03-31 20:13:49 +00001304 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001305 return 0;
1306}
1307
1308/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001309static int
paul718e3742002-12-13 20:15:29 +00001310netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1311{
1312 int status;
1313 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001314 struct iovec iov = { (void *) n, n->nlmsg_len };
1315 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001316 int save_errno;
paul7021c422003-07-15 12:52:22 +00001317
paul718e3742002-12-13 20:15:29 +00001318 memset (&snl, 0, sizeof snl);
1319 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001320
hassob7ed1ec2005-03-31 20:13:49 +00001321 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001322
1323 /* Request an acknowledgement by setting NLM_F_ACK */
1324 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001325
1326 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001327 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001328 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1329 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001330
1331 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001332 if (zserv_privs.change (ZPRIVS_RAISE))
1333 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001334 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001335 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001336 if (zserv_privs.change (ZPRIVS_LOWER))
1337 zlog (NULL, LOG_ERR, "Can't lower privileges");
1338
paul718e3742002-12-13 20:15:29 +00001339 if (status < 0)
1340 {
1341 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001342 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001343 return -1;
1344 }
paul7021c422003-07-15 12:52:22 +00001345
paul718e3742002-12-13 20:15:29 +00001346
1347 /*
1348 * Get reply from netlink socket.
1349 * The reply should either be an acknowlegement or an error.
1350 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001351 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001352}
1353
1354/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001355static int
paul718e3742002-12-13 20:15:29 +00001356netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001357 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001358{
1359 int ret;
1360 int bytelen;
1361 struct sockaddr_nl snl;
1362 int discard;
1363
paul7021c422003-07-15 12:52:22 +00001364 struct
paul718e3742002-12-13 20:15:29 +00001365 {
1366 struct nlmsghdr n;
1367 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001368 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001369 } req;
1370
1371 memset (&req, 0, sizeof req);
1372
1373 bytelen = (family == AF_INET ? 4 : 16);
1374
1375 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1376 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1377 req.n.nlmsg_type = cmd;
1378 req.r.rtm_family = family;
1379 req.r.rtm_table = table;
1380 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001381 req.r.rtm_protocol = RTPROT_ZEBRA;
1382 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001383
hasso81dfcaa2003-05-25 19:21:25 +00001384 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1385 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001386 discard = 1;
1387 else
1388 discard = 0;
1389
paul7021c422003-07-15 12:52:22 +00001390 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001391 {
paul7021c422003-07-15 12:52:22 +00001392 if (discard)
paul595db7f2003-05-25 21:35:06 +00001393 {
1394 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1395 req.r.rtm_type = RTN_BLACKHOLE;
1396 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1397 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001398 else
1399 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1400 }
paul595db7f2003-05-25 21:35:06 +00001401 else
paul7021c422003-07-15 12:52:22 +00001402 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001403 }
1404
1405 if (dest)
1406 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1407
paul7021c422003-07-15 12:52:22 +00001408 if (!discard)
paul718e3742002-12-13 20:15:29 +00001409 {
1410 if (gate)
paul7021c422003-07-15 12:52:22 +00001411 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001412 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001413 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001414 }
1415
1416 /* Destination netlink address. */
1417 memset (&snl, 0, sizeof snl);
1418 snl.nl_family = AF_NETLINK;
1419
1420 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001421 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001422 if (ret < 0)
1423 return -1;
1424
1425 return 0;
1426}
1427
1428/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001429static int
paul718e3742002-12-13 20:15:29 +00001430netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001431 int family)
paul718e3742002-12-13 20:15:29 +00001432{
1433 int bytelen;
1434 struct sockaddr_nl snl;
1435 struct nexthop *nexthop = NULL;
1436 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001437 int discard;
1438
paul7021c422003-07-15 12:52:22 +00001439 struct
paul718e3742002-12-13 20:15:29 +00001440 {
1441 struct nlmsghdr n;
1442 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001443 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001444 } req;
1445
1446 memset (&req, 0, sizeof req);
1447
1448 bytelen = (family == AF_INET ? 4 : 16);
1449
1450 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1451 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1452 req.n.nlmsg_type = cmd;
1453 req.r.rtm_family = family;
1454 req.r.rtm_table = rib->table;
1455 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001456 req.r.rtm_protocol = RTPROT_ZEBRA;
1457 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001458
paul7021c422003-07-15 12:52:22 +00001459 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001460 discard = 1;
1461 else
1462 discard = 0;
1463
paul7021c422003-07-15 12:52:22 +00001464 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001465 {
paul7021c422003-07-15 12:52:22 +00001466 if (discard)
paul595db7f2003-05-25 21:35:06 +00001467 {
1468 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1469 req.r.rtm_type = RTN_BLACKHOLE;
1470 else if (rib->flags & ZEBRA_FLAG_REJECT)
1471 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001472 else
1473 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1474 }
paul595db7f2003-05-25 21:35:06 +00001475 else
paul7021c422003-07-15 12:52:22 +00001476 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001477 }
1478
1479 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1480
1481 /* Metric. */
1482 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1483
1484 if (discard)
1485 {
1486 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001487 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1488 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001489 goto skip;
1490 }
1491
1492 /* Multipath case. */
1493 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1494 {
1495 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001496 {
paul5ec90d22003-06-19 01:41:37 +00001497
paul7021c422003-07-15 12:52:22 +00001498 if ((cmd == RTM_NEWROUTE
1499 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1500 || (cmd == RTM_DELROUTE
1501 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1502 {
paul5ec90d22003-06-19 01:41:37 +00001503
paul7021c422003-07-15 12:52:22 +00001504 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1505 {
1506 if (IS_ZEBRA_DEBUG_KERNEL)
1507 {
ajsb6178002004-12-07 21:12:56 +00001508 zlog_debug
paul7021c422003-07-15 12:52:22 +00001509 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001510 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001511#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001512 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001513 inet6_ntoa (p->u.prefix6),
1514#else
1515 inet_ntoa (p->u.prefix4),
1516#endif /* HAVE_IPV6 */
1517
1518 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001519 }
paul5ec90d22003-06-19 01:41:37 +00001520
paul7021c422003-07-15 12:52:22 +00001521 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1522 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001523 {
1524 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1525 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001526 if (nexthop->src.ipv4.s_addr)
1527 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1528 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001529 if (IS_ZEBRA_DEBUG_KERNEL)
1530 zlog_debug("netlink_route_multipath() (recursive, "
1531 "1 hop): nexthop via %s if %u",
1532 inet_ntoa (nexthop->rgate.ipv4),
1533 nexthop->rifindex);
1534 }
paul718e3742002-12-13 20:15:29 +00001535#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001536 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1537 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1538 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001539 {
1540 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1541 &nexthop->rgate.ipv6, bytelen);
1542
1543 if (IS_ZEBRA_DEBUG_KERNEL)
1544 zlog_debug("netlink_route_multipath() (recursive, "
1545 "1 hop): nexthop via %s if %u",
1546 inet6_ntoa (nexthop->rgate.ipv6),
1547 nexthop->rifindex);
1548 }
paul718e3742002-12-13 20:15:29 +00001549#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001550 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1551 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1552 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1553 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1554 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001555 {
1556 addattr32 (&req.n, sizeof req, RTA_OIF,
1557 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001558 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1559 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1560 && nexthop->src.ipv4.s_addr)
1561 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1562 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001563
1564 if (IS_ZEBRA_DEBUG_KERNEL)
1565 zlog_debug("netlink_route_multipath() (recursive, "
1566 "1 hop): nexthop via if %u",
1567 nexthop->rifindex);
1568 }
paul7021c422003-07-15 12:52:22 +00001569 }
1570 else
1571 {
1572 if (IS_ZEBRA_DEBUG_KERNEL)
1573 {
ajsb6178002004-12-07 21:12:56 +00001574 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001575 ("netlink_route_multipath() (single hop): "
1576 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001577#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001578 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001579 inet6_ntoa (p->u.prefix6),
1580#else
1581 inet_ntoa (p->u.prefix4),
1582#endif /* HAVE_IPV6 */
1583 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001584 }
paul5ec90d22003-06-19 01:41:37 +00001585
paul7021c422003-07-15 12:52:22 +00001586 if (nexthop->type == NEXTHOP_TYPE_IPV4
1587 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001588 {
1589 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1590 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001591 if (nexthop->src.ipv4.s_addr)
1592 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1593 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001594
1595 if (IS_ZEBRA_DEBUG_KERNEL)
1596 zlog_debug("netlink_route_multipath() (single hop): "
1597 "nexthop via %s if %u",
1598 inet_ntoa (nexthop->gate.ipv4),
1599 nexthop->ifindex);
1600 }
paul718e3742002-12-13 20:15:29 +00001601#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001602 if (nexthop->type == NEXTHOP_TYPE_IPV6
1603 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1604 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001605 {
1606 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1607 &nexthop->gate.ipv6, bytelen);
1608
1609 if (IS_ZEBRA_DEBUG_KERNEL)
1610 zlog_debug("netlink_route_multipath() (single hop): "
1611 "nexthop via %s if %u",
1612 inet6_ntoa (nexthop->gate.ipv6),
1613 nexthop->ifindex);
1614 }
paul718e3742002-12-13 20:15:29 +00001615#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001616 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1617 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001618 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1619 {
1620 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1621
1622 if (nexthop->src.ipv4.s_addr)
1623 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1624 &nexthop->src.ipv4, bytelen);
1625
1626 if (IS_ZEBRA_DEBUG_KERNEL)
1627 zlog_debug("netlink_route_multipath() (single hop): "
1628 "nexthop via if %u", nexthop->ifindex);
1629 }
1630 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001631 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001632 {
1633 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1634
1635 if (IS_ZEBRA_DEBUG_KERNEL)
1636 zlog_debug("netlink_route_multipath() (single hop): "
1637 "nexthop via if %u", nexthop->ifindex);
1638 }
paul7021c422003-07-15 12:52:22 +00001639 }
paul718e3742002-12-13 20:15:29 +00001640
paul7021c422003-07-15 12:52:22 +00001641 if (cmd == RTM_NEWROUTE)
1642 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001643
paul7021c422003-07-15 12:52:22 +00001644 nexthop_num++;
1645 break;
1646 }
1647 }
paul718e3742002-12-13 20:15:29 +00001648 }
1649 else
1650 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001651 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001652 struct rtattr *rta = (void *) buf;
1653 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001654 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001655
1656 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001657 rta->rta_len = RTA_LENGTH (0);
1658 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001659
1660 nexthop_num = 0;
1661 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001662 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1663 nexthop = nexthop->next)
1664 {
1665 if ((cmd == RTM_NEWROUTE
1666 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1667 || (cmd == RTM_DELROUTE
1668 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1669 {
1670 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001671
paul7021c422003-07-15 12:52:22 +00001672 rtnh->rtnh_len = sizeof (*rtnh);
1673 rtnh->rtnh_flags = 0;
1674 rtnh->rtnh_hops = 0;
1675 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001676
paul7021c422003-07-15 12:52:22 +00001677 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1678 {
1679 if (IS_ZEBRA_DEBUG_KERNEL)
1680 {
ajsb6178002004-12-07 21:12:56 +00001681 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001682 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001683 lookup (nlmsg_str, cmd),
1684#ifdef HAVE_IPV6
1685 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1686 inet6_ntoa (p->u.prefix6),
1687#else
1688 inet_ntoa (p->u.prefix4),
1689#endif /* HAVE_IPV6 */
hasso206d8052005-04-09 16:38:51 +00001690 p->prefixlen, nexthop_types_desc[nexthop->rtype]);
paul7021c422003-07-15 12:52:22 +00001691 }
1692 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1693 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1694 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001695 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
paul7021c422003-07-15 12:52:22 +00001696 &nexthop->rgate.ipv4, bytelen);
1697 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001698
Paul Jakma7514fb72007-05-02 16:05:35 +00001699 if (nexthop->src.ipv4.s_addr)
1700 src = &nexthop->src;
1701
hasso206d8052005-04-09 16:38:51 +00001702 if (IS_ZEBRA_DEBUG_KERNEL)
1703 zlog_debug("netlink_route_multipath() (recursive, "
1704 "multihop): nexthop via %s if %u",
1705 inet_ntoa (nexthop->rgate.ipv4),
1706 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001707 }
paul718e3742002-12-13 20:15:29 +00001708#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001709 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1710 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1711 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001712 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001713 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001714 &nexthop->rgate.ipv6, bytelen);
1715
1716 if (IS_ZEBRA_DEBUG_KERNEL)
1717 zlog_debug("netlink_route_multipath() (recursive, "
1718 "multihop): nexthop via %s if %u",
1719 inet6_ntoa (nexthop->rgate.ipv6),
1720 nexthop->rifindex);
1721 }
paul718e3742002-12-13 20:15:29 +00001722#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001723 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001724 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1725 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1726 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1727 {
1728 rtnh->rtnh_ifindex = nexthop->rifindex;
1729 if (nexthop->src.ipv4.s_addr)
1730 src = &nexthop->src;
1731
1732 if (IS_ZEBRA_DEBUG_KERNEL)
1733 zlog_debug("netlink_route_multipath() (recursive, "
1734 "multihop): nexthop via if %u",
1735 nexthop->rifindex);
1736 }
1737 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001738 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001739 {
1740 rtnh->rtnh_ifindex = nexthop->rifindex;
1741
1742 if (IS_ZEBRA_DEBUG_KERNEL)
1743 zlog_debug("netlink_route_multipath() (recursive, "
1744 "multihop): nexthop via if %u",
1745 nexthop->rifindex);
1746 }
paul7021c422003-07-15 12:52:22 +00001747 else
hasso206d8052005-04-09 16:38:51 +00001748 {
1749 rtnh->rtnh_ifindex = 0;
1750 }
paul7021c422003-07-15 12:52:22 +00001751 }
1752 else
1753 {
1754 if (IS_ZEBRA_DEBUG_KERNEL)
1755 {
hasso206d8052005-04-09 16:38:51 +00001756 zlog_debug ("netlink_route_multipath() (multihop): "
1757 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001758#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001759 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001760 inet6_ntoa (p->u.prefix6),
1761#else
1762 inet_ntoa (p->u.prefix4),
1763#endif /* HAVE_IPV6 */
1764 p->prefixlen, nexthop_types_desc[nexthop->type]);
paul7021c422003-07-15 12:52:22 +00001765 }
1766 if (nexthop->type == NEXTHOP_TYPE_IPV4
1767 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1768 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001769 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001770 &nexthop->gate.ipv4, bytelen);
1771 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1772
Paul Jakma7514fb72007-05-02 16:05:35 +00001773 if (nexthop->src.ipv4.s_addr)
1774 src = &nexthop->src;
1775
hasso206d8052005-04-09 16:38:51 +00001776 if (IS_ZEBRA_DEBUG_KERNEL)
1777 zlog_debug("netlink_route_multipath() (multihop): "
1778 "nexthop via %s if %u",
1779 inet_ntoa (nexthop->gate.ipv4),
1780 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001781 }
paul718e3742002-12-13 20:15:29 +00001782#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001783 if (nexthop->type == NEXTHOP_TYPE_IPV6
1784 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1785 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001786 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001787 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001788 &nexthop->gate.ipv6, bytelen);
1789
1790 if (IS_ZEBRA_DEBUG_KERNEL)
1791 zlog_debug("netlink_route_multipath() (multihop): "
1792 "nexthop via %s if %u",
1793 inet6_ntoa (nexthop->gate.ipv6),
1794 nexthop->ifindex);
1795 }
paul718e3742002-12-13 20:15:29 +00001796#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001797 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001798 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1799 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1800 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1801 {
1802 rtnh->rtnh_ifindex = nexthop->ifindex;
1803 if (nexthop->src.ipv4.s_addr)
1804 src = &nexthop->src;
1805 if (IS_ZEBRA_DEBUG_KERNEL)
1806 zlog_debug("netlink_route_multipath() (multihop): "
1807 "nexthop via if %u", nexthop->ifindex);
1808 }
1809 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001810 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001811 {
1812 rtnh->rtnh_ifindex = nexthop->ifindex;
1813
1814 if (IS_ZEBRA_DEBUG_KERNEL)
1815 zlog_debug("netlink_route_multipath() (multihop): "
1816 "nexthop via if %u", nexthop->ifindex);
1817 }
paul7021c422003-07-15 12:52:22 +00001818 else
hasso206d8052005-04-09 16:38:51 +00001819 {
1820 rtnh->rtnh_ifindex = 0;
1821 }
paul7021c422003-07-15 12:52:22 +00001822 }
1823 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001824
paul7021c422003-07-15 12:52:22 +00001825 if (cmd == RTM_NEWROUTE)
1826 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1827 }
1828 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001829 if (src)
1830 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001831
1832 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001833 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001834 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001835 }
1836
1837 /* If there is no useful nexthop then return. */
1838 if (nexthop_num == 0)
1839 {
1840 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001841 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001842 return 0;
1843 }
1844
paul7021c422003-07-15 12:52:22 +00001845skip:
paul718e3742002-12-13 20:15:29 +00001846
1847 /* Destination netlink address. */
1848 memset (&snl, 0, sizeof snl);
1849 snl.nl_family = AF_NETLINK;
1850
paul718e3742002-12-13 20:15:29 +00001851 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001852 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001853}
1854
1855int
1856kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1857{
1858 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1859}
1860
1861int
1862kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1863{
1864 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1865}
1866
1867#ifdef HAVE_IPV6
1868int
1869kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1870{
1871 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1872}
1873
1874int
1875kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1876{
1877 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1878}
1879
1880/* Delete IPv6 route from the kernel. */
1881int
1882kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001883 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001884{
paul7021c422003-07-15 12:52:22 +00001885 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1886 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001887}
1888#endif /* HAVE_IPV6 */
1889
1890/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001891static int
paul718e3742002-12-13 20:15:29 +00001892netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001893 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001894{
1895 int bytelen;
1896 struct prefix *p;
1897
paul7021c422003-07-15 12:52:22 +00001898 struct
paul718e3742002-12-13 20:15:29 +00001899 {
1900 struct nlmsghdr n;
1901 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001902 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001903 } req;
1904
1905 p = ifc->address;
1906 memset (&req, 0, sizeof req);
1907
1908 bytelen = (family == AF_INET ? 4 : 16);
1909
paul7021c422003-07-15 12:52:22 +00001910 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001911 req.n.nlmsg_flags = NLM_F_REQUEST;
1912 req.n.nlmsg_type = cmd;
1913 req.ifa.ifa_family = family;
1914
1915 req.ifa.ifa_index = ifp->ifindex;
1916 req.ifa.ifa_prefixlen = p->prefixlen;
1917
1918 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1919
1920 if (family == AF_INET && cmd == RTM_NEWADDR)
1921 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001922 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001923 {
1924 p = ifc->destination;
1925 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1926 bytelen);
1927 }
paul718e3742002-12-13 20:15:29 +00001928 }
1929
1930 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1931 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001932
paul718e3742002-12-13 20:15:29 +00001933 if (ifc->label)
1934 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001935 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001936
1937 return netlink_talk (&req.n, &netlink_cmd);
1938}
1939
1940int
1941kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1942{
1943 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1944}
1945
1946int
1947kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1948{
1949 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1950}
1951
paul718e3742002-12-13 20:15:29 +00001952
1953extern struct thread_master *master;
1954
1955/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001956static int
paul718e3742002-12-13 20:15:29 +00001957kernel_read (struct thread *thread)
1958{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001959 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001960 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001961
1962 return 0;
1963}
1964
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001965/* Filter out messages from self that occur on listener socket,
1966 caused by our actions on the command socket
1967 */
1968static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001969{
Paul Jakma768a27e2008-05-29 18:23:08 +00001970 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001971 /* 0: ldh [4] */
1972 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1973 /* 1: jeq 0x18 jt 3 jf 6 */
1974 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1975 /* 2: jeq 0x19 jt 3 jf 6 */
1976 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1977 /* 3: ldw [12] */
1978 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1979 /* 4: jeq XX jt 5 jf 6 */
1980 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1981 /* 5: ret 0 (skip) */
1982 BPF_STMT(BPF_RET|BPF_K, 0),
1983 /* 6: ret 0xffff (keep) */
1984 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001985 };
1986
1987 struct sock_fprog prog = {
1988 .len = sizeof(filter) / sizeof(filter[0]),
1989 .filter = filter,
1990 };
1991
1992 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1993 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1994}
1995
paul718e3742002-12-13 20:15:29 +00001996/* Exported interface function. This function simply calls
1997 netlink_socket (). */
1998void
paul6621ca82005-11-23 13:02:08 +00001999kernel_init (void)
paul718e3742002-12-13 20:15:29 +00002000{
2001 unsigned long groups;
2002
paul7021c422003-07-15 12:52:22 +00002003 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00002004#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00002005 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00002006#endif /* HAVE_IPV6 */
2007 netlink_socket (&netlink, groups);
2008 netlink_socket (&netlink_cmd, 0);
2009
2010 /* Register kernel socket. */
2011 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00002012 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01002013 /* Only want non-blocking on the netlink event socket */
2014 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
2015 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
2016 safe_strerror (errno));
2017
Stephen Hemminger30afea32008-08-16 18:25:47 +01002018 /* Set receive buffer size if it's set from command line */
2019 if (nl_rcvbufsize)
2020 netlink_recvbuf (&netlink, nl_rcvbufsize);
2021
Stephen Hemminger3d265b42008-08-16 17:30:39 +01002022 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00002023 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
2024 }
paul718e3742002-12-13 20:15:29 +00002025}