Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / bsd / krt-sock.c @ 9b136840

History | View | Annotate | Download (22.9 KB)

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_prefix(net->n.addr) == 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
  int af = AF_UNSPEC;
255

    
256
  switch (net->n.addr->type) {
257
    case NET_IP4:
258
      af = AF_INET;
259
      break;
260
    case NET_IP6:
261
      af = AF_INET6;
262
      break;
263
    default:
264
      log(L_ERR "KRT: Not sending VPN route %N to kernel", net->n.addr);
265
      return -1;
266
  }
267

    
268

    
269
  sockaddr_fill(&dst,  af, net_prefix(net->n.addr), NULL, 0);
270
  sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
271
  sockaddr_fill(&gate, af, gw, NULL, 0);
272

    
273
  switch (a->dest)
274
  {
275
    case RTD_ROUTER:
276
      msg.rtm.rtm_flags |= RTF_GATEWAY;
277
      msg.rtm.rtm_addrs |= RTA_GATEWAY;
278
      break;
279

    
280
#ifdef RTF_REJECT
281
    case RTD_UNREACHABLE:
282
#endif
283
#ifdef RTF_BLACKHOLE
284
    case RTD_BLACKHOLE:
285
#endif
286
    case RTD_DEVICE:
287
      if(i)
288
      {
289
#ifdef RTF_CLONING
290
        if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS)        /* PTP */
291
          msg.rtm.rtm_flags |= RTF_CLONING;
292
#endif
293

    
294
        if(!i->addr) {
295
          log(L_ERR "KRT: interface %s has no IP addess", i->name);
296
          return -1;
297
        }
298

    
299
        sockaddr_fill(&gate, BIRD_AF, i->addr->ip, NULL, 0);
300
        msg.rtm.rtm_addrs |= RTA_GATEWAY;
301
      }
302
      break;
303
    default:
304
      bug("krt-sock: unknown flags, but not filtered");
305
  }
306

    
307
  msg.rtm.rtm_index = i->index;
308

    
309
  NEXTADDR(RTA_DST, dst);
310
  NEXTADDR(RTA_GATEWAY, gate);
311
  NEXTADDR(RTA_NETMASK, mask);
312

    
313
  l = body - (char *)&msg;
314
  msg.rtm.rtm_msglen = l;
315

    
316
  if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
317
    log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
318
    return -1;
319
  }
320

    
321
  return 0;
322
}
323

    
324
void
325
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old,
326
                struct ea_list *eattrs UNUSED)
327
{
328
  int err = 0;
329

    
330
  if (old)
331
    krt_send_route(p, RTM_DELETE, old);
332

    
333
  if (new)
334
    err = krt_send_route(p, RTM_ADD, new);
335

    
336
  if (err < 0)
337
    n->n.flags |= KRF_SYNC_ERROR;
338
  else
339
    n->n.flags &= ~KRF_SYNC_ERROR;
340
}
341

    
342
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
343

    
344
static void
345
krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
346
{
347
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
348

    
349
  rte *e;
350
  net *net;
351
  sockaddr dst, gate, mask;
352
  ip_addr idst, igate, imask;
353
  net_addr ndst;
354
  void *body = (char *)msg->buf;
355
  int new = (msg->rtm.rtm_type != RTM_DELETE);
356
  char *errmsg = "KRT: Invalid route received";
357
  int flags = msg->rtm.rtm_flags;
358
  int addrs = msg->rtm.rtm_addrs;
359
  int src;
360
  byte src2;
361

    
362
  if (!(flags & RTF_UP) && scan)
363
    SKIP("not up in scan\n");
364

    
365
  if (!(flags & RTF_DONE) && !scan)
366
    SKIP("not done in async\n");
367

    
368
  if (flags & RTF_LLINFO)
369
    SKIP("link-local\n");
370

    
371
#ifdef KRT_SHARED_SOCKET
372
  if (!scan)
373
  {
374
    int table_id = msg->rtm.rtm_tableid;
375
    p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id] : NULL;
376

    
377
    if (!p)
378
      SKIP("unknown table id %d\n", table_id);
379
  }
380
#endif
381

    
382
  GETADDR(&dst, RTA_DST);
383
  GETADDR(&gate, RTA_GATEWAY);
384
  GETADDR(&mask, RTA_NETMASK);
385

    
386
  if (dst.sa.sa_family != BIRD_AF)
387
    SKIP("invalid DST");
388

    
389
  idst  = ipa_from_sa(&dst);
390
  imask = ipa_from_sa(&mask);
391
  igate = (gate.sa.sa_family == BIRD_AF) ? ipa_from_sa(&gate) : IPA_NONE;
392

    
393
  /* We do not test family for RTA_NETMASK, because BSD sends us
394
     some strange values, but interpreting them as IPv4/IPv6 works */
395

    
396

    
397
  int c = ipa_classify_net(idst);
398
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
399
    SKIP("strange class/scope\n");
400

    
401
  int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask);
402
  if (pxlen < 0)
403
    { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
404

    
405
  /* XXXX */
406
  net_fill_ipa(&ndst, idst, pxlen);
407

    
408
  if ((flags & RTF_GATEWAY) && ipa_zero(igate))
409
    { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
410

    
411
  u32 self_mask = RTF_PROTO1;
412
  u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
413

    
414
  src2 = (flags & RTF_STATIC) ? 1 : 0;
415
  src2 |= (flags & RTF_PROTO1) ? 2 : 0;
416

    
417
#ifdef RTF_PROTO2
418
  alien_mask |= RTF_PROTO2;
419
  src2 |= (flags & RTF_PROTO2) ? 4 : 0;
420
#endif
421

    
422
#ifdef RTF_PROTO3
423
  alien_mask |= RTF_PROTO3;
424
  src2 |= (flags & RTF_PROTO3) ? 8 : 0;
425
#endif
426

    
427
#ifdef RTF_REJECT
428
  alien_mask |= RTF_REJECT;
429
#endif
430

    
431
#ifdef RTF_BLACKHOLE
432
  alien_mask |= RTF_BLACKHOLE;
433
#endif
434

    
435
  if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
436
    src = KRT_SRC_REDIRECT;
437
  else if (flags & self_mask)
438
    {
439
      if (!scan)
440
        SKIP("echo\n");
441
      src = KRT_SRC_BIRD;
442
    }
443
  else if (flags & alien_mask)
444
    src = KRT_SRC_ALIEN;
445
  else
446
    src = KRT_SRC_KERNEL;
447

    
448
  net = net_get(p->p.table, &ndst);
449

    
450
  rta a = {
451
    .src = p->p.main_source,
452
    .source = RTS_INHERIT,
453
    .scope = SCOPE_UNIVERSE,
454
    .cast = RTC_UNICAST
455
  };
456

    
457
  /* reject/blackhole routes have also set RTF_GATEWAY,
458
     we wil check them first. */
459

    
460
#ifdef RTF_REJECT
461
  if(flags & RTF_REJECT) {
462
    a.dest = RTD_UNREACHABLE;
463
    goto done;
464
  }
465
#endif
466

    
467
#ifdef RTF_BLACKHOLE
468
  if(flags & RTF_BLACKHOLE) {
469
    a.dest = RTD_BLACKHOLE;
470
    goto done;
471
  }
472
#endif
473

    
474
  a.iface = if_find_by_index(msg->rtm.rtm_index);
475
  if (!a.iface)
476
    {
477
      log(L_ERR "KRT: Received route %N with unknown ifindex %u",
478
          net->n.addr, msg->rtm.rtm_index);
479
      return;
480
    }
481

    
482
  if (flags & RTF_GATEWAY)
483
  {
484
    neighbor *ng;
485
    a.dest = RTD_ROUTER;
486
    a.gw = igate;
487

    
488
#ifdef IPV6
489
    /* Clean up embedded interface ID returned in link-local address */
490
    if (ipa_is_link_local(a.gw))
491
      _I0(a.gw) = 0xfe800000;
492
#endif
493

    
494
    ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
495
    if (!ng || (ng->scope == SCOPE_HOST))
496
      {
497
        /* Ignore routes with next-hop 127.0.0.1, host routes with such
498
           next-hop appear on OpenBSD for address aliases. */
499
        if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
500
          return;
501

    
502
        log(L_ERR "KRT: Received route %N with strange next-hop %I",
503
            net->n.addr, a.gw);
504
        return;
505
      }
506
  }
507
  else
508
    a.dest = RTD_DEVICE;
509

    
510
 done:
511
  e = rte_get_temp(&a);
512
  e->net = net;
513
  e->u.krt.src = src;
514
  e->u.krt.proto = src2;
515

    
516
  /* These are probably too Linux-specific */
517
  e->u.krt.type = 0;
518
  e->u.krt.metric = 0;
519

    
520
  if (scan)
521
    krt_got_route(p, e);
522
  else
523
    krt_got_route_async(p, e, new);
524
}
525

    
526
static void
527
krt_read_ifannounce(struct ks_msg *msg)
528
{
529
  struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
530

    
531
  if (ifam->ifan_what == IFAN_ARRIVAL)
532
  {
533
    /* Not enough info to create the iface, so we just trigger iface scan */
534
    kif_request_scan();
535
  }
536
  else if (ifam->ifan_what == IFAN_DEPARTURE)
537
  {
538
    struct iface *iface = if_find_by_index(ifam->ifan_index);
539

    
540
    /* Interface is destroyed */
541
    if (!iface)
542
    {
543
      DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
544
      return;
545
    }
546

    
547
    if_delete(iface);
548
  }
549

    
550
  DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
551
}
552

    
553
static void
554
krt_read_ifinfo(struct ks_msg *msg, int scan)
555
{
556
  struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
557
  void *body = (void *)(ifm + 1);
558
  struct sockaddr_dl *dl = NULL;
559
  uint i;
560
  struct iface *iface = NULL, f = {};
561
  int fl = ifm->ifm_flags;
562
  int nlen = 0;
563

    
564
  for (i = 1; i<=RTA_IFP; i <<= 1)
565
  {
566
    if (i & ifm->ifm_addrs)
567
    {
568
      if (i == RTA_IFP)
569
      {
570
        dl = (struct sockaddr_dl *)body;
571
        break;
572
      }
573
      body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
574
    }
575
  }
576

    
577
  if (dl && (dl->sdl_family != AF_LINK))
578
  {
579
    log(L_WARN "Ignoring strange IFINFO");
580
    return;
581
  }
582

    
583
  if (dl)
584
    nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
585

    
586
  /* Note that asynchronous IFINFO messages do not contain iface
587
     name, so we have to found an existing iface by iface index */
588

    
589
  iface = if_find_by_index(ifm->ifm_index);
590
  if (!iface)
591
  {
592
    /* New interface */
593
    if (!dl)
594
      return;        /* No interface name, ignoring */
595

    
596
    memcpy(f.name, dl->sdl_data, nlen);
597
    DBG("New interface '%s' found\n", f.name);
598
  }
599
  else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
600
  {
601
    /* Interface renamed */
602
    if_delete(iface);
603
    memcpy(f.name, dl->sdl_data, nlen);
604
  }
605
  else
606
  {
607
    /* Old interface */
608
    memcpy(f.name, iface->name, sizeof(f.name));
609
  }
610

    
611
  f.index = ifm->ifm_index;
612
  f.mtu = ifm->ifm_data.ifi_mtu;
613

    
614
  if (fl & IFF_UP)
615
    f.flags |= IF_ADMIN_UP;
616
  if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
617
    f.flags |= IF_LINK_UP;          /* up or unknown */
618
  if (fl & IFF_LOOPBACK)            /* Loopback */
619
    f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
620
  else if (fl & IFF_POINTOPOINT)    /* PtP */
621
    f.flags |= IF_MULTICAST;
622
  else if (fl & IFF_BROADCAST)      /* Broadcast */
623
    f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
624
  else
625
    f.flags |= IF_MULTIACCESS;      /* NBMA */
626

    
627
  iface = if_update(&f);
628

    
629
  if (!scan)
630
    if_end_partial_update(iface);
631
}
632

    
633
static void
634
krt_read_addr(struct ks_msg *msg, int scan)
635
{
636
  struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
637
  void *body = (void *)(ifam + 1);
638
  sockaddr addr, mask, brd;
639
  struct iface *iface = NULL;
640
  struct ifa ifa;
641
  struct sockaddr null;
642
  ip_addr iaddr, imask, ibrd;
643
  int addrs = ifam->ifam_addrs;
644
  int scope, masklen = -1;
645
  int new = (ifam->ifam_type == RTM_NEWADDR);
646

    
647
  /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
648
  if (ifam->ifam_index == 0)
649
    return;
650

    
651
  if(!(iface = if_find_by_index(ifam->ifam_index)))
652
  {
653
    log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
654
    return;
655
  }
656

    
657
  GETADDR (&null, RTA_DST);
658
  GETADDR (&null, RTA_GATEWAY);
659
  GETADDR (&mask, RTA_NETMASK);
660
  GETADDR (&null, RTA_GENMASK);
661
  GETADDR (&null, RTA_IFP);
662
  GETADDR (&addr, RTA_IFA);
663
  GETADDR (&null, RTA_AUTHOR);
664
  GETADDR (&brd, RTA_BRD);
665

    
666
  /* Some other family address */
667
  if (addr.sa.sa_family != BIRD_AF)
668
    return;
669

    
670
  iaddr = ipa_from_sa(&addr);
671
  imask = ipa_from_sa(&mask);
672
  ibrd  = ipa_from_sa(&brd);
673

    
674
  /* XXXX */
675
  if ((masklen = ipa_masklen(imask)) < 0)
676
  {
677
    log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
678
    return;
679
  }
680

    
681
#ifdef IPV6
682
  /* Clean up embedded interface ID returned in link-local address */
683

    
684
  if (ipa_is_link_local(iaddr))
685
    _I0(iaddr) = 0xfe800000;
686

    
687
  if (ipa_is_link_local(ibrd))
688
    _I0(ibrd) = 0xfe800000;
689
#endif
690

    
691

    
692
  bzero(&ifa, sizeof(ifa));
693
  ifa.iface = iface;
694
  ifa.ip = iaddr;
695

    
696
  scope = ipa_classify(ifa.ip);
697
  if (scope < 0)
698
  {
699
    log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
700
    return;
701
  }
702
  ifa.scope = scope & IADDR_SCOPE_MASK;
703

    
704
  if (masklen < BITS_PER_IP_ADDRESS)
705
  {
706
    net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
707
    net_normalize(&ifa.prefix);
708

    
709
    if (masklen == (BITS_PER_IP_ADDRESS - 1))
710
      ifa.opposite = ipa_opposite_m1(ifa.ip);
711

    
712
#ifndef IPV6
713
    if (masklen == (BITS_PER_IP_ADDRESS - 2))
714
      ifa.opposite = ipa_opposite_m2(ifa.ip);
715
#endif
716

    
717
    if (iface->flags & IF_BROADCAST)
718
      ifa.brd = ibrd;
719

    
720
    if (!(iface->flags & IF_MULTIACCESS))
721
      ifa.opposite = ibrd;
722
  }
723
  else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
724
  {
725
    net_fill_ipa(&ifa.prefix, ibrd, BITS_PER_IP_ADDRESS);
726
    ifa.opposite = ibrd;
727
    ifa.flags |= IA_PEER;
728
  }
729
  else
730
  {
731
    net_fill_ipa(&ifa.prefix, ifa.ip, BITS_PER_IP_ADDRESS);
732
    ifa.flags |= IA_HOST;
733
  }
734

    
735
  if (new)
736
    ifa_update(&ifa);
737
  else
738
    ifa_delete(&ifa);
739

    
740
  if (!scan)
741
    if_end_partial_update(iface);
742
}
743

    
744
static void
745
krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
746
{
747
  /* p is NULL iff KRT_SHARED_SOCKET and !scan */
748

    
749
  switch (msg->rtm.rtm_type)
750
  {
751
    case RTM_GET:
752
      if(!scan) return;
753
    case RTM_ADD:
754
    case RTM_DELETE:
755
    case RTM_CHANGE:
756
      krt_read_route(msg, (struct krt_proto *)p, scan);
757
      break;
758
    case RTM_IFANNOUNCE:
759
      krt_read_ifannounce(msg);
760
      break;
761
    case RTM_IFINFO:
762
      krt_read_ifinfo(msg, scan);
763
      break;
764
    case RTM_NEWADDR:
765
    case RTM_DELADDR:
766
      krt_read_addr(msg, scan);
767
      break;
768
    default:
769
      break;
770
  }
771
}
772

    
773

    
774
/* Sysctl based scans */
775

    
776
static byte *krt_buffer;
777
static size_t krt_buflen, krt_bufmin;
778
static struct proto *krt_buffer_owner;
779

    
780
static byte *
781
krt_buffer_update(struct proto *p, size_t *needed)
782
{
783
  size_t req = *needed;
784

    
785
  if ((req > krt_buflen) ||
786
      ((p == krt_buffer_owner) && (req < krt_bufmin)))
787
  {
788
    /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
789
    size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
790
    krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
791
    krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
792

    
793
    if (krt_buffer) 
794
      mb_free(krt_buffer);
795
    krt_buffer = mb_alloc(krt_pool, krt_buflen);
796
    krt_buffer_owner = p;
797
  }
798

    
799
  *needed = krt_buflen;
800
  return krt_buffer;
801
}
802

    
803
static void
804
krt_buffer_release(struct proto *p)
805
{
806
  if (p == krt_buffer_owner)
807
  {
808
    mb_free(krt_buffer);
809
    krt_buffer = NULL;
810
    krt_buflen = 0;
811
    krt_buffer_owner = 0;
812
  }
813
}
814

    
815
static void
816
krt_sysctl_scan(struct proto *p, int cmd, int table_id)
817
{
818
  byte *buf, *next;
819
  int mib[7], mcnt;
820
  size_t needed;
821
  struct ks_msg *m;
822
  int retries = 3;
823
  int rv;
824

    
825
  mib[0] = CTL_NET;
826
  mib[1] = PF_ROUTE;
827
  mib[2] = 0;
828
  mib[3] = BIRD_AF;
829
  mib[4] = cmd;
830
  mib[5] = 0;
831
  mcnt = 6;
832

    
833
#ifdef KRT_USE_SYSCTL_7
834
  if (table_id >= 0)
835
  {
836
    mib[6] = table_id;
837
    mcnt = 7;
838
  }
839
#endif
840

    
841
#ifdef KRT_USE_SETFIB_SCAN
842
  if (table_id > 0)
843
    if (setfib(table_id) < 0)
844
    {
845
      log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
846
      return;
847
    }
848
#endif
849

    
850
 try:
851
  rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
852
  if (rv < 0)
853
  {
854
    /* OpenBSD returns EINVAL for not yet used tables */
855
    if ((errno == EINVAL) && (table_id > 0))
856
      goto exit;
857

    
858
    log(L_ERR "KRT: Route scan estimate failed: %m");
859
    goto exit;
860
  }
861

    
862
  /* The table is empty */
863
  if (needed == 0)
864
    goto exit;
865

    
866
  buf = krt_buffer_update(p, &needed);
867

    
868
  rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
869
  if (rv < 0)
870
  {
871
    /* The buffer size changed since last sysctl ('needed' is not changed) */
872
    if ((errno == ENOMEM) && retries--)
873
      goto try;
874

    
875
    log(L_ERR "KRT: Route scan failed: %m");
876
    goto exit;
877
  }
878

    
879
#ifdef KRT_USE_SETFIB_SCAN
880
  if (table_id > 0)
881
    if (setfib(0) < 0)
882
      die("KRT: setfib(%d) failed: %m", 0);
883
#endif
884

    
885
  /* Process received messages */
886
  for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
887
  {
888
    m = (struct ks_msg *)next;
889
    krt_read_msg(p, m, 1);
890
  }
891

    
892
  return;
893

    
894
 exit:
895
  krt_buffer_release(p);
896

    
897
#ifdef KRT_USE_SETFIB_SCAN
898
  if (table_id > 0)
899
    if (setfib(0) < 0)
900
      die("KRT: setfib(%d) failed: %m", 0);
901
#endif
902
}
903

    
904
void
905
krt_do_scan(struct krt_proto *p)
906
{
907
  krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
908
}
909

    
910
void
911
kif_do_scan(struct kif_proto *p)
912
{
913
  if_start_update();
914
  krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
915
  if_end_update();
916
}
917

    
918

    
919
/* Kernel sockets */
920

    
921
static int
922
krt_sock_hook(sock *sk, int size UNUSED)
923
{
924
  struct ks_msg msg;
925
  int l = read(sk->fd, (char *)&msg, sizeof(msg));
926

    
927
  if (l <= 0)
928
    log(L_ERR "krt-sock: read failed");
929
  else
930
    krt_read_msg((struct proto *) sk->data, &msg, 0);
931

    
932
  return 0;
933
}
934

    
935
static sock *
936
krt_sock_open(pool *pool, void *data, int table_id)
937
{
938
  sock *sk;
939
  int fd;
940

    
941
  fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
942
  if (fd < 0)
943
    die("Cannot open kernel socket for routes");
944

    
945
#ifdef KRT_USE_SETFIB_SOCK
946
  if (table_id > 0)
947
  {
948
    if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
949
      die("Cannot set FIB %d for kernel socket: %m", table_id);
950
  }
951
#endif
952

    
953
  sk = sk_new(pool);
954
  sk->type = SK_MAGIC;
955
  sk->rx_hook = krt_sock_hook;
956
  sk->fd = fd;
957
  sk->data = data;
958

    
959
  if (sk_open(sk) < 0)
960
    bug("krt-sock: sk_open failed");
961

    
962
  return sk;
963
}
964

    
965

    
966
#ifdef KRT_SHARED_SOCKET
967

    
968
static sock *krt_sock;
969
static int krt_sock_count;
970

    
971

    
972
static void
973
krt_sock_open_shared(void)
974
{
975
  if (!krt_sock_count)
976
    krt_sock = krt_sock_open(krt_pool, NULL, -1);
977
  
978
  krt_sock_count++;
979
}
980

    
981
static void
982
krt_sock_close_shared(void)
983
{
984
  krt_sock_count--;
985

    
986
  if (!krt_sock_count)
987
  {
988
    rfree(krt_sock);
989
    krt_sock = NULL;
990
  }
991
}
992

    
993
int
994
krt_sys_start(struct krt_proto *p)
995
{
996
  krt_table_map[KRT_CF->sys.table_id] = p;
997

    
998
  krt_sock_open_shared();
999
  p->sys.sk = krt_sock;
1000

    
1001
  return 1;
1002
}
1003

    
1004
void
1005
krt_sys_shutdown(struct krt_proto *p)
1006
{
1007
  krt_sock_close_shared();
1008
  p->sys.sk = NULL;
1009

    
1010
  krt_table_map[KRT_CF->sys.table_id] = NULL;
1011

    
1012
  krt_buffer_release(&p->p);
1013
}
1014

    
1015
#else
1016

    
1017
int
1018
krt_sys_start(struct krt_proto *p)
1019
{
1020
  p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
1021
  return 1;
1022
}
1023

    
1024
void
1025
krt_sys_shutdown(struct krt_proto *p)
1026
{
1027
  rfree(p->sys.sk);
1028
  p->sys.sk = NULL;
1029

    
1030
  krt_buffer_release(&p->p);
1031
}
1032

    
1033
#endif /* KRT_SHARED_SOCKET */
1034

    
1035

    
1036
/* KRT configuration callbacks */
1037

    
1038
static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32];
1039

    
1040
int
1041
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1042
{
1043
  return n->sys.table_id == o->sys.table_id;
1044
}
1045

    
1046
void
1047
krt_sys_preconfig(struct config *c UNUSED)
1048
{
1049
  krt_max_tables = krt_get_max_tables();
1050
  bzero(&krt_table_cf, sizeof(krt_table_cf));
1051
}
1052

    
1053
void
1054
krt_sys_postconfig(struct krt_config *x)
1055
{
1056
  u32 *tbl = krt_table_cf;
1057
  int id = x->sys.table_id;
1058

    
1059
  if (tbl[id/32] & (1 << (id%32)))
1060
    cf_error("Multiple kernel syncers defined for table #%d", id);
1061

    
1062
  tbl[id/32] |= (1 << (id%32));
1063
}
1064

    
1065
void krt_sys_init_config(struct krt_config *c)
1066
{
1067
  c->sys.table_id = 0; /* Default table */
1068
}
1069

    
1070
void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1071
{
1072
  d->sys.table_id = s->sys.table_id;
1073
}
1074

    
1075

    
1076
/* KIF misc code */
1077

    
1078
void
1079
kif_sys_start(struct kif_proto *p UNUSED)
1080
{
1081
}
1082

    
1083
void
1084
kif_sys_shutdown(struct kif_proto *p)
1085
{
1086
  krt_buffer_release(&p->p);
1087
}
1088

    
1089

    
1090
struct ifa *
1091
kif_get_primary_ip(struct iface *i)
1092
{
1093
#ifndef IPV6
1094
  static int fd = -1;
1095
  
1096
  if (fd < 0)
1097
    fd = socket(AF_INET, SOCK_DGRAM, 0);
1098

    
1099
  struct ifreq ifr;
1100
  memset(&ifr, 0, sizeof(ifr));
1101
  strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1102

    
1103
  int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1104
  if (rv < 0)
1105
    return NULL;
1106

    
1107
  ip_addr addr;
1108
  struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
1109
  memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr));
1110
  ipa_ntoh(addr);
1111

    
1112
  struct ifa *a;
1113
  WALK_LIST(a, i->addrs)
1114
  {
1115
    if (ipa_equal(a->ip, addr))
1116
      return a;
1117
  }
1118
#endif
1119

    
1120
  return NULL;
1121
}