Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / linux / netlink / netlink.c @ 9a158361

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
#include <asm/types.h>
29
#include <linux/netlink.h>
30
#include <linux/rtnetlink.h>
31

    
32
#ifndef MSG_TRUNC                        /* FIXME: Hack to circumvent omissions in glibc includes */
33
#define MSG_TRUNC 0x20
34
#endif
35

    
36
/*
37
 *        Synchronous Netlink interface
38
 */
39

    
40
static int nl_sync_fd = -1;                /* Unix socket for synchronous netlink actions */
41
static u32 nl_sync_seq;                        /* Sequence number of last request sent */
42

    
43
static byte *nl_rx_buffer;                /* Receive buffer */
44
#define NL_RX_SIZE 2048
45

    
46
static struct nlmsghdr *nl_last_hdr;        /* Recently received packet */
47
static unsigned int nl_last_size;
48

    
49
static void
50
nl_open(void)
51
{
52
  if (nl_sync_fd < 0)
53
    {
54
      nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
55
      if (nl_sync_fd < 0)
56
        die("Unable to open rtnetlink socket: %m");
57
      nl_sync_seq = now;
58
      nl_rx_buffer = xmalloc(NL_RX_SIZE);
59
    }
60
}
61

    
62
static void
63
nl_send(struct nlmsghdr *nh)
64
{
65
  struct sockaddr_nl sa;
66

    
67
  memset(&sa, 0, sizeof(sa));
68
  sa.nl_family = AF_NETLINK;
69
  nh->nlmsg_pid = 0;
70
  nh->nlmsg_seq = ++nl_sync_seq;
71
  if (sendto(nl_sync_fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
72
    die("rtnetlink sendto: %m");
73
  nl_last_hdr = NULL;
74
}
75

    
76
static void
77
nl_request_dump(int cmd)
78
{
79
  struct {
80
    struct nlmsghdr nh;
81
    struct rtgenmsg g;
82
  } req;
83
  req.nh.nlmsg_type = cmd;
84
  req.nh.nlmsg_len = sizeof(req);
85
  req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
86
  req.g.rtgen_family = PF_INET;
87
  nl_send(&req.nh);
88
}
89

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

    
131
static int
132
nl_error(struct nlmsghdr *h)
133
{
134
  struct nlmsgerr *e;
135
  int ec;
136

    
137
  if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
138
    {
139
      log(L_WARN "Netlink: Truncated error message received");
140
      return ENOBUFS;
141
    }
142
  e = (struct nlmsgerr *) NLMSG_DATA(h);
143
  ec = -e->error;
144
  if (ec)
145
    log(L_WARN "Netlink: %s", strerror(ec)); /* FIXME: Shut up? */
146
  return ec;
147
}
148

    
149
static struct nlmsghdr *
150
nl_get_scan(void)
151
{
152
  struct nlmsghdr *h = nl_get_reply();
153

    
154
  if (h->nlmsg_type == NLMSG_DONE)
155
    return NULL;
156
  if (h->nlmsg_type == NLMSG_ERROR)
157
    {
158
      nl_error(h);
159
      return NULL;
160
    }
161
  return h;
162
}
163

    
164
static int
165
nl_exchange(struct nlmsghdr *pkt)
166
{
167
  struct nlmsghdr *h;
168

    
169
  nl_send(pkt);
170
  for(;;)
171
    {
172
      h = nl_get_reply();
173
      if (h->nlmsg_type == NLMSG_ERROR)
174
        break;
175
      log(L_WARN "nl_exchange: Unexpected reply received");
176
    }
177
  return nl_error(h);
178
}
179

    
180
/*
181
 *        Netlink attributes
182
 */
183

    
184
static int nl_attr_len;
185

    
186
static void *
187
nl_checkin(struct nlmsghdr *h, int lsize)
188
{
189
  nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
190
  if (nl_attr_len < 0)
191
    {
192
      log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
193
      return NULL;
194
    }
195
  return NLMSG_DATA(h);
196
}
197

    
198
static int
199
nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
200
{
201
  int max = ksize / sizeof(struct rtattr *);
202
  bzero(k, ksize);
203
  while (RTA_OK(a, nl_attr_len))
204
    {
205
      if (a->rta_type < max)
206
        k[a->rta_type] = a;
207
      a = RTA_NEXT(a, nl_attr_len);
208
    }
209
  if (nl_attr_len)
210
    {
211
      log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
212
      return 0;
213
    }
214
  else
215
    return 1;
216
}
217

    
218
static void
219
nl_add_attr_u32(struct nlmsghdr *h, unsigned maxsize, int code, u32 data)
220
{
221
  unsigned len = RTA_LENGTH(4);
222
  struct rtattr *a;
223

    
224
  if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
225
    bug("nl_add_attr32: packet buffer overflow");
226
  a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
227
  a->rta_type = code;
228
  a->rta_len = len;
229
  memcpy(RTA_DATA(a), &data, 4);
230
  h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
231
}
232

    
233
static void
234
nl_add_attr_ipa(struct nlmsghdr *h, unsigned maxsize, int code, ip_addr ipa)
235
{
236
  unsigned len = RTA_LENGTH(sizeof(ipa));
237
  struct rtattr *a;
238

    
239
  if (NLMSG_ALIGN(h->nlmsg_len) + len > maxsize)
240
    bug("nl_add_attr_ipa: packet buffer overflow");
241
  a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
242
  a->rta_type = code;
243
  a->rta_len = len;
244
  ipa = ipa_hton(ipa);
245
  memcpy(RTA_DATA(a), &ipa, sizeof(ipa));
246
  h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
247
}
248

    
249
/*
250
 *        Scanning of interfaces
251
 */
252

    
253
static void
254
nl_parse_link(struct nlmsghdr *h, int scan)
255
{
256
  struct ifinfomsg *i;
257
  struct rtattr *a[IFLA_STATS+1];
258
  int new = h->nlmsg_type == RTM_NEWLINK;
259
  struct iface f;
260
  struct iface *ifi;
261
  char *name;
262
  u32 mtu;
263
  unsigned int fl;
264

    
265
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a)))
266
    return;
267
  if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 ||
268
      !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4)
269
    {
270
      log(L_ERR "nl_parse_link: Malformed message received");
271
      return;
272
    }
273
  name = RTA_DATA(a[IFLA_IFNAME]);
274
  memcpy(&mtu, RTA_DATA(a[IFLA_MTU]), sizeof(u32));
275

    
276
  ifi = if_find_by_index(i->ifi_index);
277
  if (!new)
278
    {
279
      DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
280
      if (ifi && !scan)
281
        {
282
          memcpy(&f, ifi, sizeof(struct iface));
283
          f.flags |= IF_ADMIN_DOWN;
284
          if_update(&f);
285
        }
286
    }
287
  else
288
    {
289
      DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
290
      if (ifi)
291
        memcpy(&f, ifi, sizeof(f));
292
      else
293
        {
294
          bzero(&f, sizeof(f));
295
          f.index = i->ifi_index;
296
        }
297
      strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1);
298
      f.mtu = mtu;
299
      f.flags = 0;
300
      fl = i->ifi_flags;
301
      if (fl & IFF_UP)
302
        f.flags |= IF_LINK_UP;
303
      if (fl & IFF_POINTOPOINT)
304
        f.flags |= IF_UNNUMBERED | IF_MULTICAST;
305
      if (fl & IFF_LOOPBACK)
306
        f.flags |= IF_LOOPBACK | IF_IGNORE;
307
      if (fl & IFF_BROADCAST)
308
        f.flags |= IF_BROADCAST | IF_MULTICAST;
309
      if_update(&f);
310
    }
311
}
312

    
313
static void
314
nl_parse_addr(struct nlmsghdr *h)
315
{
316
  struct ifaddrmsg *i;
317
  struct rtattr *a[IFA_ANYCAST+1];
318
  int new = h->nlmsg_type == RTM_NEWADDR;
319
  struct iface f;
320
  struct iface *ifi;
321

    
322
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
323
    return;
324
  if (i->ifa_family != AF_INET)
325
    return;
326
  if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr) ||
327
      !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) ||
328
      (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr)))
329
    {
330
      log(L_ERR "nl_parse_addr: Malformed message received");
331
      return;
332
    }
333
  if (i->ifa_flags & IFA_F_SECONDARY)
334
    {
335
      DBG("KIF: Received address message for secondary address which is not supported.\n"); /* FIXME */
336
      return;
337
    }
338

    
339
  ifi = if_find_by_index(i->ifa_index);
340
  if (!ifi)
341
    {
342
      log(L_ERR "KIF: Received address message for unknown interface %d\n", i->ifa_index);
343
      return;
344
    }
345
  memcpy(&f, ifi, sizeof(f));
346

    
347
  if (i->ifa_prefixlen > 32 || i->ifa_prefixlen == 31 ||
348
      (f.flags & IF_UNNUMBERED) && i->ifa_prefixlen != 32)
349
    {
350
      log(L_ERR "KIF: Invalid prefix length for interface %s: %d\n", f.name, i->ifa_prefixlen);
351
      new = 0;
352
    }
353

    
354
  f.ip = f.brd = f.opposite = IPA_NONE;
355
  if (!new)
356
    {
357
      DBG("KIF: IF%d IP address deleted\n");
358
      f.pxlen = 0;
359
    }
360
  else
361
    {
362
      memcpy(&f.ip, RTA_DATA(a[IFA_LOCAL]), sizeof(f.ip));
363
      f.ip = ipa_ntoh(f.ip);
364
      f.pxlen = i->ifa_prefixlen;
365
      if (f.flags & IF_UNNUMBERED)
366
        {
367
          memcpy(&f.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(f.opposite));
368
          f.opposite = f.brd = ipa_ntoh(f.opposite);
369
        }
370
      else if ((f.flags & IF_BROADCAST) && a[IFA_BROADCAST])
371
        {
372
          memcpy(&f.brd, RTA_DATA(a[IFA_BROADCAST]), sizeof(f.brd));
373
          f.brd = ipa_ntoh(f.brd);
374
        }
375
      /* else a NBMA link */
376
      f.prefix = ipa_and(f.ip, ipa_mkmask(f.pxlen));
377
      DBG("KIF: 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);
378
    }
379
  if_update(&f);
380
}
381

    
382
void
383
krt_if_scan(struct kif_proto *p)
384
{
385
  struct nlmsghdr *h;
386

    
387
  if_start_update();
388

    
389
  nl_request_dump(RTM_GETLINK);
390
  while (h = nl_get_scan())
391
    if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
392
      nl_parse_link(h, 1);
393
    else
394
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
395

    
396
  nl_request_dump(RTM_GETADDR);
397
  while (h = nl_get_scan())
398
    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
399
      nl_parse_addr(h);
400
    else
401
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
402

    
403
  if_end_update();
404
}
405

    
406
/*
407
 *        Routes
408
 */
409

    
410
int
411
krt_capable(rte *e)
412
{
413
  rta *a = e->attrs;
414

    
415
  if (a->cast != RTC_UNICAST
416
#ifdef IPV6
417
      && a->cast != RTC_ANYCAST
418
#endif
419
      )
420
    return 0;
421
  if (a->source == RTS_DEVICE)        /* Kernel takes care of device routes itself */
422
    return 0;
423
  switch (a->dest)
424
    {
425
    case RTD_ROUTER:
426
    case RTD_DEVICE:
427
    case RTD_BLACKHOLE:
428
    case RTD_UNREACHABLE:
429
    case RTD_PROHIBIT:
430
      break;
431
    default:
432
      return 0;
433
    }
434
  return 1;
435
}
436

    
437
static void
438
nl_send_route(rte *e, int new)
439
{
440
  net *net = e->net;
441
  rta *a = e->attrs;
442
  struct {
443
    struct nlmsghdr h;
444
    struct rtmsg r;
445
    char buf[128];
446
  } r;
447
  struct nlmsghdr *reply;
448

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

    
451
  bzero(&r.h, sizeof(r.h));
452
  bzero(&r.r, sizeof(r.r));
453
  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
454
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
455
  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_REPLACE : 0);
456
  /* FIXME: Do we really need to process ACKs? */
457

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

    
488
  nl_exchange(&r.h);
489
}
490

    
491
void
492
krt_set_notify(struct krt_proto *p, net *n, rte *new, rte *old)
493
{
494
  if (old && new)
495
    {
496
      /* FIXME: Priorities and TOS should be identical as well, but we don't use them yet. */
497
      nl_send_route(new, 1);
498
    }
499
  else
500
    {
501
      if (old)
502
        {
503
          if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
504
            nl_send_route(old, 0);
505
          /* else the kernel has already flushed it */
506
        }
507
      if (new)
508
        nl_send_route(new, 1);
509
    }
510
}
511

    
512
struct iface *
513
krt_temp_iface(struct krt_proto *p, unsigned index)
514
{
515
  struct iface *i, *j;
516

    
517
  WALK_LIST(i, p->scan.temp_ifs)
518
    if (i->index == index)
519
      return i;
520
  i = mb_allocz(p->p.pool, sizeof(struct iface));
521
  if (j = if_find_by_index(index))
522
    strcpy(i->name, j->name);
523
  else
524
    strcpy(i->name, "?");
525
  i->index = index;
526
  add_tail(&p->scan.temp_ifs, &i->n);
527
  return i;
528
}
529

    
530
static void
531
nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
532
{
533
  struct rtmsg *i;
534
  struct rtattr *a[RTA_CACHEINFO+1];
535
  int new = h->nlmsg_type == RTM_NEWROUTE;
536
  ip_addr dst;
537
  rta ra;
538
  rte *e;
539
  net *net;
540
  u32 oif;
541
  int src;
542

    
543
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
544
    return;
545
  if (i->rtm_family != AF_INET)
546
    return;
547
  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
548
      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
549
      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
550
      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
551
    {
552
      log(L_ERR "nl_parse_route: Malformed message received");
553
      return;
554
    }
555

    
556
  if (i->rtm_table != RT_TABLE_MAIN)        /* FIXME: What about other tables? */
557
    return;
558
  if (i->rtm_tos != 0)                        /* FIXME: What about TOS? */
559
    return;
560

    
561
  if (scan && !new)
562
    {
563
      DBG("KRT: Ignoring route deletion\n");
564
      return;
565
    }
566

    
567
  if (a[RTA_DST])
568
    {
569
      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
570
      dst = ipa_ntoh(dst);
571
    }
572
  else
573
    dst = IPA_NONE;
574
  if (a[RTA_OIF])
575
    memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
576
  else
577
    oif = ~0;
578

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

    
581
  switch (i->rtm_protocol)
582
    {
583
    case RTPROT_REDIRECT:
584
      src = KRT_SRC_REDIRECT;
585
      break;
586
    case RTPROT_KERNEL:
587
      DBG("Route originated in kernel, ignoring\n");
588
      return;
589
    case RTPROT_BIRD:
590
      if (!scan)
591
        {
592
          DBG("Echo of our own route, ignoring\n");
593
          return;
594
        }
595
      src = KRT_SRC_BIRD;
596
      break;
597
    default:
598
      src = KRT_SRC_ALIEN;
599
    }
600

    
601
  net = net_get(&master_table, dst, i->rtm_dst_len);
602
  ra.proto = &p->p;
603
  ra.source = RTS_INHERIT;
604
  ra.scope = SCOPE_UNIVERSE;
605
  ra.cast = RTC_UNICAST;
606
  ra.flags = ra.aflags = 0;
607
  ra.from = IPA_NONE;
608
  ra.gw = IPA_NONE;
609
  ra.iface = NULL;
610
  ra.attrs = NULL;
611

    
612
  switch (i->rtm_type)
613
    {
614
    case RTN_UNICAST:
615
      if (oif == ~0U)
616
        {
617
          log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);
618
          return;
619
        }
620
      if (a[RTA_GATEWAY])
621
        {
622
          neighbor *ng;
623
          ra.dest = RTD_ROUTER;
624
          memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
625
          ra.gw = ipa_ntoh(ra.gw);
626
          ng = neigh_find(&p->p, &ra.gw, 0);
627
          if (ng)
628
            ra.iface = ng->iface;
629
          else
630
            /* FIXME: Remove this warning? */
631
            log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);
632
        }
633
      else
634
        {
635
          ra.dest = RTD_DEVICE;
636
          ra.iface = krt_temp_iface(p, oif);
637
        }
638
      break;
639
    case RTN_BLACKHOLE:
640
      ra.dest = RTD_BLACKHOLE;
641
      break;
642
    case RTN_UNREACHABLE:
643
      ra.dest = RTD_UNREACHABLE;
644
      break;
645
    case RTN_PROHIBIT:
646
      ra.dest = RTD_PROHIBIT;
647
      break;
648
    /* FIXME: What about RTN_THROW? */
649
    default:
650
      DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);
651
      return;
652
    }
653

    
654
  if (i->rtm_scope != RT_SCOPE_UNIVERSE)        /* FIXME: Other scopes? */
655
    {
656
      DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);
657
      return;
658
    }
659

    
660
  e = rte_get_temp(&ra);
661
  e->net = net;
662
  e->u.krt.src = src;
663
  e->u.krt.proto = i->rtm_protocol;
664
  e->u.krt.type = i->rtm_type;
665
  if (a[RTA_PRIORITY])
666
    memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
667
  else
668
    e->u.krt.metric = 0;
669
  if (scan)
670
    krt_got_route(p, e);
671
  else
672
    krt_got_route_async(p, e, new);
673
}
674

    
675
void
676
krt_scan_fire(struct krt_proto *p)
677
{
678
  struct nlmsghdr *h;
679

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

    
688
/*
689
 *        Asynchronous Netlink interface
690
 */
691

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

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

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

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

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

    
768
  DBG("KRT: Opening async netlink socket\n");
769

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

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

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

    
794
  if (!nl_async_rx_buffer)
795
    nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
796
}
797

    
798
/*
799
 *        Interface to the UNIX krt module
800
 */
801

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

    
809
void
810
krt_scan_start(struct krt_proto *p)
811
{
812
  init_list(&p->scan.temp_ifs);
813
  nl_open();
814
  if (KRT_CF->scan.async)        /* FIXME: Async is for debugging only. Get rid of it some day. */
815
    nl_open_async(p);
816
}
817

    
818
void
819
krt_scan_shutdown(struct krt_proto *p)
820
{
821
}
822

    
823
void
824
krt_if_start(struct kif_proto *p)
825
{
826
  nl_open();
827
  /* FIXME: nl_open_async() after scan.async is gone */
828
}