Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / linux / netlink / netlink.c @ f79a749d

History | View | Annotate | Download (19.1 KB)

1
/*
2
 *        BIRD -- Linux Netlink Interface
3
 *
4
 *        (c) 1999 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <string.h>
10
#include <stdio.h>
11
#include <fcntl.h>
12
#include <net/if.h>
13
#include <sys/socket.h>
14
#include <sys/uio.h>
15
#include <errno.h>
16

    
17
#define LOCAL_DEBUG
18

    
19
#include "nest/bird.h"
20
#include "nest/route.h"
21
#include "nest/protocol.h"
22
#include "nest/iface.h"
23
#include "lib/timer.h"
24
#include "lib/unix.h"
25
#include "lib/krt.h"
26
#include "lib/socket.h"
27

    
28
/*
29
 *        We need to work around namespace conflicts between us and the kernel,
30
 *        but I prefer this way to being forced to rename our configuration symbols.
31
 *        This will disappear as soon as netlink headers become part of the libc.
32
 */
33

    
34
#undef CONFIG_NETLINK
35
#include <linux/config.h>
36
#ifndef CONFIG_NETLINK
37
#error "Kernel not configured to support netlink"
38
#endif
39

    
40
#include <asm/types.h>
41
#include <linux/netlink.h>
42
#include <linux/rtnetlink.h>
43

    
44
#ifndef MSG_TRUNC                        /* FIXME: Hack to circumvent omissions in glibc includes */
45
#define MSG_TRUNC 0x20
46
#endif
47

    
48
/*
49
 *        Synchronous Netlink interface
50
 */
51

    
52
static int nl_sync_fd = -1;                /* Unix socket for synchronous netlink actions */
53
static u32 nl_sync_seq;                        /* Sequence number of last request sent */
54

    
55
static byte *nl_rx_buffer;                /* Receive buffer */
56
#define NL_RX_SIZE 2048
57

    
58
static struct nlmsghdr *nl_last_hdr;        /* Recently received packet */
59
static unsigned int nl_last_size;
60

    
61
static void
62
nl_open(void)
63
{
64
  if (nl_sync_fd < 0)
65
    {
66
      nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
67
      if (nl_sync_fd < 0)
68
        die("Unable to open rtnetlink socket: %m");
69
      nl_sync_seq = now;
70
      nl_rx_buffer = xmalloc(NL_RX_SIZE);
71
    }
72
}
73

    
74
static void
75
nl_send(struct nlmsghdr *nh)
76
{
77
  struct sockaddr_nl sa;
78

    
79
  memset(&sa, 0, sizeof(sa));
80
  sa.nl_family = AF_NETLINK;
81
  nh->nlmsg_pid = 0;
82
  nh->nlmsg_seq = ++nl_sync_seq;
83
  if (sendto(nl_sync_fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
84
    die("rtnetlink sendto: %m");
85
  nl_last_hdr = NULL;
86
}
87

    
88
static void
89
nl_request_dump(int cmd)
90
{
91
  struct {
92
    struct nlmsghdr nh;
93
    struct rtgenmsg g;
94
  } req;
95
  req.nh.nlmsg_type = cmd;
96
  req.nh.nlmsg_len = sizeof(req);
97
  req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
98
  req.g.rtgen_family = PF_INET;
99
  nl_send(&req.nh);
100
}
101

    
102
static struct nlmsghdr *
103
nl_get_reply(void)
104
{
105
  for(;;)
106
    {
107
      if (!nl_last_hdr)
108
        {
109
          struct iovec iov = { nl_rx_buffer, NL_RX_SIZE };
110
          struct sockaddr_nl sa;
111
          struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
112
          int x = recvmsg(nl_sync_fd, &m, 0);
113
          if (x < 0)
114
            die("nl_get_reply: %m");
115
          if (sa.nl_pid)                /* It isn't from the kernel */
116
            {
117
              DBG("Non-kernel packet\n");
118
              continue;
119
            }
120
          nl_last_size = x;
121
          nl_last_hdr = (void *) nl_rx_buffer;
122
          if (m.msg_flags & MSG_TRUNC)
123
            bug("nl_get_reply: got truncated reply which should be impossible");
124
        }
125
      if (NLMSG_OK(nl_last_hdr, nl_last_size))
126
        {
127
          struct nlmsghdr *h = nl_last_hdr;
128
          if (h->nlmsg_seq != nl_sync_seq)
129
            {
130
              log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
131
                  h->nlmsg_seq, nl_sync_seq);
132
              continue;
133
            }
134
          nl_last_hdr = NLMSG_NEXT(h, nl_last_size);
135
          return h;
136
        }
137
      if (nl_last_size)
138
        log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl_last_size);
139
      nl_last_hdr = NULL;
140
    }
141
}
142

    
143
static int
144
nl_error(struct nlmsghdr *h)
145
{
146
  struct nlmsgerr *e;
147
  int ec;
148

    
149
  if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
150
    {
151
      log(L_WARN "Netlink: Truncated error message received");
152
      return ENOBUFS;
153
    }
154
  e = (struct nlmsgerr *) NLMSG_DATA(h);
155
  ec = -e->error;
156
  if (ec)
157
    log(L_WARN "Netlink: %s", strerror(ec)); /* FIXME: Shut up? */
158
  return ec;
159
}
160

    
161
static struct nlmsghdr *
162
nl_get_scan(void)
163
{
164
  struct nlmsghdr *h = nl_get_reply();
165

    
166
  if (h->nlmsg_type == NLMSG_DONE)
167
    return NULL;
168
  if (h->nlmsg_type == NLMSG_ERROR)
169
    {
170
      nl_error(h);
171
      return NULL;
172
    }
173
  return h;
174
}
175

    
176
static int
177
nl_exchange(struct nlmsghdr *pkt)
178
{
179
  struct nlmsghdr *h;
180

    
181
  nl_send(pkt);
182
  for(;;)
183
    {
184
      h = nl_get_reply();
185
      if (h->nlmsg_type == NLMSG_ERROR)
186
        break;
187
      log(L_WARN "nl_exchange: Unexpected reply received");
188
    }
189
  return nl_error(h);
190
}
191

    
192
/*
193
 *        Netlink attributes
194
 */
195

    
196
static int nl_attr_len;
197

    
198
static void *
199
nl_checkin(struct nlmsghdr *h, int lsize)
200
{
201
  nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
202
  if (nl_attr_len < 0)
203
    {
204
      log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
205
      return NULL;
206
    }
207
  return NLMSG_DATA(h);
208
}
209

    
210
static int
211
nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
212
{
213
  int max = ksize / sizeof(struct rtattr *);
214
  bzero(k, ksize);
215
  while (RTA_OK(a, nl_attr_len))
216
    {
217
      if (a->rta_type < max)
218
        k[a->rta_type] = a;
219
      a = RTA_NEXT(a, nl_attr_len);
220
    }
221
  if (nl_attr_len)
222
    {
223
      log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
224
      return 0;
225
    }
226
  else
227
    return 1;
228
}
229

    
230
static void
231
nl_add_attr_u32(struct nlmsghdr *h, unsigned maxsize, int code, u32 data)
232
{
233
  unsigned len = RTA_LENGTH(4);
234
  struct rtattr *a;
235

    
236
  if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
237
    bug("nl_add_attr32: packet buffer overflow");
238
  a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
239
  a->rta_type = code;
240
  a->rta_len = len;
241
  memcpy(RTA_DATA(a), &data, 4);
242
  h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
243
}
244

    
245
static void
246
nl_add_attr_ipa(struct nlmsghdr *h, unsigned maxsize, int code, ip_addr ipa)
247
{
248
  unsigned len = RTA_LENGTH(sizeof(ipa));
249
  struct rtattr *a;
250

    
251
  if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
252
    bug("nl_add_attr_ipa: packet buffer overflow");
253
  a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
254
  a->rta_type = code;
255
  a->rta_len = len;
256
  ipa = ipa_hton(ipa);
257
  memcpy(RTA_DATA(a), &ipa, sizeof(ipa));
258
  h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
259
}
260

    
261
/*
262
 *        Scanning of interfaces
263
 */
264

    
265
static void
266
nl_parse_link(struct nlmsghdr *h, int scan)
267
{
268
  struct ifinfomsg *i;
269
  struct rtattr *a[IFLA_STATS+1];
270
  int new = h->nlmsg_type == RTM_NEWLINK;
271
  struct iface f;
272
  struct iface *ifi;
273
  char *name;
274
  u32 mtu;
275
  unsigned int fl;
276

    
277
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a)))
278
    return;
279
  if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 ||
280
      !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4)
281
    {
282
      log(L_ERR "nl_parse_link: Malformed message received");
283
      return;
284
    }
285
  name = RTA_DATA(a[IFLA_IFNAME]);
286
  memcpy(&mtu, RTA_DATA(a[IFLA_MTU]), sizeof(u32));
287

    
288
  ifi = if_find_by_index(i->ifi_index);
289
  if (!new)
290
    {
291
      DBG("KRT: IF%d(%s) goes down\n", i->ifi_index, name);
292
      if (ifi && !scan)
293
        {
294
          memcpy(&f, ifi, sizeof(struct iface));
295
          f.flags |= IF_ADMIN_DOWN;
296
          if_update(&f);
297
        }
298
    }
299
  else
300
    {
301
      DBG("KRT: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
302
      if (ifi)
303
        memcpy(&f, ifi, sizeof(f));
304
      else
305
        {
306
          bzero(&f, sizeof(f));
307
          f.index = i->ifi_index;
308
        }
309
      strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1);
310
      f.mtu = mtu;
311
      f.flags = 0;
312
      fl = i->ifi_flags;
313
      if (fl & IFF_UP)
314
        f.flags |= IF_LINK_UP;
315
      if (fl & IFF_POINTOPOINT)
316
        f.flags |= IF_UNNUMBERED | IF_MULTICAST;
317
      if (fl & IFF_LOOPBACK)
318
        f.flags |= IF_LOOPBACK | IF_IGNORE;
319
      if (fl & IFF_BROADCAST)
320
        f.flags |= IF_BROADCAST | IF_MULTICAST;
321
      if_update(&f);
322
    }
323
}
324

    
325
static void
326
nl_parse_addr(struct nlmsghdr *h)
327
{
328
  struct ifaddrmsg *i;
329
  struct rtattr *a[IFA_ANYCAST+1];
330
  int new = h->nlmsg_type == RTM_NEWADDR;
331
  struct iface f;
332
  struct iface *ifi;
333

    
334
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
335
    return;
336
  if (i->ifa_family != AF_INET)
337
    return;
338
  if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr) ||
339
      !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) ||
340
      (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr)))
341
    {
342
      log(L_ERR "nl_parse_addr: Malformed message received");
343
      return;
344
    }
345
  if (i->ifa_flags & IFA_F_SECONDARY)
346
    {
347
      DBG("KRT: Received address message for secondary address which is not supported.\n"); /* FIXME */
348
      return;
349
    }
350

    
351
  ifi = if_find_by_index(i->ifa_index);
352
  if (!ifi)
353
    {
354
      log(L_ERR "KRT: Received address message for unknown interface %d\n", i->ifa_index);
355
      return;
356
    }
357
  memcpy(&f, ifi, sizeof(f));
358

    
359
  if (i->ifa_prefixlen > 32 || i->ifa_prefixlen == 31 ||
360
      (f.flags & IF_UNNUMBERED) && i->ifa_prefixlen != 32)
361
    {
362
      log(L_ERR "KRT: Invalid prefix length for interface %s: %d\n", f.name, i->ifa_prefixlen);
363
      new = 0;
364
    }
365

    
366
  f.ip = f.brd = f.opposite = IPA_NONE;
367
  if (!new)
368
    {
369
      DBG("KRT: IF%d IP address deleted\n");
370
      f.pxlen = 0;
371
    }
372
  else
373
    {
374
      memcpy(&f.ip, RTA_DATA(a[IFA_LOCAL]), sizeof(f.ip));
375
      f.ip = ipa_ntoh(f.ip);
376
      f.pxlen = i->ifa_prefixlen;
377
      if (f.flags & IF_UNNUMBERED)
378
        {
379
          memcpy(&f.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(f.opposite));
380
          f.opposite = f.brd = ipa_ntoh(f.opposite);
381
        }
382
      else if ((f.flags & IF_BROADCAST) && a[IFA_BROADCAST])
383
        {
384
          memcpy(&f.brd, RTA_DATA(a[IFA_BROADCAST]), sizeof(f.brd));
385
          f.brd = ipa_ntoh(f.brd);
386
        }
387
      /* else a NBMA link */
388
      f.prefix = ipa_and(f.ip, ipa_mkmask(f.pxlen));
389
      DBG("KRT: IF%d IP address set to %I, net %I/%d, brd %I, opp %I\n", f.index, f.ip, f.prefix, f.pxlen, f.brd, f.opposite);
390
    }
391
  if_update(&f);
392
}
393

    
394
void
395
krt_if_scan(struct krt_proto *p)
396
{
397
  struct nlmsghdr *h;
398

    
399
  if_start_update();
400

    
401
  nl_request_dump(RTM_GETLINK);
402
  while (h = nl_get_scan())
403
    if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
404
      nl_parse_link(h, 1);
405
    else
406
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
407

    
408
  nl_request_dump(RTM_GETADDR);
409
  while (h = nl_get_scan())
410
    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
411
      nl_parse_addr(h);
412
    else
413
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
414

    
415
  if_end_update();
416
}
417

    
418
/*
419
 *        Routes
420
 */
421

    
422
int                                        /* FIXME: Check use of this function in krt.c */
423
krt_capable(rte *e)
424
{
425
  rta *a = e->attrs;
426

    
427
  if (a->cast != RTC_UNICAST)        /* FIXME: For IPv6, we might support anycasts as well */
428
    return 0;
429
  if (a->source == RTS_DEVICE)        /* Kernel takes care of device routes itself */
430
    return 0;
431
  switch (a->dest)
432
    {
433
    case RTD_ROUTER:
434
    case RTD_DEVICE:
435
    case RTD_BLACKHOLE:
436
    case RTD_UNREACHABLE:
437
    case RTD_PROHIBIT:
438
      break;
439
    default:
440
      return 0;
441
    }
442
  return 1;
443
}
444

    
445
static void
446
nl_send_route(rte *e, int new)
447
{
448
  net *net = e->net;
449
  rta *a = e->attrs;
450
  struct {
451
    struct nlmsghdr h;
452
    struct rtmsg r;
453
    char buf[128];
454
  } r;
455
  struct nlmsghdr *reply;
456

    
457
  DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);
458

    
459
  bzero(&r.h, sizeof(r.h));
460
  bzero(&r.r, sizeof(r.r));
461
  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
462
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
463
  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_REPLACE : 0);
464
  /* FIXME: Do we really need to process ACKs? */
465

    
466
  r.r.rtm_family = AF_INET;
467
  r.r.rtm_dst_len = net->n.pxlen;
468
  r.r.rtm_tos = 0;        /* FIXME: Non-zero TOS? */
469
  r.r.rtm_table = RT_TABLE_MAIN;        /* FIXME: Other tables? */
470
  r.r.rtm_protocol = RTPROT_BIRD;
471
  r.r.rtm_scope = RT_SCOPE_UNIVERSE;        /* FIXME: Other scopes? */
472
  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
473
  switch (a->dest)
474
    {
475
    case RTD_ROUTER:
476
      r.r.rtm_type = RTN_UNICAST;
477
      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
478
      break;
479
    case RTD_DEVICE:
480
      r.r.rtm_type = RTN_UNICAST;
481
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
482
      break;
483
    case RTD_BLACKHOLE:
484
      r.r.rtm_type = RTN_BLACKHOLE;
485
      break;
486
    case RTD_UNREACHABLE:
487
      r.r.rtm_type = RTN_UNREACHABLE;
488
      break;
489
    case RTD_PROHIBIT:
490
      r.r.rtm_type = RTN_PROHIBIT;
491
      break;
492
    default:
493
      bug("krt_capable inconsistent with nl_send_route");
494
    }
495

    
496
  nl_exchange(&r.h);
497
}
498

    
499
void
500
krt_set_notify(struct proto *p, net *n, rte *new, rte *old)
501
{
502
  if (old && !krt_capable(old))
503
    old = NULL;
504
  if (new && !krt_capable(new))
505
    new = NULL;
506
  if (old && new && old->attrs->tos == new->attrs->tos)
507
    {
508
      /* FIXME: Priorities should be identical as well, but we don't use them yet. */
509
      nl_send_route(new, 1);
510
    }
511
  else
512
    {
513
      if (old)
514
        {
515
          if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
516
            nl_send_route(old, 0);
517
          /* else the kernel has already flushed it */
518
        }
519
      if (new)
520
        nl_send_route(new, 1);
521
    }
522
}
523

    
524
struct iface *
525
krt_temp_iface(struct krt_proto *p, unsigned index)
526
{
527
  struct iface *i, *j;
528

    
529
  WALK_LIST(i, p->scan.temp_ifs)
530
    if (i->index == index)
531
      return i;
532
  i = mb_allocz(p->p.pool, sizeof(struct iface));
533
  if (j = if_find_by_index(index))
534
    strcpy(i->name, j->name);
535
  else
536
    strcpy(i->name, "?");
537
  i->index = index;
538
  add_tail(&p->scan.temp_ifs, &i->n);
539
  return i;
540
}
541

    
542
static void
543
nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
544
{
545
  struct rtmsg *i;
546
  struct rtattr *a[RTA_CACHEINFO+1];
547
  int new = h->nlmsg_type == RTM_NEWROUTE;
548
  ip_addr dst;
549
  rta ra;
550
  rte *e;
551
  net *net;
552
  u32 oif;
553
  int src;
554

    
555
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
556
    return;
557
  if (i->rtm_family != AF_INET)
558
    return;
559
  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
560
      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
561
      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
562
    {
563
      log(L_ERR "nl_parse_route: Malformed message received");
564
      return;
565
    }
566

    
567
  if (i->rtm_table != RT_TABLE_MAIN)        /* FIXME: What about other tables? */
568
    return;
569
  if (i->rtm_tos != 0)                        /* FIXME: What about TOS? */
570
    return;
571

    
572
  if (scan && !new)
573
    {
574
      DBG("KRT: Ignoring route deletion\n");
575
      return;
576
    }
577

    
578
  if (a[RTA_DST])
579
    {
580
      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
581
      dst = ipa_ntoh(dst);
582
    }
583
  else
584
    dst = IPA_NONE;
585
  if (a[RTA_OIF])
586
    memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
587
  else
588
    oif = ~0;
589

    
590
  DBG("Got %I/%d, type=%d, oif=%d\n", dst, i->rtm_dst_len, i->rtm_type, oif);
591

    
592
  switch (i->rtm_protocol)
593
    {
594
    case RTPROT_REDIRECT:
595
      src = KRT_SRC_REDIRECT;
596
      break;
597
    case RTPROT_KERNEL:
598
      DBG("Route originated in kernel, ignoring\n");
599
      return;
600
    case RTPROT_BIRD:
601
      if (!scan)
602
        {
603
          DBG("Echo of our own route, ignoring\n");
604
          return;
605
        }
606
      src = KRT_SRC_BIRD;
607
      break;
608
    default:
609
      src = KRT_SRC_ALIEN;
610
    }
611

    
612
  net = net_get(&master_table, 0, dst, i->rtm_dst_len);
613
  ra.proto = &p->p;
614
  ra.source = RTS_INHERIT;
615
  ra.scope = SCOPE_UNIVERSE;        /* FIXME: Use kernel scope? */
616
  ra.cast = RTC_UNICAST;
617
  ra.tos = ra.flags = ra.aflags = 0;
618
  ra.from = IPA_NONE;
619
  ra.gw = IPA_NONE;
620
  ra.iface = NULL;
621
  ra.attrs = NULL;
622

    
623
  switch (i->rtm_type)
624
    {
625
    case RTN_UNICAST:
626
      if (oif == ~0U)
627
        {
628
          log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);
629
          return;
630
        }
631
      if (a[RTA_GATEWAY])
632
        {
633
          neighbor *ng;
634
          ra.dest = RTD_ROUTER;
635
          memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
636
          ra.gw = ipa_ntoh(ra.gw);
637
          ng = neigh_find(&p->p, &ra.gw, 0);
638
          if (ng)
639
            ra.iface = ng->iface;
640
          else
641
            /* FIXME: Remove this warning? */
642
            log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);
643
        }
644
      else
645
        {
646
          ra.dest = RTD_DEVICE;
647
          ra.iface = krt_temp_iface(p, oif);
648
        }
649
      break;
650
    case RTN_BLACKHOLE:
651
      ra.dest = RTD_BLACKHOLE;
652
      break;
653
    case RTN_UNREACHABLE:
654
      ra.dest = RTD_UNREACHABLE;
655
      break;
656
    case RTN_PROHIBIT:
657
      ra.dest = RTD_PROHIBIT;
658
      break;
659
    /* FIXME: What about RTN_THROW? */
660
    default:
661
      DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);
662
      return;
663
    }
664
  e = rte_get_temp(&ra);
665
  e->net = net;
666
  e->u.krt_sync.src = src;
667
  if (scan)
668
    krt_got_route(p, e);
669
  else
670
    krt_got_route_async(p, e, new);
671
}
672

    
673
void
674
krt_scan_fire(struct krt_proto *p)
675
{
676
  struct nlmsghdr *h;
677

    
678
  nl_request_dump(RTM_GETROUTE);
679
  while (h = nl_get_scan())
680
    if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
681
      nl_parse_route(p, h, 1);
682
    else
683
      log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
684
}
685

    
686
/*
687
 *        Asynchronous Netlink interface
688
 */
689

    
690
static sock *nl_async_sk;                /* BIRD socket for asynchronous notifications */
691
static byte *nl_async_rx_buffer;        /* Receive buffer */
692

    
693
static void
694
nl_async_msg(struct krt_proto *p, struct nlmsghdr *h)
695
{
696
  switch (h->nlmsg_type)
697
    {
698
    case RTM_NEWROUTE:
699
    case RTM_DELROUTE:
700
      DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
701
      nl_parse_route(p, h, 0);
702
      break;
703
    case RTM_NEWLINK:
704
    case RTM_DELLINK:
705
      DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
706
      nl_parse_link(h, 0);
707
      break;
708
    case RTM_NEWADDR:
709
    case RTM_DELADDR:
710
      DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
711
      nl_parse_addr(h);
712
      break;
713
    default:
714
      DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
715
    }
716
}
717

    
718
static int
719
nl_async_hook(sock *sk, int size)
720
{
721
  struct krt_proto *p = sk->data;
722
  struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
723
  struct sockaddr_nl sa;
724
  struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
725
  struct nlmsghdr *h;
726
  int x;
727
  unsigned int len;
728

    
729
  nl_last_hdr = NULL;                /* Discard packets accidentally remaining in the rxbuf */
730
  x = recvmsg(sk->fd, &m, 0);
731
  if (x < 0)
732
    {
733
      if (errno != EWOULDBLOCK)
734
        log(L_ERR "Netlink recvmsg: %m");
735
      return 0;
736
    }
737
  if (sa.nl_pid)                /* It isn't from the kernel */
738
    {
739
      DBG("Non-kernel packet\n");
740
      return 1;
741
    }
742
  h = (void *) nl_async_rx_buffer;
743
  len = x;
744
  if (m.msg_flags & MSG_TRUNC)
745
    {
746
      log(L_WARN "Netlink got truncated asynchronous message");
747
      return 1;
748
    }
749
  while (NLMSG_OK(h, len))
750
    {
751
      nl_async_msg(p, h);
752
      h = NLMSG_NEXT(h, len);
753
    }
754
  if (len)
755
    log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
756
  return 1;
757
}
758

    
759
static void
760
nl_open_async(struct krt_proto *p)
761
{
762
  sock *sk;
763
  struct sockaddr_nl sa;
764
  int fd;
765

    
766
  DBG("KRT: Opening async netlink socket\n");
767

    
768
  fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
769
  if (fd < 0)
770
    {
771
      log(L_ERR "Unable to open secondary rtnetlink socket: %m");
772
      return;
773
    }
774

    
775
  bzero(&sa, sizeof(sa));
776
  sa.nl_family = AF_NETLINK;
777
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
778
  if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
779
    {
780
      log(L_ERR "Unable to bind secondary rtnetlink socket: %m");
781
      return;
782
    }
783

    
784
  sk = nl_async_sk = sk_new(p->p.pool);
785
  sk->type = SK_MAGIC;
786
  sk->data = p;
787
  sk->rx_hook = nl_async_hook;
788
  sk->fd = fd;
789
  if (sk_open(sk))
790
    bug("Netlink: sk_open failed");
791

    
792
  if (!nl_async_rx_buffer)
793
    nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
794
}
795

    
796
/*
797
 *        Interface to the UNIX krt module
798
 */
799

    
800
void
801
krt_scan_preconfig(struct krt_config *x)
802
{
803
  x->scan.async = 1;
804
  /* FIXME: Use larger defaults for scanning times? */
805
}
806

    
807
void
808
krt_scan_start(struct krt_proto *p)
809
{
810
  init_list(&p->scan.temp_ifs);
811
  nl_open();
812
  if (KRT_CF->scan.async)
813
    nl_open_async(p);
814
}
815

    
816
void
817
krt_scan_shutdown(struct krt_proto *p)
818
{
819
}