Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / linux / netlink / netlink.c @ 6578a604

History | View | Annotate | Download (21.2 KB)

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

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

    
16
#undef LOCAL_DEBUG
17

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

    
29
#include <asm/types.h>
30
#include <linux/netlink.h>
31
#include <linux/rtnetlink.h>
32

    
33
#ifndef MSG_TRUNC                        /* Hack: Several versions of glibc miss this one :( */
34
#define MSG_TRUNC 0x20
35
#endif
36

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

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

    
44
static byte *nl_rx_buffer;                /* Receive buffer */
45
#define NL_RX_SIZE 8192
46

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

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

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

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

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

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

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

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

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

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

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

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

    
181
/*
182
 *        Netlink attributes
183
 */
184

    
185
static int nl_attr_len;
186

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

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

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

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

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

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

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

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

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

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

    
316
static void
317
nl_parse_addr(struct nlmsghdr *h)
318
{
319
  struct ifaddrmsg *i;
320
  struct rtattr *a[IFA_ANYCAST+1];
321
  int new = h->nlmsg_type == RTM_NEWADDR;
322
  struct ifa ifa;
323
  struct iface *ifi;
324
  int scope;
325

    
326
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
327
    return;
328
  if (i->ifa_family != BIRD_AF)
329
    return;
330
  if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr)
331
#ifdef IPV6
332
      || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
333
#else
334
      || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
335
      || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr))
336
#endif
337
      )
338
    {
339
      log(L_ERR "nl_parse_addr: Malformed message received");
340
      return;
341
    }
342

    
343
  ifi = if_find_by_index(i->ifa_index);
344
  if (!ifi)
345
    {
346
      log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
347
      return;
348
    }
349

    
350
  bzero(&ifa, sizeof(ifa));
351
  ifa.iface = ifi;
352
  if (i->ifa_flags & IFA_F_SECONDARY)
353
    ifa.flags |= IA_SECONDARY;
354

    
355
  /* IFA_LOCAL can be unset for IPv6 interfaces */
356
  memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
357
  ipa_ntoh(ifa.ip);
358
  ifa.pxlen = i->ifa_prefixlen;
359
  if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS ||
360
      i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
361
    {
362
      log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
363
      new = 0;
364
    }
365
  if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
366
    {
367
      ifa.flags |= IA_UNNUMBERED;
368
      memcpy(&ifa.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(ifa.opposite));
369
      ipa_ntoh(ifa.opposite);
370
      ifa.prefix = ifa.brd = ifa.opposite;
371
    }
372
  else
373
    {
374
      ip_addr netmask = ipa_mkmask(ifa.pxlen);
375
      ip_addr xbrd;
376
      ifa.prefix = ipa_and(ifa.ip, netmask);
377
      ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
378
#ifndef IPV6
379
      if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
380
        ifa.opposite = ipa_opposite(ifa.ip);
381
      if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
382
        {
383
          memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
384
          ipa_ntoh(xbrd);
385
          if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
386
            ifa.brd = xbrd;
387
          else
388
            log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
389
        }
390
#endif
391
    }
392

    
393
  scope = ipa_classify(ifa.ip);
394
  if (scope < 0)
395
    {
396
      log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
397
      return;
398
    }
399
  ifa.scope = scope & IADDR_SCOPE_MASK;
400

    
401
  DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
402
      ifi->index, ifi->name,
403
      new ? "added" : "removed",
404
      ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
405
  if (new)
406
    ifa_update(&ifa);
407
  else
408
    ifa_delete(&ifa);
409
}
410

    
411
void
412
krt_if_scan(struct kif_proto *p UNUSED)
413
{
414
  struct nlmsghdr *h;
415

    
416
  if_start_update();
417

    
418
  nl_request_dump(RTM_GETLINK);
419
  while (h = nl_get_scan())
420
    if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
421
      nl_parse_link(h, 1);
422
    else
423
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
424

    
425
  nl_request_dump(RTM_GETADDR);
426
  while (h = nl_get_scan())
427
    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
428
      nl_parse_addr(h);
429
    else
430
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
431

    
432
  if_end_update();
433
}
434

    
435
/*
436
 *        Routes
437
 */
438

    
439
static struct krt_proto *nl_table_map[NL_NUM_TABLES];
440

    
441
int
442
krt_capable(rte *e)
443
{
444
  rta *a = e->attrs;
445

    
446
  if (a->cast != RTC_UNICAST
447
#if 0
448
      && a->cast != RTC_ANYCAST
449
#endif
450
      )
451
    return 0;
452
  if (a->source == RTS_DEVICE)        /* Kernel takes care of device routes itself */
453
    return 0;
454
  switch (a->dest)
455
    {
456
    case RTD_ROUTER:
457
    case RTD_DEVICE:
458
    case RTD_BLACKHOLE:
459
    case RTD_UNREACHABLE:
460
    case RTD_PROHIBIT:
461
      break;
462
    default:
463
      return 0;
464
    }
465
  return 1;
466
}
467

    
468
static void
469
nl_send_route(struct krt_proto *p, rte *e, int new)
470
{
471
  net *net = e->net;
472
  rta *a = e->attrs;
473
  struct {
474
    struct nlmsghdr h;
475
    struct rtmsg r;
476
    char buf[128];
477
  } r;
478

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

    
481
  bzero(&r.h, sizeof(r.h));
482
  bzero(&r.r, sizeof(r.r));
483
  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
484
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
485
  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_REPLACE : 0);
486

    
487
  r.r.rtm_family = BIRD_AF;
488
  r.r.rtm_dst_len = net->n.pxlen;
489
  r.r.rtm_tos = 0;
490
  r.r.rtm_table = KRT_CF->scan.table_id;
491
  r.r.rtm_protocol = RTPROT_BIRD;
492
  r.r.rtm_scope = RT_SCOPE_UNIVERSE;
493
  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
494
  switch (a->dest)
495
    {
496
    case RTD_ROUTER:
497
      r.r.rtm_type = RTN_UNICAST;
498
      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
499
      break;
500
    case RTD_DEVICE:
501
      r.r.rtm_type = RTN_UNICAST;
502
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
503
      break;
504
    case RTD_BLACKHOLE:
505
      r.r.rtm_type = RTN_BLACKHOLE;
506
      break;
507
    case RTD_UNREACHABLE:
508
      r.r.rtm_type = RTN_UNREACHABLE;
509
      break;
510
    case RTD_PROHIBIT:
511
      r.r.rtm_type = RTN_PROHIBIT;
512
      break;
513
    default:
514
      bug("krt_capable inconsistent with nl_send_route");
515
    }
516

    
517
  nl_exchange(&r.h);
518
}
519

    
520
void
521
krt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
522
{
523
  if (old && new)
524
    {
525
      /*
526
       *  We should check whether priority and TOS is identical as well,
527
       *  but we don't use these and default value is always equal to default value. :-)
528
       */
529
      nl_send_route(p, new, 1);
530
    }
531
  else
532
    {
533
      if (old)
534
        {
535
          if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
536
            nl_send_route(p, old, 0);
537
          /* else the kernel has already flushed it */
538
        }
539
      if (new)
540
        nl_send_route(p, new, 1);
541
    }
542
}
543

    
544
struct iface *
545
krt_temp_iface(struct krt_proto *p, unsigned index)
546
{
547
  struct iface *i, *j;
548

    
549
  WALK_LIST(i, p->scan.temp_ifs)
550
    if (i->index == index)
551
      return i;
552
  i = mb_allocz(p->p.pool, sizeof(struct iface));
553
  if (j = if_find_by_index(index))
554
    strcpy(i->name, j->name);
555
  else
556
    strcpy(i->name, "?");
557
  i->index = index;
558
  add_tail(&p->scan.temp_ifs, &i->n);
559
  return i;
560
}
561

    
562
static void
563
nl_parse_route(struct nlmsghdr *h, int scan)
564
{
565
  struct krt_proto *p;
566
  struct rtmsg *i;
567
  struct rtattr *a[RTA_CACHEINFO+1];
568
  int new = h->nlmsg_type == RTM_NEWROUTE;
569
  ip_addr dst;
570
  rta ra;
571
  rte *e;
572
  net *net;
573
  u32 oif;
574
  int src;
575

    
576
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
577
    return;
578
  if (i->rtm_family != BIRD_AF)
579
    return;
580
  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
581
      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
582
      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
583
#ifdef IPV6
584
      (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
585
#endif
586
      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
587
    {
588
      log(L_ERR "nl_parse_route: Malformed message received");
589
      return;
590
    }
591

    
592
  p = nl_table_map[i->rtm_table];        /* Do we know this table? */
593
  if (!p)
594
    return;
595

    
596
#ifdef IPV6
597
  if (a[RTA_IIF])
598
    {
599
      DBG("KRT: Ignoring route with IIF set\n");
600
      return;
601
    }
602
#else
603
  if (i->rtm_tos != 0)                        /* We don't support TOS */
604
    {
605
      DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos);
606
      return;
607
    }
608
#endif
609

    
610
  if (scan && !new)
611
    {
612
      DBG("KRT: Ignoring route deletion\n");
613
      return;
614
    }
615

    
616
  if (a[RTA_DST])
617
    {
618
      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
619
      ipa_ntoh(dst);
620
    }
621
  else
622
    dst = IPA_NONE;
623
  if (a[RTA_OIF])
624
    memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
625
  else
626
    oif = ~0;
627

    
628
  DBG("Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name);
629

    
630
  switch (i->rtm_protocol)
631
    {
632
    case RTPROT_REDIRECT:
633
      src = KRT_SRC_REDIRECT;
634
      break;
635
    case RTPROT_KERNEL:
636
      DBG("Route originated in kernel, ignoring\n");
637
      return;
638
    case RTPROT_BIRD:
639
#ifdef IPV6
640
    case RTPROT_BOOT:
641
      /* Current Linux kernels don't remember rtm_protocol for IPv6 routes and supply RTPROT_BOOT instead */
642
#endif
643
      if (!scan)
644
        {
645
          DBG("Echo of our own route, ignoring\n");
646
          return;
647
        }
648
      src = KRT_SRC_BIRD;
649
      break;
650
    default:
651
      src = KRT_SRC_ALIEN;
652
    }
653

    
654
  net = net_get(p->p.table, dst, i->rtm_dst_len);
655
  ra.proto = &p->p;
656
  ra.source = RTS_INHERIT;
657
  ra.scope = SCOPE_UNIVERSE;
658
  ra.cast = RTC_UNICAST;
659
  ra.flags = ra.aflags = 0;
660
  ra.from = IPA_NONE;
661
  ra.gw = IPA_NONE;
662
  ra.iface = NULL;
663
  ra.eattrs = NULL;
664

    
665
  switch (i->rtm_type)
666
    {
667
    case RTN_UNICAST:
668
      if (oif == ~0U)
669
        {
670
          log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);
671
          return;
672
        }
673
      if (a[RTA_GATEWAY])
674
        {
675
          neighbor *ng;
676
          ra.dest = RTD_ROUTER;
677
          memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
678
          ipa_ntoh(ra.gw);
679
          ng = neigh_find(&p->p, &ra.gw, 0);
680
          if (ng && ng->scope)
681
            ra.iface = ng->iface;
682
          else
683
            /* FIXME: Remove this warning? Handle it somehow... */
684
            log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);
685
        }
686
      else
687
        {
688
          ra.dest = RTD_DEVICE;
689
          ra.iface = krt_temp_iface(p, oif);
690
        }
691
      break;
692
    case RTN_BLACKHOLE:
693
      ra.dest = RTD_BLACKHOLE;
694
      break;
695
    case RTN_UNREACHABLE:
696
      ra.dest = RTD_UNREACHABLE;
697
      break;
698
    case RTN_PROHIBIT:
699
      ra.dest = RTD_PROHIBIT;
700
      break;
701
    /* FIXME: What about RTN_THROW? */
702
    default:
703
      DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);
704
      return;
705
    }
706

    
707
  if (i->rtm_scope != RT_SCOPE_UNIVERSE)
708
    {
709
      DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);
710
      return;
711
    }
712

    
713
  e = rte_get_temp(&ra);
714
  e->net = net;
715
  e->u.krt.src = src;
716
  e->u.krt.proto = i->rtm_protocol;
717
  e->u.krt.type = i->rtm_type;
718
  if (a[RTA_PRIORITY])
719
    memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
720
  else
721
    e->u.krt.metric = 0;
722
  if (scan)
723
    krt_got_route(p, e);
724
  else
725
    krt_got_route_async(p, e, new);
726
}
727

    
728
void
729
krt_scan_fire(struct krt_proto *p UNUSED)        /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
730
{
731
  struct nlmsghdr *h;
732

    
733
  nl_request_dump(RTM_GETROUTE);
734
  while (h = nl_get_scan())
735
    if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
736
      nl_parse_route(h, 1);
737
    else
738
      log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
739
}
740

    
741
/*
742
 *        Asynchronous Netlink interface
743
 */
744

    
745
static sock *nl_async_sk;                /* BIRD socket for asynchronous notifications */
746
static byte *nl_async_rx_buffer;        /* Receive buffer */
747

    
748
static void
749
nl_async_msg(struct nlmsghdr *h)
750
{
751
  switch (h->nlmsg_type)
752
    {
753
    case RTM_NEWROUTE:
754
    case RTM_DELROUTE:
755
      DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
756
      nl_parse_route(h, 0);
757
      break;
758
    case RTM_NEWLINK:
759
    case RTM_DELLINK:
760
      DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
761
      nl_parse_link(h, 0);
762
      break;
763
    case RTM_NEWADDR:
764
    case RTM_DELADDR:
765
      DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
766
      nl_parse_addr(h);
767
      break;
768
    default:
769
      DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
770
    }
771
}
772

    
773
static int
774
nl_async_hook(sock *sk, int size UNUSED)
775
{
776
  struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
777
  struct sockaddr_nl sa;
778
  struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
779
  struct nlmsghdr *h;
780
  int x;
781
  unsigned int len;
782

    
783
  nl_last_hdr = NULL;                /* Discard packets accidentally remaining in the rxbuf */
784
  x = recvmsg(sk->fd, &m, 0);
785
  if (x < 0)
786
    {
787
      if (errno == ENOBUFS)
788
        {
789
          /*
790
           *  Netlink reports some packets have been thrown away.
791
           *  One day we might react to it by asking for route table
792
           *  scan in near future.
793
           */
794
          return 1;        /* More data are likely to be ready */
795
        }
796
      else if (errno != EWOULDBLOCK)
797
        log(L_ERR "Netlink recvmsg: %m");
798
      return 0;
799
    }
800
  if (sa.nl_pid)                /* It isn't from the kernel */
801
    {
802
      DBG("Non-kernel packet\n");
803
      return 1;
804
    }
805
  h = (void *) nl_async_rx_buffer;
806
  len = x;
807
  if (m.msg_flags & MSG_TRUNC)
808
    {
809
      log(L_WARN "Netlink got truncated asynchronous message");
810
      return 1;
811
    }
812
  while (NLMSG_OK(h, len))
813
    {
814
      nl_async_msg(h);
815
      h = NLMSG_NEXT(h, len);
816
    }
817
  if (len)
818
    log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
819
  return 1;
820
}
821

    
822
static void
823
nl_open_async(void)
824
{
825
  sock *sk;
826
  struct sockaddr_nl sa;
827
  int fd;
828
  static int nl_open_tried = 0;
829

    
830
  if (nl_open_tried)
831
    return;
832
  nl_open_tried = 1;
833

    
834
  DBG("KRT: Opening async netlink socket\n");
835

    
836
  fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
837
  if (fd < 0)
838
    {
839
      log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
840
      return;
841
    }
842

    
843
  bzero(&sa, sizeof(sa));
844
  sa.nl_family = AF_NETLINK;
845
#ifdef IPV6
846
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
847
#else
848
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
849
#endif
850
  if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
851
    {
852
      log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
853
      return;
854
    }
855

    
856
  sk = nl_async_sk = sk_new(krt_pool);
857
  sk->type = SK_MAGIC;
858
  sk->rx_hook = nl_async_hook;
859
  sk->fd = fd;
860
  if (sk_open(sk))
861
    bug("Netlink: sk_open failed");
862

    
863
  if (!nl_async_rx_buffer)
864
    nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
865
}
866

    
867
/*
868
 *        Interface to the UNIX krt module
869
 */
870

    
871
static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
872

    
873
void
874
krt_scan_preconfig(struct config *c UNUSED)
875
{
876
  bzero(&nl_cf_table, sizeof(nl_cf_table));
877
}
878

    
879
void
880
krt_scan_postconfig(struct krt_config *x)
881
{
882
  int id = x->scan.table_id;
883

    
884
  if (nl_cf_table[id/8] & (1 << (id%8)))
885
    cf_error("Multiple kernel syncers defined for table #%d", id);
886
  nl_cf_table[id/8] |= (1 << (id%8));
887
}
888

    
889
void
890
krt_scan_construct(struct krt_config *x)
891
{
892
#ifndef IPV6
893
  x->scan.table_id = RT_TABLE_MAIN;
894
#else
895
  x->scan.table_id = 254;
896
#endif
897
}
898

    
899
void
900
krt_scan_start(struct krt_proto *p, int first)
901
{
902
  init_list(&p->scan.temp_ifs);
903
  nl_table_map[KRT_CF->scan.table_id] = p;
904
  if (first)
905
    {
906
      nl_open();
907
      nl_open_async();
908
    }
909
}
910

    
911
void
912
krt_scan_shutdown(struct krt_proto *p UNUSED, int last UNUSED)
913
{
914
}
915

    
916
void
917
krt_if_start(struct kif_proto *p UNUSED)
918
{
919
  nl_open();
920
  nl_open_async();
921
}