]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/bsd/krt-sock.c
Adds krt_source route attribute.
[thirdparty/bird.git] / sysdep / bsd / krt-sock.c
CommitLineData
b1a1faba
OF
1/*
2 * BIRD -- Unix 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 <ctype.h>
11#include <fcntl.h>
12#include <unistd.h>
13#include <sys/param.h>
14#include <sys/types.h>
15#include <sys/socket.h>
16#include <sys/sysctl.h>
17#include <sys/ioctl.h>
18#include <netinet/in.h>
19#include <net/route.h>
20#include <net/if.h>
21#include <net/if_dl.h>
22
23#undef LOCAL_DEBUG
24
25#include "nest/bird.h"
26#include "nest/iface.h"
27#include "nest/route.h"
28#include "nest/protocol.h"
29#include "nest/iface.h"
30#include "lib/timer.h"
31#include "lib/unix.h"
32#include "lib/krt.h"
33#include "lib/string.h"
34#include "lib/socket.h"
35
b1a1faba
OF
36int rt_sock = 0;
37
b1a1faba
OF
38int
39krt_capable(rte *e)
40{
41 rta *a = e->attrs;
42
b1a1faba
OF
43 return
44 a->cast == RTC_UNICAST &&
45 (a->dest == RTD_ROUTER
46 || a->dest == RTD_DEVICE
47#ifdef RTF_REJECT
48 || a->dest == RTD_UNREACHABLE
49#endif
50#ifdef RTF_BLACKHOLE
ff2857b0 51 || a->dest == RTD_BLACKHOLE
b1a1faba
OF
52#endif
53 );
54}
55
56#define ROUNDUP(a) \
57 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
58
59#define NEXTADDR(w, u) \
60 if (msg.rtm.rtm_addrs & (w)) {\
61 l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
62 memmove(body, &(u), l); body += l;}
63
ff2857b0
OZ
64#define GETADDR(p, F) \
65 bzero(p, sizeof(*p));\
66 if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
67 unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
68 memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
69 body += l;}
70
32f95476 71static int
fb257e43 72krt_sock_send(int cmd, rte *e)
b1a1faba
OF
73{
74 net *net = e->net;
75 rta *a = e->attrs;
76 static int msg_seq;
77 struct iface *j, *i = a->iface;
78 int l;
79 struct ks_msg msg;
80 char *body = (char *)msg.buf;
81 sockaddr gate, mask, dst;
44aa101c 82 ip_addr gw;
b1a1faba 83
ff2857b0 84 DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
b1a1faba 85
b88a1d40 86 bzero(&msg,sizeof (struct rt_msghdr));
b1a1faba
OF
87 msg.rtm.rtm_version = RTM_VERSION;
88 msg.rtm.rtm_type = cmd;
89 msg.rtm.rtm_seq = msg_seq++;
90 msg.rtm.rtm_addrs = RTA_DST;
ff2857b0 91 msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
b1a1faba 92
ff2857b0 93 if (net->n.pxlen == MAX_PREFIX_LENGTH)
b1a1faba
OF
94 {
95 msg.rtm.rtm_flags |= RTF_HOST;
96 }
97 else
98 {
99 msg.rtm.rtm_addrs |= RTA_NETMASK;
100 }
101
102#ifdef RTF_REJECT
103 if(a->dest == RTD_UNREACHABLE)
104 msg.rtm.rtm_flags |= RTF_REJECT;
105#endif
106#ifdef RTF_BLACKHOLE
107 if(a->dest == RTD_BLACKHOLE)
108 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
109#endif
110
111 /* This is really very nasty, but I'm not able
112 * to add "(reject|blackhole)" route without
113 * gateway set
114 */
115 if(!i)
116 {
8281ff20 117 i = HEAD(iface_list);
77772dbc 118
8281ff20
OF
119 WALK_LIST(j, iface_list)
120 {
121 if (j->flags & IF_LOOPBACK)
b1a1faba 122 {
8281ff20
OF
123 i = j;
124 break;
b1a1faba
OF
125 }
126 }
127 }
128
44aa101c
OZ
129 gw = a->gw;
130
131#ifdef IPV6
132 /* Embed interface ID to link-local address */
133 if (ipa_has_link_scope(gw))
134 _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
135#endif
136
d7f469c1
OZ
137 fill_in_sockaddr(&dst, net->n.prefix, NULL, 0);
138 fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), NULL, 0);
139 fill_in_sockaddr(&gate, gw, NULL, 0);
44aa101c 140
b1a1faba
OF
141 switch (a->dest)
142 {
143 case RTD_ROUTER:
144 msg.rtm.rtm_flags |= RTF_GATEWAY;
145 msg.rtm.rtm_addrs |= RTA_GATEWAY;
146 break;
147#ifdef RTF_REJECT
148 case RTD_UNREACHABLE:
149#endif
150#ifdef RTF_BLACKHOLE
151 case RTD_BLACKHOLE:
152#endif
153 case RTD_DEVICE:
154 if(i)
155 {
7d196668 156#ifdef RTF_CLONING
b1a1faba
OF
157 if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
158 msg.rtm.rtm_flags |= RTF_CLONING;
7d196668 159#endif
b1a1faba
OF
160
161 if(!i->addr) {
c429d4a4 162 log(L_ERR "KRT: interface %s has no IP addess", i->name);
32f95476 163 return -1;
b1a1faba
OF
164 }
165
d7f469c1 166 fill_in_sockaddr(&gate, i->addr->ip, NULL, 0);
b1a1faba
OF
167 msg.rtm.rtm_addrs |= RTA_GATEWAY;
168 }
b1a1faba
OF
169 break;
170 default:
171 bug("krt-sock: unknown flags, but not filtered");
172 }
173
1554cc02 174 msg.rtm.rtm_index = i->index;
b1a1faba
OF
175
176 NEXTADDR(RTA_DST, dst);
177 NEXTADDR(RTA_GATEWAY, gate);
178 NEXTADDR(RTA_NETMASK, mask);
179
180 l = body - (char *)&msg;
181 msg.rtm.rtm_msglen = l;
182
183 if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
1cb97af4 184 log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen);
32f95476 185 return -1;
b1a1faba 186 }
32f95476
OZ
187
188 return 0;
b1a1faba
OF
189}
190
191void
32f95476 192krt_set_notify(struct krt_proto *p UNUSED, net *n, rte *new, rte *old)
b1a1faba 193{
32f95476
OZ
194 int err = 0;
195
b1a1faba 196 if (old)
32f95476
OZ
197 krt_sock_send(RTM_DELETE, old);
198
b1a1faba 199 if (new)
32f95476
OZ
200 err = krt_sock_send(RTM_ADD, new);
201
202 if (err < 0)
203 n->n.flags |= KRF_SYNC_ERROR;
204 else
205 n->n.flags &= ~KRF_SYNC_ERROR;
b1a1faba
OF
206}
207
282997f2
OF
208static int
209krt_set_hook(sock *sk, int size UNUSED)
210{
211 struct ks_msg msg;
212 int l = read(sk->fd, (char *)&msg, sizeof(msg));
213
214 if(l <= 0)
215 log(L_ERR "krt-sock: read failed");
216 else
217 krt_read_msg((struct proto *)sk->data, &msg, 0);
218
219 return 0;
220}
221
b1a1faba 222void
19d9e303 223krt_set_start(struct krt_proto *x, int first UNUSED)
b1a1faba
OF
224{
225 sock *sk_rt;
226 static int ks_open_tried = 0;
227
228 if (ks_open_tried)
229 return;
230
231 ks_open_tried = 1;
232
233 DBG("KRT: Opening kernel socket\n");
234
235 if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0)
236 die("Cannot open kernel socket for routes");
237
238 sk_rt = sk_new(krt_pool);
239 sk_rt->type = SK_MAGIC;
240 sk_rt->rx_hook = krt_set_hook;
241 sk_rt->fd = rt_sock;
242 sk_rt->data = x;
243 if (sk_open(sk_rt))
a8bb459a 244 bug("krt-sock: sk_open failed");
b1a1faba
OF
245}
246
ff2857b0
OZ
247#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
248
282997f2 249static void
b1a1faba
OF
250krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
251{
b1a1faba
OF
252 rte *e;
253 net *net;
ff2857b0 254 sockaddr dst, gate, mask;
b1a1faba
OF
255 ip_addr idst, igate, imask;
256 void *body = (char *)msg->buf;
257 int new = (msg->rtm.rtm_type == RTM_ADD);
ff2857b0 258 char *errmsg = "KRT: Invalid route received";
b1a1faba
OF
259 int flags = msg->rtm.rtm_flags;
260 int addrs = msg->rtm.rtm_addrs;
72aed1a0
OZ
261 int src;
262 byte src2;
b1a1faba 263
ff2857b0
OZ
264 if (!(flags & RTF_UP) && scan)
265 SKIP("not up in scan\n");
b1a1faba 266
ff2857b0
OZ
267 if (!(flags & RTF_DONE) && !scan)
268 SKIP("not done in async\n");
b1a1faba 269
ff2857b0
OZ
270 if (flags & RTF_LLINFO)
271 SKIP("link-local\n");
b1a1faba 272
ff2857b0
OZ
273 GETADDR(&dst, RTA_DST);
274 GETADDR(&gate, RTA_GATEWAY);
275 GETADDR(&mask, RTA_NETMASK);
b1a1faba 276
ff2857b0 277 if (sa_family_check(&dst))
d7f469c1 278 get_sockaddr(&dst, &idst, NULL, NULL, 0);
ff2857b0
OZ
279 else
280 SKIP("invalid DST");
b1a1faba 281
ff2857b0
OZ
282 /* We will check later whether we have valid gateway addr */
283 if (sa_family_check(&gate))
d7f469c1 284 get_sockaddr(&gate, &igate, NULL, NULL, 0);
ff2857b0
OZ
285 else
286 igate = IPA_NONE;
b1a1faba 287
ff2857b0
OZ
288 /* We do not test family for RTA_NETMASK, because BSD sends us
289 some strange values, but interpreting them as IPv4/IPv6 works */
d7f469c1 290 get_sockaddr(&mask, &imask, NULL, NULL, 0);
b1a1faba 291
ff2857b0
OZ
292 int c = ipa_classify_net(idst);
293 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
294 SKIP("strange class/scope\n");
b1a1faba 295
ff2857b0
OZ
296 int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask);
297 if (pxlen < 0)
298 { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
b1a1faba 299
ff2857b0
OZ
300 if ((flags & RTF_GATEWAY) && ipa_zero(igate))
301 { log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; }
302
303 u32 self_mask = RTF_PROTO1;
a9f380fe 304 u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
ff2857b0 305
72aed1a0
OZ
306 src2 = (flags & RTF_STATIC) ? 1 : 0;
307 src2 |= (flags & RTF_PROTO1) ? 2 : 0;
308
ff2857b0
OZ
309#ifdef RTF_PROTO2
310 alien_mask |= RTF_PROTO2;
72aed1a0 311 src2 |= (flags & RTF_PROTO2) ? 4 : 0;
ff2857b0 312#endif
b1a1faba 313
ff2857b0
OZ
314#ifdef RTF_PROTO3
315 alien_mask |= RTF_PROTO3;
72aed1a0 316 src2 |= (flags & RTF_PROTO3) ? 8 : 0;
ff2857b0
OZ
317#endif
318
a9f380fe
OZ
319#ifdef RTF_REJECT
320 alien_mask |= RTF_REJECT;
321#endif
322
323#ifdef RTF_BLACKHOLE
324 alien_mask |= RTF_BLACKHOLE;
325#endif
326
ff2857b0
OZ
327 if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
328 src = KRT_SRC_REDIRECT;
329 else if (flags & self_mask)
330 {
331 if (!scan)
332 SKIP("echo\n");
333 src = KRT_SRC_BIRD;
334 }
335 else if (flags & alien_mask)
336 src = KRT_SRC_ALIEN;
337 else
338 src = KRT_SRC_KERNEL;
339
340 net = net_get(p->p.table, idst, pxlen);
b1a1faba 341
cfe34a31
OZ
342 rta a = {
343 .proto = &p->p,
344 .source = RTS_INHERIT,
345 .scope = SCOPE_UNIVERSE,
346 .cast = RTC_UNICAST
347 };
b1a1faba 348
ff2857b0
OZ
349 /* reject/blackhole routes have also set RTF_GATEWAY,
350 we wil check them first. */
b1a1faba
OF
351
352#ifdef RTF_REJECT
353 if(flags & RTF_REJECT) {
354 a.dest = RTD_UNREACHABLE;
ff2857b0 355 goto done;
b1a1faba
OF
356 }
357#endif
358
359#ifdef RTF_BLACKHOLE
360 if(flags & RTF_BLACKHOLE) {
361 a.dest = RTD_BLACKHOLE;
ff2857b0 362 goto done;
b1a1faba
OF
363 }
364#endif
365
ff2857b0
OZ
366 a.iface = if_find_by_index(msg->rtm.rtm_index);
367 if (!a.iface)
368 {
369 log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
370 net->n.prefix, net->n.pxlen, msg->rtm.rtm_index);
371 return;
372 }
373
374 if (flags & RTF_GATEWAY)
b1a1faba 375 {
ff2857b0
OZ
376 neighbor *ng;
377 a.dest = RTD_ROUTER;
378 a.gw = igate;
b1a1faba 379
44aa101c
OZ
380#ifdef IPV6
381 /* Clean up embedded interface ID returned in link-local address */
382 if (ipa_has_link_scope(a.gw))
383 _I0(a.gw) = 0xfe800000;
384#endif
385
ff2857b0
OZ
386 ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
387 if (!ng || (ng->scope == SCOPE_HOST))
388 {
de14a7c7
OZ
389 /* Ignore routes with next-hop 127.0.0.1, host routes with such
390 next-hop appear on OpenBSD for address aliases. */
391 if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
392 return;
393
ff2857b0
OZ
394 log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
395 net->n.prefix, net->n.pxlen, a.gw);
396 return;
397 }
398 }
399 else
400 a.dest = RTD_DEVICE;
b1a1faba 401
ff2857b0 402 done:
b1a1faba
OF
403 e = rte_get_temp(&a);
404 e->net = net;
405 e->u.krt.src = src;
72aed1a0 406 e->u.krt.proto = src2;
ff2857b0
OZ
407
408 /* These are probably too Linux-specific */
ff2857b0 409 e->u.krt.type = 0;
b1a1faba
OF
410 e->u.krt.metric = 0;
411
412 if (scan)
413 krt_got_route(p, e);
414 else
415 krt_got_route_async(p, e, new);
416}
417
09686693
OZ
418static void
419krt_read_ifannounce(struct ks_msg *msg)
420{
421 struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
422
423 if (ifam->ifan_what == IFAN_ARRIVAL)
424 {
425 /* Not enough info to create the iface, so we just trigger iface scan */
426 kif_request_scan();
427 }
428 else if (ifam->ifan_what == IFAN_DEPARTURE)
429 {
430 struct iface *iface = if_find_by_index(ifam->ifan_index);
431
432 /* Interface is destroyed */
433 if (!iface)
434 {
435 DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
436 return;
437 }
438
439 if_delete(iface);
440 }
441
442 DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
443}
444
282997f2 445static void
b1a1faba
OF
446krt_read_ifinfo(struct ks_msg *msg)
447{
448 struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
449 void *body = (void *)(ifm + 1);
450 struct sockaddr_dl *dl = NULL;
451 unsigned int i;
732a0a25 452 struct iface *iface = NULL, f = {};
b1a1faba 453 int fl = ifm->ifm_flags;
732a0a25 454 int nlen = 0;
b1a1faba 455
d32a071d 456 for (i = 1; i<=RTA_IFP; i <<= 1)
b1a1faba 457 {
d32a071d 458 if (i & ifm->ifm_addrs)
b1a1faba 459 {
d32a071d 460 if (i == RTA_IFP)
b1a1faba
OF
461 {
462 dl = (struct sockaddr_dl *)body;
463 break;
464 }
d32a071d 465 body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
b1a1faba
OF
466 }
467 }
468
732a0a25 469 if (dl && (dl->sdl_family != AF_LINK))
b1a1faba 470 {
09686693 471 log(L_WARN "Ignoring strange IFINFO");
b1a1faba
OF
472 return;
473 }
474
732a0a25
OZ
475 if (dl)
476 nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
477
478 /* Note that asynchronous IFINFO messages do not contain iface
479 name, so we have to found an existing iface by iface index */
b1a1faba 480
732a0a25
OZ
481 iface = if_find_by_index(ifm->ifm_index);
482 if (!iface)
b1a1faba
OF
483 {
484 /* New interface */
732a0a25
OZ
485 if (!dl)
486 return; /* No interface name, ignoring */
dad7ee70 487
732a0a25
OZ
488 memcpy(f.name, dl->sdl_data, nlen);
489 DBG("New interface '%s' found\n", f.name);
490 }
491 else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
492 {
493 /* Interface renamed */
494 if_delete(iface);
495 memcpy(f.name, dl->sdl_data, nlen);
b1a1faba
OF
496 }
497 else
498 {
732a0a25
OZ
499 /* Old interface */
500 memcpy(f.name, iface->name, sizeof(f.name));
b1a1faba
OF
501 }
502
732a0a25 503 f.index = ifm->ifm_index;
b1a1faba 504 f.mtu = ifm->ifm_data.ifi_mtu;
b1a1faba
OF
505
506 if (fl & IFF_UP)
f25cb0ef
OZ
507 f.flags |= IF_ADMIN_UP;
508 if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
509 f.flags |= IF_LINK_UP; /* up or unknown */
b1a1faba
OF
510 if (fl & IFF_LOOPBACK) /* Loopback */
511 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
512 else if (fl & IFF_POINTOPOINT) /* PtP */
513 f.flags |= IF_MULTICAST;
514 else if (fl & IFF_BROADCAST) /* Broadcast */
515 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
516 else
517 f.flags |= IF_MULTIACCESS; /* NBMA */
518
b573755d 519 if_update(&f);
b1a1faba
OF
520}
521
282997f2 522static void
b1a1faba
OF
523krt_read_addr(struct ks_msg *msg)
524{
525 struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
526 void *body = (void *)(ifam + 1);
527 sockaddr addr, mask, brd;
b1a1faba
OF
528 struct iface *iface = NULL;
529 struct ifa ifa;
530 struct sockaddr null;
531 ip_addr iaddr, imask, ibrd;
532 int addrs = ifam->ifam_addrs;
533 int scope, masklen = -1;
534 int new = (ifam->ifam_type == RTM_NEWADDR);
b1a1faba 535
ff2857b0
OZ
536 /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
537 if (ifam->ifam_index == 0)
538 return;
539
b1a1faba
OF
540 if(!(iface = if_find_by_index(ifam->ifam_index)))
541 {
542 log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
543 return;
544 }
545
546 GETADDR (&null, RTA_DST);
547 GETADDR (&null, RTA_GATEWAY);
548 GETADDR (&mask, RTA_NETMASK);
549 GETADDR (&null, RTA_GENMASK);
550 GETADDR (&null, RTA_IFP);
551 GETADDR (&addr, RTA_IFA);
552 GETADDR (&null, RTA_AUTHOR);
553 GETADDR (&brd, RTA_BRD);
554
ff2857b0
OZ
555 /* Some other family address */
556 if (!sa_family_check(&addr))
557 return;
b1a1faba 558
d7f469c1
OZ
559 get_sockaddr(&addr, &iaddr, NULL, NULL, 0);
560 get_sockaddr(&mask, &imask, NULL, NULL, 0);
561 get_sockaddr(&brd, &ibrd, NULL, NULL, 0);
b1a1faba
OF
562
563 if ((masklen = ipa_mklen(imask)) < 0)
564 {
565 log("Invalid masklen");
566 return;
567 }
568
b88a1d40 569 bzero(&ifa, sizeof(ifa));
b1a1faba
OF
570
571 ifa.iface = iface;
572
573 memcpy(&ifa.ip, &iaddr, sizeof(ip_addr));
574 ifa.pxlen = masklen;
575 memcpy(&ifa.brd, &ibrd, sizeof(ip_addr));
576
577 scope = ipa_classify(ifa.ip);
b1a1faba
OF
578 if (scope < 0)
579 {
580 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
581 return;
582 }
583 ifa.scope = scope & IADDR_SCOPE_MASK;
584
44aa101c
OZ
585#ifdef IPV6
586 /* Clean up embedded interface ID returned in link-local address */
587 if (ipa_has_link_scope(ifa.ip))
97ab4c34 588 _I0(ifa.ip) = 0xfe800000;
44aa101c 589#endif
97ab4c34 590
3f584374
OZ
591#ifdef IPV6
592 /* Why not the same check also for IPv4? */
593 if ((iface->flags & IF_MULTIACCESS) || (masklen != BITS_PER_IP_ADDRESS))
594#else
afa9f66c 595 if (iface->flags & IF_MULTIACCESS)
3f584374 596#endif
ba321706 597 {
afa9f66c 598 ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
ba321706 599
52a43ae3
OZ
600 if (masklen == BITS_PER_IP_ADDRESS)
601 ifa.flags |= IA_HOST;
602
9b061f7e 603 if (masklen == (BITS_PER_IP_ADDRESS - 1))
ba321706
OZ
604 ifa.opposite = ipa_opposite_m1(ifa.ip);
605
606#ifndef IPV6
9b061f7e 607 if (masklen == (BITS_PER_IP_ADDRESS - 2))
ba321706
OZ
608 ifa.opposite = ipa_opposite_m2(ifa.ip);
609#endif
610 }
afa9f66c
OZ
611 else /* PtP iface */
612 {
52a43ae3 613 ifa.flags |= IA_PEER;
afa9f66c
OZ
614 ifa.prefix = ifa.opposite = ifa.brd;
615 }
616
b1a1faba
OF
617 if (new)
618 ifa_update(&ifa);
619 else
620 ifa_delete(&ifa);
621}
622
623
624void
625krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
626{
627 switch (msg->rtm.rtm_type)
628 {
629 case RTM_GET:
630 if(!scan) return;
631 case RTM_ADD:
632 case RTM_DELETE:
b1a1faba
OF
633 krt_read_rt(msg, (struct krt_proto *)p, scan);
634 break;
09686693
OZ
635 case RTM_IFANNOUNCE:
636 krt_read_ifannounce(msg);
637 break;
b1a1faba 638 case RTM_IFINFO:
b1a1faba
OF
639 krt_read_ifinfo(msg);
640 break;
641 case RTM_NEWADDR:
642 case RTM_DELADDR:
b1a1faba
OF
643 krt_read_addr(msg);
644 break;
b1a1faba 645 default:
b1a1faba
OF
646 break;
647 }
648}
649
b1a1faba 650void
19d9e303 651krt_scan_construct(struct krt_config *c UNUSED)
b1a1faba
OF
652{
653}
654
655void
19d9e303 656krt_scan_preconfig(struct config *c UNUSED)
b1a1faba
OF
657{
658}
659
660void
19d9e303 661krt_scan_postconfig(struct krt_config *c UNUSED)
b1a1faba
OF
662{
663}
664
665void
19d9e303 666krt_scan_start(struct krt_proto *x, int first UNUSED)
b1a1faba
OF
667{
668 init_list(&x->scan.temp_ifs);
669}
670
671void
19d9e303 672krt_scan_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
b1a1faba
OF
673{
674}
675
282997f2 676static void
80f0d676 677krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
b1a1faba
OF
678{
679 byte *next;
4aef102b 680 int mib[6];
80f0d676 681 size_t obl, needed;
b1a1faba 682 struct ks_msg *m;
4aef102b 683 int retries = 3;
b1a1faba
OF
684
685 mib[0] = CTL_NET;
686 mib[1] = PF_ROUTE;
687 mib[2] = 0;
688 mib[3] = BIRD_PF;
689 mib[4] = cmd;
690 mib[5] = 0;
691
4aef102b 692 try:
ff2857b0 693 if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
4aef102b 694 die("krt_sysctl_scan 1: %m");
b1a1faba
OF
695
696 obl = *bl;
697
ff2857b0
OZ
698 while (needed > *bl) *bl *= 2;
699 while (needed < (*bl/2)) *bl /= 2;
b1a1faba 700
ff2857b0 701 if ((obl!=*bl) || !*buf)
b1a1faba 702 {
ff2857b0
OZ
703 if (*buf) mb_free(*buf);
704 if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc");
b1a1faba
OF
705 }
706
ff2857b0 707 if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
b1a1faba 708 {
4aef102b
OZ
709 if (errno == ENOMEM)
710 {
711 /* The buffer size changed since last sysctl ('needed' is not changed) */
712 if (retries--)
713 goto try;
714
715 log(L_ERR "KRT: Route scan failed");
716 return;
717 }
718 die("krt_sysctl_scan 2: %m");
b1a1faba
OF
719 }
720
721 for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen)
722 {
723 m = (struct ks_msg *)next;
724 krt_read_msg(p, m, 1);
725 }
726}
727
ff2857b0
OZ
728static byte *krt_buffer = NULL;
729static byte *kif_buffer = NULL;
730static size_t krt_buflen = 32768;
731static size_t kif_buflen = 4096;
732
b1a1faba
OF
733void
734krt_scan_fire(struct krt_proto *p)
735{
ff2857b0 736 krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
b1a1faba
OF
737}
738
739void
740krt_if_scan(struct kif_proto *p)
741{
b1a1faba
OF
742 struct proto *P = (struct proto *)p;
743 if_start_update();
ff2857b0 744 krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST);
b1a1faba
OF
745 if_end_update();
746}
747
748
749void
19d9e303 750krt_set_construct(struct krt_config *c UNUSED)
b1a1faba
OF
751{
752}
753
754void
19d9e303 755krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
b1a1faba 756{
a209d5d8
OZ
757 if (!krt_buffer)
758 return;
759
760 mb_free(krt_buffer);
ff2857b0
OZ
761 krt_buffer = NULL;
762}
b1a1faba
OF
763
764void
765krt_if_io_init(void)
766{
767}
768
769void
19d9e303 770krt_if_construct(struct kif_config *c UNUSED)
b1a1faba
OF
771{
772}
773
774void
19d9e303 775krt_if_start(struct kif_proto *p UNUSED)
b1a1faba
OF
776{
777}
778
779void
19d9e303 780krt_if_shutdown(struct kif_proto *p UNUSED)
b1a1faba 781{
a209d5d8
OZ
782 if (!kif_buffer)
783 return;
784
ff2857b0
OZ
785 mb_free(kif_buffer);
786 kif_buffer = NULL;
b1a1faba
OF
787}
788