]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/linux/netlink.c
Add 'GENERATE/ACCEPT FROM datetime TO datetime' to password options
[thirdparty/bird.git] / sysdep / linux / netlink.c
CommitLineData
95616c82
OZ
1/*
2 * BIRD -- Linux Netlink Interface
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9#include <stdio.h>
f83ce94d 10#include <unistd.h>
95616c82
OZ
11#include <fcntl.h>
12#include <sys/socket.h>
13#include <sys/uio.h>
14#include <errno.h>
15
16#undef LOCAL_DEBUG
17
18#include "nest/bird.h"
19#include "nest/route.h"
20#include "nest/protocol.h"
21#include "nest/iface.h"
22#include "lib/alloca.h"
23#include "lib/timer.h"
24#include "lib/unix.h"
25#include "lib/krt.h"
26#include "lib/socket.h"
27#include "lib/string.h"
9ddbfbdd 28#include "lib/hash.h"
95616c82
OZ
29#include "conf/conf.h"
30
31#include <asm/types.h>
32#include <linux/if.h>
33#include <linux/netlink.h>
34#include <linux/rtnetlink.h>
35
9ddbfbdd 36
95616c82
OZ
37#ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */
38#define MSG_TRUNC 0x20
39#endif
40
41#ifndef IFF_LOWER_UP
42#define IFF_LOWER_UP 0x10000
43#endif
44
9ddbfbdd
MM
45#ifndef RTA_TABLE
46#define RTA_TABLE 15
47#endif
48
49
95616c82
OZ
50/*
51 * Synchronous Netlink interface
52 */
53
54struct nl_sock
55{
56 int fd;
57 u32 seq;
58 byte *rx_buffer; /* Receive buffer */
59 struct nlmsghdr *last_hdr; /* Recently received packet */
ae80a2de 60 uint last_size;
95616c82
OZ
61};
62
63#define NL_RX_SIZE 8192
64
65static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */
66static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */
67
68static void
69nl_open_sock(struct nl_sock *nl)
70{
71 if (nl->fd < 0)
72 {
73 nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
74 if (nl->fd < 0)
75 die("Unable to open rtnetlink socket: %m");
76 nl->seq = now;
77 nl->rx_buffer = xmalloc(NL_RX_SIZE);
78 nl->last_hdr = NULL;
79 nl->last_size = 0;
80 }
81}
82
83static void
84nl_open(void)
85{
86 nl_open_sock(&nl_scan);
87 nl_open_sock(&nl_req);
88}
89
90static void
91nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
92{
93 struct sockaddr_nl sa;
94
95 memset(&sa, 0, sizeof(sa));
96 sa.nl_family = AF_NETLINK;
97 nh->nlmsg_pid = 0;
98 nh->nlmsg_seq = ++(nl->seq);
99 if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
100 die("rtnetlink sendto: %m");
101 nl->last_hdr = NULL;
102}
103
104static void
86c3eea0 105nl_request_dump(int af, int cmd)
95616c82
OZ
106{
107 struct {
108 struct nlmsghdr nh;
109 struct rtgenmsg g;
641172c6
OZ
110 } req = {
111 .nh.nlmsg_type = cmd,
112 .nh.nlmsg_len = sizeof(req),
113 .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
114 .g.rtgen_family = af
115 };
95616c82
OZ
116 nl_send(&nl_scan, &req.nh);
117}
118
119static struct nlmsghdr *
120nl_get_reply(struct nl_sock *nl)
121{
122 for(;;)
123 {
124 if (!nl->last_hdr)
125 {
126 struct iovec iov = { nl->rx_buffer, NL_RX_SIZE };
127 struct sockaddr_nl sa;
128 struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
129 int x = recvmsg(nl->fd, &m, 0);
130 if (x < 0)
131 die("nl_get_reply: %m");
132 if (sa.nl_pid) /* It isn't from the kernel */
133 {
134 DBG("Non-kernel packet\n");
135 continue;
136 }
137 nl->last_size = x;
138 nl->last_hdr = (void *) nl->rx_buffer;
139 if (m.msg_flags & MSG_TRUNC)
140 bug("nl_get_reply: got truncated reply which should be impossible");
141 }
142 if (NLMSG_OK(nl->last_hdr, nl->last_size))
143 {
144 struct nlmsghdr *h = nl->last_hdr;
145 nl->last_hdr = NLMSG_NEXT(h, nl->last_size);
146 if (h->nlmsg_seq != nl->seq)
147 {
148 log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
149 h->nlmsg_seq, nl->seq);
150 continue;
151 }
152 return h;
153 }
154 if (nl->last_size)
155 log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size);
156 nl->last_hdr = NULL;
157 }
158}
159
1123e707 160static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
95616c82
OZ
161
162static int
163nl_error(struct nlmsghdr *h)
164{
165 struct nlmsgerr *e;
166 int ec;
167
168 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
169 {
170 log(L_WARN "Netlink: Truncated error message received");
171 return ENOBUFS;
172 }
173 e = (struct nlmsgerr *) NLMSG_DATA(h);
174 ec = -e->error;
175 if (ec)
176 log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec));
177 return ec;
178}
179
180static struct nlmsghdr *
181nl_get_scan(void)
182{
183 struct nlmsghdr *h = nl_get_reply(&nl_scan);
184
185 if (h->nlmsg_type == NLMSG_DONE)
186 return NULL;
187 if (h->nlmsg_type == NLMSG_ERROR)
188 {
189 nl_error(h);
190 return NULL;
191 }
192 return h;
193}
194
195static int
196nl_exchange(struct nlmsghdr *pkt)
197{
198 struct nlmsghdr *h;
199
200 nl_send(&nl_req, pkt);
201 for(;;)
202 {
203 h = nl_get_reply(&nl_req);
204 if (h->nlmsg_type == NLMSG_ERROR)
205 break;
206 log(L_WARN "nl_exchange: Unexpected reply received");
207 }
208 return nl_error(h) ? -1 : 0;
209}
210
211/*
212 * Netlink attributes
213 */
214
215static int nl_attr_len;
216
217static void *
218nl_checkin(struct nlmsghdr *h, int lsize)
219{
220 nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
221 if (nl_attr_len < 0)
222 {
223 log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
224 return NULL;
225 }
226 return NLMSG_DATA(h);
227}
228
ad276157
MM
229struct nl_want_attrs {
230 u8 defined:1;
231 u8 checksize:1;
232 u8 size;
233};
234
235
236#define BIRD_IFLA_MAX (IFLA_WIRELESS+1)
237
238static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
239 [IFLA_IFNAME] = { 1, 0, 0 },
240 [IFLA_MTU] = { 1, 1, sizeof(u32) },
241 [IFLA_WIRELESS] = { 1, 0, 0 },
242};
243
29a64162 244
ad276157
MM
245#define BIRD_IFA_MAX (IFA_ANYCAST+1)
246
ad276157
MM
247static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = {
248 [IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) },
249 [IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) },
250 [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
251};
29a64162 252
ad276157
MM
253static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
254 [IFA_ADDRESS] = { 1, 1, sizeof(ip6_addr) },
255 [IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) },
256};
29a64162 257
ad276157 258
ad276157
MM
259#define BIRD_RTA_MAX (RTA_TABLE+1)
260
261static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
262 [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
263};
264
ad276157
MM
265static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
266 [RTA_DST] = { 1, 1, sizeof(ip4_addr) },
267 [RTA_OIF] = { 1, 1, sizeof(u32) },
268 [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
269 [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
270 [RTA_PREFSRC] = { 1, 1, sizeof(ip4_addr) },
271 [RTA_METRICS] = { 1, 0, 0 },
272 [RTA_MULTIPATH] = { 1, 0, 0 },
273 [RTA_FLOW] = { 1, 1, sizeof(u32) },
274 [RTA_TABLE] = { 1, 1, sizeof(u32) },
275};
29a64162 276
ad276157
MM
277static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
278 [RTA_DST] = { 1, 1, sizeof(ip6_addr) },
279 [RTA_IIF] = { 1, 1, sizeof(u32) },
280 [RTA_OIF] = { 1, 1, sizeof(u32) },
281 [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
282 [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
283 [RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) },
284 [RTA_METRICS] = { 1, 0, 0 },
285 [RTA_FLOW] = { 1, 1, sizeof(u32) },
286 [RTA_TABLE] = { 1, 1, sizeof(u32) },
287};
ad276157
MM
288
289
95616c82 290static int
ad276157 291nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k, int ksize)
95616c82
OZ
292{
293 int max = ksize / sizeof(struct rtattr *);
294 bzero(k, ksize);
ad276157
MM
295
296 for ( ; RTA_OK(a, nl_attr_len); a = RTA_NEXT(a, nl_attr_len))
95616c82 297 {
ad276157
MM
298 if ((a->rta_type >= max) || !want[a->rta_type].defined)
299 continue;
300
301 if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
302 {
9b136840 303 log(L_ERR "nl_parse_attrs: Malformed attribute received");
ad276157
MM
304 return 0;
305 }
306
307 k[a->rta_type] = a;
95616c82 308 }
ad276157 309
95616c82
OZ
310 if (nl_attr_len)
311 {
312 log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
313 return 0;
314 }
ad276157
MM
315
316 return 1;
95616c82
OZ
317}
318
fce764f9 319static inline u32 rta_get_u32(struct rtattr *a)
acb04cfd
OZ
320{ return *(u32 *) RTA_DATA(a); }
321
322static inline ip4_addr rta_get_ip4(struct rtattr *a)
323{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); }
324
325static inline ip6_addr rta_get_ip6(struct rtattr *a)
326{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
327
9b136840
MM
328static inline ip_addr rta_get_ipa(struct rtattr *a)
329{
330 if (RTA_PAYLOAD(a) == sizeof(ip4_addr))
331 return ipa_from_ip4(rta_get_ip4(a));
332 else
333 return ipa_from_ip6(rta_get_ip6(a));
334}
acb04cfd 335
9fdf9d29
OZ
336struct rtattr *
337nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
95616c82 338{
9fdf9d29
OZ
339 uint pos = NLMSG_ALIGN(h->nlmsg_len);
340 uint len = RTA_LENGTH(dlen);
95616c82
OZ
341
342 if (pos + len > bufsize)
343 bug("nl_add_attr: packet buffer overflow");
9fdf9d29
OZ
344
345 struct rtattr *a = (struct rtattr *)((char *)h + pos);
95616c82
OZ
346 a->rta_type = code;
347 a->rta_len = len;
348 h->nlmsg_len = pos + len;
9fdf9d29
OZ
349
350 if (dlen > 0)
351 memcpy(RTA_DATA(a), data, dlen);
352
353 return a;
95616c82
OZ
354}
355
356static inline void
29a64162 357nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
95616c82
OZ
358{
359 nl_add_attr(h, bufsize, code, &data, 4);
360}
361
362static inline void
29a64162 363nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4)
95616c82 364{
29a64162
OZ
365 ip4 = ip4_hton(ip4);
366 nl_add_attr(h, bufsize, code, &ip4, sizeof(ip4));
367}
368
369static inline void
370nl_add_attr_ip6(struct nlmsghdr *h, uint bufsize, int code, ip6_addr ip6)
371{
372 ip6 = ip6_hton(ip6);
373 nl_add_attr(h, bufsize, code, &ip6, sizeof(ip6));
374}
375
376static inline void
377nl_add_attr_ipa(struct nlmsghdr *h, uint bufsize, int code, ip_addr ipa)
378{
379 if (ipa_is_ip4(ipa))
380 nl_add_attr_ip4(h, bufsize, code, ipa_to_ip4(ipa));
9b136840 381 else
29a64162 382 nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa));
95616c82
OZ
383}
384
9fdf9d29
OZ
385static inline struct rtattr *
386nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
387{
388 return nl_add_attr(h, bufsize, code, NULL, 0);
389}
95616c82
OZ
390
391static inline void
9fdf9d29 392nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
95616c82 393{
9fdf9d29 394 a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
95616c82
OZ
395}
396
9fdf9d29
OZ
397static inline struct rtnexthop *
398nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
399{
400 uint pos = NLMSG_ALIGN(h->nlmsg_len);
401 uint len = RTNH_LENGTH(0);
402
403 if (pos + len > bufsize)
404 bug("nl_open_nexthop: packet buffer overflow");
405
406 h->nlmsg_len = pos + len;
407
408 return (void *)h + pos;
409}
410
411static inline void
412nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
413{
414 nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
415}
95616c82
OZ
416
417static void
29a64162 418nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct mpnh *nh)
95616c82 419{
9fdf9d29
OZ
420 struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
421
95616c82 422 for (; nh; nh = nh->next)
9fdf9d29
OZ
423 {
424 struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
95616c82 425
9fdf9d29
OZ
426 rtnh->rtnh_flags = 0;
427 rtnh->rtnh_hops = nh->weight;
428 rtnh->rtnh_ifindex = nh->iface->index;
95616c82 429
29a64162 430 nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
95616c82 431
9fdf9d29
OZ
432 nl_close_nexthop(h, rtnh);
433 }
434
435 nl_close_attr(h, a);
436}
95616c82
OZ
437
438static struct mpnh *
439nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
440{
441 /* Temporary buffer for multicast nexthops */
442 static struct mpnh *nh_buffer;
443 static int nh_buf_size; /* in number of structures */
444 static int nh_buf_used;
445
ad276157 446 struct rtattr *a[BIRD_RTA_MAX];
95616c82
OZ
447 struct rtnexthop *nh = RTA_DATA(ra);
448 struct mpnh *rv, *first, **last;
449 int len = RTA_PAYLOAD(ra);
450
451 first = NULL;
452 last = &first;
453 nh_buf_used = 0;
454
455 while (len)
456 {
457 /* Use RTNH_OK(nh,len) ?? */
458 if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
459 return NULL;
460
461 if (nh_buf_used == nh_buf_size)
462 {
463 nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
464 nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct mpnh));
465 }
466 *last = rv = nh_buffer + nh_buf_used++;
467 rv->next = NULL;
468 last = &(rv->next);
469
470 rv->weight = nh->rtnh_hops;
471 rv->iface = if_find_by_index(nh->rtnh_ifindex);
472 if (!rv->iface)
473 return NULL;
474
475 /* Nonexistent RTNH_PAYLOAD ?? */
476 nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
ad276157 477 nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a));
95616c82
OZ
478 if (a[RTA_GATEWAY])
479 {
23c212e7 480 rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
95616c82 481
23c212e7
OZ
482 neighbor *nbr;
483 nbr = neigh_find2(&p->p, &rv->gw, rv->iface,
484 (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
485 if (!nbr || (nbr->scope == SCOPE_HOST))
95616c82
OZ
486 return NULL;
487 }
488 else
489 return NULL;
490
491 len -= NLMSG_ALIGN(nh->rtnh_len);
492 nh = RTNH_NEXT(nh);
493 }
494
495 return first;
496}
497
9fdf9d29
OZ
498static void
499nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
500{
501 struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
502 int t;
503
504 for (t = 1; t < max; t++)
505 if (metrics[0] & (1 << t))
506 nl_add_attr_u32(h, bufsize, t, metrics[t]);
507
508 nl_close_attr(h, a);
509}
510
511static int
512nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
513{
514 struct rtattr *a = RTA_DATA(hdr);
515 int len = RTA_PAYLOAD(hdr);
516
517 metrics[0] = 0;
518 for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
519 {
520 if (a->rta_type == RTA_UNSPEC)
521 continue;
522
523 if (a->rta_type >= max)
524 continue;
525
526 if (RTA_PAYLOAD(a) != 4)
527 return -1;
528
529 metrics[0] |= 1 << a->rta_type;
acb04cfd 530 metrics[a->rta_type] = rta_get_u32(a);
9fdf9d29
OZ
531 }
532
533 if (len > 0)
534 return -1;
535
536 return 0;
537}
538
95616c82
OZ
539
540/*
541 * Scanning of interfaces
542 */
543
544static void
545nl_parse_link(struct nlmsghdr *h, int scan)
546{
547 struct ifinfomsg *i;
ad276157 548 struct rtattr *a[BIRD_IFLA_MAX];
95616c82
OZ
549 int new = h->nlmsg_type == RTM_NEWLINK;
550 struct iface f = {};
551 struct iface *ifi;
552 char *name;
553 u32 mtu;
ae80a2de 554 uint fl;
95616c82 555
ad276157 556 if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))
95616c82 557 return;
ad276157 558 if (!a[IFLA_IFNAME] || (RTA_PAYLOAD(a[IFLA_IFNAME]) < 2) || !a[IFLA_MTU])
95616c82 559 {
ad276157
MM
560 /*
561 * IFLA_IFNAME and IFLA_MTU are required, in fact, but there may also come
562 * a message with IFLA_WIRELESS set, where (e.g.) no IFLA_IFNAME exists.
563 * We simply ignore all such messages with IFLA_WIRELESS without notice.
564 */
565
566 if (a[IFLA_WIRELESS])
567 return;
568
569 log(L_ERR "KIF: Malformed message received");
95616c82
OZ
570 return;
571 }
ad276157 572
95616c82 573 name = RTA_DATA(a[IFLA_IFNAME]);
acb04cfd 574 mtu = rta_get_u32(a[IFLA_MTU]);
95616c82
OZ
575
576 ifi = if_find_by_index(i->ifi_index);
577 if (!new)
578 {
579 DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
580 if (!ifi)
581 return;
582
583 if_delete(ifi);
584 }
585 else
586 {
587 DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
588 if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
589 if_delete(ifi);
590
591 strncpy(f.name, name, sizeof(f.name)-1);
592 f.index = i->ifi_index;
593 f.mtu = mtu;
594
595 fl = i->ifi_flags;
596 if (fl & IFF_UP)
597 f.flags |= IF_ADMIN_UP;
598 if (fl & IFF_LOWER_UP)
599 f.flags |= IF_LINK_UP;
600 if (fl & IFF_LOOPBACK) /* Loopback */
601 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
602 else if (fl & IFF_POINTOPOINT) /* PtP */
603 f.flags |= IF_MULTICAST;
604 else if (fl & IFF_BROADCAST) /* Broadcast */
605 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
606 else
607 f.flags |= IF_MULTIACCESS; /* NBMA */
3216eb03 608
16a3254c
OZ
609 if (fl & IFF_MULTICAST)
610 f.flags |= IF_MULTICAST;
611
3216eb03
OZ
612 ifi = if_update(&f);
613
614 if (!scan)
615 if_end_partial_update(ifi);
95616c82
OZ
616 }
617}
618
619static void
9b136840 620nl_parse_addr4(struct ifaddrmsg *i, int scan, int new)
95616c82 621{
ad276157 622 struct rtattr *a[BIRD_IFA_MAX];
95616c82
OZ
623 struct iface *ifi;
624 int scope;
625
9b136840 626 if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
95616c82 627 return;
ad276157 628
9b136840 629 if (!a[IFA_LOCAL])
ad276157 630 {
9b136840
MM
631 log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
632 return;
ad276157 633 }
ad276157 634 if (!a[IFA_ADDRESS])
95616c82 635 {
ad276157 636 log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
95616c82
OZ
637 return;
638 }
639
640 ifi = if_find_by_index(i->ifa_index);
641 if (!ifi)
642 {
643 log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
644 return;
645 }
646
9b136840 647 struct ifa ifa;
95616c82
OZ
648 bzero(&ifa, sizeof(ifa));
649 ifa.iface = ifi;
650 if (i->ifa_flags & IFA_F_SECONDARY)
651 ifa.flags |= IA_SECONDARY;
652
9b136840
MM
653 ifa.ip = rta_get_ipa(a[IFA_LOCAL]);
654
d7661fbe 655 if (i->ifa_prefixlen > IP4_MAX_PREFIX_LENGTH)
95616c82
OZ
656 {
657 log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
658 new = 0;
659 }
d7661fbe 660 if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH)
95616c82 661 {
9b136840
MM
662 ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
663 net_fill_ip4(&ifa.prefix, rta_get_ip4(a[IFA_ADDRESS]), i->ifa_prefixlen);
95616c82
OZ
664
665 /* It is either a host address or a peer address */
9b136840 666 if (ipa_equal(ifa.ip, ifa.brd))
95616c82
OZ
667 ifa.flags |= IA_HOST;
668 else
669 {
670 ifa.flags |= IA_PEER;
9b136840 671 ifa.opposite = ifa.brd;
95616c82
OZ
672 }
673 }
674 else
675 {
9b136840
MM
676 net_fill_ip4(&ifa.prefix, ipa_to_ip4(ifa.ip), i->ifa_prefixlen);
677 net_normalize(&ifa.prefix);
678
d7661fbe 679 if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 1)
95616c82
OZ
680 ifa.opposite = ipa_opposite_m1(ifa.ip);
681
d7661fbe 682 if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 2)
95616c82
OZ
683 ifa.opposite = ipa_opposite_m2(ifa.ip);
684
685 if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
686 {
9b136840
MM
687 ip4_addr xbrd = rta_get_ip4(a[IFA_BROADCAST]);
688 ip4_addr ybrd = ip4_or(ipa_to_ip4(ifa.ip), ip4_not(ip4_mkmask(i->ifa_prefixlen)));
689
690 if (ip4_equal(xbrd, net4_prefix(&ifa.prefix)) || ip4_equal(xbrd, ybrd))
691 ifa.brd = ipa_from_ip4(xbrd);
95616c82 692 else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
9b136840 693 {
e691d16a 694 log(L_ERR "KIF: Invalid broadcast address %I4 for %s", xbrd, ifi->name);
9b136840
MM
695 ifa.brd = ipa_from_ip4(ybrd);
696 }
697 }
698 }
699
700 scope = ipa_classify(ifa.ip);
701 if (scope < 0)
702 {
703 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
704 return;
705 }
706 ifa.scope = scope & IADDR_SCOPE_MASK;
707
708 DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
709 ifi->index, ifi->name,
710 new ? "added" : "removed",
711 ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
712
713 if (new)
714 ifa_update(&ifa);
715 else
716 ifa_delete(&ifa);
717
718 if (!scan)
719 if_end_partial_update(ifi);
720}
721
722static void
723nl_parse_addr6(struct ifaddrmsg *i, int scan, int new)
724{
725 struct rtattr *a[BIRD_IFA_MAX];
726 struct iface *ifi;
727 int scope;
728
729 if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
730 return;
731
732 if (!a[IFA_ADDRESS])
733 {
734 log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
735 return;
736 }
737
738 ifi = if_find_by_index(i->ifa_index);
739 if (!ifi)
740 {
741 log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
742 return;
743 }
744
745 struct ifa ifa;
746 bzero(&ifa, sizeof(ifa));
747 ifa.iface = ifi;
748 if (i->ifa_flags & IFA_F_SECONDARY)
749 ifa.flags |= IA_SECONDARY;
750
751 /* IFA_LOCAL can be unset for IPv6 interfaces */
752
753 ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_ADDRESS]);
754
d7661fbe 755 if (i->ifa_prefixlen > IP6_MAX_PREFIX_LENGTH)
9b136840
MM
756 {
757 log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
758 new = 0;
759 }
d7661fbe 760 if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH)
9b136840
MM
761 {
762 ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
763 net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen);
764
765 /* It is either a host address or a peer address */
766 if (ipa_equal(ifa.ip, ifa.brd))
767 ifa.flags |= IA_HOST;
768 else
769 {
770 ifa.flags |= IA_PEER;
771 ifa.opposite = ifa.brd;
95616c82 772 }
9b136840
MM
773 }
774 else
775 {
776 net_fill_ip6(&ifa.prefix, ipa_to_ip6(ifa.ip), i->ifa_prefixlen);
777 net_normalize(&ifa.prefix);
778
d7661fbe 779 if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH - 1)
9b136840 780 ifa.opposite = ipa_opposite_m1(ifa.ip);
95616c82
OZ
781 }
782
783 scope = ipa_classify(ifa.ip);
784 if (scope < 0)
785 {
786 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
787 return;
788 }
789 ifa.scope = scope & IADDR_SCOPE_MASK;
790
9b136840 791 DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
95616c82
OZ
792 ifi->index, ifi->name,
793 new ? "added" : "removed",
9b136840 794 ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
3216eb03 795
95616c82
OZ
796 if (new)
797 ifa_update(&ifa);
798 else
799 ifa_delete(&ifa);
3216eb03
OZ
800
801 if (!scan)
802 if_end_partial_update(ifi);
95616c82
OZ
803}
804
9b136840
MM
805static void
806nl_parse_addr(struct nlmsghdr *h, int scan)
807{
808 struct ifaddrmsg *i;
809
810 if (!(i = nl_checkin(h, sizeof(*i))))
811 return;
812
813 int new = (h->nlmsg_type == RTM_NEWADDR);
814
815 switch (i->ifa_family)
816 {
9b136840
MM
817 case AF_INET:
818 return nl_parse_addr4(i, scan, new);
29a64162 819
9b136840
MM
820 case AF_INET6:
821 return nl_parse_addr6(i, scan, new);
9b136840
MM
822 }
823}
824
95616c82
OZ
825void
826kif_do_scan(struct kif_proto *p UNUSED)
827{
828 struct nlmsghdr *h;
829
830 if_start_update();
831
86c3eea0 832 nl_request_dump(AF_UNSPEC, RTM_GETLINK);
95616c82
OZ
833 while (h = nl_get_scan())
834 if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
835 nl_parse_link(h, 1);
836 else
837 log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
29a64162 838
d7661fbe 839 nl_request_dump(AF_INET, RTM_GETADDR);
95616c82
OZ
840 while (h = nl_get_scan())
841 if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
3216eb03 842 nl_parse_addr(h, 1);
95616c82
OZ
843 else
844 log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
29a64162 845
d7661fbe
MM
846 nl_request_dump(AF_INET6, RTM_GETADDR);
847 while (h = nl_get_scan())
848 if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
849 nl_parse_addr(h, 1);
850 else
851 log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
29a64162 852
95616c82
OZ
853 if_end_update();
854}
855
856/*
857 * Routes
858 */
859
9ddbfbdd
MM
860static inline u32
861krt_table_id(struct krt_proto *p)
862{
863 return KRT_CF->sys.table_id;
864}
865
866static HASH(struct krt_proto) nl_table_map;
867
29a64162
OZ
868#define RTH_KEY(p) p->af, krt_table_id(p)
869#define RTH_NEXT(p) p->sys.hash_next
870#define RTH_EQ(a1,i1,a2,i2) a1 == a2 && i1 == i2
871#define RTH_FN(a,i) a ^ u32_hash(i)
9ddbfbdd
MM
872
873#define RTH_REHASH rth_rehash
874#define RTH_PARAMS /8, *2, 2, 2, 6, 20
875
876HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
95616c82
OZ
877
878int
879krt_capable(rte *e)
880{
881 rta *a = e->attrs;
882
883 if (a->cast != RTC_UNICAST)
884 return 0;
885
886 switch (a->dest)
887 {
888 case RTD_ROUTER:
889 case RTD_DEVICE:
890 if (a->iface == NULL)
891 return 0;
892 case RTD_BLACKHOLE:
893 case RTD_UNREACHABLE:
894 case RTD_PROHIBIT:
895 case RTD_MULTIPATH:
896 break;
897 default:
898 return 0;
899 }
900 return 1;
901}
902
903static inline int
904nh_bufsize(struct mpnh *nh)
905{
906 int rv = 0;
907 for (; nh != NULL; nh = nh->next)
9fdf9d29 908 rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
95616c82
OZ
909 return rv;
910}
911
912static int
913nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
914{
915 eattr *ea;
916 net *net = e->net;
917 rta *a = e->attrs;
918 struct {
919 struct nlmsghdr h;
920 struct rtmsg r;
9fdf9d29 921 char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
95616c82
OZ
922 } r;
923
9b136840 924 DBG("nl_send_route(%N,new=%d)\n", net->n.addr, new);
95616c82
OZ
925
926 bzero(&r.h, sizeof(r.h));
927 bzero(&r.r, sizeof(r.r));
928 r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
929 r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
930 r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0);
931
29a64162 932 r.r.rtm_family = p->af;
9b136840 933 r.r.rtm_dst_len = net_pxlen(net->n.addr);
95616c82
OZ
934 r.r.rtm_protocol = RTPROT_BIRD;
935 r.r.rtm_scope = RT_SCOPE_UNIVERSE;
29a64162 936 nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net_prefix(net->n.addr));
95616c82 937
9ddbfbdd
MM
938 if (krt_table_id(p) < 256)
939 r.r.rtm_table = krt_table_id(p);
940 else
941 nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));
942
78a2cc28
OZ
943 /* For route delete, we do not specify route attributes */
944 if (!new)
945 return nl_exchange(&r.h);
946
947
95616c82 948 if (ea = ea_find(eattrs, EA_KRT_METRIC))
9fdf9d29 949 nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
95616c82
OZ
950
951 if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
29a64162 952 nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
95616c82
OZ
953
954 if (ea = ea_find(eattrs, EA_KRT_REALM))
955 nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
956
9fdf9d29
OZ
957
958 u32 metrics[KRT_METRICS_MAX];
959 metrics[0] = 0;
960
961 struct ea_walk_state ews = { .eattrs = eattrs };
962 while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
963 {
964 int id = ea->id - EA_KRT_METRICS;
965 metrics[0] |= 1 << id;
966 metrics[id] = ea->u.data;
967 }
968
969 if (metrics[0])
970 nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
971
972
95616c82
OZ
973 /* a->iface != NULL checked in krt_capable() for router and device routes */
974
975 switch (a->dest)
976 {
977 case RTD_ROUTER:
978 r.r.rtm_type = RTN_UNICAST;
979 nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
29a64162 980 nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
95616c82
OZ
981 break;
982 case RTD_DEVICE:
983 r.r.rtm_type = RTN_UNICAST;
984 nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
985 break;
986 case RTD_BLACKHOLE:
987 r.r.rtm_type = RTN_BLACKHOLE;
988 break;
989 case RTD_UNREACHABLE:
990 r.r.rtm_type = RTN_UNREACHABLE;
991 break;
992 case RTD_PROHIBIT:
993 r.r.rtm_type = RTN_PROHIBIT;
994 break;
995 case RTD_MULTIPATH:
996 r.r.rtm_type = RTN_UNICAST;
997 nl_add_multipath(&r.h, sizeof(r), a->nexthops);
998 break;
999 default:
1000 bug("krt_capable inconsistent with nl_send_route");
1001 }
1002
1003 return nl_exchange(&r.h);
1004}
1005
1006void
1007krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
1008{
1009 int err = 0;
1010
1011 /*
1012 * NULL for eattr of the old route is a little hack, but we don't
1013 * get proper eattrs for old in rt_notify() anyway. NULL means no
1014 * extended route attributes and therefore matches if the kernel
1015 * route has any of them.
1016 */
1017
1018 if (old)
1019 nl_send_route(p, old, NULL, 0);
1020
1021 if (new)
1022 err = nl_send_route(p, new, eattrs, 1);
1023
1024 if (err < 0)
1025 n->n.flags |= KRF_SYNC_ERROR;
1026 else
1027 n->n.flags &= ~KRF_SYNC_ERROR;
1028}
1029
1030
1031#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
1032
1033static void
1034nl_parse_route(struct nlmsghdr *h, int scan)
1035{
1036 struct krt_proto *p;
1037 struct rtmsg *i;
ad276157 1038 struct rtattr *a[BIRD_RTA_MAX];
95616c82
OZ
1039 int new = h->nlmsg_type == RTM_NEWROUTE;
1040
29a64162 1041 net_addr dst;
95616c82 1042 u32 oif = ~0;
29a64162 1043 u32 table_id;
95616c82
OZ
1044 int src;
1045
ad276157 1046 if (!(i = nl_checkin(h, sizeof(*i))))
95616c82 1047 return;
ad276157
MM
1048
1049 switch (i->rtm_family)
95616c82 1050 {
29a64162
OZ
1051 case AF_INET:
1052 if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a)))
1053 return;
1054
1055 if (a[RTA_DST])
1056 net_fill_ip4(&dst, rta_get_ip4(a[RTA_DST]), i->rtm_dst_len);
1057 else
1058 net_fill_ip4(&dst, IP4_NONE, 0);
1059 break;
1060
ad276157
MM
1061 case AF_INET6:
1062 if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
1063 return;
29a64162
OZ
1064
1065 if (a[RTA_DST])
1066 net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
1067 else
1068 net_fill_ip6(&dst, IP6_NONE, 0);
1069 break;
1070
1071 default:
1072 return;
95616c82
OZ
1073 }
1074
95616c82 1075 if (a[RTA_OIF])
acb04cfd 1076 oif = rta_get_u32(a[RTA_OIF]);
95616c82 1077
9ddbfbdd 1078 if (a[RTA_TABLE])
29a64162 1079 table_id = rta_get_u32(a[RTA_TABLE]);
9ddbfbdd 1080 else
29a64162 1081 table_id = i->rtm_table;
9ddbfbdd 1082
29a64162
OZ
1083 /* Do we know this table? */
1084 p = HASH_FIND(nl_table_map, RTH, i->rtm_family, table_id);
95616c82 1085 if (!p)
9ddbfbdd 1086 SKIP("unknown table %d\n", table);
95616c82
OZ
1087
1088
95616c82
OZ
1089 if (a[RTA_IIF])
1090 SKIP("IIF set\n");
29a64162 1091
95616c82
OZ
1092 if (i->rtm_tos != 0) /* We don't support TOS */
1093 SKIP("TOS %02x\n", i->rtm_tos);
95616c82
OZ
1094
1095 if (scan && !new)
1096 SKIP("RTM_DELROUTE in scan\n");
1097
9b136840 1098 int c = net_classify(&dst);
95616c82
OZ
1099 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
1100 SKIP("strange class/scope\n");
1101
1102 // ignore rtm_scope, it is not a real scope
1103 // if (i->rtm_scope != RT_SCOPE_UNIVERSE)
1104 // SKIP("scope %u\n", i->rtm_scope);
1105
1106 switch (i->rtm_protocol)
1107 {
1108 case RTPROT_UNSPEC:
1109 SKIP("proto unspec\n");
1110
1111 case RTPROT_REDIRECT:
1112 src = KRT_SRC_REDIRECT;
1113 break;
1114
1115 case RTPROT_KERNEL:
1116 src = KRT_SRC_KERNEL;
1117 return;
1118
1119 case RTPROT_BIRD:
1120 if (!scan)
1121 SKIP("echo\n");
1122 src = KRT_SRC_BIRD;
1123 break;
1124
1125 case RTPROT_BOOT:
1126 default:
1127 src = KRT_SRC_ALIEN;
1128 }
1129
9b136840 1130 net *net = net_get(p->p.table, &dst);
95616c82
OZ
1131
1132 rta ra = {
094d2bdb 1133 .src= p->p.main_source,
95616c82
OZ
1134 .source = RTS_INHERIT,
1135 .scope = SCOPE_UNIVERSE,
1136 .cast = RTC_UNICAST
1137 };
1138
1139 switch (i->rtm_type)
1140 {
1141 case RTN_UNICAST:
1142
ad276157 1143 if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
95616c82
OZ
1144 {
1145 ra.dest = RTD_MULTIPATH;
1146 ra.nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);
1147 if (!ra.nexthops)
1148 {
fe9f1a6d 1149 log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
95616c82
OZ
1150 return;
1151 }
9fdf9d29 1152
95616c82
OZ
1153 break;
1154 }
1155
1156 ra.iface = if_find_by_index(oif);
1157 if (!ra.iface)
1158 {
fe9f1a6d 1159 log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
95616c82
OZ
1160 return;
1161 }
1162
1163 if (a[RTA_GATEWAY])
1164 {
95616c82 1165 ra.dest = RTD_ROUTER;
23c212e7 1166 ra.gw = rta_get_ipa(a[RTA_GATEWAY]);
95616c82
OZ
1167
1168 /* Silently skip strange 6to4 routes */
0bf95f99
OZ
1169 const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
1170 if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra.gw, (net_addr *) &sit))
95616c82
OZ
1171 return;
1172
23c212e7
OZ
1173 neighbor *nbr;
1174 nbr = neigh_find2(&p->p, &ra.gw, ra.iface,
1175 (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
1176 if (!nbr || (nbr->scope == SCOPE_HOST))
95616c82 1177 {
fe9f1a6d 1178 log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, ra.gw);
95616c82
OZ
1179 return;
1180 }
1181 }
1182 else
1183 {
1184 ra.dest = RTD_DEVICE;
95616c82
OZ
1185 }
1186
1187 break;
1188 case RTN_BLACKHOLE:
1189 ra.dest = RTD_BLACKHOLE;
1190 break;
1191 case RTN_UNREACHABLE:
1192 ra.dest = RTD_UNREACHABLE;
1193 break;
1194 case RTN_PROHIBIT:
1195 ra.dest = RTD_PROHIBIT;
1196 break;
1197 /* FIXME: What about RTN_THROW? */
1198 default:
1199 SKIP("type %d\n", i->rtm_type);
1200 return;
1201 }
1202
1203 rte *e = rte_get_temp(&ra);
1204 e->net = net;
1205 e->u.krt.src = src;
1206 e->u.krt.proto = i->rtm_protocol;
1207 e->u.krt.type = i->rtm_type;
acb04cfd 1208 e->u.krt.metric = 0;
95616c82
OZ
1209
1210 if (a[RTA_PRIORITY])
acb04cfd 1211 e->u.krt.metric = rta_get_u32(a[RTA_PRIORITY]);
95616c82
OZ
1212
1213 if (a[RTA_PREFSRC])
1214 {
9b136840 1215 ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
95616c82
OZ
1216
1217 ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
1218 ea->next = ra.eattrs;
1219 ra.eattrs = ea;
1220 ea->flags = EALF_SORTED;
1221 ea->count = 1;
1222 ea->attrs[0].id = EA_KRT_PREFSRC;
1223 ea->attrs[0].flags = 0;
1224 ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
1225 ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps));
1226 ea->attrs[0].u.ptr->length = sizeof(ps);
1227 memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
1228 }
1229
1230 if (a[RTA_FLOW])
1231 {
1232 ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
1233 ea->next = ra.eattrs;
1234 ra.eattrs = ea;
1235 ea->flags = EALF_SORTED;
1236 ea->count = 1;
1237 ea->attrs[0].id = EA_KRT_REALM;
1238 ea->attrs[0].flags = 0;
1239 ea->attrs[0].type = EAF_TYPE_INT;
acb04cfd 1240 ea->attrs[0].u.data = rta_get_u32(a[RTA_FLOW]);
95616c82
OZ
1241 }
1242
9fdf9d29
OZ
1243 if (a[RTA_METRICS])
1244 {
1245 u32 metrics[KRT_METRICS_MAX];
1246 ea_list *ea = alloca(sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
1247 int t, n = 0;
1248
1249 if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
1250 {
fe9f1a6d 1251 log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
9fdf9d29
OZ
1252 return;
1253 }
1254
1255 for (t = 1; t < KRT_METRICS_MAX; t++)
1256 if (metrics[0] & (1 << t))
1257 {
1258 ea->attrs[n].id = EA_CODE(EAP_KRT, KRT_METRICS_OFFSET + t);
1259 ea->attrs[n].flags = 0;
1260 ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
1261 ea->attrs[n].u.data = metrics[t];
1262 n++;
1263 }
1264
1265 if (n > 0)
1266 {
1267 ea->next = ra.eattrs;
1268 ea->flags = EALF_SORTED;
1269 ea->count = n;
1270 ra.eattrs = ea;
1271 }
1272 }
1273
95616c82
OZ
1274 if (scan)
1275 krt_got_route(p, e);
1276 else
1277 krt_got_route_async(p, e, new);
1278}
1279
1280void
1281krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
1282{
1283 struct nlmsghdr *h;
1284
d7661fbe 1285 nl_request_dump(AF_INET, RTM_GETROUTE);
95616c82
OZ
1286 while (h = nl_get_scan())
1287 if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
1288 nl_parse_route(h, 1);
1289 else
1290 log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
29a64162 1291
d7661fbe
MM
1292 nl_request_dump(AF_INET6, RTM_GETROUTE);
1293 while (h = nl_get_scan())
1294 if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
1295 nl_parse_route(h, 1);
1296 else
1297 log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
95616c82
OZ
1298}
1299
1300/*
1301 * Asynchronous Netlink interface
1302 */
1303
1304static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */
1305static byte *nl_async_rx_buffer; /* Receive buffer */
1306
1307static void
1308nl_async_msg(struct nlmsghdr *h)
1309{
1310 switch (h->nlmsg_type)
1311 {
1312 case RTM_NEWROUTE:
1313 case RTM_DELROUTE:
1314 DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
1315 nl_parse_route(h, 0);
1316 break;
1317 case RTM_NEWLINK:
1318 case RTM_DELLINK:
1319 DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
1e4891e4
OZ
1320 if (kif_proto)
1321 nl_parse_link(h, 0);
95616c82
OZ
1322 break;
1323 case RTM_NEWADDR:
1324 case RTM_DELADDR:
1325 DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
1e4891e4
OZ
1326 if (kif_proto)
1327 nl_parse_addr(h, 0);
95616c82
OZ
1328 break;
1329 default:
1330 DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
1331 }
1332}
1333
1334static int
1335nl_async_hook(sock *sk, int size UNUSED)
1336{
1337 struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
1338 struct sockaddr_nl sa;
1339 struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
1340 struct nlmsghdr *h;
1341 int x;
ae80a2de 1342 uint len;
95616c82
OZ
1343
1344 x = recvmsg(sk->fd, &m, 0);
1345 if (x < 0)
1346 {
1347 if (errno == ENOBUFS)
1348 {
1349 /*
1350 * Netlink reports some packets have been thrown away.
1351 * One day we might react to it by asking for route table
1352 * scan in near future.
1353 */
1354 return 1; /* More data are likely to be ready */
1355 }
1356 else if (errno != EWOULDBLOCK)
1357 log(L_ERR "Netlink recvmsg: %m");
1358 return 0;
1359 }
1360 if (sa.nl_pid) /* It isn't from the kernel */
1361 {
1362 DBG("Non-kernel packet\n");
1363 return 1;
1364 }
1365 h = (void *) nl_async_rx_buffer;
1366 len = x;
1367 if (m.msg_flags & MSG_TRUNC)
1368 {
1369 log(L_WARN "Netlink got truncated asynchronous message");
1370 return 1;
1371 }
1372 while (NLMSG_OK(h, len))
1373 {
1374 nl_async_msg(h);
1375 h = NLMSG_NEXT(h, len);
1376 }
1377 if (len)
1378 log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
1379 return 1;
1380}
1381
1382static void
1383nl_open_async(void)
1384{
1385 sock *sk;
1386 struct sockaddr_nl sa;
1387 int fd;
95616c82 1388
f83ce94d 1389 if (nl_async_sk)
95616c82 1390 return;
95616c82
OZ
1391
1392 DBG("KRT: Opening async netlink socket\n");
1393
1394 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1395 if (fd < 0)
1396 {
1397 log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
1398 return;
1399 }
1400
1401 bzero(&sa, sizeof(sa));
1402 sa.nl_family = AF_NETLINK;
29a64162
OZ
1403 sa.nl_groups = RTMGRP_LINK |
1404 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
1405 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
1406
95616c82
OZ
1407 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
1408 {
1409 log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
f83ce94d 1410 close(fd);
95616c82
OZ
1411 return;
1412 }
1413
f83ce94d
OZ
1414 nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
1415
95616c82
OZ
1416 sk = nl_async_sk = sk_new(krt_pool);
1417 sk->type = SK_MAGIC;
1418 sk->rx_hook = nl_async_hook;
1419 sk->fd = fd;
05476c4d 1420 if (sk_open(sk) < 0)
95616c82 1421 bug("Netlink: sk_open failed");
95616c82
OZ
1422}
1423
9ddbfbdd 1424
95616c82
OZ
1425/*
1426 * Interface to the UNIX krt module
1427 */
1428
95616c82 1429void
9ddbfbdd
MM
1430krt_sys_io_init(void)
1431{
1432 HASH_INIT(nl_table_map, krt_pool, 6);
1433}
1434
1435int
c6964c30 1436krt_sys_start(struct krt_proto *p)
95616c82 1437{
29a64162 1438 struct krt_proto *old = HASH_FIND(nl_table_map, RTH, p->af, krt_table_id(p));
9ddbfbdd
MM
1439
1440 if (old)
1441 {
1442 log(L_ERR "%s: Kernel table %u already registered by %s",
1443 p->p.name, krt_table_id(p), old->p.name);
1444 return 0;
1445 }
1446
1447 HASH_INSERT2(nl_table_map, RTH, krt_pool, p);
c6964c30
OZ
1448
1449 nl_open();
1450 nl_open_async();
9ddbfbdd
MM
1451
1452 return 1;
95616c82
OZ
1453}
1454
1455void
9ddbfbdd 1456krt_sys_shutdown(struct krt_proto *p)
95616c82 1457{
9ddbfbdd 1458 HASH_REMOVE2(nl_table_map, RTH, krt_pool, p);
95616c82
OZ
1459}
1460
1461int
1462krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1463{
1464 return n->sys.table_id == o->sys.table_id;
1465}
1466
95616c82
OZ
1467void
1468krt_sys_init_config(struct krt_config *cf)
1469{
1470 cf->sys.table_id = RT_TABLE_MAIN;
1471}
1472
1473void
1474krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1475{
1476 d->sys.table_id = s->sys.table_id;
1477}
1478
9fdf9d29
OZ
1479static const char *krt_metrics_names[KRT_METRICS_MAX] = {
1480 NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
1481 "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
1482};
1483
1484static const char *krt_features_names[KRT_FEATURES_MAX] = {
1485 "ecn", NULL, NULL, "allfrag"
1486};
1487
1488int
1489krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
1490{
1491 switch (a->id)
1492 {
1493 case EA_KRT_PREFSRC:
1494 bsprintf(buf, "prefsrc");
1495 return GA_NAME;
1496
1497 case EA_KRT_REALM:
1498 bsprintf(buf, "realm");
1499 return GA_NAME;
1500
1501 case EA_KRT_LOCK:
1502 buf += bsprintf(buf, "lock:");
1503 ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
1504 return GA_FULL;
1505
1506 case EA_KRT_FEATURES:
1507 buf += bsprintf(buf, "features:");
1508 ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
1509 return GA_FULL;
1510
1511 default:;
1512 int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
1513 if (id > 0 && id < KRT_METRICS_MAX)
1514 {
1515 bsprintf(buf, "%s", krt_metrics_names[id]);
1516 return GA_NAME;
1517 }
1518
1519 return GA_UNKNOWN;
1520 }
1521}
1522
95616c82
OZ
1523
1524
1525void
1526kif_sys_start(struct kif_proto *p UNUSED)
1527{
1528 nl_open();
1529 nl_open_async();
1530}
1531
1532void
1533kif_sys_shutdown(struct kif_proto *p UNUSED)
1534{
1535}