blob: fa446a56fcb3195308cdf633e9d3f13b1430a5a9 [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
Stephen Hemminger30afea32008-08-16 18:25:47 +0100104static int
105netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
106{
107 u_int32_t oldsize;
108 socklen_t newlen = sizeof(newsize);
109 socklen_t oldlen = sizeof(oldsize);
110 int ret;
111
112 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
113 if (ret < 0)
114 {
115 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
116 safe_strerror (errno));
117 return -1;
118 }
119
120 ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
121 sizeof(nl_rcvbufsize));
122 if (ret < 0)
123 {
124 zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
125 safe_strerror (errno));
126 return -1;
127 }
128
129 ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
130 if (ret < 0)
131 {
132 zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
133 safe_strerror (errno));
134 return -1;
135 }
136
137 zlog (NULL, LOG_INFO,
138 "Setting netlink socket receive buffer size: %u -> %u",
139 oldsize, newsize);
140 return 0;
141}
142
paul718e3742002-12-13 20:15:29 +0000143/* Make socket for Linux netlink interface. */
144static int
145netlink_socket (struct nlsock *nl, unsigned long groups)
146{
147 int ret;
148 struct sockaddr_nl snl;
149 int sock;
150 int namelen;
ajs4be019d2005-01-29 16:12:41 +0000151 int save_errno;
paul718e3742002-12-13 20:15:29 +0000152
153 sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
154 if (sock < 0)
155 {
156 zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000157 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000158 return -1;
159 }
160
paul718e3742002-12-13 20:15:29 +0000161 memset (&snl, 0, sizeof snl);
162 snl.nl_family = AF_NETLINK;
163 snl.nl_groups = groups;
164
165 /* Bind the socket to the netlink structure for anything. */
paul7021c422003-07-15 12:52:22 +0000166 if (zserv_privs.change (ZPRIVS_RAISE))
167 {
168 zlog (NULL, LOG_ERR, "Can't raise privileges");
169 return -1;
170 }
pauledd7c242003-06-04 13:59:38 +0000171
paul718e3742002-12-13 20:15:29 +0000172 ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000173 save_errno = errno;
hasso55e7ecd2004-08-06 08:41:56 +0000174 if (zserv_privs.change (ZPRIVS_LOWER))
175 zlog (NULL, LOG_ERR, "Can't lower privileges");
176
paul718e3742002-12-13 20:15:29 +0000177 if (ret < 0)
178 {
paul7021c422003-07-15 12:52:22 +0000179 zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
ajs4be019d2005-01-29 16:12:41 +0000180 nl->name, snl.nl_groups, safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000181 close (sock);
182 return -1;
183 }
paul7021c422003-07-15 12:52:22 +0000184
paul718e3742002-12-13 20:15:29 +0000185 /* multiple netlink sockets will have different nl_pid */
186 namelen = sizeof snl;
hassoc9e52be2004-09-26 16:09:34 +0000187 ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
paul718e3742002-12-13 20:15:29 +0000188 if (ret < 0 || namelen != sizeof snl)
189 {
190 zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
ajs6099b3b2004-11-20 02:06:59 +0000191 safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000192 close (sock);
193 return -1;
194 }
195
196 nl->snl = snl;
197 nl->sock = sock;
198 return ret;
199}
200
201/* Get type specified information from netlink. */
202static int
203netlink_request (int family, int type, struct nlsock *nl)
204{
205 int ret;
206 struct sockaddr_nl snl;
ajs4be019d2005-01-29 16:12:41 +0000207 int save_errno;
paul718e3742002-12-13 20:15:29 +0000208
209 struct
210 {
211 struct nlmsghdr nlh;
212 struct rtgenmsg g;
213 } req;
214
215
216 /* Check netlink socket. */
217 if (nl->sock < 0)
218 {
219 zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
220 return -1;
221 }
222
223 memset (&snl, 0, sizeof snl);
224 snl.nl_family = AF_NETLINK;
225
ajsc05612b2005-10-01 16:36:54 +0000226 memset (&req, 0, sizeof req);
paul718e3742002-12-13 20:15:29 +0000227 req.nlh.nlmsg_len = sizeof req;
228 req.nlh.nlmsg_type = type;
229 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Stephen Hemminger3d265b42008-08-16 17:30:39 +0100230 req.nlh.nlmsg_pid = nl->snl.nl_pid;
paul718e3742002-12-13 20:15:29 +0000231 req.nlh.nlmsg_seq = ++nl->seq;
232 req.g.rtgen_family = family;
pauledd7c242003-06-04 13:59:38 +0000233
234 /* linux appears to check capabilities on every message
235 * have to raise caps for every message sent
236 */
paul7021c422003-07-15 12:52:22 +0000237 if (zserv_privs.change (ZPRIVS_RAISE))
pauledd7c242003-06-04 13:59:38 +0000238 {
239 zlog (NULL, LOG_ERR, "Can't raise privileges");
240 return -1;
241 }
paul7021c422003-07-15 12:52:22 +0000242
243 ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
244 (struct sockaddr *) &snl, sizeof snl);
ajs4be019d2005-01-29 16:12:41 +0000245 save_errno = errno;
paul7021c422003-07-15 12:52:22 +0000246
247 if (zserv_privs.change (ZPRIVS_LOWER))
248 zlog (NULL, LOG_ERR, "Can't lower privileges");
249
paul718e3742002-12-13 20:15:29 +0000250 if (ret < 0)
paul7021c422003-07-15 12:52:22 +0000251 {
252 zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
ajs4be019d2005-01-29 16:12:41 +0000253 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +0000254 return -1;
255 }
pauledd7c242003-06-04 13:59:38 +0000256
paul718e3742002-12-13 20:15:29 +0000257 return 0;
258}
259
260/* Receive message from netlink interface and pass those information
261 to the given function. */
262static int
263netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
paul7021c422003-07-15 12:52:22 +0000264 struct nlsock *nl)
paul718e3742002-12-13 20:15:29 +0000265{
266 int status;
267 int ret = 0;
268 int error;
269
270 while (1)
271 {
JR Rivers3cadc0c2012-04-01 12:16:31 -0700272 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +0000273 struct iovec iov = { buf, sizeof buf };
274 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +0000275 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
paul718e3742002-12-13 20:15:29 +0000276 struct nlmsghdr *h;
paul7021c422003-07-15 12:52:22 +0000277
paul718e3742002-12-13 20:15:29 +0000278 status = recvmsg (nl->sock, &msg, 0);
paul718e3742002-12-13 20:15:29 +0000279 if (status < 0)
paul7021c422003-07-15 12:52:22 +0000280 {
Stephen Hemminger4c699472008-08-17 17:01:44 +0100281 if (errno == EINTR)
paul7021c422003-07-15 12:52:22 +0000282 continue;
Stephen Hemminger4c699472008-08-17 17:01:44 +0100283 if (errno == EWOULDBLOCK || errno == EAGAIN)
paul7021c422003-07-15 12:52:22 +0000284 break;
ajs4be019d2005-01-29 16:12:41 +0000285 zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
Stephen Hemminger4c699472008-08-17 17:01:44 +0100286 nl->name, safe_strerror(errno));
paul7021c422003-07-15 12:52:22 +0000287 continue;
288 }
paul718e3742002-12-13 20:15:29 +0000289
290 if (status == 0)
paul7021c422003-07-15 12:52:22 +0000291 {
292 zlog (NULL, LOG_ERR, "%s EOF", nl->name);
293 return -1;
294 }
paul718e3742002-12-13 20:15:29 +0000295
296 if (msg.msg_namelen != sizeof snl)
paul7021c422003-07-15 12:52:22 +0000297 {
298 zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
299 nl->name, msg.msg_namelen);
300 return -1;
301 }
paulb84d3a12003-11-17 10:31:01 +0000302
hasso206d8052005-04-09 16:38:51 +0000303 for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
paul7021c422003-07-15 12:52:22 +0000304 h = NLMSG_NEXT (h, status))
305 {
306 /* Finish of reading. */
307 if (h->nlmsg_type == NLMSG_DONE)
308 return ret;
paul718e3742002-12-13 20:15:29 +0000309
paul7021c422003-07-15 12:52:22 +0000310 /* Error handling. */
311 if (h->nlmsg_type == NLMSG_ERROR)
312 {
313 struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
Stephen Hemminger898987e2008-08-17 16:56:15 +0100314 int errnum = err->error;
315 int msg_type = err->msg.nlmsg_type;
paul7021c422003-07-15 12:52:22 +0000316
paul718e3742002-12-13 20:15:29 +0000317 /* If the error field is zero, then this is an ACK */
paul7021c422003-07-15 12:52:22 +0000318 if (err->error == 0)
paul718e3742002-12-13 20:15:29 +0000319 {
paul7021c422003-07-15 12:52:22 +0000320 if (IS_ZEBRA_DEBUG_KERNEL)
321 {
hasso1ada8192005-06-12 11:28:18 +0000322 zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000323 __FUNCTION__, nl->name,
324 lookup (nlmsg_str, err->msg.nlmsg_type),
325 err->msg.nlmsg_type, err->msg.nlmsg_seq,
326 err->msg.nlmsg_pid);
paul718e3742002-12-13 20:15:29 +0000327 }
paul7021c422003-07-15 12:52:22 +0000328
329 /* return if not a multipart message, otherwise continue */
330 if (!(h->nlmsg_flags & NLM_F_MULTI))
331 {
332 return 0;
paul718e3742002-12-13 20:15:29 +0000333 }
paul7021c422003-07-15 12:52:22 +0000334 continue;
paul718e3742002-12-13 20:15:29 +0000335 }
paul7021c422003-07-15 12:52:22 +0000336
paul718e3742002-12-13 20:15:29 +0000337 if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
paul7021c422003-07-15 12:52:22 +0000338 {
339 zlog (NULL, LOG_ERR, "%s error: message truncated",
340 nl->name);
341 return -1;
342 }
pauld753e9e2003-01-22 19:45:50 +0000343
Stephen Hemminger898987e2008-08-17 16:56:15 +0100344 /* Deal with errors that occur because of races in link handling */
345 if (nl == &netlink_cmd
346 && ((msg_type == RTM_DELROUTE &&
347 (-errnum == ENODEV || -errnum == ESRCH))
348 || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
349 {
350 if (IS_ZEBRA_DEBUG_KERNEL)
351 zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
352 nl->name, safe_strerror (-errnum),
353 lookup (nlmsg_str, msg_type),
354 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
355 return 0;
356 }
paul718e3742002-12-13 20:15:29 +0000357
Stephen Hemminger898987e2008-08-17 16:56:15 +0100358 zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
359 nl->name, safe_strerror (-errnum),
360 lookup (nlmsg_str, msg_type),
361 msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
paul7021c422003-07-15 12:52:22 +0000362 return -1;
363 }
paul718e3742002-12-13 20:15:29 +0000364
paul7021c422003-07-15 12:52:22 +0000365 /* OK we got netlink message. */
366 if (IS_ZEBRA_DEBUG_KERNEL)
hasso1ada8192005-06-12 11:28:18 +0000367 zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
paul7021c422003-07-15 12:52:22 +0000368 nl->name,
369 lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
370 h->nlmsg_seq, h->nlmsg_pid);
371
372 /* skip unsolicited messages originating from command socket */
373 if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
374 {
375 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000376 zlog_debug ("netlink_parse_info: %s packet comes from %s",
hasso1ada8192005-06-12 11:28:18 +0000377 netlink_cmd.name, nl->name);
paul7021c422003-07-15 12:52:22 +0000378 continue;
379 }
380
381 error = (*filter) (&snl, h);
382 if (error < 0)
383 {
384 zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
385 ret = error;
386 }
387 }
paul718e3742002-12-13 20:15:29 +0000388
389 /* After error care. */
390 if (msg.msg_flags & MSG_TRUNC)
paul7021c422003-07-15 12:52:22 +0000391 {
392 zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
393 continue;
394 }
paul718e3742002-12-13 20:15:29 +0000395 if (status)
paul7021c422003-07-15 12:52:22 +0000396 {
397 zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
398 status);
399 return -1;
400 }
paul718e3742002-12-13 20:15:29 +0000401 }
402 return ret;
403}
404
405/* Utility function for parse rtattr. */
406static void
paul7021c422003-07-15 12:52:22 +0000407netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
408 int len)
paul718e3742002-12-13 20:15:29 +0000409{
paul7021c422003-07-15 12:52:22 +0000410 while (RTA_OK (rta, len))
paul718e3742002-12-13 20:15:29 +0000411 {
412 if (rta->rta_type <= max)
paul7021c422003-07-15 12:52:22 +0000413 tb[rta->rta_type] = rta;
414 rta = RTA_NEXT (rta, len);
paul718e3742002-12-13 20:15:29 +0000415 }
416}
417
Josh Bailey26e2ae32012-03-22 01:09:21 -0700418/* Utility function to parse hardware link-layer address and update ifp */
419static void
420netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
421{
422 int i;
423
424 if (tb[IFLA_ADDRESS])
425 {
426 int hw_addr_len;
427
428 hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
429
430 if (hw_addr_len > INTERFACE_HWADDR_MAX)
431 zlog_warn ("Hardware address is too large: %d", hw_addr_len);
432 else
433 {
434 ifp->hw_addr_len = hw_addr_len;
435 memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
436
437 for (i = 0; i < hw_addr_len; i++)
438 if (ifp->hw_addr[i] != 0)
439 break;
440
441 if (i == hw_addr_len)
442 ifp->hw_addr_len = 0;
443 else
444 ifp->hw_addr_len = hw_addr_len;
445 }
446 }
447}
448
paul718e3742002-12-13 20:15:29 +0000449/* Called from interface_lookup_netlink(). This function is only used
450 during bootstrap. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100451static int
paul718e3742002-12-13 20:15:29 +0000452netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
453{
454 int len;
455 struct ifinfomsg *ifi;
456 struct rtattr *tb[IFLA_MAX + 1];
457 struct interface *ifp;
458 char *name;
paul718e3742002-12-13 20:15:29 +0000459
460 ifi = NLMSG_DATA (h);
461
462 if (h->nlmsg_type != RTM_NEWLINK)
463 return 0;
464
465 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
466 if (len < 0)
467 return -1;
468
469 /* Looking up interface name. */
470 memset (tb, 0, sizeof tb);
471 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +0000472
paul1e193152005-02-14 23:53:05 +0000473#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +0000474 /* check for wireless messages to ignore */
475 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
476 {
477 if (IS_ZEBRA_DEBUG_KERNEL)
478 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
479 return 0;
480 }
paul1e193152005-02-14 23:53:05 +0000481#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +0000482
paul718e3742002-12-13 20:15:29 +0000483 if (tb[IFLA_IFNAME] == NULL)
484 return -1;
paul7021c422003-07-15 12:52:22 +0000485 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +0000486
487 /* Add interface. */
488 ifp = if_get_by_name (name);
ajsd2fc8892005-04-02 18:38:43 +0000489 set_ifindex(ifp, ifi->ifi_index);
paul718e3742002-12-13 20:15:29 +0000490 ifp->flags = ifi->ifi_flags & 0x0000fffff;
Stephen Hemminger4308abb2008-12-01 14:19:38 -0800491 ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
paul718e3742002-12-13 20:15:29 +0000492 ifp->metric = 1;
493
494 /* Hardware type and address. */
495 ifp->hw_type = ifi->ifi_type;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700496 netlink_interface_update_hw_addr (tb, ifp);
paul718e3742002-12-13 20:15:29 +0000497
498 if_add_update (ifp);
499
500 return 0;
501}
502
503/* Lookup interface IPv4/IPv6 address. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100504static int
paul718e3742002-12-13 20:15:29 +0000505netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
506{
507 int len;
508 struct ifaddrmsg *ifa;
paul7021c422003-07-15 12:52:22 +0000509 struct rtattr *tb[IFA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000510 struct interface *ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000511 void *addr;
512 void *broad;
paul718e3742002-12-13 20:15:29 +0000513 u_char flags = 0;
514 char *label = NULL;
515
516 ifa = NLMSG_DATA (h);
517
paul7021c422003-07-15 12:52:22 +0000518 if (ifa->ifa_family != AF_INET
paul718e3742002-12-13 20:15:29 +0000519#ifdef HAVE_IPV6
520 && ifa->ifa_family != AF_INET6
521#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +0000522 )
paul718e3742002-12-13 20:15:29 +0000523 return 0;
524
525 if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
526 return 0;
527
paul7021c422003-07-15 12:52:22 +0000528 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +0000529 if (len < 0)
530 return -1;
531
532 memset (tb, 0, sizeof tb);
533 netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
534
535 ifp = if_lookup_by_index (ifa->ifa_index);
536 if (ifp == NULL)
537 {
538 zlog_err ("netlink_interface_addr can't find interface by index %d",
paul7021c422003-07-15 12:52:22 +0000539 ifa->ifa_index);
paul718e3742002-12-13 20:15:29 +0000540 return -1;
541 }
542
paul7021c422003-07-15 12:52:22 +0000543 if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
paul718e3742002-12-13 20:15:29 +0000544 {
paul00df0c12002-12-13 21:07:36 +0000545 char buf[BUFSIZ];
hasso206d8052005-04-09 16:38:51 +0000546 zlog_debug ("netlink_interface_addr %s %s:",
547 lookup (nlmsg_str, h->nlmsg_type), ifp->name);
paul718e3742002-12-13 20:15:29 +0000548 if (tb[IFA_LOCAL])
hasso206d8052005-04-09 16:38:51 +0000549 zlog_debug (" IFA_LOCAL %s/%d",
550 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
551 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000552 if (tb[IFA_ADDRESS])
hasso206d8052005-04-09 16:38:51 +0000553 zlog_debug (" IFA_ADDRESS %s/%d",
554 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
555 buf, BUFSIZ), ifa->ifa_prefixlen);
paul718e3742002-12-13 20:15:29 +0000556 if (tb[IFA_BROADCAST])
hasso206d8052005-04-09 16:38:51 +0000557 zlog_debug (" IFA_BROADCAST %s/%d",
558 inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
559 buf, BUFSIZ), ifa->ifa_prefixlen);
paul00df0c12002-12-13 21:07:36 +0000560 if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
ajsb6178002004-12-07 21:12:56 +0000561 zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL]));
pauld34b8992006-01-17 18:03:04 +0000562
563 if (tb[IFA_CACHEINFO])
564 {
565 struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
566 zlog_debug (" IFA_CACHEINFO pref %d, valid %d",
567 ci->ifa_prefered, ci->ifa_valid);
568 }
paul718e3742002-12-13 20:15:29 +0000569 }
paul31a476c2003-09-29 19:54:53 +0000570
Andrew J. Schorre4529632006-12-12 19:18:21 +0000571 /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
572 if (tb[IFA_LOCAL] == NULL)
573 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
paul31a476c2003-09-29 19:54:53 +0000574 if (tb[IFA_ADDRESS] == NULL)
575 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
576
Andrew J. Schorre4529632006-12-12 19:18:21 +0000577 /* local interface address */
578 addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
579
580 /* is there a peer address? */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000581 if (tb[IFA_ADDRESS] &&
vize068fd772007-08-10 06:25:20 +0000582 memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
paul7021c422003-07-15 12:52:22 +0000583 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000584 broad = RTA_DATA(tb[IFA_ADDRESS]);
585 SET_FLAG (flags, ZEBRA_IFA_PEER);
paul7021c422003-07-15 12:52:22 +0000586 }
paul31a476c2003-09-29 19:54:53 +0000587 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000588 /* seeking a broadcast address */
589 broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
paul00df0c12002-12-13 21:07:36 +0000590
Paul Jakma27b47252006-07-02 16:38:54 +0000591 /* addr is primary key, SOL if we don't have one */
592 if (addr == NULL)
593 {
594 zlog_debug ("%s: NULL address", __func__);
595 return -1;
596 }
597
paul718e3742002-12-13 20:15:29 +0000598 /* Flags. */
599 if (ifa->ifa_flags & IFA_F_SECONDARY)
600 SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
601
602 /* Label */
603 if (tb[IFA_LABEL])
604 label = (char *) RTA_DATA (tb[IFA_LABEL]);
605
606 if (ifp && label && strcmp (ifp->name, label) == 0)
607 label = NULL;
608
609 /* Register interface address to the interface. */
610 if (ifa->ifa_family == AF_INET)
611 {
paul7021c422003-07-15 12:52:22 +0000612 if (h->nlmsg_type == RTM_NEWADDR)
613 connected_add_ipv4 (ifp, flags,
614 (struct in_addr *) addr, ifa->ifa_prefixlen,
615 (struct in_addr *) broad, label);
616 else
617 connected_delete_ipv4 (ifp, flags,
618 (struct in_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000619 (struct in_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000620 }
621#ifdef HAVE_IPV6
622 if (ifa->ifa_family == AF_INET6)
623 {
624 if (h->nlmsg_type == RTM_NEWADDR)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000625 connected_add_ipv6 (ifp, flags,
paul7021c422003-07-15 12:52:22 +0000626 (struct in6_addr *) addr, ifa->ifa_prefixlen,
paul0752ef02005-11-03 12:35:21 +0000627 (struct in6_addr *) broad, label);
paul718e3742002-12-13 20:15:29 +0000628 else
paul7021c422003-07-15 12:52:22 +0000629 connected_delete_ipv6 (ifp,
630 (struct in6_addr *) addr, ifa->ifa_prefixlen,
631 (struct in6_addr *) broad);
paul718e3742002-12-13 20:15:29 +0000632 }
paul7021c422003-07-15 12:52:22 +0000633#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +0000634
635 return 0;
636}
637
638/* Looking up routing table by netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100639static int
paul718e3742002-12-13 20:15:29 +0000640netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
641{
642 int len;
643 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000644 struct rtattr *tb[RTA_MAX + 1];
paul718e3742002-12-13 20:15:29 +0000645 u_char flags = 0;
paul7021c422003-07-15 12:52:22 +0000646
647 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000648
649 int index;
650 int table;
hasso34195bf2004-04-06 12:07:06 +0000651 int metric;
652
paul718e3742002-12-13 20:15:29 +0000653 void *dest;
654 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000655 void *src;
paul718e3742002-12-13 20:15:29 +0000656
657 rtm = NLMSG_DATA (h);
658
659 if (h->nlmsg_type != RTM_NEWROUTE)
660 return 0;
661 if (rtm->rtm_type != RTN_UNICAST)
662 return 0;
663
664 table = rtm->rtm_table;
paul7021c422003-07-15 12:52:22 +0000665#if 0 /* we weed them out later in rib_weed_tables () */
paulb21b19c2003-06-15 01:28:29 +0000666 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000667 return 0;
668#endif
669
paul7021c422003-07-15 12:52:22 +0000670 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000671 if (len < 0)
672 return -1;
673
674 memset (tb, 0, sizeof tb);
675 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
676
677 if (rtm->rtm_flags & RTM_F_CLONED)
678 return 0;
679 if (rtm->rtm_protocol == RTPROT_REDIRECT)
680 return 0;
681 if (rtm->rtm_protocol == RTPROT_KERNEL)
682 return 0;
683
684 if (rtm->rtm_src_len != 0)
685 return 0;
686
687 /* Route which inserted by Zebra. */
688 if (rtm->rtm_protocol == RTPROT_ZEBRA)
689 flags |= ZEBRA_FLAG_SELFROUTE;
paul7021c422003-07-15 12:52:22 +0000690
paul718e3742002-12-13 20:15:29 +0000691 index = 0;
hasso34195bf2004-04-06 12:07:06 +0000692 metric = 0;
paul718e3742002-12-13 20:15:29 +0000693 dest = NULL;
694 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000695 src = NULL;
paul718e3742002-12-13 20:15:29 +0000696
697 if (tb[RTA_OIF])
698 index = *(int *) RTA_DATA (tb[RTA_OIF]);
699
700 if (tb[RTA_DST])
701 dest = RTA_DATA (tb[RTA_DST]);
702 else
703 dest = anyaddr;
704
Paul Jakma7514fb72007-05-02 16:05:35 +0000705 if (tb[RTA_PREFSRC])
706 src = RTA_DATA (tb[RTA_PREFSRC]);
707
paul718e3742002-12-13 20:15:29 +0000708 if (tb[RTA_GATEWAY])
709 gate = RTA_DATA (tb[RTA_GATEWAY]);
710
hasso34195bf2004-04-06 12:07:06 +0000711 if (tb[RTA_PRIORITY])
712 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
713
paul718e3742002-12-13 20:15:29 +0000714 if (rtm->rtm_family == AF_INET)
715 {
716 struct prefix_ipv4 p;
717 p.family = AF_INET;
718 memcpy (&p.prefix, dest, 4);
719 p.prefixlen = rtm->rtm_dst_len;
720
Josh Bailey26e2ae32012-03-22 01:09:21 -0700721 if (!tb[RTA_MULTIPATH])
722 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700723 table, metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700724 else
725 {
726 /* This is a multipath route */
727
728 struct rib *rib;
729 struct rtnexthop *rtnh =
730 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
731
732 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
733
734 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
735 rib->type = ZEBRA_ROUTE_KERNEL;
736 rib->distance = 0;
737 rib->flags = flags;
738 rib->metric = metric;
739 rib->table = table;
740 rib->nexthop_num = 0;
741 rib->uptime = time (NULL);
742
743 for (;;)
744 {
745 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
746 break;
747
748 rib->nexthop_num++;
749 index = rtnh->rtnh_ifindex;
750 gate = 0;
751 if (rtnh->rtnh_len > sizeof (*rtnh))
752 {
753 memset (tb, 0, sizeof (tb));
754 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
755 rtnh->rtnh_len - sizeof (*rtnh));
756 if (tb[RTA_GATEWAY])
757 gate = RTA_DATA (tb[RTA_GATEWAY]);
758 }
759
760 if (gate)
761 {
762 if (index)
763 nexthop_ipv4_ifindex_add (rib, gate, src, index);
764 else
765 nexthop_ipv4_add (rib, gate, src);
766 }
767 else
768 nexthop_ifindex_add (rib, index);
769
770 len -= NLMSG_ALIGN(rtnh->rtnh_len);
771 rtnh = RTNH_NEXT(rtnh);
772 }
773
774 if (rib->nexthop_num == 0)
775 XFREE (MTYPE_RIB, rib);
776 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700777 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700778 }
paul718e3742002-12-13 20:15:29 +0000779 }
780#ifdef HAVE_IPV6
781 if (rtm->rtm_family == AF_INET6)
782 {
783 struct prefix_ipv6 p;
784 p.family = AF_INET6;
785 memcpy (&p.prefix, dest, 16);
786 p.prefixlen = rtm->rtm_dst_len;
787
hassobe61c4e2005-08-27 06:05:47 +0000788 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
G.Balajif768f362011-11-26 22:10:39 +0400789 metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000790 }
791#endif /* HAVE_IPV6 */
792
793 return 0;
794}
795
Stephen Hemminger1423c802008-08-14 17:59:25 +0100796static const struct message rtproto_str[] = {
paul718e3742002-12-13 20:15:29 +0000797 {RTPROT_REDIRECT, "redirect"},
798 {RTPROT_KERNEL, "kernel"},
799 {RTPROT_BOOT, "boot"},
800 {RTPROT_STATIC, "static"},
801 {RTPROT_GATED, "GateD"},
802 {RTPROT_RA, "router advertisement"},
803 {RTPROT_MRT, "MRT"},
804 {RTPROT_ZEBRA, "Zebra"},
805#ifdef RTPROT_BIRD
806 {RTPROT_BIRD, "BIRD"},
807#endif /* RTPROT_BIRD */
808 {0, NULL}
809};
810
811/* Routing information change from the kernel. */
Stephen Hemminger6072b242008-08-14 16:52:26 +0100812static int
paul718e3742002-12-13 20:15:29 +0000813netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
814{
815 int len;
816 struct rtmsg *rtm;
paul7021c422003-07-15 12:52:22 +0000817 struct rtattr *tb[RTA_MAX + 1];
818
819 char anyaddr[16] = { 0 };
paul718e3742002-12-13 20:15:29 +0000820
821 int index;
822 int table;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700823 int metric;
Dmitry Popov83d16142011-09-11 13:48:25 +0400824
paul718e3742002-12-13 20:15:29 +0000825 void *dest;
826 void *gate;
Paul Jakma7514fb72007-05-02 16:05:35 +0000827 void *src;
paul718e3742002-12-13 20:15:29 +0000828
829 rtm = NLMSG_DATA (h);
830
paul7021c422003-07-15 12:52:22 +0000831 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
paul718e3742002-12-13 20:15:29 +0000832 {
833 /* If this is not route add/delete message print warning. */
834 zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
835 return 0;
836 }
837
838 /* Connected route. */
839 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000840 zlog_debug ("%s %s %s proto %s",
paul7021c422003-07-15 12:52:22 +0000841 h->nlmsg_type ==
842 RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
843 rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
844 rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
845 lookup (rtproto_str, rtm->rtm_protocol));
paul718e3742002-12-13 20:15:29 +0000846
847 if (rtm->rtm_type != RTN_UNICAST)
848 {
849 return 0;
850 }
851
852 table = rtm->rtm_table;
paulb21b19c2003-06-15 01:28:29 +0000853 if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
paul718e3742002-12-13 20:15:29 +0000854 {
855 return 0;
856 }
857
paul7021c422003-07-15 12:52:22 +0000858 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
paul718e3742002-12-13 20:15:29 +0000859 if (len < 0)
860 return -1;
861
862 memset (tb, 0, sizeof tb);
863 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
864
865 if (rtm->rtm_flags & RTM_F_CLONED)
866 return 0;
867 if (rtm->rtm_protocol == RTPROT_REDIRECT)
868 return 0;
869 if (rtm->rtm_protocol == RTPROT_KERNEL)
870 return 0;
871
872 if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
873 return 0;
874
875 if (rtm->rtm_src_len != 0)
876 {
877 zlog_warn ("netlink_route_change(): no src len");
878 return 0;
879 }
paul7021c422003-07-15 12:52:22 +0000880
paul718e3742002-12-13 20:15:29 +0000881 index = 0;
Josh Bailey26e2ae32012-03-22 01:09:21 -0700882 metric = 0;
paul718e3742002-12-13 20:15:29 +0000883 dest = NULL;
884 gate = NULL;
Paul Jakma7514fb72007-05-02 16:05:35 +0000885 src = NULL;
paul718e3742002-12-13 20:15:29 +0000886
887 if (tb[RTA_OIF])
888 index = *(int *) RTA_DATA (tb[RTA_OIF]);
889
890 if (tb[RTA_DST])
891 dest = RTA_DATA (tb[RTA_DST]);
892 else
893 dest = anyaddr;
894
895 if (tb[RTA_GATEWAY])
896 gate = RTA_DATA (tb[RTA_GATEWAY]);
897
Paul Jakma7514fb72007-05-02 16:05:35 +0000898 if (tb[RTA_PREFSRC])
899 src = RTA_DATA (tb[RTA_PREFSRC]);
900
Dmitry Popov83d16142011-09-11 13:48:25 +0400901 if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
Josh Bailey26e2ae32012-03-22 01:09:21 -0700902 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
903
paul718e3742002-12-13 20:15:29 +0000904 if (rtm->rtm_family == AF_INET)
905 {
906 struct prefix_ipv4 p;
907 p.family = AF_INET;
908 memcpy (&p.prefix, dest, 4);
909 p.prefixlen = rtm->rtm_dst_len;
910
911 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000912 {
913 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000914 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000915 inet_ntoa (p.prefix), p.prefixlen);
916 else
ajsb6178002004-12-07 21:12:56 +0000917 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +0000918 inet_ntoa (p.prefix), p.prefixlen);
919 }
paul718e3742002-12-13 20:15:29 +0000920
921 if (h->nlmsg_type == RTM_NEWROUTE)
Josh Bailey26e2ae32012-03-22 01:09:21 -0700922 {
923 if (!tb[RTA_MULTIPATH])
924 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700925 metric, 0, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700926 else
927 {
928 /* This is a multipath route */
929
930 struct rib *rib;
931 struct rtnexthop *rtnh =
932 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
933
934 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
935
936 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
937 rib->type = ZEBRA_ROUTE_KERNEL;
938 rib->distance = 0;
939 rib->flags = 0;
940 rib->metric = metric;
941 rib->table = table;
942 rib->nexthop_num = 0;
943 rib->uptime = time (NULL);
944
945 for (;;)
946 {
947 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
948 break;
949
950 rib->nexthop_num++;
951 index = rtnh->rtnh_ifindex;
952 gate = 0;
953 if (rtnh->rtnh_len > sizeof (*rtnh))
954 {
955 memset (tb, 0, sizeof (tb));
956 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
957 rtnh->rtnh_len - sizeof (*rtnh));
958 if (tb[RTA_GATEWAY])
959 gate = RTA_DATA (tb[RTA_GATEWAY]);
960 }
961
962 if (gate)
963 {
964 if (index)
965 nexthop_ipv4_ifindex_add (rib, gate, src, index);
966 else
967 nexthop_ipv4_add (rib, gate, src);
968 }
969 else
970 nexthop_ifindex_add (rib, index);
971
972 len -= NLMSG_ALIGN(rtnh->rtnh_len);
973 rtnh = RTNH_NEXT(rtnh);
974 }
975
976 if (rib->nexthop_num == 0)
977 XFREE (MTYPE_RIB, rib);
978 else
Avneesh Sachdev14d2bba2012-04-11 23:51:08 -0700979 rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
Josh Bailey26e2ae32012-03-22 01:09:21 -0700980 }
981 }
paul718e3742002-12-13 20:15:29 +0000982 else
G.Balajicddf3912011-11-26 21:59:32 +0400983 rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000984 }
985
986#ifdef HAVE_IPV6
987 if (rtm->rtm_family == AF_INET6)
988 {
989 struct prefix_ipv6 p;
990 char buf[BUFSIZ];
991
992 p.family = AF_INET6;
993 memcpy (&p.prefix, dest, 16);
994 p.prefixlen = rtm->rtm_dst_len;
995
996 if (IS_ZEBRA_DEBUG_KERNEL)
paul7021c422003-07-15 12:52:22 +0000997 {
998 if (h->nlmsg_type == RTM_NEWROUTE)
ajsb6178002004-12-07 21:12:56 +0000999 zlog_debug ("RTM_NEWROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001000 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1001 p.prefixlen);
1002 else
ajsb6178002004-12-07 21:12:56 +00001003 zlog_debug ("RTM_DELROUTE %s/%d",
paul7021c422003-07-15 12:52:22 +00001004 inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
1005 p.prefixlen);
1006 }
paul718e3742002-12-13 20:15:29 +00001007
1008 if (h->nlmsg_type == RTM_NEWROUTE)
G.Balajif768f362011-11-26 22:10:39 +04001009 rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001010 else
G.Balajif768f362011-11-26 22:10:39 +04001011 rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +00001012 }
1013#endif /* HAVE_IPV6 */
1014
1015 return 0;
1016}
1017
Stephen Hemminger6072b242008-08-14 16:52:26 +01001018static int
paul718e3742002-12-13 20:15:29 +00001019netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
1020{
1021 int len;
1022 struct ifinfomsg *ifi;
paul7021c422003-07-15 12:52:22 +00001023 struct rtattr *tb[IFLA_MAX + 1];
paul718e3742002-12-13 20:15:29 +00001024 struct interface *ifp;
1025 char *name;
1026
1027 ifi = NLMSG_DATA (h);
1028
paul7021c422003-07-15 12:52:22 +00001029 if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
paul718e3742002-12-13 20:15:29 +00001030 {
1031 /* If this is not link add/delete message so print warning. */
1032 zlog_warn ("netlink_link_change: wrong kernel message %d\n",
paul7021c422003-07-15 12:52:22 +00001033 h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001034 return 0;
1035 }
1036
1037 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
1038 if (len < 0)
1039 return -1;
1040
1041 /* Looking up interface name. */
1042 memset (tb, 0, sizeof tb);
1043 netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
paulc15cb242005-01-24 09:05:27 +00001044
paul1e193152005-02-14 23:53:05 +00001045#ifdef IFLA_WIRELESS
paulc15cb242005-01-24 09:05:27 +00001046 /* check for wireless messages to ignore */
1047 if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
1048 {
1049 if (IS_ZEBRA_DEBUG_KERNEL)
1050 zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
1051 return 0;
1052 }
paul1e193152005-02-14 23:53:05 +00001053#endif /* IFLA_WIRELESS */
paulc15cb242005-01-24 09:05:27 +00001054
paul718e3742002-12-13 20:15:29 +00001055 if (tb[IFLA_IFNAME] == NULL)
1056 return -1;
paul7021c422003-07-15 12:52:22 +00001057 name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
paul718e3742002-12-13 20:15:29 +00001058
1059 /* Add interface. */
1060 if (h->nlmsg_type == RTM_NEWLINK)
1061 {
1062 ifp = if_lookup_by_name (name);
1063
paul7021c422003-07-15 12:52:22 +00001064 if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
1065 {
1066 if (ifp == NULL)
1067 ifp = if_get_by_name (name);
paul718e3742002-12-13 20:15:29 +00001068
ajsd2fc8892005-04-02 18:38:43 +00001069 set_ifindex(ifp, ifi->ifi_index);
paul7021c422003-07-15 12:52:22 +00001070 ifp->flags = ifi->ifi_flags & 0x0000fffff;
paul44145db2004-05-09 11:00:23 +00001071 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001072 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001073
Josh Bailey26e2ae32012-03-22 01:09:21 -07001074 netlink_interface_update_hw_addr (tb, ifp);
1075
paul7021c422003-07-15 12:52:22 +00001076 /* If new link is added. */
1077 if_add_update (ifp);
1078 }
paul718e3742002-12-13 20:15:29 +00001079 else
paul7021c422003-07-15 12:52:22 +00001080 {
1081 /* Interface status change. */
ajsd2fc8892005-04-02 18:38:43 +00001082 set_ifindex(ifp, ifi->ifi_index);
paul44145db2004-05-09 11:00:23 +00001083 ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
paul7021c422003-07-15 12:52:22 +00001084 ifp->metric = 1;
paul718e3742002-12-13 20:15:29 +00001085
Josh Bailey26e2ae32012-03-22 01:09:21 -07001086 netlink_interface_update_hw_addr (tb, ifp);
1087
paul7021c422003-07-15 12:52:22 +00001088 if (if_is_operative (ifp))
1089 {
1090 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1091 if (!if_is_operative (ifp))
1092 if_down (ifp);
ajsa608bbf2005-03-29 17:03:49 +00001093 else
1094 /* Must notify client daemons of new interface status. */
1095 zebra_interface_up_update (ifp);
paul7021c422003-07-15 12:52:22 +00001096 }
1097 else
1098 {
1099 ifp->flags = ifi->ifi_flags & 0x0000fffff;
1100 if (if_is_operative (ifp))
1101 if_up (ifp);
1102 }
1103 }
paul718e3742002-12-13 20:15:29 +00001104 }
1105 else
1106 {
1107 /* RTM_DELLINK. */
1108 ifp = if_lookup_by_name (name);
1109
1110 if (ifp == NULL)
paul7021c422003-07-15 12:52:22 +00001111 {
1112 zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
paul718e3742002-12-13 20:15:29 +00001113 name);
paul7021c422003-07-15 12:52:22 +00001114 return 0;
1115 }
1116
paul718e3742002-12-13 20:15:29 +00001117 if_delete_update (ifp);
1118 }
1119
1120 return 0;
1121}
1122
Stephen Hemminger6072b242008-08-14 16:52:26 +01001123static int
paul718e3742002-12-13 20:15:29 +00001124netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
1125{
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001126 /* JF: Ignore messages that aren't from the kernel */
1127 if ( snl->nl_pid != 0 )
1128 {
1129 zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
1130 return 0;
1131 }
1132
paul718e3742002-12-13 20:15:29 +00001133 switch (h->nlmsg_type)
1134 {
1135 case RTM_NEWROUTE:
1136 return netlink_route_change (snl, h);
1137 break;
1138 case RTM_DELROUTE:
1139 return netlink_route_change (snl, h);
1140 break;
1141 case RTM_NEWLINK:
1142 return netlink_link_change (snl, h);
1143 break;
1144 case RTM_DELLINK:
1145 return netlink_link_change (snl, h);
1146 break;
1147 case RTM_NEWADDR:
1148 return netlink_interface_addr (snl, h);
1149 break;
1150 case RTM_DELADDR:
1151 return netlink_interface_addr (snl, h);
1152 break;
1153 default:
1154 zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
1155 break;
1156 }
1157 return 0;
1158}
1159
1160/* Interface lookup by netlink socket. */
1161int
paul6621ca82005-11-23 13:02:08 +00001162interface_lookup_netlink (void)
paul718e3742002-12-13 20:15:29 +00001163{
1164 int ret;
paul7021c422003-07-15 12:52:22 +00001165
paul718e3742002-12-13 20:15:29 +00001166 /* Get interface information. */
1167 ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
1168 if (ret < 0)
1169 return ret;
1170 ret = netlink_parse_info (netlink_interface, &netlink_cmd);
1171 if (ret < 0)
1172 return ret;
1173
1174 /* Get IPv4 address of the interfaces. */
1175 ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
1176 if (ret < 0)
1177 return ret;
1178 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1179 if (ret < 0)
1180 return ret;
1181
1182#ifdef HAVE_IPV6
1183 /* Get IPv6 address of the interfaces. */
1184 ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
1185 if (ret < 0)
1186 return ret;
1187 ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
1188 if (ret < 0)
1189 return ret;
1190#endif /* HAVE_IPV6 */
1191
1192 return 0;
1193}
1194
1195/* Routing table read function using netlink interface. Only called
1196 bootstrap time. */
1197int
paul6621ca82005-11-23 13:02:08 +00001198netlink_route_read (void)
paul718e3742002-12-13 20:15:29 +00001199{
1200 int ret;
paul7021c422003-07-15 12:52:22 +00001201
paul718e3742002-12-13 20:15:29 +00001202 /* Get IPv4 routing table. */
1203 ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
1204 if (ret < 0)
1205 return ret;
1206 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1207 if (ret < 0)
1208 return ret;
1209
1210#ifdef HAVE_IPV6
1211 /* Get IPv6 routing table. */
1212 ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
1213 if (ret < 0)
1214 return ret;
1215 ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
1216 if (ret < 0)
1217 return ret;
1218#endif /* HAVE_IPV6 */
1219
1220 return 0;
1221}
1222
1223/* Utility function comes from iproute2.
1224 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001225int
paul718e3742002-12-13 20:15:29 +00001226addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
1227{
1228 int len;
1229 struct rtattr *rta;
1230
paul7021c422003-07-15 12:52:22 +00001231 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001232
paul7021c422003-07-15 12:52:22 +00001233 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001234 return -1;
1235
paul7021c422003-07-15 12:52:22 +00001236 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001237 rta->rta_type = type;
1238 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001239 memcpy (RTA_DATA (rta), data, alen);
paul718e3742002-12-13 20:15:29 +00001240 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1241
1242 return 0;
1243}
1244
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001245int
paul718e3742002-12-13 20:15:29 +00001246rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
1247{
1248 int len;
1249 struct rtattr *subrta;
1250
paul7021c422003-07-15 12:52:22 +00001251 len = RTA_LENGTH (alen);
paul718e3742002-12-13 20:15:29 +00001252
paul7021c422003-07-15 12:52:22 +00001253 if (RTA_ALIGN (rta->rta_len) + len > maxlen)
paul718e3742002-12-13 20:15:29 +00001254 return -1;
1255
paul7021c422003-07-15 12:52:22 +00001256 subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
paul718e3742002-12-13 20:15:29 +00001257 subrta->rta_type = type;
1258 subrta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001259 memcpy (RTA_DATA (subrta), data, alen);
paul718e3742002-12-13 20:15:29 +00001260 rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
1261
1262 return 0;
1263}
1264
1265/* Utility function comes from iproute2.
1266 Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001267int
paul718e3742002-12-13 20:15:29 +00001268addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
1269{
1270 int len;
1271 struct rtattr *rta;
paul7021c422003-07-15 12:52:22 +00001272
1273 len = RTA_LENGTH (4);
1274
paul718e3742002-12-13 20:15:29 +00001275 if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
1276 return -1;
1277
paul7021c422003-07-15 12:52:22 +00001278 rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
paul718e3742002-12-13 20:15:29 +00001279 rta->rta_type = type;
1280 rta->rta_len = len;
paul7021c422003-07-15 12:52:22 +00001281 memcpy (RTA_DATA (rta), &data, 4);
paul718e3742002-12-13 20:15:29 +00001282 n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
1283
1284 return 0;
1285}
1286
1287static int
1288netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
1289{
hassob7ed1ec2005-03-31 20:13:49 +00001290 zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
paul718e3742002-12-13 20:15:29 +00001291 return 0;
1292}
1293
1294/* sendmsg() to netlink socket then recvmsg(). */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001295static int
paul718e3742002-12-13 20:15:29 +00001296netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
1297{
1298 int status;
1299 struct sockaddr_nl snl;
paul7021c422003-07-15 12:52:22 +00001300 struct iovec iov = { (void *) n, n->nlmsg_len };
1301 struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
ajs4be019d2005-01-29 16:12:41 +00001302 int save_errno;
paul7021c422003-07-15 12:52:22 +00001303
paul718e3742002-12-13 20:15:29 +00001304 memset (&snl, 0, sizeof snl);
1305 snl.nl_family = AF_NETLINK;
paul7021c422003-07-15 12:52:22 +00001306
hassob7ed1ec2005-03-31 20:13:49 +00001307 n->nlmsg_seq = ++nl->seq;
paul718e3742002-12-13 20:15:29 +00001308
1309 /* Request an acknowledgement by setting NLM_F_ACK */
1310 n->nlmsg_flags |= NLM_F_ACK;
paul7021c422003-07-15 12:52:22 +00001311
1312 if (IS_ZEBRA_DEBUG_KERNEL)
hassob7ed1ec2005-03-31 20:13:49 +00001313 zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
paul7021c422003-07-15 12:52:22 +00001314 lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
1315 n->nlmsg_seq);
paul718e3742002-12-13 20:15:29 +00001316
1317 /* Send message to netlink interface. */
paul7021c422003-07-15 12:52:22 +00001318 if (zserv_privs.change (ZPRIVS_RAISE))
1319 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +00001320 status = sendmsg (nl->sock, &msg, 0);
ajs4be019d2005-01-29 16:12:41 +00001321 save_errno = errno;
paul7021c422003-07-15 12:52:22 +00001322 if (zserv_privs.change (ZPRIVS_LOWER))
1323 zlog (NULL, LOG_ERR, "Can't lower privileges");
1324
paul718e3742002-12-13 20:15:29 +00001325 if (status < 0)
1326 {
1327 zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
ajs4be019d2005-01-29 16:12:41 +00001328 safe_strerror (save_errno));
paul718e3742002-12-13 20:15:29 +00001329 return -1;
1330 }
paul7021c422003-07-15 12:52:22 +00001331
paul718e3742002-12-13 20:15:29 +00001332
1333 /*
1334 * Get reply from netlink socket.
1335 * The reply should either be an acknowlegement or an error.
1336 */
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001337 return netlink_parse_info (netlink_talk_filter, nl);
paul718e3742002-12-13 20:15:29 +00001338}
1339
1340/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001341static int
paul718e3742002-12-13 20:15:29 +00001342netlink_route (int cmd, int family, void *dest, int length, void *gate,
paul7021c422003-07-15 12:52:22 +00001343 int index, int zebra_flags, int table)
paul718e3742002-12-13 20:15:29 +00001344{
1345 int ret;
1346 int bytelen;
1347 struct sockaddr_nl snl;
1348 int discard;
1349
paul7021c422003-07-15 12:52:22 +00001350 struct
paul718e3742002-12-13 20:15:29 +00001351 {
1352 struct nlmsghdr n;
1353 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001354 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001355 } req;
1356
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001357 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001358
1359 bytelen = (family == AF_INET ? 4 : 16);
1360
1361 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1362 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1363 req.n.nlmsg_type = cmd;
1364 req.r.rtm_family = family;
1365 req.r.rtm_table = table;
1366 req.r.rtm_dst_len = length;
Timo Teräs40da2212008-08-13 17:37:14 +01001367 req.r.rtm_protocol = RTPROT_ZEBRA;
1368 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001369
hasso81dfcaa2003-05-25 19:21:25 +00001370 if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1371 || (zebra_flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001372 discard = 1;
1373 else
1374 discard = 0;
1375
paul7021c422003-07-15 12:52:22 +00001376 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001377 {
paul7021c422003-07-15 12:52:22 +00001378 if (discard)
paul595db7f2003-05-25 21:35:06 +00001379 {
1380 if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
1381 req.r.rtm_type = RTN_BLACKHOLE;
1382 else if (zebra_flags & ZEBRA_FLAG_REJECT)
1383 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001384 else
1385 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1386 }
paul595db7f2003-05-25 21:35:06 +00001387 else
paul7021c422003-07-15 12:52:22 +00001388 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001389 }
1390
1391 if (dest)
1392 addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
1393
paul7021c422003-07-15 12:52:22 +00001394 if (!discard)
paul718e3742002-12-13 20:15:29 +00001395 {
1396 if (gate)
paul7021c422003-07-15 12:52:22 +00001397 addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
paul718e3742002-12-13 20:15:29 +00001398 if (index > 0)
paul7021c422003-07-15 12:52:22 +00001399 addattr32 (&req.n, sizeof req, RTA_OIF, index);
paul718e3742002-12-13 20:15:29 +00001400 }
1401
1402 /* Destination netlink address. */
1403 memset (&snl, 0, sizeof snl);
1404 snl.nl_family = AF_NETLINK;
1405
1406 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001407 ret = netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001408 if (ret < 0)
1409 return -1;
1410
1411 return 0;
1412}
1413
1414/* Routing table change via netlink interface. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001415static int
paul718e3742002-12-13 20:15:29 +00001416netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
paul7021c422003-07-15 12:52:22 +00001417 int family)
paul718e3742002-12-13 20:15:29 +00001418{
1419 int bytelen;
1420 struct sockaddr_nl snl;
1421 struct nexthop *nexthop = NULL;
1422 int nexthop_num = 0;
paul718e3742002-12-13 20:15:29 +00001423 int discard;
1424
paul7021c422003-07-15 12:52:22 +00001425 struct
paul718e3742002-12-13 20:15:29 +00001426 {
1427 struct nlmsghdr n;
1428 struct rtmsg r;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001429 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001430 } req;
1431
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001432 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001433
1434 bytelen = (family == AF_INET ? 4 : 16);
1435
1436 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1437 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1438 req.n.nlmsg_type = cmd;
1439 req.r.rtm_family = family;
1440 req.r.rtm_table = rib->table;
1441 req.r.rtm_dst_len = p->prefixlen;
Timo Teräs40da2212008-08-13 17:37:14 +01001442 req.r.rtm_protocol = RTPROT_ZEBRA;
1443 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
paul718e3742002-12-13 20:15:29 +00001444
paul7021c422003-07-15 12:52:22 +00001445 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
paul718e3742002-12-13 20:15:29 +00001446 discard = 1;
1447 else
1448 discard = 0;
1449
paul7021c422003-07-15 12:52:22 +00001450 if (cmd == RTM_NEWROUTE)
paul718e3742002-12-13 20:15:29 +00001451 {
paul7021c422003-07-15 12:52:22 +00001452 if (discard)
paul595db7f2003-05-25 21:35:06 +00001453 {
1454 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1455 req.r.rtm_type = RTN_BLACKHOLE;
1456 else if (rib->flags & ZEBRA_FLAG_REJECT)
1457 req.r.rtm_type = RTN_UNREACHABLE;
paul7021c422003-07-15 12:52:22 +00001458 else
1459 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1460 }
paul595db7f2003-05-25 21:35:06 +00001461 else
paul7021c422003-07-15 12:52:22 +00001462 req.r.rtm_type = RTN_UNICAST;
paul718e3742002-12-13 20:15:29 +00001463 }
1464
1465 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
1466
1467 /* Metric. */
1468 addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
1469
1470 if (discard)
1471 {
1472 if (cmd == RTM_NEWROUTE)
paul7021c422003-07-15 12:52:22 +00001473 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
1474 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001475 goto skip;
1476 }
1477
1478 /* Multipath case. */
1479 if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
1480 {
1481 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
paul7021c422003-07-15 12:52:22 +00001482 {
paul5ec90d22003-06-19 01:41:37 +00001483
paul7021c422003-07-15 12:52:22 +00001484 if ((cmd == RTM_NEWROUTE
1485 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1486 || (cmd == RTM_DELROUTE
1487 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1488 {
paul5ec90d22003-06-19 01:41:37 +00001489
paul7021c422003-07-15 12:52:22 +00001490 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1491 {
1492 if (IS_ZEBRA_DEBUG_KERNEL)
1493 {
ajsb6178002004-12-07 21:12:56 +00001494 zlog_debug
paul7021c422003-07-15 12:52:22 +00001495 ("netlink_route_multipath() (recursive, 1 hop): "
hasso206d8052005-04-09 16:38:51 +00001496 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001497#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001498 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001499 inet6_ntoa (p->u.prefix6),
1500#else
1501 inet_ntoa (p->u.prefix4),
1502#endif /* HAVE_IPV6 */
1503
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001504 p->prefixlen, nexthop_type_to_str (nexthop->rtype));
paul7021c422003-07-15 12:52:22 +00001505 }
paul5ec90d22003-06-19 01:41:37 +00001506
paul7021c422003-07-15 12:52:22 +00001507 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1508 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001509 {
1510 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1511 &nexthop->rgate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001512 if (nexthop->src.ipv4.s_addr)
1513 addattr_l(&req.n, sizeof req, RTA_PREFSRC,
1514 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001515 if (IS_ZEBRA_DEBUG_KERNEL)
1516 zlog_debug("netlink_route_multipath() (recursive, "
1517 "1 hop): nexthop via %s if %u",
1518 inet_ntoa (nexthop->rgate.ipv4),
1519 nexthop->rifindex);
1520 }
paul718e3742002-12-13 20:15:29 +00001521#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001522 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1523 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1524 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001525 {
1526 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1527 &nexthop->rgate.ipv6, bytelen);
1528
1529 if (IS_ZEBRA_DEBUG_KERNEL)
1530 zlog_debug("netlink_route_multipath() (recursive, "
1531 "1 hop): nexthop via %s if %u",
1532 inet6_ntoa (nexthop->rgate.ipv6),
1533 nexthop->rifindex);
1534 }
paul718e3742002-12-13 20:15:29 +00001535#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001536 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1537 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
1538 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1539 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
1540 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001541 {
1542 addattr32 (&req.n, sizeof req, RTA_OIF,
1543 nexthop->rifindex);
Paul Jakma7514fb72007-05-02 16:05:35 +00001544 if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1545 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
1546 && nexthop->src.ipv4.s_addr)
1547 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1548 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001549
1550 if (IS_ZEBRA_DEBUG_KERNEL)
1551 zlog_debug("netlink_route_multipath() (recursive, "
1552 "1 hop): nexthop via if %u",
1553 nexthop->rifindex);
1554 }
paul7021c422003-07-15 12:52:22 +00001555 }
1556 else
1557 {
1558 if (IS_ZEBRA_DEBUG_KERNEL)
1559 {
ajsb6178002004-12-07 21:12:56 +00001560 zlog_debug
hasso206d8052005-04-09 16:38:51 +00001561 ("netlink_route_multipath() (single hop): "
1562 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001563#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001564 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001565 inet6_ntoa (p->u.prefix6),
1566#else
1567 inet_ntoa (p->u.prefix4),
1568#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001569 p->prefixlen, nexthop_type_to_str (nexthop->type));
paul7021c422003-07-15 12:52:22 +00001570 }
paul5ec90d22003-06-19 01:41:37 +00001571
paul7021c422003-07-15 12:52:22 +00001572 if (nexthop->type == NEXTHOP_TYPE_IPV4
1573 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001574 {
1575 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1576 &nexthop->gate.ipv4, bytelen);
Paul Jakma7514fb72007-05-02 16:05:35 +00001577 if (nexthop->src.ipv4.s_addr)
1578 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1579 &nexthop->src.ipv4, bytelen);
hasso206d8052005-04-09 16:38:51 +00001580
1581 if (IS_ZEBRA_DEBUG_KERNEL)
1582 zlog_debug("netlink_route_multipath() (single hop): "
1583 "nexthop via %s if %u",
1584 inet_ntoa (nexthop->gate.ipv4),
1585 nexthop->ifindex);
1586 }
paul718e3742002-12-13 20:15:29 +00001587#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001588 if (nexthop->type == NEXTHOP_TYPE_IPV6
1589 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1590 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001591 {
1592 addattr_l (&req.n, sizeof req, RTA_GATEWAY,
1593 &nexthop->gate.ipv6, bytelen);
1594
1595 if (IS_ZEBRA_DEBUG_KERNEL)
1596 zlog_debug("netlink_route_multipath() (single hop): "
1597 "nexthop via %s if %u",
1598 inet6_ntoa (nexthop->gate.ipv6),
1599 nexthop->ifindex);
1600 }
paul718e3742002-12-13 20:15:29 +00001601#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001602 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
1603 || nexthop->type == NEXTHOP_TYPE_IFNAME
Paul Jakma7514fb72007-05-02 16:05:35 +00001604 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1605 {
1606 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1607
1608 if (nexthop->src.ipv4.s_addr)
1609 addattr_l (&req.n, sizeof req, RTA_PREFSRC,
1610 &nexthop->src.ipv4, bytelen);
1611
1612 if (IS_ZEBRA_DEBUG_KERNEL)
1613 zlog_debug("netlink_route_multipath() (single hop): "
1614 "nexthop via if %u", nexthop->ifindex);
1615 }
1616 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001617 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001618 {
1619 addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
1620
1621 if (IS_ZEBRA_DEBUG_KERNEL)
1622 zlog_debug("netlink_route_multipath() (single hop): "
1623 "nexthop via if %u", nexthop->ifindex);
1624 }
paul7021c422003-07-15 12:52:22 +00001625 }
paul718e3742002-12-13 20:15:29 +00001626
paul7021c422003-07-15 12:52:22 +00001627 if (cmd == RTM_NEWROUTE)
1628 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
paul718e3742002-12-13 20:15:29 +00001629
paul7021c422003-07-15 12:52:22 +00001630 nexthop_num++;
1631 break;
1632 }
1633 }
paul718e3742002-12-13 20:15:29 +00001634 }
1635 else
1636 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001637 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001638 struct rtattr *rta = (void *) buf;
1639 struct rtnexthop *rtnh;
Paul Jakma7514fb72007-05-02 16:05:35 +00001640 union g_addr *src = NULL;
paul718e3742002-12-13 20:15:29 +00001641
1642 rta->rta_type = RTA_MULTIPATH;
paul7021c422003-07-15 12:52:22 +00001643 rta->rta_len = RTA_LENGTH (0);
1644 rtnh = RTA_DATA (rta);
paul718e3742002-12-13 20:15:29 +00001645
1646 nexthop_num = 0;
1647 for (nexthop = rib->nexthop;
paul7021c422003-07-15 12:52:22 +00001648 nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
1649 nexthop = nexthop->next)
1650 {
1651 if ((cmd == RTM_NEWROUTE
1652 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1653 || (cmd == RTM_DELROUTE
1654 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1655 {
1656 nexthop_num++;
paul718e3742002-12-13 20:15:29 +00001657
paul7021c422003-07-15 12:52:22 +00001658 rtnh->rtnh_len = sizeof (*rtnh);
1659 rtnh->rtnh_flags = 0;
1660 rtnh->rtnh_hops = 0;
1661 rta->rta_len += rtnh->rtnh_len;
paul718e3742002-12-13 20:15:29 +00001662
paul7021c422003-07-15 12:52:22 +00001663 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1664 {
1665 if (IS_ZEBRA_DEBUG_KERNEL)
1666 {
ajsb6178002004-12-07 21:12:56 +00001667 zlog_debug ("netlink_route_multipath() "
hasso206d8052005-04-09 16:38:51 +00001668 "(recursive, multihop): %s %s/%d type %s",
hasso1ada8192005-06-12 11:28:18 +00001669 lookup (nlmsg_str, cmd),
1670#ifdef HAVE_IPV6
1671 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
1672 inet6_ntoa (p->u.prefix6),
1673#else
1674 inet_ntoa (p->u.prefix4),
1675#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001676 p->prefixlen, nexthop_type_to_str (nexthop->rtype));
paul7021c422003-07-15 12:52:22 +00001677 }
1678 if (nexthop->rtype == NEXTHOP_TYPE_IPV4
1679 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
1680 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001681 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
paul7021c422003-07-15 12:52:22 +00001682 &nexthop->rgate.ipv4, bytelen);
1683 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
hasso206d8052005-04-09 16:38:51 +00001684
Paul Jakma7514fb72007-05-02 16:05:35 +00001685 if (nexthop->src.ipv4.s_addr)
1686 src = &nexthop->src;
1687
hasso206d8052005-04-09 16:38:51 +00001688 if (IS_ZEBRA_DEBUG_KERNEL)
1689 zlog_debug("netlink_route_multipath() (recursive, "
1690 "multihop): nexthop via %s if %u",
1691 inet_ntoa (nexthop->rgate.ipv4),
1692 nexthop->rifindex);
paul7021c422003-07-15 12:52:22 +00001693 }
paul718e3742002-12-13 20:15:29 +00001694#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001695 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
1696 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
1697 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001698 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001699 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001700 &nexthop->rgate.ipv6, bytelen);
1701
1702 if (IS_ZEBRA_DEBUG_KERNEL)
1703 zlog_debug("netlink_route_multipath() (recursive, "
1704 "multihop): nexthop via %s if %u",
1705 inet6_ntoa (nexthop->rgate.ipv6),
1706 nexthop->rifindex);
1707 }
paul718e3742002-12-13 20:15:29 +00001708#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001709 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001710 if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
1711 || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
1712 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
1713 {
1714 rtnh->rtnh_ifindex = nexthop->rifindex;
1715 if (nexthop->src.ipv4.s_addr)
1716 src = &nexthop->src;
1717
1718 if (IS_ZEBRA_DEBUG_KERNEL)
1719 zlog_debug("netlink_route_multipath() (recursive, "
1720 "multihop): nexthop via if %u",
1721 nexthop->rifindex);
1722 }
1723 else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
paul7021c422003-07-15 12:52:22 +00001724 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
hasso206d8052005-04-09 16:38:51 +00001725 {
1726 rtnh->rtnh_ifindex = nexthop->rifindex;
1727
1728 if (IS_ZEBRA_DEBUG_KERNEL)
1729 zlog_debug("netlink_route_multipath() (recursive, "
1730 "multihop): nexthop via if %u",
1731 nexthop->rifindex);
1732 }
paul7021c422003-07-15 12:52:22 +00001733 else
hasso206d8052005-04-09 16:38:51 +00001734 {
1735 rtnh->rtnh_ifindex = 0;
1736 }
paul7021c422003-07-15 12:52:22 +00001737 }
1738 else
1739 {
1740 if (IS_ZEBRA_DEBUG_KERNEL)
1741 {
hasso206d8052005-04-09 16:38:51 +00001742 zlog_debug ("netlink_route_multipath() (multihop): "
1743 "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
hasso1ada8192005-06-12 11:28:18 +00001744#ifdef HAVE_IPV6
hasso206d8052005-04-09 16:38:51 +00001745 (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
hasso1ada8192005-06-12 11:28:18 +00001746 inet6_ntoa (p->u.prefix6),
1747#else
1748 inet_ntoa (p->u.prefix4),
1749#endif /* HAVE_IPV6 */
Avneesh Sachdev78deec42012-11-13 22:48:56 +00001750 p->prefixlen, nexthop_type_to_str (nexthop->type));
paul7021c422003-07-15 12:52:22 +00001751 }
1752 if (nexthop->type == NEXTHOP_TYPE_IPV4
1753 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1754 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001755 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001756 &nexthop->gate.ipv4, bytelen);
1757 rtnh->rtnh_len += sizeof (struct rtattr) + 4;
1758
Paul Jakma7514fb72007-05-02 16:05:35 +00001759 if (nexthop->src.ipv4.s_addr)
1760 src = &nexthop->src;
1761
hasso206d8052005-04-09 16:38:51 +00001762 if (IS_ZEBRA_DEBUG_KERNEL)
1763 zlog_debug("netlink_route_multipath() (multihop): "
1764 "nexthop via %s if %u",
1765 inet_ntoa (nexthop->gate.ipv4),
1766 nexthop->ifindex);
paul7021c422003-07-15 12:52:22 +00001767 }
paul718e3742002-12-13 20:15:29 +00001768#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001769 if (nexthop->type == NEXTHOP_TYPE_IPV6
1770 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
1771 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001772 {
JR Rivers3cadc0c2012-04-01 12:16:31 -07001773 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
hasso206d8052005-04-09 16:38:51 +00001774 &nexthop->gate.ipv6, bytelen);
1775
1776 if (IS_ZEBRA_DEBUG_KERNEL)
1777 zlog_debug("netlink_route_multipath() (multihop): "
1778 "nexthop via %s if %u",
1779 inet6_ntoa (nexthop->gate.ipv6),
1780 nexthop->ifindex);
1781 }
paul718e3742002-12-13 20:15:29 +00001782#endif /* HAVE_IPV6 */
paul7021c422003-07-15 12:52:22 +00001783 /* ifindex */
Paul Jakma7514fb72007-05-02 16:05:35 +00001784 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
1785 || nexthop->type == NEXTHOP_TYPE_IFINDEX
1786 || nexthop->type == NEXTHOP_TYPE_IFNAME)
1787 {
1788 rtnh->rtnh_ifindex = nexthop->ifindex;
1789 if (nexthop->src.ipv4.s_addr)
1790 src = &nexthop->src;
1791 if (IS_ZEBRA_DEBUG_KERNEL)
1792 zlog_debug("netlink_route_multipath() (multihop): "
1793 "nexthop via if %u", nexthop->ifindex);
1794 }
1795 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
paul7021c422003-07-15 12:52:22 +00001796 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
hasso206d8052005-04-09 16:38:51 +00001797 {
1798 rtnh->rtnh_ifindex = nexthop->ifindex;
1799
1800 if (IS_ZEBRA_DEBUG_KERNEL)
1801 zlog_debug("netlink_route_multipath() (multihop): "
1802 "nexthop via if %u", nexthop->ifindex);
1803 }
paul7021c422003-07-15 12:52:22 +00001804 else
hasso206d8052005-04-09 16:38:51 +00001805 {
1806 rtnh->rtnh_ifindex = 0;
1807 }
paul7021c422003-07-15 12:52:22 +00001808 }
1809 rtnh = RTNH_NEXT (rtnh);
paul718e3742002-12-13 20:15:29 +00001810
paul7021c422003-07-15 12:52:22 +00001811 if (cmd == RTM_NEWROUTE)
1812 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1813 }
1814 }
Paul Jakma7514fb72007-05-02 16:05:35 +00001815 if (src)
1816 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
paul718e3742002-12-13 20:15:29 +00001817
1818 if (rta->rta_len > RTA_LENGTH (0))
JR Rivers3cadc0c2012-04-01 12:16:31 -07001819 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
paul7021c422003-07-15 12:52:22 +00001820 RTA_PAYLOAD (rta));
paul718e3742002-12-13 20:15:29 +00001821 }
1822
1823 /* If there is no useful nexthop then return. */
1824 if (nexthop_num == 0)
1825 {
1826 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +00001827 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +00001828 return 0;
1829 }
1830
paul7021c422003-07-15 12:52:22 +00001831skip:
paul718e3742002-12-13 20:15:29 +00001832
1833 /* Destination netlink address. */
1834 memset (&snl, 0, sizeof snl);
1835 snl.nl_family = AF_NETLINK;
1836
paul718e3742002-12-13 20:15:29 +00001837 /* Talk to netlink socket. */
hassob7ed1ec2005-03-31 20:13:49 +00001838 return netlink_talk (&req.n, &netlink_cmd);
paul718e3742002-12-13 20:15:29 +00001839}
1840
1841int
1842kernel_add_ipv4 (struct prefix *p, struct rib *rib)
1843{
1844 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
1845}
1846
1847int
1848kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
1849{
1850 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
1851}
1852
1853#ifdef HAVE_IPV6
1854int
1855kernel_add_ipv6 (struct prefix *p, struct rib *rib)
1856{
1857 return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
1858}
1859
1860int
1861kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
1862{
1863 return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
1864}
1865
1866/* Delete IPv6 route from the kernel. */
1867int
1868kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +00001869 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +00001870{
paul7021c422003-07-15 12:52:22 +00001871 return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
1872 dest->prefixlen, gate, index, flags, table);
paul718e3742002-12-13 20:15:29 +00001873}
1874#endif /* HAVE_IPV6 */
1875
1876/* Interface address modification. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001877static int
paul718e3742002-12-13 20:15:29 +00001878netlink_address (int cmd, int family, struct interface *ifp,
paul7021c422003-07-15 12:52:22 +00001879 struct connected *ifc)
paul718e3742002-12-13 20:15:29 +00001880{
1881 int bytelen;
1882 struct prefix *p;
1883
paul7021c422003-07-15 12:52:22 +00001884 struct
paul718e3742002-12-13 20:15:29 +00001885 {
1886 struct nlmsghdr n;
1887 struct ifaddrmsg ifa;
JR Rivers3cadc0c2012-04-01 12:16:31 -07001888 char buf[NL_PKT_BUF_SIZE];
paul718e3742002-12-13 20:15:29 +00001889 } req;
1890
1891 p = ifc->address;
Jorge Boncompte [DTI2]a4c06de2012-04-20 14:28:40 +02001892 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
paul718e3742002-12-13 20:15:29 +00001893
1894 bytelen = (family == AF_INET ? 4 : 16);
1895
paul7021c422003-07-15 12:52:22 +00001896 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
paul718e3742002-12-13 20:15:29 +00001897 req.n.nlmsg_flags = NLM_F_REQUEST;
1898 req.n.nlmsg_type = cmd;
1899 req.ifa.ifa_family = family;
1900
1901 req.ifa.ifa_index = ifp->ifindex;
1902 req.ifa.ifa_prefixlen = p->prefixlen;
1903
1904 addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
1905
1906 if (family == AF_INET && cmd == RTM_NEWADDR)
1907 {
Andrew J. Schorre4529632006-12-12 19:18:21 +00001908 if (!CONNECTED_PEER(ifc) && ifc->destination)
paul7021c422003-07-15 12:52:22 +00001909 {
1910 p = ifc->destination;
1911 addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
1912 bytelen);
1913 }
paul718e3742002-12-13 20:15:29 +00001914 }
1915
1916 if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
1917 SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
paul7021c422003-07-15 12:52:22 +00001918
paul718e3742002-12-13 20:15:29 +00001919 if (ifc->label)
1920 addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
paul7021c422003-07-15 12:52:22 +00001921 strlen (ifc->label) + 1);
paul718e3742002-12-13 20:15:29 +00001922
1923 return netlink_talk (&req.n, &netlink_cmd);
1924}
1925
1926int
1927kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
1928{
1929 return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
1930}
1931
1932int
1933kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
1934{
1935 return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
1936}
1937
paul718e3742002-12-13 20:15:29 +00001938
1939extern struct thread_master *master;
1940
1941/* Kernel route reflection. */
Stephen Hemminger6072b242008-08-14 16:52:26 +01001942static int
paul718e3742002-12-13 20:15:29 +00001943kernel_read (struct thread *thread)
1944{
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001945 netlink_parse_info (netlink_information_fetch, &netlink);
paulb21b19c2003-06-15 01:28:29 +00001946 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
paul718e3742002-12-13 20:15:29 +00001947
1948 return 0;
1949}
1950
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001951/* Filter out messages from self that occur on listener socket,
1952 caused by our actions on the command socket
1953 */
1954static void netlink_install_filter (int sock, __u32 pid)
Paul Jakma768a27e2008-05-29 18:23:08 +00001955{
Paul Jakma768a27e2008-05-29 18:23:08 +00001956 struct sock_filter filter[] = {
Stephen Hemminger3d265b42008-08-16 17:30:39 +01001957 /* 0: ldh [4] */
1958 BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
1959 /* 1: jeq 0x18 jt 3 jf 6 */
1960 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
1961 /* 2: jeq 0x19 jt 3 jf 6 */
1962 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
1963 /* 3: ldw [12] */
1964 BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
1965 /* 4: jeq XX jt 5 jf 6 */
1966 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
1967 /* 5: ret 0 (skip) */
1968 BPF_STMT(BPF_RET|BPF_K, 0),
1969 /* 6: ret 0xffff (keep) */
1970 BPF_STMT(BPF_RET|BPF_K, 0xffff),
Paul Jakma768a27e2008-05-29 18:23:08 +00001971 };
1972
1973 struct sock_fprog prog = {
Balaji.G837d16c2012-09-26 14:09:10 +05301974 .len = array_size(filter),
Paul Jakma768a27e2008-05-29 18:23:08 +00001975 .filter = filter,
1976 };
1977
1978 if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
1979 zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
1980}
1981
paul718e3742002-12-13 20:15:29 +00001982/* Exported interface function. This function simply calls
1983 netlink_socket (). */
1984void
paul6621ca82005-11-23 13:02:08 +00001985kernel_init (void)
paul718e3742002-12-13 20:15:29 +00001986{
1987 unsigned long groups;
1988
paul7021c422003-07-15 12:52:22 +00001989 groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
paul718e3742002-12-13 20:15:29 +00001990#ifdef HAVE_IPV6
paul7021c422003-07-15 12:52:22 +00001991 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
paul718e3742002-12-13 20:15:29 +00001992#endif /* HAVE_IPV6 */
1993 netlink_socket (&netlink, groups);
1994 netlink_socket (&netlink_cmd, 0);
1995
1996 /* Register kernel socket. */
1997 if (netlink.sock > 0)
Paul Jakma768a27e2008-05-29 18:23:08 +00001998 {
Stephen Hemminger4cde9312008-08-16 17:51:27 +01001999 /* Only want non-blocking on the netlink event socket */
2000 if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
2001 zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
2002 safe_strerror (errno));
2003
Stephen Hemminger30afea32008-08-16 18:25:47 +01002004 /* Set receive buffer size if it's set from command line */
2005 if (nl_rcvbufsize)
2006 netlink_recvbuf (&netlink, nl_rcvbufsize);
2007
Stephen Hemminger3d265b42008-08-16 17:30:39 +01002008 netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
Paul Jakma768a27e2008-05-29 18:23:08 +00002009 thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
2010 }
paul718e3742002-12-13 20:15:29 +00002011}
Avneesh Sachdev78deec42012-11-13 22:48:56 +00002012
2013/*
2014 * nl_msg_type_to_str
2015 */
2016const char *
2017nl_msg_type_to_str (uint16_t msg_type)
2018{
2019 return lookup (nlmsg_str, msg_type);
2020}
2021
2022/*
2023 * nl_rtproto_to_str
2024 */
2025const char *
2026nl_rtproto_to_str (u_char rtproto)
2027{
2028 return lookup (rtproto_str, rtproto);
2029}