Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (29.5 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
    .nh.nlmsg_type = cmd,
105
    .nh.nlmsg_len = sizeof(req),
106
    .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
107
    .g.rtgen_family = af
108
  };
109
  nl_send(&nl_scan, &req.nh);
110
}
111

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

    
153
static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
154

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

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

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

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

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

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

    
204
/*
205
 *        Netlink attributes
206
 */
207

    
208
static int nl_attr_len;
209

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

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

    
242
static inline ip4_addr rta_get_u32(struct rtattr *a)
243
{ return *(u32 *) RTA_DATA(a); }
244

    
245
static inline ip4_addr rta_get_ip4(struct rtattr *a)
246
{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); }
247

    
248
static inline ip6_addr rta_get_ip6(struct rtattr *a)
249
{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
250

    
251

    
252
struct rtattr *
253
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
254
{
255
  uint pos = NLMSG_ALIGN(h->nlmsg_len);
256
  uint len = RTA_LENGTH(dlen);
257

    
258
  if (pos + len > bufsize)
259
    bug("nl_add_attr: packet buffer overflow");
260

    
261
  struct rtattr *a = (struct rtattr *)((char *)h + pos);
262
  a->rta_type = code;
263
  a->rta_len = len;
264
  h->nlmsg_len = pos + len;
265

    
266
  if (dlen > 0)
267
    memcpy(RTA_DATA(a), data, dlen);
268

    
269
  return a;
270
}
271

    
272
static inline void
273
nl_add_attr_u32(struct nlmsghdr *h, unsigned bufsize, int code, u32 data)
274
{
275
  nl_add_attr(h, bufsize, code, &data, 4);
276
}
277

    
278
static inline void
279
nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
280
{
281
  ipa_hton(ipa);
282
  nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
283
}
284

    
285
static inline struct rtattr *
286
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
287
{
288
  return nl_add_attr(h, bufsize, code, NULL, 0);
289
}
290

    
291
static inline void
292
nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
293
{
294
  a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
295
}
296

    
297
static inline struct rtnexthop *
298
nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
299
{
300
  uint pos = NLMSG_ALIGN(h->nlmsg_len);
301
  uint len = RTNH_LENGTH(0);
302

    
303
  if (pos + len > bufsize)
304
    bug("nl_open_nexthop: packet buffer overflow");
305

    
306
  h->nlmsg_len = pos + len;
307

    
308
  return (void *)h + pos;
309
}
310

    
311
static inline void
312
nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
313
{
314
  nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
315
}
316

    
317
static void
318
nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
319
{
320
  struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
321

    
322
  for (; nh; nh = nh->next)
323
  {
324
    struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
325

    
326
    rtnh->rtnh_flags = 0;
327
    rtnh->rtnh_hops = nh->weight;
328
    rtnh->rtnh_ifindex = nh->iface->index;
329

    
330
    nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
331

    
332
    nl_close_nexthop(h, rtnh);
333
  }
334

    
335
  nl_close_attr(h, a);
336
}
337

    
338
static struct mpnh *
339
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
340
{
341
  /* Temporary buffer for multicast nexthops */
342
  static struct mpnh *nh_buffer;
343
  static int nh_buf_size;        /* in number of structures */
344
  static int nh_buf_used;
345

    
346
  struct rtattr *a[RTA_CACHEINFO+1];
347
  struct rtnexthop *nh = RTA_DATA(ra);
348
  struct mpnh *rv, *first, **last;
349
  int len = RTA_PAYLOAD(ra);
350

    
351
  first = NULL;
352
  last = &first;
353
  nh_buf_used = 0;
354

    
355
  while (len)
356
    {
357
      /* Use RTNH_OK(nh,len) ?? */
358
      if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
359
        return NULL;
360

    
361
      if (nh_buf_used == nh_buf_size)
362
      {
363
        nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4;
364
        nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct mpnh));
365
      }
366
      *last = rv = nh_buffer + nh_buf_used++;
367
      rv->next = NULL;
368
      last = &(rv->next);
369

    
370
      rv->weight = nh->rtnh_hops;
371
      rv->iface = if_find_by_index(nh->rtnh_ifindex);
372
      if (!rv->iface)
373
        return NULL;
374

    
375
      /* Nonexistent RTNH_PAYLOAD ?? */
376
      nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
377
      nl_parse_attrs(RTNH_DATA(nh), a, sizeof(a));
378
      if (a[RTA_GATEWAY])
379
        {
380
          if (RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))
381
            return NULL;
382

    
383
          memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr));
384
          ipa_ntoh(rv->gw);
385

    
386
          neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
387
                                     (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
388
          if (!ng || (ng->scope == SCOPE_HOST))
389
            return NULL;
390
        }
391
      else
392
        return NULL;
393

    
394
      len -= NLMSG_ALIGN(nh->rtnh_len);
395
      nh = RTNH_NEXT(nh);
396
    }
397

    
398
  return first;
399
}
400

    
401
static void
402
nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
403
{
404
  struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
405
  int t;
406

    
407
  for (t = 1; t < max; t++)
408
    if (metrics[0] & (1 << t))
409
      nl_add_attr_u32(h, bufsize, t, metrics[t]);
410

    
411
  nl_close_attr(h, a);
412
}
413

    
414
static int
415
nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
416
{
417
  struct rtattr *a = RTA_DATA(hdr);
418
  int len = RTA_PAYLOAD(hdr);
419

    
420
  metrics[0] = 0;
421
  for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
422
  {
423
    if (a->rta_type == RTA_UNSPEC)
424
      continue;
425

    
426
    if (a->rta_type >= max)
427
      continue;
428

    
429
    if (RTA_PAYLOAD(a) != 4)
430
      return -1;
431

    
432
    metrics[0] |= 1 << a->rta_type;
433
    metrics[a->rta_type] = rta_get_u32(a);
434
  }
435

    
436
  if (len > 0)
437
    return -1;
438

    
439
  return 0;
440
}
441

    
442

    
443
/*
444
 *        Scanning of interfaces
445
 */
446

    
447
static void
448
nl_parse_link(struct nlmsghdr *h, int scan)
449
{
450
  struct ifinfomsg *i;
451
  struct rtattr *a[IFLA_WIRELESS+1];
452
  int new = h->nlmsg_type == RTM_NEWLINK;
453
  struct iface f = {};
454
  struct iface *ifi;
455
  char *name;
456
  u32 mtu;
457
  uint fl;
458

    
459
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a)))
460
    return;
461
  if (!a[IFLA_IFNAME] || RTA_PAYLOAD(a[IFLA_IFNAME]) < 2 ||
462
      !a[IFLA_MTU] || RTA_PAYLOAD(a[IFLA_MTU]) != 4)
463
    {
464
      if (scan || !a[IFLA_WIRELESS])
465
        log(L_ERR "nl_parse_link: Malformed message received");
466
      return;
467
    }
468
  name = RTA_DATA(a[IFLA_IFNAME]);
469
  mtu = rta_get_u32(a[IFLA_MTU]);
470

    
471
  ifi = if_find_by_index(i->ifi_index);
472
  if (!new)
473
    {
474
      DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
475
      if (!ifi)
476
        return;
477

    
478
      if_delete(ifi);
479
    }
480
  else
481
    {
482
      DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
483
      if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
484
        if_delete(ifi);
485

    
486
      strncpy(f.name, name, sizeof(f.name)-1);
487
      f.index = i->ifi_index;
488
      f.mtu = mtu;
489

    
490
      fl = i->ifi_flags;
491
      if (fl & IFF_UP)
492
        f.flags |= IF_ADMIN_UP;
493
      if (fl & IFF_LOWER_UP)
494
        f.flags |= IF_LINK_UP;
495
      if (fl & IFF_LOOPBACK)                /* Loopback */
496
        f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
497
      else if (fl & IFF_POINTOPOINT)        /* PtP */
498
        f.flags |= IF_MULTICAST;
499
      else if (fl & IFF_BROADCAST)        /* Broadcast */
500
        f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
501
      else
502
        f.flags |= IF_MULTIACCESS;        /* NBMA */
503

    
504
      if (fl & IFF_MULTICAST)
505
        f.flags |= IF_MULTICAST;
506

    
507
      ifi = if_update(&f);
508

    
509
      if (!scan)
510
        if_end_partial_update(ifi);
511
    }
512
}
513

    
514
static void
515
nl_parse_addr(struct nlmsghdr *h, int scan)
516
{
517
  struct ifaddrmsg *i;
518
  struct rtattr *a[IFA_ANYCAST+1];
519
  int new = h->nlmsg_type == RTM_NEWADDR;
520
  struct ifa ifa;
521
  struct iface *ifi;
522
  int scope;
523

    
524
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a)))
525
    return;
526
  if (i->ifa_family != BIRD_AF)
527
    return;
528
  if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr)
529
#ifdef IPV6
530
      || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
531
#else
532
      || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr)
533
      || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr))
534
#endif
535
      )
536
    {
537
      log(L_ERR "nl_parse_addr: Malformed message received");
538
      return;
539
    }
540

    
541
  ifi = if_find_by_index(i->ifa_index);
542
  if (!ifi)
543
    {
544
      log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
545
      return;
546
    }
547

    
548
  bzero(&ifa, sizeof(ifa));
549
  ifa.iface = ifi;
550
  if (i->ifa_flags & IFA_F_SECONDARY)
551
    ifa.flags |= IA_SECONDARY;
552

    
553
  /* IFA_LOCAL can be unset for IPv6 interfaces */
554
  memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
555
  ipa_ntoh(ifa.ip);
556
  ifa.pxlen = i->ifa_prefixlen;
557
  if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
558
    {
559
      log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
560
      new = 0;
561
    }
562
  if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
563
    {
564
      ip_addr addr;
565
      memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr));
566
      ipa_ntoh(addr);
567
      ifa.prefix = ifa.brd = addr;
568

    
569
      /* It is either a host address or a peer address */
570
      if (ipa_equal(ifa.ip, addr))
571
        ifa.flags |= IA_HOST;
572
      else
573
        {
574
          ifa.flags |= IA_PEER;
575
          ifa.opposite = addr;
576
        }
577
    }
578
  else
579
    {
580
      ip_addr netmask = ipa_mkmask(ifa.pxlen);
581
      ifa.prefix = ipa_and(ifa.ip, netmask);
582
      ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
583
      if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
584
        ifa.opposite = ipa_opposite_m1(ifa.ip);
585

    
586
#ifndef IPV6
587
      if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
588
        ifa.opposite = ipa_opposite_m2(ifa.ip);
589

    
590
      if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
591
        {
592
          ip_addr xbrd;
593
          memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
594
          ipa_ntoh(xbrd);
595
          if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
596
            ifa.brd = xbrd;
597
          else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
598
            log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
599
        }
600
#endif
601
    }
602

    
603
  scope = ipa_classify(ifa.ip);
604
  if (scope < 0)
605
    {
606
      log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
607
      return;
608
    }
609
  ifa.scope = scope & IADDR_SCOPE_MASK;
610

    
611
  DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
612
      ifi->index, ifi->name,
613
      new ? "added" : "removed",
614
      ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
615

    
616
  if (new)
617
    ifa_update(&ifa);
618
  else
619
    ifa_delete(&ifa);
620

    
621
  if (!scan)
622
    if_end_partial_update(ifi);
623
}
624

    
625
void
626
kif_do_scan(struct kif_proto *p UNUSED)
627
{
628
  struct nlmsghdr *h;
629

    
630
  if_start_update();
631

    
632
  nl_request_dump(AF_UNSPEC, RTM_GETLINK);
633
  while (h = nl_get_scan())
634
    if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
635
      nl_parse_link(h, 1);
636
    else
637
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
638

    
639
  nl_request_dump(BIRD_AF, RTM_GETADDR);
640
  while (h = nl_get_scan())
641
    if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
642
      nl_parse_addr(h, 1);
643
    else
644
      log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
645

    
646
  if_end_update();
647
}
648

    
649
/*
650
 *        Routes
651
 */
652

    
653
static struct krt_proto *nl_table_map[NL_NUM_TABLES];
654

    
655
int
656
krt_capable(rte *e)
657
{
658
  rta *a = e->attrs;
659

    
660
  if (a->cast != RTC_UNICAST)
661
    return 0;
662

    
663
  switch (a->dest)
664
    {
665
    case RTD_ROUTER:
666
    case RTD_DEVICE:
667
      if (a->iface == NULL)
668
        return 0;
669
    case RTD_BLACKHOLE:
670
    case RTD_UNREACHABLE:
671
    case RTD_PROHIBIT:
672
    case RTD_MULTIPATH:
673
      break;
674
    default:
675
      return 0;
676
    }
677
  return 1;
678
}
679

    
680
static inline int
681
nh_bufsize(struct mpnh *nh)
682
{
683
  int rv = 0;
684
  for (; nh != NULL; nh = nh->next)
685
    rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
686
  return rv;
687
}
688

    
689
static int
690
nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
691
{
692
  eattr *ea;
693
  net *net = e->net;
694
  rta *a = e->attrs;
695
  struct {
696
    struct nlmsghdr h;
697
    struct rtmsg r;
698
    char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
699
  } r;
700

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

    
703
  bzero(&r.h, sizeof(r.h));
704
  bzero(&r.r, sizeof(r.r));
705
  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;
706
  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
707
  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0);
708

    
709
  r.r.rtm_family = BIRD_AF;
710
  r.r.rtm_dst_len = net->n.pxlen;
711
  r.r.rtm_tos = 0;
712
  r.r.rtm_table = KRT_CF->sys.table_id;
713
  r.r.rtm_protocol = RTPROT_BIRD;
714
  r.r.rtm_scope = RT_SCOPE_UNIVERSE;
715
  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
716

    
717
  /* For route delete, we do not specify route attributes */
718
  if (!new)
719
    return nl_exchange(&r.h);
720

    
721

    
722
  if (ea = ea_find(eattrs, EA_KRT_METRIC))
723
    nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
724

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

    
728
  if (ea = ea_find(eattrs, EA_KRT_REALM))
729
    nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
730

    
731

    
732
  u32 metrics[KRT_METRICS_MAX];
733
  metrics[0] = 0;
734

    
735
  struct ea_walk_state ews = { .eattrs = eattrs };
736
  while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
737
  {
738
    int id = ea->id - EA_KRT_METRICS;
739
    metrics[0] |= 1 << id;
740
    metrics[id] = ea->u.data;
741
  }
742

    
743
  if (metrics[0])
744
    nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
745

    
746

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

    
749
  switch (a->dest)
750
    {
751
    case RTD_ROUTER:
752
      r.r.rtm_type = RTN_UNICAST;
753
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
754
      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
755
      break;
756
    case RTD_DEVICE:
757
      r.r.rtm_type = RTN_UNICAST;
758
      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
759
      break;
760
    case RTD_BLACKHOLE:
761
      r.r.rtm_type = RTN_BLACKHOLE;
762
      break;
763
    case RTD_UNREACHABLE:
764
      r.r.rtm_type = RTN_UNREACHABLE;
765
      break;
766
    case RTD_PROHIBIT:
767
      r.r.rtm_type = RTN_PROHIBIT;
768
      break;
769
    case RTD_MULTIPATH:
770
      r.r.rtm_type = RTN_UNICAST;
771
      nl_add_multipath(&r.h, sizeof(r), a->nexthops);
772
      break;
773
    default:
774
      bug("krt_capable inconsistent with nl_send_route");
775
    }
776

    
777
  return nl_exchange(&r.h);
778
}
779

    
780
void
781
krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
782
{
783
  int err = 0;
784

    
785
  /*
786
   * NULL for eattr of the old route is a little hack, but we don't
787
   * get proper eattrs for old in rt_notify() anyway. NULL means no
788
   * extended route attributes and therefore matches if the kernel
789
   * route has any of them.
790
   */
791

    
792
  if (old)
793
    nl_send_route(p, old, NULL, 0);
794

    
795
  if (new)
796
    err = nl_send_route(p, new, eattrs, 1);
797

    
798
  if (err < 0)
799
    n->n.flags |= KRF_SYNC_ERROR;
800
  else
801
    n->n.flags &= ~KRF_SYNC_ERROR;
802
}
803

    
804

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

    
807
static void
808
nl_parse_route(struct nlmsghdr *h, int scan)
809
{
810
  struct krt_proto *p;
811
  struct rtmsg *i;
812
  struct rtattr *a[RTA_CACHEINFO+1];
813
  int new = h->nlmsg_type == RTM_NEWROUTE;
814

    
815
  ip_addr dst = IPA_NONE;
816
  u32 oif = ~0;
817
  int src;
818

    
819
  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
820
    return;
821
  if (i->rtm_family != BIRD_AF)
822
    return;
823
  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||
824
#ifdef IPV6
825
      (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
826
#endif
827
      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
828
      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) ||
829
      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
830
      (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) ||
831
      (a[RTA_FLOW] && RTA_PAYLOAD(a[RTA_FLOW]) != 4))
832
    {
833
      log(L_ERR "KRT: Malformed message received");
834
      return;
835
    }
836

    
837
  if (a[RTA_DST])
838
    {
839
      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
840
      ipa_ntoh(dst);
841
    }
842

    
843
  if (a[RTA_OIF])
844
    oif = rta_get_u32(a[RTA_OIF]);
845

    
846
  p = nl_table_map[i->rtm_table];        /* Do we know this table? */
847
  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)");
848
  if (!p)
849
    SKIP("unknown table %d\n", i->rtm_table);
850

    
851

    
852
#ifdef IPV6
853
  if (a[RTA_IIF])
854
    SKIP("IIF set\n");
855
#else
856
  if (i->rtm_tos != 0)                        /* We don't support TOS */
857
    SKIP("TOS %02x\n", i->rtm_tos);
858
#endif
859

    
860
  if (scan && !new)
861
    SKIP("RTM_DELROUTE in scan\n");
862

    
863
  int c = ipa_classify_net(dst);
864
  if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
865
    SKIP("strange class/scope\n");
866

    
867
  // ignore rtm_scope, it is not a real scope
868
  // if (i->rtm_scope != RT_SCOPE_UNIVERSE)
869
  //   SKIP("scope %u\n", i->rtm_scope);
870

    
871
  switch (i->rtm_protocol)
872
    {
873
    case RTPROT_UNSPEC:
874
      SKIP("proto unspec\n");
875

    
876
    case RTPROT_REDIRECT:
877
      src = KRT_SRC_REDIRECT;
878
      break;
879

    
880
    case RTPROT_KERNEL:
881
      src = KRT_SRC_KERNEL;
882
      return;
883

    
884
    case RTPROT_BIRD:
885
      if (!scan)
886
        SKIP("echo\n");
887
      src = KRT_SRC_BIRD;
888
      break;
889

    
890
    case RTPROT_BOOT:
891
    default:
892
      src = KRT_SRC_ALIEN;
893
    }
894

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

    
897
  rta ra = {
898
    .src= p->p.main_source,
899
    .source = RTS_INHERIT,
900
    .scope = SCOPE_UNIVERSE,
901
    .cast = RTC_UNICAST
902
  };
903

    
904
  switch (i->rtm_type)
905
    {
906
    case RTN_UNICAST:
907

    
908
      if (a[RTA_MULTIPATH])
909
        {
910
          ra.dest = RTD_MULTIPATH;
911
          ra.nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);
912
          if (!ra.nexthops)
913
            {
914
              log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
915
              return;
916
            }
917

    
918
          break;
919
        }
920

    
921
      ra.iface = if_find_by_index(oif);
922
      if (!ra.iface)
923
        {
924
          log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
925
          return;
926
        }
927

    
928
      if (a[RTA_GATEWAY])
929
        {
930
          neighbor *ng;
931
          ra.dest = RTD_ROUTER;
932
          memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
933
          ipa_ntoh(ra.gw);
934

    
935
#ifdef IPV6
936
          /* Silently skip strange 6to4 routes */
937
          if (ipa_in_net(ra.gw, IPA_NONE, 96))
938
            return;
939
#endif
940

    
941
          ng = neigh_find2(&p->p, &ra.gw, ra.iface,
942
                           (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
943
          if (!ng || (ng->scope == SCOPE_HOST))
944
            {
945
              log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, ra.gw);
946
              return;
947
            }
948
        }
949
      else
950
        {
951
          ra.dest = RTD_DEVICE;
952
        }
953

    
954
      break;
955
    case RTN_BLACKHOLE:
956
      ra.dest = RTD_BLACKHOLE;
957
      break;
958
    case RTN_UNREACHABLE:
959
      ra.dest = RTD_UNREACHABLE;
960
      break;
961
    case RTN_PROHIBIT:
962
      ra.dest = RTD_PROHIBIT;
963
      break;
964
    /* FIXME: What about RTN_THROW? */
965
    default:
966
      SKIP("type %d\n", i->rtm_type);
967
      return;
968
    }
969

    
970
  rte *e = rte_get_temp(&ra);
971
  e->net = net;
972
  e->u.krt.src = src;
973
  e->u.krt.proto = i->rtm_protocol;
974
  e->u.krt.type = i->rtm_type;
975
  e->u.krt.metric = 0;
976

    
977
  if (a[RTA_PRIORITY])
978
    e->u.krt.metric = rta_get_u32(a[RTA_PRIORITY]);
979

    
980
  if (a[RTA_PREFSRC])
981
    {
982
      ip_addr ps;
983
      memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
984
      ipa_ntoh(ps);
985

    
986
      ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
987
      ea->next = ra.eattrs;
988
      ra.eattrs = ea;
989
      ea->flags = EALF_SORTED;
990
      ea->count = 1;
991
      ea->attrs[0].id = EA_KRT_PREFSRC;
992
      ea->attrs[0].flags = 0;
993
      ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
994
      ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps));
995
      ea->attrs[0].u.ptr->length = sizeof(ps);
996
      memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps));
997
    }
998

    
999
  if (a[RTA_FLOW])
1000
    {
1001
      ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
1002
      ea->next = ra.eattrs;
1003
      ra.eattrs = ea;
1004
      ea->flags = EALF_SORTED;
1005
      ea->count = 1;
1006
      ea->attrs[0].id = EA_KRT_REALM;
1007
      ea->attrs[0].flags = 0;
1008
      ea->attrs[0].type = EAF_TYPE_INT;
1009
      ea->attrs[0].u.data = rta_get_u32(a[RTA_FLOW]);
1010
    }
1011

    
1012
  if (a[RTA_METRICS])
1013
    {
1014
      u32 metrics[KRT_METRICS_MAX];
1015
      ea_list *ea = alloca(sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
1016
      int t, n = 0;
1017

    
1018
      if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
1019
        {
1020
          log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
1021
          return;
1022
        }
1023

    
1024
      for (t = 1; t < KRT_METRICS_MAX; t++)
1025
        if (metrics[0] & (1 << t))
1026
          {
1027
            ea->attrs[n].id = EA_CODE(EAP_KRT, KRT_METRICS_OFFSET + t);
1028
            ea->attrs[n].flags = 0;
1029
            ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
1030
            ea->attrs[n].u.data = metrics[t];
1031
            n++;
1032
          }
1033

    
1034
      if (n > 0)
1035
        {
1036
          ea->next = ra.eattrs;
1037
          ea->flags = EALF_SORTED;
1038
          ea->count = n;
1039
          ra.eattrs = ea;
1040
        }
1041
    }
1042

    
1043
  if (scan)
1044
    krt_got_route(p, e);
1045
  else
1046
    krt_got_route_async(p, e, new);
1047
}
1048

    
1049
void
1050
krt_do_scan(struct krt_proto *p UNUSED)        /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
1051
{
1052
  struct nlmsghdr *h;
1053

    
1054
  nl_request_dump(BIRD_AF, RTM_GETROUTE);
1055
  while (h = nl_get_scan())
1056
    if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
1057
      nl_parse_route(h, 1);
1058
    else
1059
      log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
1060
}
1061

    
1062
/*
1063
 *        Asynchronous Netlink interface
1064
 */
1065

    
1066
static sock *nl_async_sk;                /* BIRD socket for asynchronous notifications */
1067
static byte *nl_async_rx_buffer;        /* Receive buffer */
1068

    
1069
static void
1070
nl_async_msg(struct nlmsghdr *h)
1071
{
1072
  switch (h->nlmsg_type)
1073
    {
1074
    case RTM_NEWROUTE:
1075
    case RTM_DELROUTE:
1076
      DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
1077
      nl_parse_route(h, 0);
1078
      break;
1079
    case RTM_NEWLINK:
1080
    case RTM_DELLINK:
1081
      DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
1082
      nl_parse_link(h, 0);
1083
      break;
1084
    case RTM_NEWADDR:
1085
    case RTM_DELADDR:
1086
      DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
1087
      nl_parse_addr(h, 0);
1088
      break;
1089
    default:
1090
      DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
1091
    }
1092
}
1093

    
1094
static int
1095
nl_async_hook(sock *sk, int size UNUSED)
1096
{
1097
  struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
1098
  struct sockaddr_nl sa;
1099
  struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
1100
  struct nlmsghdr *h;
1101
  int x;
1102
  uint len;
1103

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

    
1142
static void
1143
nl_open_async(void)
1144
{
1145
  sock *sk;
1146
  struct sockaddr_nl sa;
1147
  int fd;
1148

    
1149
  if (nl_async_sk)
1150
    return;
1151

    
1152
  DBG("KRT: Opening async netlink socket\n");
1153

    
1154
  fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1155
  if (fd < 0)
1156
    {
1157
      log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
1158
      return;
1159
    }
1160

    
1161
  bzero(&sa, sizeof(sa));
1162
  sa.nl_family = AF_NETLINK;
1163
#ifdef IPV6
1164
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
1165
#else
1166
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
1167
#endif
1168
  if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
1169
    {
1170
      log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
1171
      close(fd);
1172
      return;
1173
    }
1174

    
1175
  nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
1176

    
1177
  sk = nl_async_sk = sk_new(krt_pool);
1178
  sk->type = SK_MAGIC;
1179
  sk->rx_hook = nl_async_hook;
1180
  sk->fd = fd;
1181
  if (sk_open(sk) < 0)
1182
    bug("Netlink: sk_open failed");
1183
}
1184

    
1185
/*
1186
 *        Interface to the UNIX krt module
1187
 */
1188

    
1189
static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
1190

    
1191
void
1192
krt_sys_start(struct krt_proto *p)
1193
{
1194
  nl_table_map[KRT_CF->sys.table_id] = p;
1195

    
1196
  nl_open();
1197
  nl_open_async();
1198
}
1199

    
1200
void
1201
krt_sys_shutdown(struct krt_proto *p UNUSED)
1202
{
1203
  nl_table_map[KRT_CF->sys.table_id] = NULL;
1204
}
1205

    
1206
int
1207
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1208
{
1209
  return n->sys.table_id == o->sys.table_id;
1210
}
1211

    
1212

    
1213
void
1214
krt_sys_preconfig(struct config *c UNUSED)
1215
{
1216
  bzero(&nl_cf_table, sizeof(nl_cf_table));
1217
}
1218

    
1219
void
1220
krt_sys_postconfig(struct krt_config *x)
1221
{
1222
  int id = x->sys.table_id;
1223

    
1224
  if (nl_cf_table[id/8] & (1 << (id%8)))
1225
    cf_error("Multiple kernel syncers defined for table #%d", id);
1226
  nl_cf_table[id/8] |= (1 << (id%8));
1227
}
1228

    
1229
void
1230
krt_sys_init_config(struct krt_config *cf)
1231
{
1232
  cf->sys.table_id = RT_TABLE_MAIN;
1233
}
1234

    
1235
void
1236
krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1237
{
1238
  d->sys.table_id = s->sys.table_id;
1239
}
1240

    
1241
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
1242
  NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
1243
  "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
1244
};
1245

    
1246
static const char *krt_features_names[KRT_FEATURES_MAX] = {
1247
  "ecn", NULL, NULL, "allfrag"
1248
};
1249

    
1250
int
1251
krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
1252
{
1253
  switch (a->id)
1254
  {
1255
  case EA_KRT_PREFSRC:
1256
    bsprintf(buf, "prefsrc");
1257
    return GA_NAME;
1258

    
1259
  case EA_KRT_REALM:
1260
    bsprintf(buf, "realm");
1261
    return GA_NAME;
1262

    
1263
  case EA_KRT_LOCK:
1264
    buf += bsprintf(buf, "lock:");
1265
    ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
1266
    return GA_FULL;
1267

    
1268
  case EA_KRT_FEATURES:
1269
    buf += bsprintf(buf, "features:");
1270
    ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
1271
    return GA_FULL;
1272

    
1273
  default:;
1274
    int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
1275
    if (id > 0 && id < KRT_METRICS_MAX)
1276
    {
1277
      bsprintf(buf, "%s", krt_metrics_names[id]);
1278
      return GA_NAME;
1279
    }
1280

    
1281
    return GA_UNKNOWN;
1282
  }
1283
}
1284

    
1285

    
1286

    
1287
void
1288
kif_sys_start(struct kif_proto *p UNUSED)
1289
{
1290
  nl_open();
1291
  nl_open_async();
1292
}
1293

    
1294
void
1295
kif_sys_shutdown(struct kif_proto *p UNUSED)
1296
{
1297
}