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