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