]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/linux/netlink/netlink.c
bdc879f6ef4ba7dc8d5f49c1da4d493cf8f9613b
[thirdparty/bird.git] / sysdep / linux / netlink / netlink.c
1 /*
2 * BIRD -- Linux Netlink Interface
3 *
4 * (c) 1999 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <string.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <net/if.h>
13 #include <sys/socket.h>
14 #include <sys/uio.h>
15 #include <errno.h>
16
17 #define LOCAL_DEBUG
18
19 #include "nest/bird.h"
20 #include "nest/route.h"
21 #include "nest/protocol.h"
22 #include "nest/iface.h"
23 #include "lib/timer.h"
24 #include "lib/unix.h"
25 #include "lib/krt.h"
26 #include "lib/socket.h"
27 #include "conf/conf.h"
28
29 #include <asm/types.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
32
33 #ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */
34 #define MSG_TRUNC 0x20
35 #endif
36
37 /*
38 * Synchronous Netlink interface
39 */
40
41 static int nl_sync_fd = -1; /* Unix socket for synchronous netlink actions */
42 static u32 nl_sync_seq; /* Sequence number of last request sent */
43
44 static byte *nl_rx_buffer; /* Receive buffer */
45 #define NL_RX_SIZE 2048
46
47 static struct nlmsghdr *nl_last_hdr; /* Recently received packet */
48 static unsigned int nl_last_size;
49
50 static void
51 nl_open(void)
52 {
53 if (nl_sync_fd < 0)
54 {
55 nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
56 if (nl_sync_fd < 0)
57 die("Unable to open rtnetlink socket: %m");
58 nl_sync_seq = now;
59 nl_rx_buffer = xmalloc(NL_RX_SIZE);
60 }
61 }
62
63 static void
64 nl_send(struct nlmsghdr *nh)
65 {
66 struct sockaddr_nl sa;
67
68 memset(&sa, 0, sizeof(sa));
69 sa.nl_family = AF_NETLINK;
70 nh->nlmsg_pid = 0;
71 nh->nlmsg_seq = ++nl_sync_seq;
72 if (sendto(nl_sync_fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
73 die("rtnetlink sendto: %m");
74 nl_last_hdr = NULL;
75 }
76
77 static void
78 nl_request_dump(int cmd)
79 {
80 struct {
81 struct nlmsghdr nh;
82 struct rtgenmsg g;
83 } req;
84 req.nh.nlmsg_type = cmd;
85 req.nh.nlmsg_len = sizeof(req);
86 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
87 req.g.rtgen_family = BIRD_PF;
88 nl_send(&req.nh);
89 }
90
91 static struct nlmsghdr *
92 nl_get_reply(void)
93 {
94 for(;;)
95 {
96 if (!nl_last_hdr)
97 {
98 struct iovec iov = { nl_rx_buffer, NL_RX_SIZE };
99 struct sockaddr_nl sa;
100 struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
101 int x = recvmsg(nl_sync_fd, &m, 0);
102 if (x < 0)
103 die("nl_get_reply: %m");
104 if (sa.nl_pid) /* It isn't from the kernel */
105 {
106 DBG("Non-kernel packet\n");
107 continue;
108 }
109 nl_last_size = x;
110 nl_last_hdr = (void *) nl_rx_buffer;
111 if (m.msg_flags & MSG_TRUNC)
112 bug("nl_get_reply: got truncated reply which should be impossible");
113 }
114 if (NLMSG_OK(nl_last_hdr, nl_last_size))
115 {
116 struct nlmsghdr *h = nl_last_hdr;
117 if (h->nlmsg_seq != nl_sync_seq)
118 {
119 log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
120 h->nlmsg_seq, nl_sync_seq);
121 continue;
122 }
123 nl_last_hdr = NLMSG_NEXT(h, nl_last_size);
124 return h;
125 }
126 if (nl_last_size)
127 log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl_last_size);
128 nl_last_hdr = NULL;
129 }
130 }
131
132 static int
133 nl_error(struct nlmsghdr *h)
134 {
135 struct nlmsgerr *e;
136 int ec;
137
138 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
139 {
140 log(L_WARN "Netlink: Truncated error message received");
141 return ENOBUFS;
142 }
143 e = (struct nlmsgerr *) NLMSG_DATA(h);
144 ec = -e->error;
145 if (ec)
146 log(L_WARN "Netlink: %s", strerror(ec));
147 return ec;
148 }
149
150 static struct nlmsghdr *
151 nl_get_scan(void)
152 {
153 struct nlmsghdr *h = nl_get_reply();
154
155 if (h->nlmsg_type == NLMSG_DONE)
156 return NULL;
157 if (h->nlmsg_type == NLMSG_ERROR)
158 {
159 nl_error(h);
160 return NULL;
161 }
162 return h;
163 }
164
165 static int
166 nl_exchange(struct nlmsghdr *pkt)
167 {
168 struct nlmsghdr *h;
169
170 nl_send(pkt);
171 for(;;)
172 {
173 h = nl_get_reply();
174 if (h->nlmsg_type == NLMSG_ERROR)
175 break;
176 log(L_WARN "nl_exchange: Unexpected reply received");
177 }
178 return nl_error(h);
179 }
180
181 /*
182 * Netlink attributes
183 */
184
185 static int nl_attr_len;
186
187 static void *
188 nl_checkin(struct nlmsghdr *h, int lsize)
189 {
190 nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
191 if (nl_attr_len < 0)
192 {
193 log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
194 return NULL;
195 }
196 return NLMSG_DATA(h);
197 }
198
199 static int
200 nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
201 {
202 int max = ksize / sizeof(struct rtattr *);
203 bzero(k, ksize);
204 while (RTA_OK(a, nl_attr_len))
205 {
206 if (a->rta_type < max)
207 k[a->rta_type] = a;
208 a = RTA_NEXT(a, nl_attr_len);
209 }
210 if (nl_attr_len)
211 {
212 log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
213 return 0;
214 }
215 else
216 return 1;
217 }
218
219 static void
220 nl_add_attr_u32(struct nlmsghdr *h, unsigned maxsize, int code, u32 data)
221 {
222 unsigned len = RTA_LENGTH(4);
223 struct rtattr *a;
224
225 if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
226 bug("nl_add_attr32: packet buffer overflow");
227 a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
228 a->rta_type = code;
229 a->rta_len = len;
230 memcpy(RTA_DATA(a), &data, 4);
231 h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
232 }
233
234 static void
235 nl_add_attr_ipa(struct nlmsghdr *h, unsigned maxsize, int code, ip_addr ipa)
236 {
237 unsigned len = RTA_LENGTH(sizeof(ipa));
238 struct rtattr *a;
239
240 if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
241 bug("nl_add_attr_ipa: packet buffer overflow");
242 a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
243 a->rta_type = code;
244 a->rta_len = len;
245 ipa_hton(ipa);
246 memcpy(RTA_DATA(a), &ipa, sizeof(ipa));
247 h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
248 }
249
250 /*
251 * Scanning of interfaces
252 */
253
254 static void
255 nl_parse_link(struct nlmsghdr *h, int scan)
256 {
257 struct ifinfomsg *i;
258 struct rtattr *a[IFLA_STATS+1];
259 int new = h->nlmsg_type == RTM_NEWLINK;
260 struct iface f;
261 struct iface *ifi;
262 char *name;
263 u32 mtu;
264 unsigned int fl;
265
266 if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a)))
267 return;
268 if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 ||
269 !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4)
270 {
271 log(L_ERR "nl_parse_link: Malformed message received");
272 return;
273 }
274 name = RTA_DATA(a[IFLA_IFNAME]);
275 memcpy(&mtu, RTA_DATA(a[IFLA_MTU]), sizeof(u32));
276
277 ifi = if_find_by_index(i->ifi_index);
278 if (!new)
279 {
280 DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
281 if (ifi && !scan)
282 {
283 memcpy(&f, ifi, sizeof(struct iface));
284 f.flags |= IF_ADMIN_DOWN;
285 if_update(&f);
286 }
287 }
288 else
289 {
290 DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
291 if (ifi)
292 memcpy(&f, ifi, sizeof(f));
293 else
294 {
295 bzero(&f, sizeof(f));
296 f.index = i->ifi_index;
297 }
298 strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1);
299 f.mtu = mtu;
300 f.flags = 0;
301 fl = i->ifi_flags;
302 if (fl & IFF_UP)
303 f.flags |= IF_LINK_UP;
304 if (fl & IFF_LOOPBACK) /* Loopback */
305 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
306 else if (fl & IFF_POINTOPOINT) /* PtP */
307 f.flags |= IF_MULTICAST;
308 else if (fl & IFF_BROADCAST) /* Broadcast */
309 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
310 else
311 f.flags |= IF_MULTIACCESS; /* NBMA */
312 if_update(&f);
313 }
314 }
315
316 static void
317 nl_parse_addr(struct nlmsghdr *h)
318 {
319 struct ifaddrmsg *i;
320 struct rtattr *a[IFA_ANYCAST+1];
321 int new = h->nlmsg_type == RTM_NEWADDR;
322 struct ifa ifa;
323 struct iface *ifi;
324
325 if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
326 return;
327 if (i->ifa_family != BIRD_AF)
328 return;
329 if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr)
330 #ifdef IPV6
331 || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
332 #else
333 || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
334 || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr))
335 #endif
336 )
337 {
338 log(L_ERR "nl_parse_addr: Malformed message received");
339 return;
340 }
341
342 #ifdef IPV6
343 if (i->ifa_scope == RT_SCOPE_LINK)
344 return;
345 #endif
346
347 ifi = if_find_by_index(i->ifa_index);
348 if (!ifi)
349 {
350 log(L_ERR "KIF: Received address message for unknown interface %d\n", i->ifa_index);
351 return;
352 }
353
354 bzero(&ifa, sizeof(ifa));
355 ifa.iface = ifi;
356 if (i->ifa_flags & IFA_F_SECONDARY)
357 ifa.flags |= IA_SECONDARY;
358 /* IFA_LOCAL can be unset for IPv6 interfaces */
359 memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
360 ipa_ntoh(ifa.ip);
361 ifa.pxlen = i->ifa_prefixlen;
362 if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS ||
363 i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
364 {
365 log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
366 new = 0;
367 }
368 if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
369 {
370 ifa.flags |= IA_UNNUMBERED;
371 memcpy(&ifa.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(ifa.opposite));
372 ipa_ntoh(ifa.opposite);
373 ifa.prefix = ifa.brd = ifa.opposite;
374 }
375 else
376 {
377 #ifndef IPV6
378 if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
379 ifa.opposite = ipa_opposite(ifa.ip);
380 if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
381 {
382 memcpy(&ifa.brd, RTA_DATA(a[IFA_BROADCAST]), sizeof(ifa.brd));
383 ipa_ntoh(ifa.brd);
384 }
385 #endif
386 ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(ifa.pxlen));
387 }
388
389 DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
390 ifi->index, ifi->name,
391 new ? "added" : "removed",
392 ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
393 if (new)
394 ifa_update(&ifa);
395 else
396 ifa_delete(&ifa);
397 }
398
399 void
400 krt_if_scan(struct kif_proto *p)
401 {
402 struct nlmsghdr *h;
403
404 if_start_update();
405
406 nl_request_dump(RTM_GETLINK);
407 while (h = nl_get_scan())
408 if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
409 nl_parse_link(h, 1);
410 else
411 log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
412
413 nl_request_dump(RTM_GETADDR);
414 while (h = nl_get_scan())
415 if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
416 nl_parse_addr(h);
417 else
418 log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
419
420 if_end_update();
421 }
422
423 /*
424 * Routes
425 */
426
427 static struct krt_proto *nl_table_map[NL_NUM_TABLES];
428
429 int
430 krt_capable(rte *e)
431 {
432 rta *a = e->attrs;
433
434 if (a->cast != RTC_UNICAST
435 #if 0
436 && a->cast != RTC_ANYCAST
437 #endif
438 )
439 return 0;
440 if (a->source == RTS_DEVICE) /* Kernel takes care of device routes itself */
441 return 0;
442 switch (a->dest)
443 {
444 case RTD_ROUTER:
445 case RTD_DEVICE:
446 case RTD_BLACKHOLE:
447 case RTD_UNREACHABLE:
448 case RTD_PROHIBIT:
449 break;
450 default:
451 return 0;
452 }
453 return 1;
454 }
455
456 static void
457 nl_send_route(struct krt_proto *p, rte *e, int new)
458 {
459 net *net = e->net;
460 rta *a = e->attrs;
461 struct {
462 struct nlmsghdr h;
463 struct rtmsg r;
464 char buf[128];
465 } r;
466 struct nlmsghdr *reply;
467
468 DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);
469
470 bzero(&r.h, sizeof(r.h));
471 bzero(&r.r, sizeof(r.r));
472 r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
473 r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
474 r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_REPLACE : 0);
475
476 r.r.rtm_family = BIRD_AF;
477 r.r.rtm_dst_len = net->n.pxlen;
478 r.r.rtm_tos = 0;
479 r.r.rtm_table = KRT_CF->scan.table_id;
480 r.r.rtm_protocol = RTPROT_BIRD;
481 r.r.rtm_scope = RT_SCOPE_UNIVERSE;
482 nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
483 switch (a->dest)
484 {
485 case RTD_ROUTER:
486 r.r.rtm_type = RTN_UNICAST;
487 nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
488 break;
489 case RTD_DEVICE:
490 r.r.rtm_type = RTN_UNICAST;
491 nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
492 break;
493 case RTD_BLACKHOLE:
494 r.r.rtm_type = RTN_BLACKHOLE;
495 break;
496 case RTD_UNREACHABLE:
497 r.r.rtm_type = RTN_UNREACHABLE;
498 break;
499 case RTD_PROHIBIT:
500 r.r.rtm_type = RTN_PROHIBIT;
501 break;
502 default:
503 bug("krt_capable inconsistent with nl_send_route");
504 }
505
506 nl_exchange(&r.h);
507 }
508
509 void
510 krt_set_notify(struct krt_proto *p, net *n, rte *new, rte *old)
511 {
512 if (old && new)
513 {
514 /*
515 * We should check whether priority and TOS is identical as well,
516 * but we don't use these and default value is always equal to default value. :-)
517 */
518 nl_send_route(p, new, 1);
519 }
520 else
521 {
522 if (old)
523 {
524 if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
525 nl_send_route(p, old, 0);
526 /* else the kernel has already flushed it */
527 }
528 if (new)
529 nl_send_route(p, new, 1);
530 }
531 }
532
533 struct iface *
534 krt_temp_iface(struct krt_proto *p, unsigned index)
535 {
536 struct iface *i, *j;
537
538 WALK_LIST(i, p->scan.temp_ifs)
539 if (i->index == index)
540 return i;
541 i = mb_allocz(p->p.pool, sizeof(struct iface));
542 if (j = if_find_by_index(index))
543 strcpy(i->name, j->name);
544 else
545 strcpy(i->name, "?");
546 i->index = index;
547 add_tail(&p->scan.temp_ifs, &i->n);
548 return i;
549 }
550
551 static void
552 nl_parse_route(struct nlmsghdr *h, int scan)
553 {
554 struct krt_proto *p;
555 struct rtmsg *i;
556 struct rtattr *a[RTA_CACHEINFO+1];
557 int new = h->nlmsg_type == RTM_NEWROUTE;
558 ip_addr dst;
559 rta ra;
560 rte *e;
561 net *net;
562 u32 oif;
563 int src;
564
565 if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
566 return;
567 if (i->rtm_family != BIRD_AF)
568 return;
569 if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
570 (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
571 (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
572 #ifdef IPV6
573 (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
574 #endif
575 (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
576 {
577 log(L_ERR "nl_parse_route: Malformed message received");
578 return;
579 }
580
581 p = nl_table_map[i->rtm_table]; /* Do we know this table? */
582 if (!p)
583 return;
584
585 #ifdef IPV6
586 if (a[RTA_IIF])
587 {
588 DBG("KRT: Ignoring route with IIF set\n");
589 return;
590 }
591 #else
592 if (i->rtm_tos != 0) /* We don't support TOS */
593 {
594 DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos);
595 return;
596 }
597 #endif
598
599 if (scan && !new)
600 {
601 DBG("KRT: Ignoring route deletion\n");
602 return;
603 }
604
605 if (a[RTA_DST])
606 {
607 memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
608 ipa_ntoh(dst);
609 }
610 else
611 dst = IPA_NONE;
612 if (a[RTA_OIF])
613 memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
614 else
615 oif = ~0;
616
617 DBG("Got %I/%d, type=%d, oif=%d, table=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, p->p.name);
618
619 switch (i->rtm_protocol)
620 {
621 case RTPROT_REDIRECT:
622 src = KRT_SRC_REDIRECT;
623 break;
624 case RTPROT_KERNEL:
625 DBG("Route originated in kernel, ignoring\n");
626 return;
627 case RTPROT_BIRD:
628 if (!scan)
629 {
630 DBG("Echo of our own route, ignoring\n");
631 return;
632 }
633 src = KRT_SRC_BIRD;
634 break;
635 default:
636 src = KRT_SRC_ALIEN;
637 }
638
639 net = net_get(p->p.table, dst, i->rtm_dst_len);
640 ra.proto = &p->p;
641 ra.source = RTS_INHERIT;
642 ra.scope = SCOPE_UNIVERSE;
643 ra.cast = RTC_UNICAST;
644 ra.flags = ra.aflags = 0;
645 ra.from = IPA_NONE;
646 ra.gw = IPA_NONE;
647 ra.iface = NULL;
648 ra.eattrs = NULL;
649
650 switch (i->rtm_type)
651 {
652 case RTN_UNICAST:
653 if (oif == ~0U)
654 {
655 log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);
656 return;
657 }
658 if (a[RTA_GATEWAY])
659 {
660 neighbor *ng;
661 ra.dest = RTD_ROUTER;
662 memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
663 ipa_ntoh(ra.gw);
664 ng = neigh_find(&p->p, &ra.gw, 0);
665 if (ng)
666 ra.iface = ng->iface;
667 else
668 /* FIXME: Remove this warning? Handle it somehow... */
669 log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);
670 }
671 else
672 {
673 ra.dest = RTD_DEVICE;
674 ra.iface = krt_temp_iface(p, oif);
675 }
676 break;
677 case RTN_BLACKHOLE:
678 ra.dest = RTD_BLACKHOLE;
679 break;
680 case RTN_UNREACHABLE:
681 ra.dest = RTD_UNREACHABLE;
682 break;
683 case RTN_PROHIBIT:
684 ra.dest = RTD_PROHIBIT;
685 break;
686 /* FIXME: What about RTN_THROW? */
687 default:
688 DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);
689 return;
690 }
691
692 if (i->rtm_scope != RT_SCOPE_UNIVERSE)
693 {
694 DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);
695 return;
696 }
697
698 e = rte_get_temp(&ra);
699 e->net = net;
700 e->u.krt.src = src;
701 e->u.krt.proto = i->rtm_protocol;
702 e->u.krt.type = i->rtm_type;
703 if (a[RTA_PRIORITY])
704 memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
705 else
706 e->u.krt.metric = 0;
707 if (scan)
708 krt_got_route(p, e);
709 else
710 krt_got_route_async(p, e, new);
711 }
712
713 void
714 krt_scan_fire(struct krt_proto *p) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
715 {
716 struct nlmsghdr *h;
717
718 nl_request_dump(RTM_GETROUTE);
719 while (h = nl_get_scan())
720 if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
721 nl_parse_route(h, 1);
722 else
723 log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
724 }
725
726 /*
727 * Asynchronous Netlink interface
728 */
729
730 static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */
731 static byte *nl_async_rx_buffer; /* Receive buffer */
732
733 static void
734 nl_async_msg(struct nlmsghdr *h)
735 {
736 switch (h->nlmsg_type)
737 {
738 case RTM_NEWROUTE:
739 case RTM_DELROUTE:
740 DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
741 nl_parse_route(h, 0);
742 break;
743 case RTM_NEWLINK:
744 case RTM_DELLINK:
745 DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
746 nl_parse_link(h, 0);
747 break;
748 case RTM_NEWADDR:
749 case RTM_DELADDR:
750 DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
751 nl_parse_addr(h);
752 break;
753 default:
754 DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
755 }
756 }
757
758 static int
759 nl_async_hook(sock *sk, int size)
760 {
761 struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
762 struct sockaddr_nl sa;
763 struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
764 struct nlmsghdr *h;
765 int x;
766 unsigned int len;
767
768 nl_last_hdr = NULL; /* Discard packets accidentally remaining in the rxbuf */
769 x = recvmsg(sk->fd, &m, 0);
770 if (x < 0)
771 {
772 if (errno != EWOULDBLOCK)
773 log(L_ERR "Netlink recvmsg: %m");
774 return 0;
775 }
776 if (sa.nl_pid) /* It isn't from the kernel */
777 {
778 DBG("Non-kernel packet\n");
779 return 1;
780 }
781 h = (void *) nl_async_rx_buffer;
782 len = x;
783 if (m.msg_flags & MSG_TRUNC)
784 {
785 log(L_WARN "Netlink got truncated asynchronous message");
786 return 1;
787 }
788 while (NLMSG_OK(h, len))
789 {
790 nl_async_msg(h);
791 h = NLMSG_NEXT(h, len);
792 }
793 if (len)
794 log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
795 return 1;
796 }
797
798 static void
799 nl_open_async(void)
800 {
801 sock *sk;
802 struct sockaddr_nl sa;
803 int fd;
804
805 DBG("KRT: Opening async netlink socket\n");
806
807 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
808 if (fd < 0)
809 {
810 log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
811 return;
812 }
813
814 bzero(&sa, sizeof(sa));
815 sa.nl_family = AF_NETLINK;
816 #ifdef IPV6
817 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
818 #else
819 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
820 #endif
821 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
822 {
823 log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
824 return;
825 }
826
827 sk = nl_async_sk = sk_new(krt_pool);
828 sk->type = SK_MAGIC;
829 sk->rx_hook = nl_async_hook;
830 sk->fd = fd;
831 if (sk_open(sk))
832 bug("Netlink: sk_open failed");
833
834 if (!nl_async_rx_buffer)
835 nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
836 }
837
838 /*
839 * Interface to the UNIX krt module
840 */
841
842 static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
843
844 void
845 krt_scan_preconfig(struct config *c)
846 {
847 bzero(&nl_cf_table, sizeof(nl_cf_table));
848 }
849
850 void
851 krt_scan_postconfig(struct krt_config *x)
852 {
853 int id = x->scan.table_id;
854
855 if (nl_cf_table[id/8] & (1 << (id%8)))
856 cf_error("Multiple kernel syncers defined for table #%d", id);
857 nl_cf_table[id/8] |= (1 << (id%8));
858 }
859
860 void
861 krt_scan_construct(struct krt_config *x)
862 {
863 x->scan.async = 1;
864 #ifndef IPV6
865 x->scan.table_id = RT_TABLE_MAIN;
866 #endif
867 /* FIXME: Use larger defaults for scanning times? */
868 }
869
870 void
871 krt_scan_start(struct krt_proto *p, int first)
872 {
873 init_list(&p->scan.temp_ifs);
874 nl_table_map[KRT_CF->scan.table_id] = p;
875 if (first)
876 {
877 nl_open();
878 if (KRT_CF->scan.async) /* FIXME: Async is for debugging only. Get rid of it some day. */
879 nl_open_async();
880 }
881 }
882
883 void
884 krt_scan_shutdown(struct krt_proto *p, int last)
885 {
886 }
887
888 void
889 krt_if_start(struct kif_proto *p)
890 {
891 nl_open();
892 /* FIXME: nl_open_async() after scan.async is gone */
893 }