Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (29.3 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 <unistd.h>
11
#include <fcntl.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/alloca.h"
23
#include "lib/timer.h"
24
#include "lib/unix.h"
25
#include "lib/krt.h"
26
#include "lib/socket.h"
27
#include "lib/string.h"
28
#include "conf/conf.h"
29

    
30
#include <asm/types.h>
31
#include <linux/if.h>
32
#include <linux/netlink.h>
33
#include <linux/rtnetlink.h>
34

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

    
39
#ifndef IFF_LOWER_UP
40
#define IFF_LOWER_UP 0x10000
41
#endif
42

    
43
/*
44
 *        Synchronous Netlink interface
45
 */
46

    
47
struct nl_sock
48
{
49
  int fd;
50
  u32 seq;
51
  byte *rx_buffer;                        /* Receive buffer */
52
  struct nlmsghdr *last_hdr;                /* Recently received packet */
53
  uint last_size;
54
};
55

    
56
#define NL_RX_SIZE 8192
57

    
58
static struct nl_sock nl_scan = {.fd = -1};        /* Netlink socket for synchronous scan */
59
static struct nl_sock nl_req  = {.fd = -1};        /* Netlink socket for requests */
60

    
61
static void
62
nl_open_sock(struct nl_sock *nl)
63
{
64
  if (nl->fd < 0)
65
    {
66
      nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
67
      if (nl->fd < 0)
68
        die("Unable to open rtnetlink socket: %m");
69
      nl->seq = now;
70
      nl->rx_buffer = xmalloc(NL_RX_SIZE);
71
      nl->last_hdr = NULL;
72
      nl->last_size = 0;
73
    }
74
}
75

    
76
static void
77
nl_open(void)
78
{
79
  nl_open_sock(&nl_scan);
80
  nl_open_sock(&nl_req);
81
}
82

    
83
static void
84
nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
85
{
86
  struct sockaddr_nl sa;
87

    
88
  memset(&sa, 0, sizeof(sa));
89
  sa.nl_family = AF_NETLINK;
90
  nh->nlmsg_pid = 0;
91
  nh->nlmsg_seq = ++(nl->seq);
92
  if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
93
    die("rtnetlink sendto: %m");
94
  nl->last_hdr = NULL;
95
}
96

    
97
static void
98
nl_request_dump(int af, int cmd)
99
{
100
  struct {
101
    struct nlmsghdr nh;
102
    struct rtgenmsg g;
103
  } req;
104
  req.nh.nlmsg_type = cmd;
105
  req.nh.nlmsg_len = sizeof(req);
106
  req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
107
  req.g.rtgen_family = af;
108
  nl_send(&nl_scan, &req.nh);
109
}
110

    
111
static struct nlmsghdr *
112
nl_get_reply(struct nl_sock *nl)
113
{
114
  for(;;)
115
    {
116
      if (!nl->last_hdr)
117
        {
118
          struct iovec iov = { nl->rx_buffer, NL_RX_SIZE };
119
          struct sockaddr_nl sa;
120
          struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
121
          int x = recvmsg(nl->fd, &m, 0);
122
          if (x < 0)
123
            die("nl_get_reply: %m");
124
          if (sa.nl_pid)                /* It isn't from the kernel */
125
            {
126
              DBG("Non-kernel packet\n");
127
              continue;
128
            }
129
          nl->last_size = x;
130
          nl->last_hdr = (void *) nl->rx_buffer;
131
          if (m.msg_flags & MSG_TRUNC)
132
            bug("nl_get_reply: got truncated reply which should be impossible");
133
        }
134
      if (NLMSG_OK(nl->last_hdr, nl->last_size))
135
        {
136
          struct nlmsghdr *h = nl->last_hdr;
137
          nl->last_hdr = NLMSG_NEXT(h, nl->last_size);
138
          if (h->nlmsg_seq != nl->seq)
139
            {
140
              log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
141
                  h->nlmsg_seq, nl->seq);
142
              continue;
143
            }
144
          return h;
145
        }
146
      if (nl->last_size)
147
        log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size);
148
      nl->last_hdr = NULL;
149
    }
150
}
151

    
152
static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
153

    
154
static int
155
nl_error(struct nlmsghdr *h)
156
{
157
  struct nlmsgerr *e;
158
  int ec;
159

    
160
  if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
161
    {
162
      log(L_WARN "Netlink: Truncated error message received");
163
      return ENOBUFS;
164
    }
165
  e = (struct nlmsgerr *) NLMSG_DATA(h);
166
  ec = -e->error;
167
  if (ec)
168
    log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec));
169
  return ec;
170
}
171

    
172
static struct nlmsghdr *
173
nl_get_scan(void)
174
{
175
  struct nlmsghdr *h = nl_get_reply(&nl_scan);
176

    
177
  if (h->nlmsg_type == NLMSG_DONE)
178
    return NULL;
179
  if (h->nlmsg_type == NLMSG_ERROR)
180
    {
181
      nl_error(h);
182
      return NULL;
183
    }
184
  return h;
185
}
186

    
187
static int
188
nl_exchange(struct nlmsghdr *pkt)
189
{
190
  struct nlmsghdr *h;
191

    
192
  nl_send(&nl_req, pkt);
193
  for(;;)
194
    {
195
      h = nl_get_reply(&nl_req);
196
      if (h->nlmsg_type == NLMSG_ERROR)
197
        break;
198
      log(L_WARN "nl_exchange: Unexpected reply received");
199
    }
200
  return nl_error(h) ? -1 : 0;
201
}
202

    
203
/*
204
 *        Netlink attributes
205
 */
206

    
207
static int nl_attr_len;
208

    
209
static void *
210
nl_checkin(struct nlmsghdr *h, int lsize)
211
{
212
  nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
213
  if (nl_attr_len < 0)
214
    {
215
      log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
216
      return NULL;
217
    }
218
  return NLMSG_DATA(h);
219
}
220

    
221
static int
222
nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
223
{
224
  int max = ksize / sizeof(struct rtattr *);
225
  bzero(k, ksize);
226
  while (RTA_OK(a, nl_attr_len))
227
    {
228
      if (a->rta_type < max)
229
        k[a->rta_type] = a;
230
      a = RTA_NEXT(a, nl_attr_len);
231
    }
232
  if (nl_attr_len)
233
    {
234
      log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
235
      return 0;
236
    }
237
  else
238
    return 1;
239
}
240

    
241
struct rtattr *
242
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
243
{
244
  uint pos = NLMSG_ALIGN(h->nlmsg_len);
245
  uint len = RTA_LENGTH(dlen);
246

    
247
  if (pos + len > bufsize)
248
    bug("nl_add_attr: packet buffer overflow");
249

    
250
  struct rtattr *a = (struct rtattr *)((char *)h + pos);
251
  a->rta_type = code;
252
  a->rta_len = len;
253
  h->nlmsg_len = pos + len;
254

    
255
  if (dlen > 0)
256
    memcpy(RTA_DATA(a), data, dlen);
257

    
258
  return a;
259
}
260

    
261
static inline void
262
nl_add_attr_u32(struct nlmsghdr *h, unsigned bufsize, int code, u32 data)
263
{
264
  nl_add_attr(h, bufsize, code, &data, 4);
265
}
266

    
267
static inline void
268
nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
269
{
270
  ipa_hton(ipa);
271
  nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
272
}
273

    
274
static inline struct rtattr *
275
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
276
{
277
  return nl_add_attr(h, bufsize, code, NULL, 0);
278
}
279

    
280
static inline void
281
nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
282
{
283
  a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
284
}
285

    
286
static inline struct rtnexthop *
287
nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
288
{
289
  uint pos = NLMSG_ALIGN(h->nlmsg_len);
290
  uint len = RTNH_LENGTH(0);
291

    
292
  if (pos + len > bufsize)
293
    bug("nl_open_nexthop: packet buffer overflow");
294

    
295
  h->nlmsg_len = pos + len;
296

    
297
  return (void *)h + pos;
298
}
299

    
300
static inline void
301
nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
302
{
303
  nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
304
}
305

    
306
static void
307
nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
308
{
309
  struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
310

    
311
  for (; nh; nh = nh->next)
312
  {
313
    struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
314

    
315
    rtnh->rtnh_flags = 0;
316
    rtnh->rtnh_hops = nh->weight;
317
    rtnh->rtnh_ifindex = nh->iface->index;
318

    
319
    nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
320

    
321
    nl_close_nexthop(h, rtnh);
322
  }
323

    
324
  nl_close_attr(h, a);
325
}
326

    
327
static struct mpnh *
328
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
329
{
330
  /* Temporary buffer for multicast nexthops */
331
  static struct mpnh *nh_buffer;
332
  static int nh_buf_size;        /* in number of structures */
333
  static int nh_buf_used;
334

    
335
  struct rtattr *a[RTA_CACHEINFO+1];
336
  struct rtnexthop *nh = RTA_DATA(ra);
337
  struct mpnh *rv, *first, **last;
338
  int len = RTA_PAYLOAD(ra);
339

    
340
  first = NULL;
341
  last = &first;
342
  nh_buf_used = 0;
343

    
344
  while (len)
345
    {
346
      /* Use RTNH_OK(nh,len) ?? */
347
      if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
348
        return NULL;
349

    
350
      if (nh_buf_used == nh_buf_size)
351
      {
352
        nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
353
        nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct mpnh));
354
      }
355
      *last = rv = nh_buffer + nh_buf_used++;
356
      rv->next = NULL;
357
      last = &(rv->next);
358

    
359
      rv->weight = nh->rtnh_hops;
360
      rv->iface = if_find_by_index(nh->rtnh_ifindex);
361
      if (!rv->iface)
362
        return NULL;
363

    
364
      /* Nonexistent RTNH_PAYLOAD ?? */
365
      nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
366
      nl_parse_attrs(RTNH_DATA(nh), a, sizeof(a));
367
      if (a[RTA_GATEWAY])
368
        {
369
          if (RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))
370
            return NULL;
371

    
372
          memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr));
373
          ipa_ntoh(rv->gw);
374

    
375
          neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
376
                                     (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
377
          if (!ng || (ng->scope == SCOPE_HOST))
378
            return NULL;
379
        }
380
      else
381
        return NULL;
382

    
383
      len -= NLMSG_ALIGN(nh->rtnh_len);
384
      nh = RTNH_NEXT(nh);
385
    }
386

    
387
  return first;
388
}
389

    
390
static void
391
nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
392
{
393
  struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
394
  int t;
395

    
396
  for (t = 1; t < max; t++)
397
    if (metrics[0] & (1 << t))
398
      nl_add_attr_u32(h, bufsize, t, metrics[t]);
399

    
400
  nl_close_attr(h, a);
401
}
402

    
403
static int
404
nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
405
{
406
  struct rtattr *a = RTA_DATA(hdr);
407
  int len = RTA_PAYLOAD(hdr);
408

    
409
  metrics[0] = 0;
410
  for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
411
  {
412
    if (a->rta_type == RTA_UNSPEC)
413
      continue;
414

    
415
    if (a->rta_type >= max)
416
      continue;
417

    
418
    if (RTA_PAYLOAD(a) != 4)
419
      return -1;
420

    
421
    metrics[0] |= 1 << a->rta_type;
422
    metrics[a->rta_type] = *(u32 *)RTA_DATA(a);
423
  }
424

    
425
  if (len > 0)
426
    return -1;
427

    
428
  return 0;
429
}
430

    
431

    
432
/*
433
 *        Scanning of interfaces
434
 */
435

    
436
static void
437
nl_parse_link(struct nlmsghdr *h, int scan)
438
{
439
  struct ifinfomsg *i;
440
  struct rtattr *a[IFLA_WIRELESS+1];
441
  int new = h->nlmsg_type == RTM_NEWLINK;
442
  struct iface f = {};
443
  struct iface *ifi;
444
  char *name;
445
  u32 mtu;
446
  uint fl;
447

    
448
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a)))
449
    return;
450
  if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 ||
451
      !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4)
452
    {
453
      if (scan || !a[IFLA_WIRELESS])
454
        log(L_ERR "nl_parse_link: Malformed message received");
455
      return;
456
    }
457
  name = RTA_DATA(a[IFLA_IFNAME]);
458
  memcpy(&mtu, RTA_DATA(a[IFLA_MTU]), sizeof(u32));
459

    
460
  ifi = if_find_by_index(i->ifi_index);
461
  if (!new)
462
    {
463
      DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
464
      if (!ifi)
465
        return;
466

    
467
      if_delete(ifi);
468
    }
469
  else
470
    {
471
      DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
472
      if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
473
        if_delete(ifi);
474

    
475
      strncpy(f.name, name, sizeof(f.name)-1);
476
      f.index = i->ifi_index;
477
      f.mtu = mtu;
478

    
479
      fl = i->ifi_flags;
480
      if (fl & IFF_UP)
481
        f.flags |= IF_ADMIN_UP;
482
      if (fl & IFF_LOWER_UP)
483
        f.flags |= IF_LINK_UP;
484
      if (fl & IFF_LOOPBACK)                /* Loopback */
485
        f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
486
      else if (fl & IFF_POINTOPOINT)        /* PtP */
487
        f.flags |= IF_MULTICAST;
488
      else if (fl & IFF_BROADCAST)        /* Broadcast */
489
        f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
490
      else
491
        f.flags |= IF_MULTIACCESS;        /* NBMA */
492

    
493
      if (fl & IFF_MULTICAST)
494
        f.flags |= IF_MULTICAST;
495

    
496
      ifi = if_update(&f);
497

    
498
      if (!scan)
499
        if_end_partial_update(ifi);
500
    }
501
}
502

    
503
static void
504
nl_parse_addr(struct nlmsghdr *h, int scan)
505
{
506
  struct ifaddrmsg *i;
507
  struct rtattr *a[IFA_ANYCAST+1];
508
  int new = h->nlmsg_type == RTM_NEWADDR;
509
  struct ifa ifa;
510
  struct iface *ifi;
511
  int scope;
512

    
513
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
514
    return;
515
  if (i->ifa_family != BIRD_AF)
516
    return;
517
  if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr)
518
#ifdef IPV6
519
      || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
520
#else
521
      || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
522
      || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr))
523
#endif
524
      )
525
    {
526
      log(L_ERR "nl_parse_addr: Malformed message received");
527
      return;
528
    }
529

    
530
  ifi = if_find_by_index(i->ifa_index);
531
  if (!ifi)
532
    {
533
      log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
534
      return;
535
    }
536

    
537
  bzero(&ifa, sizeof(ifa));
538
  ifa.iface = ifi;
539
  if (i->ifa_flags & IFA_F_SECONDARY)
540
    ifa.flags |= IA_SECONDARY;
541

    
542
  /* IFA_LOCAL can be unset for IPv6 interfaces */
543
  memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
544
  ipa_ntoh(ifa.ip);
545
  ifa.pxlen = i->ifa_prefixlen;
546
  if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
547
    {
548
      log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
549
      new = 0;
550
    }
551
  if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
552
    {
553
      ip_addr addr;
554
      memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr));
555
      ipa_ntoh(addr);
556
      ifa.prefix = ifa.brd = addr;
557

    
558
      /* It is either a host address or a peer address */
559
      if (ipa_equal(ifa.ip, addr))
560
        ifa.flags |= IA_HOST;
561
      else
562
        {
563
          ifa.flags |= IA_PEER;
564
          ifa.opposite = addr;
565
        }
566
    }
567
  else
568
    {
569
      ip_addr netmask = ipa_mkmask(ifa.pxlen);
570
      ifa.prefix = ipa_and(ifa.ip, netmask);
571
      ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
572
      if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
573
        ifa.opposite = ipa_opposite_m1(ifa.ip);
574

    
575
#ifndef IPV6
576
      if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
577
        ifa.opposite = ipa_opposite_m2(ifa.ip);
578

    
579
      if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
580
        {
581
          ip_addr xbrd;
582
          memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
583
          ipa_ntoh(xbrd);
584
          if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
585
            ifa.brd = xbrd;
586
          else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
587
            log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
588
        }
589
#endif
590
    }
591

    
592
  scope = ipa_classify(ifa.ip);
593
  if (scope < 0)
594
    {
595
      log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
596
      return;
597
    }
598
  ifa.scope = scope & IADDR_SCOPE_MASK;
599

    
600
  DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
601
      ifi->index, ifi->name,
602
      new ? "added" : "removed",
603
      ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
604

    
605
  if (new)
606
    ifa_update(&ifa);
607
  else
608
    ifa_delete(&ifa);
609

    
610
  if (!scan)
611
    if_end_partial_update(ifi);
612
}
613

    
614
void
615
kif_do_scan(struct kif_proto *p UNUSED)
616
{
617
  struct nlmsghdr *h;
618

    
619
  if_start_update();
620

    
621
  nl_request_dump(AF_UNSPEC, RTM_GETLINK);
622
  while (h = nl_get_scan())
623
    if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
624
      nl_parse_link(h, 1);
625
    else
626
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
627

    
628
  nl_request_dump(BIRD_AF, RTM_GETADDR);
629
  while (h = nl_get_scan())
630
    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
631
      nl_parse_addr(h, 1);
632
    else
633
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
634

    
635
  if_end_update();
636
}
637

    
638
/*
639
 *        Routes
640
 */
641

    
642
static struct krt_proto *nl_table_map[NL_NUM_TABLES];
643

    
644
int
645
krt_capable(rte *e)
646
{
647
  rta *a = e->attrs;
648

    
649
  if (a->cast != RTC_UNICAST)
650
    return 0;
651

    
652
  switch (a->dest)
653
    {
654
    case RTD_ROUTER:
655
    case RTD_DEVICE:
656
      if (a->iface == NULL)
657
        return 0;
658
    case RTD_BLACKHOLE:
659
    case RTD_UNREACHABLE:
660
    case RTD_PROHIBIT:
661
    case RTD_MULTIPATH:
662
      break;
663
    default:
664
      return 0;
665
    }
666
  return 1;
667
}
668

    
669
static inline int
670
nh_bufsize(struct mpnh *nh)
671
{
672
  int rv = 0;
673
  for (; nh != NULL; nh = nh->next)
674
    rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
675
  return rv;
676
}
677

    
678
static int
679
nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
680
{
681
  eattr *ea;
682
  net *net = e->net;
683
  rta *a = e->attrs;
684
  struct {
685
    struct nlmsghdr h;
686
    struct rtmsg r;
687
    char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
688
  } r;
689

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

    
692
  bzero(&r.h, sizeof(r.h));
693
  bzero(&r.r, sizeof(r.r));
694
  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
695
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
696
  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0);
697

    
698
  r.r.rtm_family = BIRD_AF;
699
  r.r.rtm_dst_len = net->n.pxlen;
700
  r.r.rtm_tos = 0;
701
  r.r.rtm_table = KRT_CF->sys.table_id;
702
  r.r.rtm_protocol = RTPROT_BIRD;
703
  r.r.rtm_scope = RT_SCOPE_UNIVERSE;
704
  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
705

    
706
  if (ea = ea_find(eattrs, EA_KRT_METRIC))
707
    nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
708

    
709
  if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
710
    nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
711

    
712
  if (ea = ea_find(eattrs, EA_KRT_REALM))
713
    nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
714

    
715

    
716
  u32 metrics[KRT_METRICS_MAX];
717
  metrics[0] = 0;
718

    
719
  struct ea_walk_state ews = { .eattrs = eattrs };
720
  while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
721
  {
722
    int id = ea->id - EA_KRT_METRICS;
723
    metrics[0] |= 1 << id;
724
    metrics[id] = ea->u.data;
725
  }
726

    
727
  if (metrics[0])
728
    nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
729

    
730

    
731
  /* a->iface != NULL checked in krt_capable() for router and device routes */
732

    
733
  switch (a->dest)
734
    {
735
    case RTD_ROUTER:
736
      r.r.rtm_type = RTN_UNICAST;
737
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
738
      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
739
      break;
740
    case RTD_DEVICE:
741
      r.r.rtm_type = RTN_UNICAST;
742
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
743
      break;
744
    case RTD_BLACKHOLE:
745
      r.r.rtm_type = RTN_BLACKHOLE;
746
      break;
747
    case RTD_UNREACHABLE:
748
      r.r.rtm_type = RTN_UNREACHABLE;
749
      break;
750
    case RTD_PROHIBIT:
751
      r.r.rtm_type = RTN_PROHIBIT;
752
      break;
753
    case RTD_MULTIPATH:
754
      r.r.rtm_type = RTN_UNICAST;
755
      nl_add_multipath(&r.h, sizeof(r), a->nexthops);
756
      break;
757
    default:
758
      bug("krt_capable inconsistent with nl_send_route");
759
    }
760

    
761
  return nl_exchange(&r.h);
762
}
763

    
764
void
765
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
766
{
767
  int err = 0;
768

    
769
  /*
770
   * NULL for eattr of the old route is a little hack, but we don't
771
   * get proper eattrs for old in rt_notify() anyway. NULL means no
772
   * extended route attributes and therefore matches if the kernel
773
   * route has any of them.
774
   */
775

    
776
  if (old)
777
    nl_send_route(p, old, NULL, 0);
778

    
779
  if (new)
780
    err = nl_send_route(p, new, eattrs, 1);
781

    
782
  if (err < 0)
783
    n->n.flags |= KRF_SYNC_ERROR;
784
  else
785
    n->n.flags &= ~KRF_SYNC_ERROR;
786
}
787

    
788

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

    
791
static void
792
nl_parse_route(struct nlmsghdr *h, int scan)
793
{
794
  struct krt_proto *p;
795
  struct rtmsg *i;
796
  struct rtattr *a[RTA_CACHEINFO+1];
797
  int new = h->nlmsg_type == RTM_NEWROUTE;
798

    
799
  ip_addr dst = IPA_NONE;
800
  u32 oif = ~0;
801
  int src;
802

    
803
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
804
    return;
805
  if (i->rtm_family != BIRD_AF)
806
    return;
807
  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
808
#ifdef IPV6
809
      (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
810
#endif
811
      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
812
      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) ||
813
      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
814
      (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) ||
815
      (a[RTA_FLOW] && RTA_PAYLOAD(a[RTA_FLOW]) != 4))
816
    {
817
      log(L_ERR "KRT: Malformed message received");
818
      return;
819
    }
820

    
821
  if (a[RTA_DST])
822
    {
823
      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
824
      ipa_ntoh(dst);
825
    }
826

    
827
  if (a[RTA_OIF])
828
    memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
829

    
830
  p = nl_table_map[i->rtm_table];        /* Do we know this table? */
831
  DBG("KRT: 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->p.name : "(none)");
832
  if (!p)
833
    SKIP("unknown table %d\n", i->rtm_table);
834

    
835

    
836
#ifdef IPV6
837
  if (a[RTA_IIF])
838
    SKIP("IIF set\n");
839
#else
840
  if (i->rtm_tos != 0)                        /* We don't support TOS */
841
    SKIP("TOS %02x\n", i->rtm_tos);
842
#endif
843

    
844
  if (scan && !new)
845
    SKIP("RTM_DELROUTE in scan\n");
846

    
847
  int c = ipa_classify_net(dst);
848
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
849
    SKIP("strange class/scope\n");
850

    
851
  // ignore rtm_scope, it is not a real scope
852
  // if (i->rtm_scope != RT_SCOPE_UNIVERSE)
853
  //   SKIP("scope %u\n", i->rtm_scope);
854

    
855
  switch (i->rtm_protocol)
856
    {
857
    case RTPROT_UNSPEC:
858
      SKIP("proto unspec\n");
859

    
860
    case RTPROT_REDIRECT:
861
      src = KRT_SRC_REDIRECT;
862
      break;
863

    
864
    case RTPROT_KERNEL:
865
      src = KRT_SRC_KERNEL;
866
      return;
867

    
868
    case RTPROT_BIRD:
869
      if (!scan)
870
        SKIP("echo\n");
871
      src = KRT_SRC_BIRD;
872
      break;
873

    
874
    case RTPROT_BOOT:
875
    default:
876
      src = KRT_SRC_ALIEN;
877
    }
878

    
879
  net *net = net_get(p->p.table, dst, i->rtm_dst_len);
880

    
881
  rta ra = {
882
    .src= p->p.main_source,
883
    .source = RTS_INHERIT,
884
    .scope = SCOPE_UNIVERSE,
885
    .cast = RTC_UNICAST
886
  };
887

    
888
  switch (i->rtm_type)
889
    {
890
    case RTN_UNICAST:
891

    
892
      if (a[RTA_MULTIPATH])
893
        {
894
          ra.dest = RTD_MULTIPATH;
895
          ra.nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);
896
          if (!ra.nexthops)
897
            {
898
              log(L_ERR "KRT: Received strange multipath route %I/%d",
899
                  net->n.prefix, net->n.pxlen);
900
              return;
901
            }
902

    
903
          break;
904
        }
905

    
906
      ra.iface = if_find_by_index(oif);
907
      if (!ra.iface)
908
        {
909
          log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
910
              net->n.prefix, net->n.pxlen, oif);
911
          return;
912
        }
913

    
914
      if (a[RTA_GATEWAY])
915
        {
916
          neighbor *ng;
917
          ra.dest = RTD_ROUTER;
918
          memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
919
          ipa_ntoh(ra.gw);
920

    
921
#ifdef IPV6
922
          /* Silently skip strange 6to4 routes */
923
          if (ipa_in_net(ra.gw, IPA_NONE, 96))
924
            return;
925
#endif
926

    
927
          ng = neigh_find2(&p->p, &ra.gw, ra.iface,
928
                           (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
929
          if (!ng || (ng->scope == SCOPE_HOST))
930
            {
931
              log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
932
                  net->n.prefix, net->n.pxlen, ra.gw);
933
              return;
934
            }
935
        }
936
      else
937
        {
938
          ra.dest = RTD_DEVICE;
939
        }
940

    
941
      break;
942
    case RTN_BLACKHOLE:
943
      ra.dest = RTD_BLACKHOLE;
944
      break;
945
    case RTN_UNREACHABLE:
946
      ra.dest = RTD_UNREACHABLE;
947
      break;
948
    case RTN_PROHIBIT:
949
      ra.dest = RTD_PROHIBIT;
950
      break;
951
    /* FIXME: What about RTN_THROW? */
952
    default:
953
      SKIP("type %d\n", i->rtm_type);
954
      return;
955
    }
956

    
957
  rte *e = rte_get_temp(&ra);
958
  e->net = net;
959
  e->u.krt.src = src;
960
  e->u.krt.proto = i->rtm_protocol;
961
  e->u.krt.type = i->rtm_type;
962

    
963
  if (a[RTA_PRIORITY])
964
    memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
965
  else
966
    e->u.krt.metric = 0;
967

    
968
  if (a[RTA_PREFSRC])
969
    {
970
      ip_addr ps;
971
      memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
972
      ipa_ntoh(ps);
973

    
974
      ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
975
      ea->next = ra.eattrs;
976
      ra.eattrs = ea;
977
      ea->flags = EALF_SORTED;
978
      ea->count = 1;
979
      ea->attrs[0].id = EA_KRT_PREFSRC;
980
      ea->attrs[0].flags = 0;
981
      ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
982
      ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps));
983
      ea->attrs[0].u.ptr->length = sizeof(ps);
984
      memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
985
    }
986

    
987
  if (a[RTA_FLOW])
988
    {
989
      ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
990
      ea->next = ra.eattrs;
991
      ra.eattrs = ea;
992
      ea->flags = EALF_SORTED;
993
      ea->count = 1;
994
      ea->attrs[0].id = EA_KRT_REALM;
995
      ea->attrs[0].flags = 0;
996
      ea->attrs[0].type = EAF_TYPE_INT;
997
      memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4);
998
    }
999

    
1000
  if (a[RTA_METRICS])
1001
    {
1002
      u32 metrics[KRT_METRICS_MAX];
1003
      ea_list *ea = alloca(sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
1004
      int t, n = 0;
1005

    
1006
      if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
1007
        {
1008
          log(L_ERR "KRT: Received route %I/%d with strange RTA_METRICS attribute",
1009
              net->n.prefix, net->n.pxlen);
1010
          return;
1011
        }
1012

    
1013
      for (t = 1; t < KRT_METRICS_MAX; t++)
1014
        if (metrics[0] & (1 << t))
1015
          {
1016
            ea->attrs[n].id = EA_CODE(EAP_KRT, KRT_METRICS_OFFSET + t);
1017
            ea->attrs[n].flags = 0;
1018
            ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
1019
            ea->attrs[n].u.data = metrics[t];
1020
            n++;
1021
          }
1022

    
1023
      if (n > 0)
1024
        {
1025
          ea->next = ra.eattrs;
1026
          ea->flags = EALF_SORTED;
1027
          ea->count = n;
1028
          ra.eattrs = ea;
1029
        }
1030
    }
1031

    
1032
  if (scan)
1033
    krt_got_route(p, e);
1034
  else
1035
    krt_got_route_async(p, e, new);
1036
}
1037

    
1038
void
1039
krt_do_scan(struct krt_proto *p UNUSED)        /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
1040
{
1041
  struct nlmsghdr *h;
1042

    
1043
  nl_request_dump(BIRD_AF, RTM_GETROUTE);
1044
  while (h = nl_get_scan())
1045
    if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
1046
      nl_parse_route(h, 1);
1047
    else
1048
      log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
1049
}
1050

    
1051
/*
1052
 *        Asynchronous Netlink interface
1053
 */
1054

    
1055
static sock *nl_async_sk;                /* BIRD socket for asynchronous notifications */
1056
static byte *nl_async_rx_buffer;        /* Receive buffer */
1057

    
1058
static void
1059
nl_async_msg(struct nlmsghdr *h)
1060
{
1061
  switch (h->nlmsg_type)
1062
    {
1063
    case RTM_NEWROUTE:
1064
    case RTM_DELROUTE:
1065
      DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
1066
      nl_parse_route(h, 0);
1067
      break;
1068
    case RTM_NEWLINK:
1069
    case RTM_DELLINK:
1070
      DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
1071
      nl_parse_link(h, 0);
1072
      break;
1073
    case RTM_NEWADDR:
1074
    case RTM_DELADDR:
1075
      DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
1076
      nl_parse_addr(h, 0);
1077
      break;
1078
    default:
1079
      DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
1080
    }
1081
}
1082

    
1083
static int
1084
nl_async_hook(sock *sk, int size UNUSED)
1085
{
1086
  struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
1087
  struct sockaddr_nl sa;
1088
  struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
1089
  struct nlmsghdr *h;
1090
  int x;
1091
  uint len;
1092

    
1093
  x = recvmsg(sk->fd, &m, 0);
1094
  if (x < 0)
1095
    {
1096
      if (errno == ENOBUFS)
1097
        {
1098
          /*
1099
           *  Netlink reports some packets have been thrown away.
1100
           *  One day we might react to it by asking for route table
1101
           *  scan in near future.
1102
           */
1103
          return 1;        /* More data are likely to be ready */
1104
        }
1105
      else if (errno != EWOULDBLOCK)
1106
        log(L_ERR "Netlink recvmsg: %m");
1107
      return 0;
1108
    }
1109
  if (sa.nl_pid)                /* It isn't from the kernel */
1110
    {
1111
      DBG("Non-kernel packet\n");
1112
      return 1;
1113
    }
1114
  h = (void *) nl_async_rx_buffer;
1115
  len = x;
1116
  if (m.msg_flags & MSG_TRUNC)
1117
    {
1118
      log(L_WARN "Netlink got truncated asynchronous message");
1119
      return 1;
1120
    }
1121
  while (NLMSG_OK(h, len))
1122
    {
1123
      nl_async_msg(h);
1124
      h = NLMSG_NEXT(h, len);
1125
    }
1126
  if (len)
1127
    log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
1128
  return 1;
1129
}
1130

    
1131
static void
1132
nl_open_async(void)
1133
{
1134
  sock *sk;
1135
  struct sockaddr_nl sa;
1136
  int fd;
1137

    
1138
  if (nl_async_sk)
1139
    return;
1140

    
1141
  DBG("KRT: Opening async netlink socket\n");
1142

    
1143
  fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1144
  if (fd < 0)
1145
    {
1146
      log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
1147
      return;
1148
    }
1149

    
1150
  bzero(&sa, sizeof(sa));
1151
  sa.nl_family = AF_NETLINK;
1152
#ifdef IPV6
1153
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
1154
#else
1155
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
1156
#endif
1157
  if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
1158
    {
1159
      log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
1160
      close(fd);
1161
      return;
1162
    }
1163

    
1164
  nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
1165

    
1166
  sk = nl_async_sk = sk_new(krt_pool);
1167
  sk->type = SK_MAGIC;
1168
  sk->rx_hook = nl_async_hook;
1169
  sk->fd = fd;
1170
  if (sk_open(sk) < 0)
1171
    bug("Netlink: sk_open failed");
1172
}
1173

    
1174
/*
1175
 *        Interface to the UNIX krt module
1176
 */
1177

    
1178
static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
1179

    
1180
void
1181
krt_sys_start(struct krt_proto *p)
1182
{
1183
  nl_table_map[KRT_CF->sys.table_id] = p;
1184

    
1185
  nl_open();
1186
  nl_open_async();
1187
}
1188

    
1189
void
1190
krt_sys_shutdown(struct krt_proto *p UNUSED)
1191
{
1192
  nl_table_map[KRT_CF->sys.table_id] = NULL;
1193
}
1194

    
1195
int
1196
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1197
{
1198
  return n->sys.table_id == o->sys.table_id;
1199
}
1200

    
1201

    
1202
void
1203
krt_sys_preconfig(struct config *c UNUSED)
1204
{
1205
  bzero(&nl_cf_table, sizeof(nl_cf_table));
1206
}
1207

    
1208
void
1209
krt_sys_postconfig(struct krt_config *x)
1210
{
1211
  int id = x->sys.table_id;
1212

    
1213
  if (nl_cf_table[id/8] & (1 << (id%8)))
1214
    cf_error("Multiple kernel syncers defined for table #%d", id);
1215
  nl_cf_table[id/8] |= (1 << (id%8));
1216
}
1217

    
1218
void
1219
krt_sys_init_config(struct krt_config *cf)
1220
{
1221
  cf->sys.table_id = RT_TABLE_MAIN;
1222
}
1223

    
1224
void
1225
krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1226
{
1227
  d->sys.table_id = s->sys.table_id;
1228
}
1229

    
1230
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
1231
  NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
1232
  "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
1233
};
1234

    
1235
static const char *krt_features_names[KRT_FEATURES_MAX] = {
1236
  "ecn", NULL, NULL, "allfrag"
1237
};
1238

    
1239
int
1240
krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
1241
{
1242
  switch (a->id)
1243
  {
1244
  case EA_KRT_PREFSRC:
1245
    bsprintf(buf, "prefsrc");
1246
    return GA_NAME;
1247

    
1248
  case EA_KRT_REALM:
1249
    bsprintf(buf, "realm");
1250
    return GA_NAME;
1251

    
1252
  case EA_KRT_LOCK:
1253
    buf += bsprintf(buf, "lock:");
1254
    ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
1255
    return GA_FULL;
1256

    
1257
  case EA_KRT_FEATURES:
1258
    buf += bsprintf(buf, "features:");
1259
    ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
1260
    return GA_FULL;
1261

    
1262
  default:;
1263
    int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
1264
    if (id > 0 && id < KRT_METRICS_MAX)
1265
    {
1266
      bsprintf(buf, "%s", krt_metrics_names[id]);
1267
      return GA_NAME;
1268
    }
1269

    
1270
    return GA_UNKNOWN;
1271
  }
1272
}
1273

    
1274

    
1275

    
1276
void
1277
kif_sys_start(struct kif_proto *p UNUSED)
1278
{
1279
  nl_open();
1280
  nl_open_async();
1281
}
1282

    
1283
void
1284
kif_sys_shutdown(struct kif_proto *p UNUSED)
1285
{
1286
}