]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/bsd/krt-sock.c
29203d1b8168a4ea5d76637d43d7d2a73f765df9
[thirdparty/bird.git] / sysdep / bsd / krt-sock.c
1 /*
2 * BIRD -- BSD Routing Table Syncing
3 *
4 * (c) 2004 Ondrej Filip <feela@network.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/sysctl.h>
18 #include <sys/ioctl.h>
19 #include <netinet/in.h>
20 #include <net/route.h>
21 #include <net/if.h>
22 #include <net/if_dl.h>
23
24 #undef LOCAL_DEBUG
25
26 #include "nest/bird.h"
27 #include "nest/iface.h"
28 #include "nest/route.h"
29 #include "nest/protocol.h"
30 #include "nest/iface.h"
31 #include "lib/timer.h"
32 #include "lib/unix.h"
33 #include "lib/krt.h"
34 #include "lib/string.h"
35 #include "lib/socket.h"
36
37
38 /*
39 * There are significant differences in multiple tables support between BSD variants.
40 *
41 * OpenBSD has table_id field for routes in route socket protocol, therefore all
42 * tables could be managed by one kernel socket. FreeBSD lacks such field,
43 * therefore multiple sockets (locked to specific table using SO_SETFIB socket
44 * option) must be used.
45 *
46 * Both FreeBSD and OpenBSD uses separate scans for each table. In OpenBSD,
47 * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it
48 * is handled implicitly by changing default table using setfib() syscall.
49 *
50 * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto
51 * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan
52 * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets
53 * KRT_USE_SYSCTL_7 - use 7-th arg of sysctl() as table id for route scans
54 * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs
55 */
56
57 #ifdef __FreeBSD__
58 #define KRT_MAX_TABLES 256
59 #define KRT_USE_SETFIB_SCAN
60 #define KRT_USE_SETFIB_SOCK
61 #define KRT_USE_SYSCTL_NET_FIBS
62 #endif
63
64 #ifdef __OpenBSD__
65 #define KRT_MAX_TABLES (RT_TABLEID_MAX+1)
66 #define KRT_SHARED_SOCKET
67 #define KRT_USE_SYSCTL_7
68 #endif
69
70 #ifndef KRT_MAX_TABLES
71 #define KRT_MAX_TABLES 1
72 #endif
73
74
75
76 /* Dynamic max number of tables */
77
78 int krt_max_tables;
79
80 #ifdef KRT_USE_SYSCTL_NET_FIBS
81
82 static int
83 krt_get_max_tables(void)
84 {
85 int fibs;
86 size_t fibs_len = sizeof(fibs);
87
88 if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
89 {
90 log(L_WARN "KRT: unable to get max number of fib tables: %m");
91 return 1;
92 }
93
94 return MIN(fibs, KRT_MAX_TABLES);
95 }
96
97 #else
98
99 static int
100 krt_get_max_tables(void)
101 {
102 return KRT_MAX_TABLES;
103 }
104
105 #endif /* KRT_USE_SYSCTL_NET_FIBS */
106
107
108 /* setfib() syscall for FreeBSD scans */
109
110 #ifdef KRT_USE_SETFIB_SCAN
111
112 /*
113 static int krt_default_fib;
114
115 static int
116 krt_get_active_fib(void)
117 {
118 int fib;
119 size_t fib_len = sizeof(fib);
120
121 if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
122 {
123 log(L_WARN "KRT: unable to get active fib number: %m");
124 return 0;
125 }
126
127 return fib;
128 }
129 */
130
131 extern int setfib(int fib);
132
133 #endif /* KRT_USE_SETFIB_SCAN */
134
135
136 /* table_id -> krt_proto map */
137
138 #ifdef KRT_SHARED_SOCKET
139 static struct krt_proto *krt_table_map[KRT_MAX_TABLES];
140 #endif
141
142
143 /* Route socket message processing */
144
145 int
146 krt_capable(rte *e)
147 {
148 rta *a = e->attrs;
149
150 return
151 a->cast == RTC_UNICAST &&
152 (a->dest == RTD_ROUTER
153 || a->dest == RTD_DEVICE
154 #ifdef RTF_REJECT
155 || a->dest == RTD_UNREACHABLE
156 #endif
157 #ifdef RTF_BLACKHOLE
158 || a->dest == RTD_BLACKHOLE
159 #endif
160 );
161 }
162
163 #ifndef RTAX_MAX
164 #define RTAX_MAX 8
165 #endif
166
167 struct ks_msg
168 {
169 struct rt_msghdr rtm;
170 struct sockaddr_storage buf[RTAX_MAX];
171 };
172
173 #define ROUNDUP(a) \
174 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
175
176 #define NEXTADDR(w, u) \
177 if (msg.rtm.rtm_addrs & (w)) {\
178 l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
179 memmove(body, &(u), l); body += l;}
180
181 #define GETADDR(p, F) \
182 bzero(p, sizeof(*p));\
183 if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
184 uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
185 memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
186 body += l;}
187
188 static int
189 krt_send_route(struct krt_proto *p, int cmd, rte *e)
190 {
191 net *net = e->net;
192 rta *a = e->attrs;
193 static int msg_seq;
194 struct iface *j, *i = a->iface;
195 int l;
196 struct ks_msg msg;
197 char *body = (char *)msg.buf;
198 sockaddr gate, mask, dst;
199 ip_addr gw;
200
201 DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
202
203 bzero(&msg,sizeof (struct rt_msghdr));
204 msg.rtm.rtm_version = RTM_VERSION;
205 msg.rtm.rtm_type = cmd;
206 msg.rtm.rtm_seq = msg_seq++;
207 msg.rtm.rtm_addrs = RTA_DST;
208 msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
209
210 if (net->n.pxlen == MAX_PREFIX_LENGTH)
211 msg.rtm.rtm_flags |= RTF_HOST;
212 else
213 msg.rtm.rtm_addrs |= RTA_NETMASK;
214
215 #ifdef KRT_SHARED_SOCKET
216 msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
217 #endif
218
219 #ifdef RTF_REJECT
220 if(a->dest == RTD_UNREACHABLE)
221 msg.rtm.rtm_flags |= RTF_REJECT;
222 #endif
223 #ifdef RTF_BLACKHOLE
224 if(a->dest == RTD_BLACKHOLE)
225 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
226 #endif
227
228 /* This is really very nasty, but I'm not able
229 * to add "(reject|blackhole)" route without
230 * gateway set
231 */
232 if(!i)
233 {
234 i = HEAD(iface_list);
235
236 WALK_LIST(j, iface_list)
237 {
238 if (j->flags & IF_LOOPBACK)
239 {
240 i = j;
241 break;
242 }
243 }
244 }
245
246 gw = a->gw;
247
248 #ifdef IPV6
249 /* Embed interface ID to link-local address */
250 if (ipa_is_link_local(gw))
251 _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
252 #endif
253
254 sockaddr_fill(&dst, BIRD_AF, net->n.prefix, NULL, 0);
255 sockaddr_fill(&mask, BIRD_AF, ipa_mkmask(net->n.pxlen), NULL, 0);
256 sockaddr_fill(&gate, BIRD_AF, gw, NULL, 0);
257
258 switch (a->dest)
259 {
260 case RTD_ROUTER:
261 msg.rtm.rtm_flags |= RTF_GATEWAY;
262 msg.rtm.rtm_addrs |= RTA_GATEWAY;
263 break;
264
265 #ifdef RTF_REJECT
266 case RTD_UNREACHABLE:
267 #endif
268 #ifdef RTF_BLACKHOLE
269 case RTD_BLACKHOLE:
270 #endif
271 case RTD_DEVICE:
272 if(i)
273 {
274 #ifdef RTF_CLONING
275 if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
276 msg.rtm.rtm_flags |= RTF_CLONING;
277 #endif
278
279 if(!i->addr) {
280 log(L_ERR "KRT: interface %s has no IP addess", i->name);
281 return -1;
282 }
283
284 sockaddr_fill(&gate, BIRD_AF, i->addr->ip, NULL, 0);
285 msg.rtm.rtm_addrs |= RTA_GATEWAY;
286 }
287 break;
288 default:
289 bug("krt-sock: unknown flags, but not filtered");
290 }
291
292 msg.rtm.rtm_index = i->index;
293
294 NEXTADDR(RTA_DST, dst);
295 NEXTADDR(RTA_GATEWAY, gate);
296 NEXTADDR(RTA_NETMASK, mask);
297
298 l = body - (char *)&msg;
299 msg.rtm.rtm_msglen = l;
300
301 if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
302 log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen);
303 return -1;
304 }
305
306 return 0;
307 }
308
309 void
310 krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
311 struct ea_list *eattrs UNUSED)
312 {
313 int err = 0;
314
315 if (old)
316 krt_send_route(p, RTM_DELETE, old);
317
318 if (new)
319 err = krt_send_route(p, RTM_ADD, new);
320
321 if (err < 0)
322 n->n.flags |= KRF_SYNC_ERROR;
323 else
324 n->n.flags &= ~KRF_SYNC_ERROR;
325 }
326
327 #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
328
329 static void
330 krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
331 {
332 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
333
334 rte *e;
335 net *net;
336 sockaddr dst, gate, mask;
337 ip_addr idst, igate, imask;
338 void *body = (char *)msg->buf;
339 int new = (msg->rtm.rtm_type != RTM_DELETE);
340 char *errmsg = "KRT: Invalid route received";
341 int flags = msg->rtm.rtm_flags;
342 int addrs = msg->rtm.rtm_addrs;
343 int src;
344 byte src2;
345
346 if (!(flags & RTF_UP) && scan)
347 SKIP("not up in scan\n");
348
349 if (!(flags & RTF_DONE) && !scan)
350 SKIP("not done in async\n");
351
352 if (flags & RTF_LLINFO)
353 SKIP("link-local\n");
354
355 #ifdef KRT_SHARED_SOCKET
356 if (!scan)
357 {
358 int table_id = msg->rtm.rtm_tableid;
359 p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id] : NULL;
360
361 if (!p)
362 SKIP("unknown table id %d\n", table_id);
363 }
364 #endif
365
366 GETADDR(&dst, RTA_DST);
367 GETADDR(&gate, RTA_GATEWAY);
368 GETADDR(&mask, RTA_NETMASK);
369
370 if (dst.sa.sa_family != BIRD_AF)
371 SKIP("invalid DST");
372
373 idst = ipa_from_sa(&dst);
374 imask = ipa_from_sa(&mask);
375 igate = (gate.sa.sa_family == BIRD_AF) ? ipa_from_sa(&gate) : IPA_NONE;
376
377 /* We do not test family for RTA_NETMASK, because BSD sends us
378 some strange values, but interpreting them as IPv4/IPv6 works */
379
380
381 int c = ipa_classify_net(idst);
382 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
383 SKIP("strange class/scope\n");
384
385 int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask);
386 if (pxlen < 0)
387 { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
388
389 if ((flags & RTF_GATEWAY) && ipa_zero(igate))
390 { log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; }
391
392 u32 self_mask = RTF_PROTO1;
393 u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
394
395 src2 = (flags & RTF_STATIC) ? 1 : 0;
396 src2 |= (flags & RTF_PROTO1) ? 2 : 0;
397
398 #ifdef RTF_PROTO2
399 alien_mask |= RTF_PROTO2;
400 src2 |= (flags & RTF_PROTO2) ? 4 : 0;
401 #endif
402
403 #ifdef RTF_PROTO3
404 alien_mask |= RTF_PROTO3;
405 src2 |= (flags & RTF_PROTO3) ? 8 : 0;
406 #endif
407
408 #ifdef RTF_REJECT
409 alien_mask |= RTF_REJECT;
410 #endif
411
412 #ifdef RTF_BLACKHOLE
413 alien_mask |= RTF_BLACKHOLE;
414 #endif
415
416 if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
417 src = KRT_SRC_REDIRECT;
418 else if (flags & self_mask)
419 {
420 if (!scan)
421 SKIP("echo\n");
422 src = KRT_SRC_BIRD;
423 }
424 else if (flags & alien_mask)
425 src = KRT_SRC_ALIEN;
426 else
427 src = KRT_SRC_KERNEL;
428
429 net = net_get(p->p.table, idst, pxlen);
430
431 rta a = {
432 .src = p->p.main_source,
433 .source = RTS_INHERIT,
434 .scope = SCOPE_UNIVERSE,
435 .cast = RTC_UNICAST
436 };
437
438 /* reject/blackhole routes have also set RTF_GATEWAY,
439 we wil check them first. */
440
441 #ifdef RTF_REJECT
442 if(flags & RTF_REJECT) {
443 a.dest = RTD_UNREACHABLE;
444 goto done;
445 }
446 #endif
447
448 #ifdef RTF_BLACKHOLE
449 if(flags & RTF_BLACKHOLE) {
450 a.dest = RTD_BLACKHOLE;
451 goto done;
452 }
453 #endif
454
455 a.iface = if_find_by_index(msg->rtm.rtm_index);
456 if (!a.iface)
457 {
458 log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
459 net->n.prefix, net->n.pxlen, msg->rtm.rtm_index);
460 return;
461 }
462
463 if (flags & RTF_GATEWAY)
464 {
465 neighbor *ng;
466 a.dest = RTD_ROUTER;
467 a.gw = igate;
468
469 #ifdef IPV6
470 /* Clean up embedded interface ID returned in link-local address */
471 if (ipa_is_link_local(a.gw))
472 _I0(a.gw) = 0xfe800000;
473 #endif
474
475 ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
476 if (!ng || (ng->scope == SCOPE_HOST))
477 {
478 /* Ignore routes with next-hop 127.0.0.1, host routes with such
479 next-hop appear on OpenBSD for address aliases. */
480 if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
481 return;
482
483 log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
484 net->n.prefix, net->n.pxlen, a.gw);
485 return;
486 }
487 }
488 else
489 a.dest = RTD_DEVICE;
490
491 done:
492 e = rte_get_temp(&a);
493 e->net = net;
494 e->u.krt.src = src;
495 e->u.krt.proto = src2;
496
497 /* These are probably too Linux-specific */
498 e->u.krt.type = 0;
499 e->u.krt.metric = 0;
500
501 if (scan)
502 krt_got_route(p, e);
503 else
504 krt_got_route_async(p, e, new);
505 }
506
507 static void
508 krt_read_ifannounce(struct ks_msg *msg)
509 {
510 struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
511
512 if (ifam->ifan_what == IFAN_ARRIVAL)
513 {
514 /* Not enough info to create the iface, so we just trigger iface scan */
515 kif_request_scan();
516 }
517 else if (ifam->ifan_what == IFAN_DEPARTURE)
518 {
519 struct iface *iface = if_find_by_index(ifam->ifan_index);
520
521 /* Interface is destroyed */
522 if (!iface)
523 {
524 DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
525 return;
526 }
527
528 if_delete(iface);
529 }
530
531 DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
532 }
533
534 static void
535 krt_read_ifinfo(struct ks_msg *msg, int scan)
536 {
537 struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
538 void *body = (void *)(ifm + 1);
539 struct sockaddr_dl *dl = NULL;
540 uint i;
541 struct iface *iface = NULL, f = {};
542 int fl = ifm->ifm_flags;
543 int nlen = 0;
544
545 for (i = 1; i<=RTA_IFP; i <<= 1)
546 {
547 if (i & ifm->ifm_addrs)
548 {
549 if (i == RTA_IFP)
550 {
551 dl = (struct sockaddr_dl *)body;
552 break;
553 }
554 body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
555 }
556 }
557
558 if (dl && (dl->sdl_family != AF_LINK))
559 {
560 log(L_WARN "Ignoring strange IFINFO");
561 return;
562 }
563
564 if (dl)
565 nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
566
567 /* Note that asynchronous IFINFO messages do not contain iface
568 name, so we have to found an existing iface by iface index */
569
570 iface = if_find_by_index(ifm->ifm_index);
571 if (!iface)
572 {
573 /* New interface */
574 if (!dl)
575 return; /* No interface name, ignoring */
576
577 memcpy(f.name, dl->sdl_data, nlen);
578 DBG("New interface '%s' found\n", f.name);
579 }
580 else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
581 {
582 /* Interface renamed */
583 if_delete(iface);
584 memcpy(f.name, dl->sdl_data, nlen);
585 }
586 else
587 {
588 /* Old interface */
589 memcpy(f.name, iface->name, sizeof(f.name));
590 }
591
592 f.index = ifm->ifm_index;
593 f.mtu = ifm->ifm_data.ifi_mtu;
594
595 if (fl & IFF_UP)
596 f.flags |= IF_ADMIN_UP;
597 if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
598 f.flags |= IF_LINK_UP; /* up or unknown */
599 if (fl & IFF_LOOPBACK) /* Loopback */
600 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
601 else if (fl & IFF_POINTOPOINT) /* PtP */
602 f.flags |= IF_MULTICAST;
603 else if (fl & IFF_BROADCAST) /* Broadcast */
604 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
605 else
606 f.flags |= IF_MULTIACCESS; /* NBMA */
607
608 iface = if_update(&f);
609
610 if (!scan)
611 if_end_partial_update(iface);
612 }
613
614 static void
615 krt_read_addr(struct ks_msg *msg, int scan)
616 {
617 struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
618 void *body = (void *)(ifam + 1);
619 sockaddr addr, mask, brd;
620 struct iface *iface = NULL;
621 struct ifa ifa;
622 struct sockaddr null;
623 ip_addr iaddr, imask, ibrd;
624 int addrs = ifam->ifam_addrs;
625 int scope, masklen = -1;
626 int new = (ifam->ifam_type == RTM_NEWADDR);
627
628 /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
629 if (ifam->ifam_index == 0)
630 return;
631
632 if(!(iface = if_find_by_index(ifam->ifam_index)))
633 {
634 log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
635 return;
636 }
637
638 GETADDR (&null, RTA_DST);
639 GETADDR (&null, RTA_GATEWAY);
640 GETADDR (&mask, RTA_NETMASK);
641 GETADDR (&null, RTA_GENMASK);
642 GETADDR (&null, RTA_IFP);
643 GETADDR (&addr, RTA_IFA);
644 GETADDR (&null, RTA_AUTHOR);
645 GETADDR (&brd, RTA_BRD);
646
647 /* Some other family address */
648 if (addr.sa.sa_family != BIRD_AF)
649 return;
650
651 iaddr = ipa_from_sa(&addr);
652 imask = ipa_from_sa(&mask);
653 ibrd = ipa_from_sa(&brd);
654
655
656 if ((masklen = ipa_masklen(imask)) < 0)
657 {
658 log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
659 return;
660 }
661
662 #ifdef IPV6
663 /* Clean up embedded interface ID returned in link-local address */
664
665 if (ipa_is_link_local(iaddr))
666 _I0(iaddr) = 0xfe800000;
667
668 if (ipa_is_link_local(ibrd))
669 _I0(ibrd) = 0xfe800000;
670 #endif
671
672
673 bzero(&ifa, sizeof(ifa));
674 ifa.iface = iface;
675 ifa.ip = iaddr;
676 ifa.pxlen = masklen;
677
678 scope = ipa_classify(ifa.ip);
679 if (scope < 0)
680 {
681 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
682 return;
683 }
684 ifa.scope = scope & IADDR_SCOPE_MASK;
685
686 if (masklen < BITS_PER_IP_ADDRESS)
687 {
688 ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
689
690 if (masklen == (BITS_PER_IP_ADDRESS - 1))
691 ifa.opposite = ipa_opposite_m1(ifa.ip);
692
693 #ifndef IPV6
694 if (masklen == (BITS_PER_IP_ADDRESS - 2))
695 ifa.opposite = ipa_opposite_m2(ifa.ip);
696 #endif
697
698 if (iface->flags & IF_BROADCAST)
699 ifa.brd = ibrd;
700
701 if (!(iface->flags & IF_MULTIACCESS))
702 ifa.opposite = ibrd;
703 }
704 else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
705 {
706 ifa.prefix = ifa.opposite = ibrd;
707 ifa.flags |= IA_PEER;
708 }
709 else
710 {
711 ifa.prefix = ifa.ip;
712 ifa.flags |= IA_HOST;
713 }
714
715 if (new)
716 ifa_update(&ifa);
717 else
718 ifa_delete(&ifa);
719
720 if (!scan)
721 if_end_partial_update(iface);
722 }
723
724 static void
725 krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
726 {
727 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
728
729 switch (msg->rtm.rtm_type)
730 {
731 case RTM_GET:
732 if(!scan) return;
733 case RTM_ADD:
734 case RTM_DELETE:
735 case RTM_CHANGE:
736 krt_read_route(msg, (struct krt_proto *)p, scan);
737 break;
738 case RTM_IFANNOUNCE:
739 krt_read_ifannounce(msg);
740 break;
741 case RTM_IFINFO:
742 krt_read_ifinfo(msg, scan);
743 break;
744 case RTM_NEWADDR:
745 case RTM_DELADDR:
746 krt_read_addr(msg, scan);
747 break;
748 default:
749 break;
750 }
751 }
752
753
754 /* Sysctl based scans */
755
756 static byte *krt_buffer;
757 static size_t krt_buflen, krt_bufmin;
758 static struct proto *krt_buffer_owner;
759
760 static byte *
761 krt_buffer_update(struct proto *p, size_t *needed)
762 {
763 size_t req = *needed;
764
765 if ((req > krt_buflen) ||
766 ((p == krt_buffer_owner) && (req < krt_bufmin)))
767 {
768 /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
769 size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
770 krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
771 krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
772
773 if (krt_buffer)
774 mb_free(krt_buffer);
775 krt_buffer = mb_alloc(krt_pool, krt_buflen);
776 krt_buffer_owner = p;
777 }
778
779 *needed = krt_buflen;
780 return krt_buffer;
781 }
782
783 static void
784 krt_buffer_release(struct proto *p)
785 {
786 if (p == krt_buffer_owner)
787 {
788 mb_free(krt_buffer);
789 krt_buffer = NULL;
790 krt_buflen = 0;
791 krt_buffer_owner = 0;
792 }
793 }
794
795 static void
796 krt_sysctl_scan(struct proto *p, int cmd, int table_id)
797 {
798 byte *buf, *next;
799 int mib[7], mcnt;
800 size_t needed;
801 struct ks_msg *m;
802 int retries = 3;
803 int rv;
804
805 mib[0] = CTL_NET;
806 mib[1] = PF_ROUTE;
807 mib[2] = 0;
808 mib[3] = BIRD_AF;
809 mib[4] = cmd;
810 mib[5] = 0;
811 mcnt = 6;
812
813 #ifdef KRT_USE_SYSCTL_7
814 if (table_id >= 0)
815 {
816 mib[6] = table_id;
817 mcnt = 7;
818 }
819 #endif
820
821 #ifdef KRT_USE_SETFIB_SCAN
822 if (table_id > 0)
823 if (setfib(table_id) < 0)
824 {
825 log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
826 return;
827 }
828 #endif
829
830 try:
831 rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
832 if (rv < 0)
833 {
834 /* OpenBSD returns EINVAL for not yet used tables */
835 if ((errno == EINVAL) && (table_id > 0))
836 goto exit;
837
838 log(L_ERR "KRT: Route scan estimate failed: %m");
839 goto exit;
840 }
841
842 /* The table is empty */
843 if (needed == 0)
844 goto exit;
845
846 buf = krt_buffer_update(p, &needed);
847
848 rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
849 if (rv < 0)
850 {
851 /* The buffer size changed since last sysctl ('needed' is not changed) */
852 if ((errno == ENOMEM) && retries--)
853 goto try;
854
855 log(L_ERR "KRT: Route scan failed: %m");
856 goto exit;
857 }
858
859 #ifdef KRT_USE_SETFIB_SCAN
860 if (table_id > 0)
861 if (setfib(0) < 0)
862 die("KRT: setfib(%d) failed: %m", 0);
863 #endif
864
865 /* Process received messages */
866 for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
867 {
868 m = (struct ks_msg *)next;
869 krt_read_msg(p, m, 1);
870 }
871
872 return;
873
874 exit:
875 krt_buffer_release(p);
876
877 #ifdef KRT_USE_SETFIB_SCAN
878 if (table_id > 0)
879 if (setfib(0) < 0)
880 die("KRT: setfib(%d) failed: %m", 0);
881 #endif
882 }
883
884 void
885 krt_do_scan(struct krt_proto *p)
886 {
887 krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
888 }
889
890 void
891 kif_do_scan(struct kif_proto *p)
892 {
893 if_start_update();
894 krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
895 if_end_update();
896 }
897
898
899 /* Kernel sockets */
900
901 static int
902 krt_sock_hook(sock *sk, int size UNUSED)
903 {
904 struct ks_msg msg;
905 int l = read(sk->fd, (char *)&msg, sizeof(msg));
906
907 if (l <= 0)
908 log(L_ERR "krt-sock: read failed");
909 else
910 krt_read_msg((struct proto *) sk->data, &msg, 0);
911
912 return 0;
913 }
914
915 static sock *
916 krt_sock_open(pool *pool, void *data, int table_id)
917 {
918 sock *sk;
919 int fd;
920
921 fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
922 if (fd < 0)
923 die("Cannot open kernel socket for routes");
924
925 #ifdef KRT_USE_SETFIB_SOCK
926 if (table_id > 0)
927 {
928 if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
929 die("Cannot set FIB %d for kernel socket: %m", table_id);
930 }
931 #endif
932
933 sk = sk_new(pool);
934 sk->type = SK_MAGIC;
935 sk->rx_hook = krt_sock_hook;
936 sk->fd = fd;
937 sk->data = data;
938
939 if (sk_open(sk) < 0)
940 bug("krt-sock: sk_open failed");
941
942 return sk;
943 }
944
945
946 #ifdef KRT_SHARED_SOCKET
947
948 static sock *krt_sock;
949 static int krt_sock_count;
950
951
952 static void
953 krt_sock_open_shared(void)
954 {
955 if (!krt_sock_count)
956 krt_sock = krt_sock_open(krt_pool, NULL, -1);
957
958 krt_sock_count++;
959 }
960
961 static void
962 krt_sock_close_shared(void)
963 {
964 krt_sock_count--;
965
966 if (!krt_sock_count)
967 {
968 rfree(krt_sock);
969 krt_sock = NULL;
970 }
971 }
972
973 int
974 krt_sys_start(struct krt_proto *p)
975 {
976 krt_table_map[KRT_CF->sys.table_id] = p;
977
978 krt_sock_open_shared();
979 p->sys.sk = krt_sock;
980
981 return 1;
982 }
983
984 void
985 krt_sys_shutdown(struct krt_proto *p)
986 {
987 krt_sock_close_shared();
988 p->sys.sk = NULL;
989
990 krt_table_map[KRT_CF->sys.table_id] = NULL;
991
992 krt_buffer_release(&p->p);
993 }
994
995 #else
996
997 int
998 krt_sys_start(struct krt_proto *p)
999 {
1000 p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
1001 return 1;
1002 }
1003
1004 void
1005 krt_sys_shutdown(struct krt_proto *p)
1006 {
1007 rfree(p->sys.sk);
1008 p->sys.sk = NULL;
1009
1010 krt_buffer_release(&p->p);
1011 }
1012
1013 #endif /* KRT_SHARED_SOCKET */
1014
1015
1016 /* KRT configuration callbacks */
1017
1018 static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32];
1019
1020 int
1021 krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1022 {
1023 return n->sys.table_id == o->sys.table_id;
1024 }
1025
1026 void
1027 krt_sys_preconfig(struct config *c UNUSED)
1028 {
1029 krt_max_tables = krt_get_max_tables();
1030 bzero(&krt_table_cf, sizeof(krt_table_cf));
1031 }
1032
1033 void
1034 krt_sys_postconfig(struct krt_config *x)
1035 {
1036 u32 *tbl = krt_table_cf;
1037 int id = x->sys.table_id;
1038
1039 if (tbl[id/32] & (1 << (id%32)))
1040 cf_error("Multiple kernel syncers defined for table #%d", id);
1041
1042 tbl[id/32] |= (1 << (id%32));
1043 }
1044
1045 void krt_sys_init_config(struct krt_config *c)
1046 {
1047 c->sys.table_id = 0; /* Default table */
1048 }
1049
1050 void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1051 {
1052 d->sys.table_id = s->sys.table_id;
1053 }
1054
1055
1056 /* KIF misc code */
1057
1058 void
1059 kif_sys_start(struct kif_proto *p UNUSED)
1060 {
1061 }
1062
1063 void
1064 kif_sys_shutdown(struct kif_proto *p)
1065 {
1066 krt_buffer_release(&p->p);
1067 }
1068
1069
1070 struct ifa *
1071 kif_get_primary_ip(struct iface *i)
1072 {
1073 #ifndef IPV6
1074 static int fd = -1;
1075
1076 if (fd < 0)
1077 fd = socket(AF_INET, SOCK_DGRAM, 0);
1078
1079 struct ifreq ifr;
1080 memset(&ifr, 0, sizeof(ifr));
1081 strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1082
1083 int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1084 if (rv < 0)
1085 return NULL;
1086
1087 ip_addr addr;
1088 struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
1089 memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr));
1090 ipa_ntoh(addr);
1091
1092 struct ifa *a;
1093 WALK_LIST(a, i->addrs)
1094 {
1095 if (ipa_equal(a->ip, addr))
1096 return a;
1097 }
1098 #endif
1099
1100 return NULL;
1101 }