]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/bsd/krt-sock.c
BSD: IPv4 over IPv6 nexthop support on FreeBSD
[thirdparty/bird.git] / sysdep / bsd / krt-sock.c
CommitLineData
b1a1faba 1/*
c01a9466 2 * BIRD -- BSD Routing Table Syncing
b1a1faba
OF
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>
c01a9466 10#include <stdlib.h>
b1a1faba
OF
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"
7152e5ef
JMM
31#include "sysdep/unix/unix.h"
32#include "sysdep/unix/krt.h"
b1a1faba
OF
33#include "lib/string.h"
34#include "lib/socket.h"
35
517d05df 36const int rt_default_ecmp = 0;
396dfa90 37
c01a9466
OZ
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 *
7fb23041
OZ
50 * OpenBSD allows to use route metric. The behavior is controlled by these macro
51 * KRT_USE_METRIC, which enables use of rtm_priority in route send/recevive.
52 * There is also KRT_DEFAULT_METRIC and KRT_MAX_METRIC for default and maximum
53 * metric values.
54 *
c01a9466
OZ
55 * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto
56 * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan
57 * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets
58 * KRT_USE_SYSCTL_7 - use 7-th arg of sysctl() as table id for route scans
59 * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs
60 */
61
62#ifdef __FreeBSD__
63#define KRT_MAX_TABLES 256
64#define KRT_USE_SETFIB_SCAN
65#define KRT_USE_SETFIB_SOCK
66#define KRT_USE_SYSCTL_NET_FIBS
396dfa90
OZ
67#endif
68
c01a9466
OZ
69#ifdef __OpenBSD__
70#define KRT_MAX_TABLES (RT_TABLEID_MAX+1)
7fb23041
OZ
71#define KRT_USE_METRIC
72#define KRT_MAX_METRIC 255
73#define KRT_DEFAULT_METRIC 56
c01a9466
OZ
74#define KRT_SHARED_SOCKET
75#define KRT_USE_SYSCTL_7
76#endif
77
78#ifndef KRT_MAX_TABLES
79#define KRT_MAX_TABLES 1
80#endif
81
7fb23041
OZ
82#ifndef KRT_MAX_METRIC
83#define KRT_MAX_METRIC 0
84#endif
85
86#ifndef KRT_DEFAULT_METRIC
87#define KRT_DEFAULT_METRIC 0
88#endif
89
c01a9466
OZ
90
91/* Dynamic max number of tables */
92
ac48e72b 93uint krt_max_tables;
c01a9466
OZ
94
95#ifdef KRT_USE_SYSCTL_NET_FIBS
96
ac48e72b 97static uint
c01a9466 98krt_get_max_tables(void)
396dfa90 99{
c01a9466
OZ
100 int fibs;
101 size_t fibs_len = sizeof(fibs);
102
103 if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
104 {
105 log(L_WARN "KRT: unable to get max number of fib tables: %m");
106 return 1;
107 }
108
ac48e72b
OZ
109 /* Should not happen */
110 if (fibs < 1)
111 return 1;
112
113 return (uint) MIN(fibs, KRT_MAX_TABLES);
c01a9466
OZ
114}
115
116#else
117
118static int
119krt_get_max_tables(void)
120{
121 return KRT_MAX_TABLES;
122}
123
124#endif /* KRT_USE_SYSCTL_NET_FIBS */
125
126
127/* setfib() syscall for FreeBSD scans */
128
129#ifdef KRT_USE_SETFIB_SCAN
130
131/*
132static int krt_default_fib;
133
134static int
135krt_get_active_fib(void)
136{
137 int fib;
138 size_t fib_len = sizeof(fib);
139
140 if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
141 {
142 log(L_WARN "KRT: unable to get active fib number: %m");
143 return 0;
144 }
145
146 return fib;
147}
148*/
149
150extern int setfib(int fib);
396dfa90 151
c01a9466 152#endif /* KRT_USE_SETFIB_SCAN */
396dfa90 153
c01a9466
OZ
154
155/* table_id -> krt_proto map */
156
157#ifdef KRT_SHARED_SOCKET
8109eb76 158static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
c01a9466 159#endif
396dfa90
OZ
160
161
7fb23041
OZ
162/* Make it available to parser code */
163const uint krt_max_metric = KRT_MAX_METRIC;
164
165
c01a9466 166/* Route socket message processing */
b1a1faba 167
b1a1faba
OF
168int
169krt_capable(rte *e)
170{
171 rta *a = e->attrs;
172
b1a1faba 173 return
517d05df 174 ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */
b1a1faba
OF
175#ifdef RTF_REJECT
176 || a->dest == RTD_UNREACHABLE
177#endif
178#ifdef RTF_BLACKHOLE
ff2857b0 179 || a->dest == RTD_BLACKHOLE
b1a1faba
OF
180#endif
181 );
182}
183
c01a9466
OZ
184#ifndef RTAX_MAX
185#define RTAX_MAX 8
186#endif
187
188struct ks_msg
189{
190 struct rt_msghdr rtm;
191 struct sockaddr_storage buf[RTAX_MAX];
9befc7cc 192} PACKED;
c01a9466 193
b1a1faba
OF
194#define ROUNDUP(a) \
195 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
196
197#define NEXTADDR(w, u) \
198 if (msg.rtm.rtm_addrs & (w)) {\
199 l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
200 memmove(body, &(u), l); body += l;}
201
ff2857b0
OZ
202#define GETADDR(p, F) \
203 bzero(p, sizeof(*p));\
204 if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
ae80a2de 205 uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
ff2857b0
OZ
206 memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
207 body += l;}
208
f8276812 209static inline void UNUSED
4d367961
OZ
210sockaddr_fill_dl(struct sockaddr_dl *sa, struct iface *ifa)
211{
212 uint len = OFFSETOF(struct sockaddr_dl, sdl_data);
34ebc4e1
OZ
213
214 /* Workaround for FreeBSD 13.0 */
215 len = MAX(len, sizeof(struct sockaddr));
216
4d367961
OZ
217 memset(sa, 0, len);
218 sa->sdl_len = len;
219 sa->sdl_family = AF_LINK;
220 sa->sdl_index = ifa->index;
221}
222
32f95476 223static int
c01a9466 224krt_send_route(struct krt_proto *p, int cmd, rte *e)
b1a1faba
OF
225{
226 net *net = e->net;
227 rta *a = e->attrs;
228 static int msg_seq;
4e276a89 229 struct iface *j, *i = a->nh.iface;
b1a1faba
OF
230 int l;
231 struct ks_msg msg;
232 char *body = (char *)msg.buf;
233 sockaddr gate, mask, dst;
234
ff2857b0 235 DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
b1a1faba 236
b88a1d40 237 bzero(&msg,sizeof (struct rt_msghdr));
b1a1faba
OF
238 msg.rtm.rtm_version = RTM_VERSION;
239 msg.rtm.rtm_type = cmd;
240 msg.rtm.rtm_seq = msg_seq++;
241 msg.rtm.rtm_addrs = RTA_DST;
ff2857b0 242 msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
b1a1faba 243
d7661fbe
JMM
244 /* XXXX */
245 if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
b1a1faba 246 msg.rtm.rtm_flags |= RTF_HOST;
b1a1faba 247 else
b1a1faba 248 msg.rtm.rtm_addrs |= RTA_NETMASK;
c01a9466
OZ
249
250#ifdef KRT_SHARED_SOCKET
251 msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
252#endif
b1a1faba 253
7fb23041
OZ
254#ifdef KRT_USE_METRIC
255 msg.rtm.rtm_priority = KRT_CF->sys.metric;
256#endif
257
b1a1faba
OF
258#ifdef RTF_REJECT
259 if(a->dest == RTD_UNREACHABLE)
260 msg.rtm.rtm_flags |= RTF_REJECT;
261#endif
262#ifdef RTF_BLACKHOLE
263 if(a->dest == RTD_BLACKHOLE)
264 msg.rtm.rtm_flags |= RTF_BLACKHOLE;
265#endif
266
62e64905
OZ
267 /*
268 * This is really very nasty, but I'm not able to add reject/blackhole route
269 * without gateway address.
b1a1faba 270 */
62e64905 271 if (!i)
b1a1faba 272 {
8281ff20
OF
273 WALK_LIST(j, iface_list)
274 {
275 if (j->flags & IF_LOOPBACK)
b1a1faba 276 {
8281ff20
OF
277 i = j;
278 break;
b1a1faba
OF
279 }
280 }
b1a1faba 281
62e64905
OZ
282 if (!i)
283 {
284 log(L_ERR "KRT: Cannot find loopback iface");
285 return -1;
286 }
287 }
44aa101c 288
9b136840
JMM
289 int af = AF_UNSPEC;
290
291 switch (net->n.addr->type) {
292 case NET_IP4:
293 af = AF_INET;
294 break;
295 case NET_IP6:
296 af = AF_INET6;
297 break;
298 default:
1d213067 299 log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
9b136840
JMM
300 return -1;
301 }
302
9b136840
JMM
303 sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
304 sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
44aa101c 305
b1a1faba
OF
306 switch (a->dest)
307 {
62e64905
OZ
308 case RTD_UNICAST:
309 if (ipa_nonzero(a->nh.gw))
310 {
311 ip_addr gw = a->nh.gw;
4e276a89 312
62e64905
OZ
313 /* Embed interface ID to link-local address */
314 if (ipa_is_link_local(gw))
315 _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
316
d61505b0 317 sockaddr_fill(&gate, (ipa_is_ip4(gw) ? AF_INET : AF_INET6), gw, NULL, 0);
62e64905
OZ
318 msg.rtm.rtm_flags |= RTF_GATEWAY;
319 msg.rtm.rtm_addrs |= RTA_GATEWAY;
b1a1faba 320 break;
62e64905 321 }
029ec22d 322
b1a1faba 323#ifdef RTF_REJECT
62e64905 324 case RTD_UNREACHABLE:
b1a1faba
OF
325#endif
326#ifdef RTF_BLACKHOLE
62e64905 327 case RTD_BLACKHOLE:
b1a1faba 328#endif
62e64905
OZ
329 {
330 /* Fallback for all other valid cases */
62e64905 331
4d367961
OZ
332#if __OpenBSD__
333 /* Keeping temporarily old code for OpenBSD */
153f02da
OZ
334 struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
335
336 if (!addr)
337 {
338 log(L_ERR "KRT: interface %s has no IP addess", i->name);
339 return -1;
340 }
341
4d367961
OZ
342 /* Embed interface ID to link-local address */
343 ip_addr gw = addr->ip;
344 if (ipa_is_link_local(gw))
345 _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
346
347 sockaddr_fill(&gate, af, gw, i, 0);
348#else
349 sockaddr_fill_dl(&gate, i);
350#endif
351
62e64905 352 msg.rtm.rtm_addrs |= RTA_GATEWAY;
1d213067 353 break;
62e64905
OZ
354 }
355
356 default:
357 bug("krt-sock: unknown flags, but not filtered");
b1a1faba
OF
358 }
359
1554cc02 360 msg.rtm.rtm_index = i->index;
b1a1faba
OF
361
362 NEXTADDR(RTA_DST, dst);
363 NEXTADDR(RTA_GATEWAY, gate);
364 NEXTADDR(RTA_NETMASK, mask);
365
366 l = body - (char *)&msg;
367 msg.rtm.rtm_msglen = l;
368
c01a9466 369 if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
9b136840 370 log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
32f95476 371 return -1;
b1a1faba 372 }
32f95476
OZ
373
374 return 0;
b1a1faba
OF
375}
376
377void
543c8ba0 378krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
b1a1faba 379{
32f95476
OZ
380 int err = 0;
381
b1a1faba 382 if (old)
c01a9466 383 krt_send_route(p, RTM_DELETE, old);
32f95476 384
b1a1faba 385 if (new)
c01a9466 386 err = krt_send_route(p, RTM_ADD, new);
32f95476 387
cc75b3e1
OZ
388 if (new)
389 {
390 if (err < 0)
391 bmap_clear(&p->sync_map, new->id);
392 else
393 bmap_set(&p->sync_map, new->id);
394 }
b1a1faba
OF
395}
396
a39cd2cc
OZ
397/**
398 * krt_assume_onlink - check if routes on interface are considered onlink
399 * @iface: The interface of the next hop
400 * @ipv6: Switch to only consider IPv6 or IPv4 addresses.
401 *
402 * The BSD kernel does not support an onlink flag. If the interface has only
403 * host addresses configured, all routes should be considered as onlink and
404 * the function returns 1.
405 */
406static int
407krt_assume_onlink(struct iface *iface, int ipv6)
408{
409 const u8 type = ipv6 ? NET_IP6 : NET_IP4;
410
411 struct ifa *ifa;
412 WALK_LIST(ifa, iface->addrs)
413 {
414 if ((ifa->prefix.type == type) && !(ifa->flags & IA_HOST))
415 return 0;
416 }
417
418 return 1;
419}
420
ff2857b0
OZ
421#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
422
282997f2 423static void
c01a9466 424krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
b1a1faba 425{
c01a9466
OZ
426 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
427
3f358161 428 int ipv6;
b1a1faba
OF
429 rte *e;
430 net *net;
ff2857b0 431 sockaddr dst, gate, mask;
b1a1faba 432 ip_addr idst, igate, imask;
9b136840 433 net_addr ndst;
b1a1faba 434 void *body = (char *)msg->buf;
90097f4f 435 int new = (msg->rtm.rtm_type != RTM_DELETE);
ff2857b0 436 char *errmsg = "KRT: Invalid route received";
b1a1faba
OF
437 int flags = msg->rtm.rtm_flags;
438 int addrs = msg->rtm.rtm_addrs;
72aed1a0
OZ
439 int src;
440 byte src2;
b1a1faba 441
ff2857b0
OZ
442 if (!(flags & RTF_UP) && scan)
443 SKIP("not up in scan\n");
b1a1faba 444
ff2857b0
OZ
445 if (!(flags & RTF_DONE) && !scan)
446 SKIP("not done in async\n");
b1a1faba 447
ff2857b0
OZ
448 if (flags & RTF_LLINFO)
449 SKIP("link-local\n");
b1a1faba 450
ff2857b0
OZ
451 GETADDR(&dst, RTA_DST);
452 GETADDR(&gate, RTA_GATEWAY);
453 GETADDR(&mask, RTA_NETMASK);
b1a1faba 454
d7661fbe
JMM
455 switch (dst.sa.sa_family) {
456 case AF_INET:
3f358161
JMM
457 ipv6 = 0;
458 break;
8109eb76 459 case AF_INET6:
3f358161 460 ipv6 = 1;
8109eb76 461 break;
d7661fbe
JMM
462 default:
463 SKIP("invalid DST");
464 }
b1a1faba 465
3f358161
JMM
466 /* We do not test family for RTA_NETMASK, because BSD sends us
467 some strange values, but interpreting them as IPv4/IPv6 works */
468 mask.sa.sa_family = dst.sa.sa_family;
469
05476c4d 470 idst = ipa_from_sa(&dst);
8109eb76 471 imask = ipa_from_sa(&mask);
d61505b0 472 igate = ipa_from_sa(&gate);
b1a1faba 473
8109eb76
JMM
474#ifdef KRT_SHARED_SOCKET
475 if (!scan)
476 {
477 int table_id = msg->rtm.rtm_tableid;
3f358161 478 p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL;
05476c4d 479
8109eb76
JMM
480 if (!p)
481 SKIP("unknown table id %d\n", table_id);
482 }
483#endif
ade389b3 484 if ((!ipv6) && (p->p.main_channel->table->addr_type != NET_IP4))
3f358161 485 SKIP("reading only IPv4 routes");
ade389b3 486 if ( ipv6 && (p->p.main_channel->table->addr_type != NET_IP6))
3f358161 487 SKIP("reading only IPv6 routes");
b1a1faba 488
ff2857b0
OZ
489 int c = ipa_classify_net(idst);
490 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
491 SKIP("strange class/scope\n");
b1a1faba 492
8109eb76 493 int pxlen;
3f358161 494 if (ipv6)
8109eb76 495 pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask));
3f358161
JMM
496 else
497 pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask));
8109eb76 498
ff2857b0
OZ
499 if (pxlen < 0)
500 { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
b1a1faba 501
3f358161
JMM
502 if (ipv6)
503 net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen);
504 else
505 net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
9b136840 506
ff2857b0 507 if ((flags & RTF_GATEWAY) && ipa_zero(igate))
a7c9515e 508 { log(L_ERR "%s (%N) - missing gateway", errmsg, &ndst); return; }
ff2857b0
OZ
509
510 u32 self_mask = RTF_PROTO1;
a9f380fe 511 u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
ff2857b0 512
72aed1a0
OZ
513 src2 = (flags & RTF_STATIC) ? 1 : 0;
514 src2 |= (flags & RTF_PROTO1) ? 2 : 0;
515
ff2857b0
OZ
516#ifdef RTF_PROTO2
517 alien_mask |= RTF_PROTO2;
72aed1a0 518 src2 |= (flags & RTF_PROTO2) ? 4 : 0;
ff2857b0 519#endif
b1a1faba 520
ff2857b0
OZ
521#ifdef RTF_PROTO3
522 alien_mask |= RTF_PROTO3;
72aed1a0 523 src2 |= (flags & RTF_PROTO3) ? 8 : 0;
ff2857b0
OZ
524#endif
525
a9f380fe
OZ
526#ifdef RTF_REJECT
527 alien_mask |= RTF_REJECT;
528#endif
529
530#ifdef RTF_BLACKHOLE
531 alien_mask |= RTF_BLACKHOLE;
532#endif
533
ff2857b0
OZ
534 if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
535 src = KRT_SRC_REDIRECT;
536 else if (flags & self_mask)
537 {
538 if (!scan)
539 SKIP("echo\n");
540 src = KRT_SRC_BIRD;
541 }
542 else if (flags & alien_mask)
543 src = KRT_SRC_ALIEN;
544 else
545 src = KRT_SRC_KERNEL;
546
ade389b3 547 net = net_get(p->p.main_channel->table, &ndst);
b1a1faba 548
cfe34a31 549 rta a = {
cfe34a31
OZ
550 .source = RTS_INHERIT,
551 .scope = SCOPE_UNIVERSE,
cfe34a31 552 };
b1a1faba 553
ff2857b0
OZ
554 /* reject/blackhole routes have also set RTF_GATEWAY,
555 we wil check them first. */
b1a1faba
OF
556
557#ifdef RTF_REJECT
558 if(flags & RTF_REJECT) {
559 a.dest = RTD_UNREACHABLE;
ff2857b0 560 goto done;
b1a1faba
OF
561 }
562#endif
563
564#ifdef RTF_BLACKHOLE
565 if(flags & RTF_BLACKHOLE) {
566 a.dest = RTD_BLACKHOLE;
ff2857b0 567 goto done;
b1a1faba
OF
568 }
569#endif
570
4e276a89
JMM
571 a.nh.iface = if_find_by_index(msg->rtm.rtm_index);
572 if (!a.nh.iface)
ff2857b0 573 {
9b136840
JMM
574 log(L_ERR "KRT: Received route %N with unknown ifindex %u",
575 net->n.addr, msg->rtm.rtm_index);
ff2857b0
OZ
576 return;
577 }
578
4e276a89 579 a.dest = RTD_UNICAST;
ff2857b0 580 if (flags & RTF_GATEWAY)
b1a1faba 581 {
4e276a89 582 a.nh.gw = igate;
b1a1faba 583
44aa101c 584 /* Clean up embedded interface ID returned in link-local address */
4e276a89
JMM
585 if (ipa_is_link_local(a.nh.gw))
586 _I0(a.nh.gw) = 0xfe800000;
44aa101c 587
a39cd2cc
OZ
588 /* The BSD kernel does not support an onlink flag. We heuristically
589 set the onlink flag, if the iface has only host addresses. */
590 if (krt_assume_onlink(a.nh.iface, ipv6))
591 a.nh.flags |= RNF_ONLINK;
592
593 neighbor *nbr;
594 nbr = neigh_find(&p->p, a.nh.gw, a.nh.iface,
595 (a.nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
596 if (!nbr || (nbr->scope == SCOPE_HOST))
ff2857b0 597 {
de14a7c7
OZ
598 /* Ignore routes with next-hop 127.0.0.1, host routes with such
599 next-hop appear on OpenBSD for address aliases. */
4e276a89 600 if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST))
de14a7c7
OZ
601 return;
602
9b136840 603 log(L_ERR "KRT: Received route %N with strange next-hop %I",
4e276a89 604 net->n.addr, a.nh.gw);
ff2857b0
OZ
605 return;
606 }
607 }
b1a1faba 608
ff2857b0 609 done:
543c8ba0 610 e = rte_get_temp(&a, p->p.main_source);
b1a1faba 611 e->net = net;
e42eedb9 612
7fb23041 613 ea_list *ea = alloca(sizeof(ea_list) + 2 * sizeof(eattr));
e42eedb9
MM
614 *ea = (ea_list) { .count = 1, .next = e->attrs->eattrs };
615 e->attrs->eattrs = ea;
616
617 ea->attrs[0] = (eattr) {
618 .id = EA_KRT_SOURCE,
619 .type = EAF_TYPE_INT,
620 .u.data = src2,
621 };
b1a1faba 622
7fb23041
OZ
623#ifdef KRT_USE_METRIC
624 ea->count++;
625 ea->attrs[1] = (eattr) {
626 .id = EA_KRT_METRIC,
627 .type = EAF_TYPE_INT,
628 .u.data = msg->rtm.rtm_priority,
629 };
630#endif
631
b1a1faba 632 if (scan)
e42eedb9 633 krt_got_route(p, e, src);
b1a1faba 634 else
e42eedb9 635 krt_got_route_async(p, e, new, src);
b1a1faba
OF
636}
637
09686693
OZ
638static void
639krt_read_ifannounce(struct ks_msg *msg)
640{
641 struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
642
643 if (ifam->ifan_what == IFAN_ARRIVAL)
644 {
645 /* Not enough info to create the iface, so we just trigger iface scan */
646 kif_request_scan();
647 }
648 else if (ifam->ifan_what == IFAN_DEPARTURE)
649 {
650 struct iface *iface = if_find_by_index(ifam->ifan_index);
651
652 /* Interface is destroyed */
653 if (!iface)
654 {
655 DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
656 return;
657 }
658
659 if_delete(iface);
660 }
661
662 DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
663}
664
282997f2 665static void
3216eb03 666krt_read_ifinfo(struct ks_msg *msg, int scan)
b1a1faba
OF
667{
668 struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
669 void *body = (void *)(ifm + 1);
670 struct sockaddr_dl *dl = NULL;
ae80a2de 671 uint i;
732a0a25 672 struct iface *iface = NULL, f = {};
b1a1faba 673 int fl = ifm->ifm_flags;
732a0a25 674 int nlen = 0;
b1a1faba 675
d32a071d 676 for (i = 1; i<=RTA_IFP; i <<= 1)
b1a1faba 677 {
d32a071d 678 if (i & ifm->ifm_addrs)
b1a1faba 679 {
d32a071d 680 if (i == RTA_IFP)
b1a1faba
OF
681 {
682 dl = (struct sockaddr_dl *)body;
683 break;
684 }
d32a071d 685 body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
b1a1faba
OF
686 }
687 }
688
732a0a25 689 if (dl && (dl->sdl_family != AF_LINK))
b1a1faba 690 {
09686693 691 log(L_WARN "Ignoring strange IFINFO");
b1a1faba
OF
692 return;
693 }
694
732a0a25
OZ
695 if (dl)
696 nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
697
698 /* Note that asynchronous IFINFO messages do not contain iface
699 name, so we have to found an existing iface by iface index */
b1a1faba 700
732a0a25
OZ
701 iface = if_find_by_index(ifm->ifm_index);
702 if (!iface)
b1a1faba
OF
703 {
704 /* New interface */
732a0a25
OZ
705 if (!dl)
706 return; /* No interface name, ignoring */
dad7ee70 707
732a0a25
OZ
708 memcpy(f.name, dl->sdl_data, nlen);
709 DBG("New interface '%s' found\n", f.name);
710 }
711 else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
712 {
713 /* Interface renamed */
714 if_delete(iface);
715 memcpy(f.name, dl->sdl_data, nlen);
b1a1faba
OF
716 }
717 else
718 {
732a0a25
OZ
719 /* Old interface */
720 memcpy(f.name, iface->name, sizeof(f.name));
b1a1faba
OF
721 }
722
732a0a25 723 f.index = ifm->ifm_index;
b1a1faba 724 f.mtu = ifm->ifm_data.ifi_mtu;
b1a1faba
OF
725
726 if (fl & IFF_UP)
f25cb0ef
OZ
727 f.flags |= IF_ADMIN_UP;
728 if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
729 f.flags |= IF_LINK_UP; /* up or unknown */
b1a1faba
OF
730 if (fl & IFF_LOOPBACK) /* Loopback */
731 f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
732 else if (fl & IFF_POINTOPOINT) /* PtP */
733 f.flags |= IF_MULTICAST;
734 else if (fl & IFF_BROADCAST) /* Broadcast */
735 f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
736 else
737 f.flags |= IF_MULTIACCESS; /* NBMA */
738
b17adf07
THJ
739 if (fl & IFF_MULTICAST)
740 f.flags |= IF_MULTICAST;
741
3216eb03
OZ
742 iface = if_update(&f);
743
744 if (!scan)
745 if_end_partial_update(iface);
b1a1faba
OF
746}
747
282997f2 748static void
3216eb03 749krt_read_addr(struct ks_msg *msg, int scan)
b1a1faba
OF
750{
751 struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
752 void *body = (void *)(ifam + 1);
753 sockaddr addr, mask, brd;
b1a1faba
OF
754 struct iface *iface = NULL;
755 struct ifa ifa;
756 struct sockaddr null;
757 ip_addr iaddr, imask, ibrd;
758 int addrs = ifam->ifam_addrs;
759 int scope, masklen = -1;
760 int new = (ifam->ifam_type == RTM_NEWADDR);
b1a1faba 761
ff2857b0
OZ
762 /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
763 if (ifam->ifam_index == 0)
764 return;
765
b1a1faba
OF
766 if(!(iface = if_find_by_index(ifam->ifam_index)))
767 {
768 log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
769 return;
770 }
771
772 GETADDR (&null, RTA_DST);
773 GETADDR (&null, RTA_GATEWAY);
774 GETADDR (&mask, RTA_NETMASK);
775 GETADDR (&null, RTA_GENMASK);
776 GETADDR (&null, RTA_IFP);
777 GETADDR (&addr, RTA_IFA);
778 GETADDR (&null, RTA_AUTHOR);
779 GETADDR (&brd, RTA_BRD);
780
d7661fbe
JMM
781 /* Is addr family IP4 or IP6? */
782 int ipv6;
783 switch (addr.sa.sa_family) {
784 case AF_INET: ipv6 = 0; break;
785 case AF_INET6: ipv6 = 1; break;
786 default: return;
787 }
b1a1faba 788
b644a490
OZ
789 /* We do not test family for RTA_NETMASK, because BSD sends us
790 some strange values, but interpreting them as IPv4/IPv6 works */
791 mask.sa.sa_family = addr.sa.sa_family;
792
05476c4d
OZ
793 iaddr = ipa_from_sa(&addr);
794 imask = ipa_from_sa(&mask);
795 ibrd = ipa_from_sa(&brd);
796
8109eb76 797 if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0)
b1a1faba 798 {
8109eb76 799 log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name);
b1a1faba
OF
800 return;
801 }
802
64534ea2 803 /* Clean up embedded interface ID returned in link-local address */
b1a1faba 804
304ac2e8 805 if (ipa_is_link_local(iaddr))
64534ea2 806 _I0(iaddr) = 0xfe800000;
b1a1faba 807
304ac2e8 808 if (ipa_is_link_local(ibrd))
64534ea2 809 _I0(ibrd) = 0xfe800000;
b1a1faba 810
b1a1faba 811
64534ea2
OZ
812 bzero(&ifa, sizeof(ifa));
813 ifa.iface = iface;
814 ifa.ip = iaddr;
b1a1faba
OF
815
816 scope = ipa_classify(ifa.ip);
b1a1faba
OF
817 if (scope < 0)
818 {
819 log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
820 return;
821 }
822 ifa.scope = scope & IADDR_SCOPE_MASK;
823
d7661fbe 824 if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
ba321706 825 {
9b136840
JMM
826 net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
827 net_normalize(&ifa.prefix);
ba321706 828
d7661fbe 829 if (masklen == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1))
ba321706
OZ
830 ifa.opposite = ipa_opposite_m1(ifa.ip);
831
8109eb76 832 if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2))
ba321706 833 ifa.opposite = ipa_opposite_m2(ifa.ip);
f515e229 834
64534ea2
OZ
835 if (iface->flags & IF_BROADCAST)
836 ifa.brd = ibrd;
837
f515e229 838 if (!(iface->flags & IF_MULTIACCESS))
64534ea2 839 ifa.opposite = ibrd;
ba321706 840 }
64534ea2 841 else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
afa9f66c 842 {
d7661fbe 843 net_fill_ipa(&ifa.prefix, ibrd, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
9b136840 844 ifa.opposite = ibrd;
52a43ae3 845 ifa.flags |= IA_PEER;
f515e229
OZ
846 }
847 else
848 {
d7661fbe 849 net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
f515e229 850 ifa.flags |= IA_HOST;
afa9f66c
OZ
851 }
852
b1a1faba
OF
853 if (new)
854 ifa_update(&ifa);
855 else
856 ifa_delete(&ifa);
3216eb03
OZ
857
858 if (!scan)
859 if_end_partial_update(iface);
b1a1faba
OF
860}
861
c01a9466 862static void
b1a1faba
OF
863krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
864{
c01a9466
OZ
865 /* p is NULL iff KRT_SHARED_SOCKET and !scan */
866
b1a1faba
OF
867 switch (msg->rtm.rtm_type)
868 {
869 case RTM_GET:
870 if(!scan) return;
871 case RTM_ADD:
872 case RTM_DELETE:
90097f4f 873 case RTM_CHANGE:
c01a9466 874 krt_read_route(msg, (struct krt_proto *)p, scan);
b1a1faba 875 break;
09686693
OZ
876 case RTM_IFANNOUNCE:
877 krt_read_ifannounce(msg);
878 break;
b1a1faba 879 case RTM_IFINFO:
3216eb03 880 krt_read_ifinfo(msg, scan);
b1a1faba
OF
881 break;
882 case RTM_NEWADDR:
883 case RTM_DELADDR:
3216eb03 884 krt_read_addr(msg, scan);
b1a1faba 885 break;
b1a1faba 886 default:
b1a1faba
OF
887 break;
888 }
889}
890
c01a9466
OZ
891
892/* Sysctl based scans */
893
894static byte *krt_buffer;
895static size_t krt_buflen, krt_bufmin;
896static struct proto *krt_buffer_owner;
897
898static byte *
899krt_buffer_update(struct proto *p, size_t *needed)
900{
901 size_t req = *needed;
902
903 if ((req > krt_buflen) ||
904 ((p == krt_buffer_owner) && (req < krt_bufmin)))
905 {
906 /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
907 size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
908 krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
909 krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
910
911 if (krt_buffer)
912 mb_free(krt_buffer);
913 krt_buffer = mb_alloc(krt_pool, krt_buflen);
914 krt_buffer_owner = p;
915 }
916
917 *needed = krt_buflen;
918 return krt_buffer;
919}
920
282997f2 921static void
c01a9466 922krt_buffer_release(struct proto *p)
b1a1faba 923{
c01a9466
OZ
924 if (p == krt_buffer_owner)
925 {
926 mb_free(krt_buffer);
927 krt_buffer = NULL;
928 krt_buflen = 0;
929 krt_buffer_owner = 0;
930 }
931}
932
282997f2 933static void
c01a9466 934krt_sysctl_scan(struct proto *p, int cmd, int table_id)
b1a1faba 935{
c01a9466
OZ
936 byte *buf, *next;
937 int mib[7], mcnt;
938 size_t needed;
b1a1faba 939 struct ks_msg *m;
4aef102b 940 int retries = 3;
c01a9466 941 int rv;
b1a1faba
OF
942
943 mib[0] = CTL_NET;
944 mib[1] = PF_ROUTE;
945 mib[2] = 0;
8109eb76 946 mib[3] = 0; // Set AF to 0 for all available families
b1a1faba
OF
947 mib[4] = cmd;
948 mib[5] = 0;
c01a9466 949 mcnt = 6;
b1a1faba 950
c01a9466
OZ
951#ifdef KRT_USE_SYSCTL_7
952 if (table_id >= 0)
953 {
954 mib[6] = table_id;
955 mcnt = 7;
956 }
957#endif
b1a1faba 958
c01a9466
OZ
959#ifdef KRT_USE_SETFIB_SCAN
960 if (table_id > 0)
961 if (setfib(table_id) < 0)
962 {
963 log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
964 return;
965 }
966#endif
b1a1faba 967
c01a9466
OZ
968 try:
969 rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
970 if (rv < 0)
b1a1faba 971 {
c01a9466
OZ
972 /* OpenBSD returns EINVAL for not yet used tables */
973 if ((errno == EINVAL) && (table_id > 0))
974 goto exit;
975
976 log(L_ERR "KRT: Route scan estimate failed: %m");
977 goto exit;
b1a1faba
OF
978 }
979
c01a9466
OZ
980 /* The table is empty */
981 if (needed == 0)
982 goto exit;
983
984 buf = krt_buffer_update(p, &needed);
985
986 rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
987 if (rv < 0)
b1a1faba 988 {
c01a9466
OZ
989 /* The buffer size changed since last sysctl ('needed' is not changed) */
990 if ((errno == ENOMEM) && retries--)
991 goto try;
4aef102b 992
c01a9466
OZ
993 log(L_ERR "KRT: Route scan failed: %m");
994 goto exit;
b1a1faba
OF
995 }
996
c01a9466
OZ
997#ifdef KRT_USE_SETFIB_SCAN
998 if (table_id > 0)
999 if (setfib(0) < 0)
1000 die("KRT: setfib(%d) failed: %m", 0);
1001#endif
1002
1003 /* Process received messages */
1004 for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
b1a1faba
OF
1005 {
1006 m = (struct ks_msg *)next;
1007 krt_read_msg(p, m, 1);
1008 }
b1a1faba 1009
c01a9466
OZ
1010 return;
1011
1012 exit:
1013 krt_buffer_release(p);
1014
1015#ifdef KRT_USE_SETFIB_SCAN
1016 if (table_id > 0)
1017 if (setfib(0) < 0)
1018 die("KRT: setfib(%d) failed: %m", 0);
1019#endif
1020}
ff2857b0 1021
b1a1faba 1022void
396dfa90 1023krt_do_scan(struct krt_proto *p)
b1a1faba 1024{
c01a9466 1025 krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
b1a1faba
OF
1026}
1027
1028void
396dfa90 1029kif_do_scan(struct kif_proto *p)
b1a1faba 1030{
b1a1faba 1031 if_start_update();
c01a9466 1032 krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
b1a1faba
OF
1033 if_end_update();
1034}
1035
c01a9466
OZ
1036
1037/* Kernel sockets */
1038
396dfa90 1039static int
3e236955 1040krt_sock_hook(sock *sk, uint size UNUSED)
396dfa90
OZ
1041{
1042 struct ks_msg msg;
1043 int l = read(sk->fd, (char *)&msg, sizeof(msg));
1044
c01a9466 1045 if (l <= 0)
396dfa90
OZ
1046 log(L_ERR "krt-sock: read failed");
1047 else
c01a9466 1048 krt_read_msg((struct proto *) sk->data, &msg, 0);
396dfa90
OZ
1049
1050 return 0;
1051}
b1a1faba 1052
ccd2a3ed
JMM
1053static void
1054krt_sock_err_hook(sock *sk, int e UNUSED)
1055{
1056 krt_sock_hook(sk, 0);
1057}
1058
c01a9466 1059static sock *
3e236955 1060krt_sock_open(pool *pool, void *data, int table_id UNUSED)
c01a9466
OZ
1061{
1062 sock *sk;
1063 int fd;
1064
1065 fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
1066 if (fd < 0)
1067 die("Cannot open kernel socket for routes");
1068
1069#ifdef KRT_USE_SETFIB_SOCK
1070 if (table_id > 0)
1071 {
1072 if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
1073 die("Cannot set FIB %d for kernel socket: %m", table_id);
1074 }
1075#endif
1076
1077 sk = sk_new(pool);
1078 sk->type = SK_MAGIC;
1079 sk->rx_hook = krt_sock_hook;
ccd2a3ed 1080 sk->err_hook = krt_sock_err_hook;
c01a9466
OZ
1081 sk->fd = fd;
1082 sk->data = data;
1083
1084 if (sk_open(sk) < 0)
1085 bug("krt-sock: sk_open failed");
1086
1087 return sk;
1088}
1089
8109eb76 1090static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2];
c01a9466
OZ
1091
1092#ifdef KRT_SHARED_SOCKET
1093
1094static sock *krt_sock;
1095static int krt_sock_count;
1096
1097
1098static void
1099krt_sock_open_shared(void)
1100{
1101 if (!krt_sock_count)
1102 krt_sock = krt_sock_open(krt_pool, NULL, -1);
1103
1104 krt_sock_count++;
1105}
1106
1107static void
1108krt_sock_close_shared(void)
1109{
1110 krt_sock_count--;
1111
1112 if (!krt_sock_count)
1113 {
1114 rfree(krt_sock);
1115 krt_sock = NULL;
1116 }
1117}
1118
9ddbfbdd 1119int
c01a9466 1120krt_sys_start(struct krt_proto *p)
b1a1faba 1121{
8109eb76
JMM
1122 int id = KRT_CF->sys.table_id;
1123
1124 if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1125 {
1126 log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1127 return 0;
1128 }
1129
1130 krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1131
1132 krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p;
396dfa90 1133
c01a9466
OZ
1134 krt_sock_open_shared();
1135 p->sys.sk = krt_sock;
9ddbfbdd
JMM
1136
1137 return 1;
c01a9466 1138}
396dfa90 1139
c01a9466
OZ
1140void
1141krt_sys_shutdown(struct krt_proto *p)
1142{
8109eb76
JMM
1143 krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1144
c01a9466
OZ
1145 krt_sock_close_shared();
1146 p->sys.sk = NULL;
396dfa90 1147
8109eb76 1148 krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL;
396dfa90 1149
c01a9466
OZ
1150 krt_buffer_release(&p->p);
1151}
396dfa90 1152
c01a9466
OZ
1153#else
1154
9ddbfbdd 1155int
c01a9466
OZ
1156krt_sys_start(struct krt_proto *p)
1157{
8109eb76
JMM
1158 int id = KRT_CF->sys.table_id;
1159
1160 if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1161 {
1162 log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1163 return 0;
1164 }
1165
1166 krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1167
c01a9466 1168 p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
9ddbfbdd 1169 return 1;
b1a1faba
OF
1170}
1171
1172void
c01a9466 1173krt_sys_shutdown(struct krt_proto *p)
b1a1faba 1174{
8109eb76
JMM
1175 krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1176
c01a9466
OZ
1177 rfree(p->sys.sk);
1178 p->sys.sk = NULL;
a209d5d8 1179
c01a9466 1180 krt_buffer_release(&p->p);
ff2857b0 1181}
b1a1faba 1182
c01a9466
OZ
1183#endif /* KRT_SHARED_SOCKET */
1184
a209d5d8 1185
c01a9466
OZ
1186/* KRT configuration callbacks */
1187
c01a9466
OZ
1188int
1189krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1190{
7fb23041 1191 return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric);
ff2857b0 1192}
b1a1faba
OF
1193
1194void
c01a9466 1195krt_sys_preconfig(struct config *c UNUSED)
b1a1faba 1196{
c01a9466
OZ
1197 krt_max_tables = krt_get_max_tables();
1198 bzero(&krt_table_cf, sizeof(krt_table_cf));
b1a1faba
OF
1199}
1200
c01a9466
OZ
1201void krt_sys_init_config(struct krt_config *c)
1202{
1203 c->sys.table_id = 0; /* Default table */
7fb23041 1204 c->sys.metric = KRT_DEFAULT_METRIC;
c01a9466 1205}
a209d5d8 1206
c01a9466
OZ
1207void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1208{
1209 d->sys.table_id = s->sys.table_id;
7fb23041 1210 d->sys.metric = s->sys.metric;
c01a9466
OZ
1211}
1212
1213
1214/* KIF misc code */
1215
b1a1faba 1216void
c01a9466 1217kif_sys_start(struct kif_proto *p UNUSED)
b1a1faba 1218{
c01a9466 1219}
a209d5d8 1220
c01a9466
OZ
1221void
1222kif_sys_shutdown(struct kif_proto *p)
1223{
1224 krt_buffer_release(&p->p);
b1a1faba
OF
1225}
1226
153f02da
OZ
1227int
1228kif_update_sysdep_addr(struct iface *i)
e237b28a 1229{
e237b28a 1230 static int fd = -1;
153f02da 1231
e237b28a
OZ
1232 if (fd < 0)
1233 fd = socket(AF_INET, SOCK_DGRAM, 0);
1234
1235 struct ifreq ifr;
1236 memset(&ifr, 0, sizeof(ifr));
1237 strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1238
1239 int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1240 if (rv < 0)
153f02da 1241 return 0;
e237b28a 1242
153f02da 1243 ip4_addr old = i->sysdep;
543c8ba0 1244 i->sysdep = ipa_to_ip4(ipa_from_sa4((sockaddr *) &ifr.ifr_addr));
e237b28a 1245
7c454d91 1246 return !ip4_equal(i->sysdep, old);
e237b28a 1247}