]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'c01a94663cc18f53fd741c5d44387eead9ca88af' into integrated
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 31 Jul 2013 16:03:35 +0000 (18:03 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 31 Jul 2013 16:03:35 +0000 (18:03 +0200)
Conflicts:

sysdep/bsd/krt-sock.c
sysdep/bsd/krt-sys.h

1  2 
sysdep/bsd/krt-sock.c
sysdep/linux/netlink.c

index 49c45e668f903f3f567b299f542b4c5bfc4b8e9f,08dfccc81c4b2b6be2804b2dbf7d4ec194e9f3ec..d33486cf3723b3fcea36318cdb5cfd4d58309dbc
@@@ -65,19 -160,15 +160,29 @@@ krt_capable(rte *e
       );
  }
  
++
 +static int
 +rt_to_af(int rt)
 +{
 +  if (rt == RT_IPV4)
 +    return AF_INET;
 +  else if (rt == RT_IPV6)
 +    return AF_INET6;
 +
 +  /* RT_IP (0) maps to 0 (every AF) */
 +
 +  return 0;
 +}
 +
+ #ifndef RTAX_MAX
+ #define RTAX_MAX 8
+ #endif
+ struct ks_msg
+ {
+   struct rt_msghdr rtm;
+   struct sockaddr_storage buf[RTAX_MAX];
+ };
  
  #define ROUNDUP(a) \
          ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
@@@ -116,6 -207,15 +221,10 @@@ krt_send_route(struct krt_proto *p, in
    msg.rtm.rtm_addrs = RTA_DST;
    msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
  
 -  if (net->n.pxlen == MAX_PREFIX_LENGTH)
 -    msg.rtm.rtm_flags |= RTF_HOST;
 -  else
 -    msg.rtm.rtm_addrs |= RTA_NETMASK;
 -
+ #ifdef KRT_SHARED_SOCKET
+   msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
+ #endif
  #ifdef RTF_REJECT
    if(a->dest == RTD_UNREACHABLE)
      msg.rtm.rtm_flags |= RTF_REJECT;
    l = body - (char *)&msg;
    msg.rtm.rtm_msglen = l;
  
-   if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
+   if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
 -    log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen);
 +    log(L_ERR "KRT: Error sending route %F to kernel: %m",  &net->n);
      return -1;
    }
  
@@@ -255,11 -326,13 +364,13 @@@ krt_replace_rte(struct krt_proto *p, ne
  #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
  
  static void
- krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
+ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
  {
+   /* p is NULL iff KRT_SHARED_SOCKET and !scan */
    rte *e;
    net *net;
 -  sockaddr dst, gate, mask;
 +  struct sockaddr_in6 dst, gate, mask;
    ip_addr idst, igate, imask;
    void *body = (char *)msg->buf;
    int new = (msg->rtm.rtm_type == RTM_ADD);
@@@ -689,52 -740,120 +812,120 @@@ krt_read_msg(struct proto *p, struct ks
    }
  }
  
+ /* Sysctl based scans */
+ static byte *krt_buffer;
+ static size_t krt_buflen, krt_bufmin;
+ static struct proto *krt_buffer_owner;
+ static byte *
+ krt_buffer_update(struct proto *p, size_t *needed)
+ {
+   size_t req = *needed;
+   if ((req > krt_buflen) ||
+       ((p == krt_buffer_owner) && (req < krt_bufmin)))
+   {
+     /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
+     size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
+     krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
+     krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
+     if (krt_buffer) 
+       mb_free(krt_buffer);
+     krt_buffer = mb_alloc(krt_pool, krt_buflen);
+     krt_buffer_owner = p;
+   }
+   *needed = krt_buflen;
+   return krt_buffer;
+ }
  static void
- krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd, int af)
+ krt_buffer_release(struct proto *p)
  {
-   byte *next;
-   int mib[6];
-   size_t obl, needed;
+   if (p == krt_buffer_owner)
+   {
+     mb_free(krt_buffer);
+     krt_buffer = NULL;
+     krt_buflen = 0;
+     krt_buffer_owner = 0;
+   }
+ }
+ static void
 -krt_sysctl_scan(struct proto *p, int cmd, int table_id)
++krt_sysctl_scan(struct proto *p, int cmd, int af, int table_id)
+ {
+   byte *buf, *next;
+   int mib[7], mcnt;
+   size_t needed;
    struct ks_msg *m;
    int retries = 3;
+   int rv;
  
    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
 -  mib[3] = BIRD_PF;
 +  mib[3] = af;
    mib[4] = cmd;
    mib[5] = 0;
+   mcnt = 6;
  
-  try:
-   if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
-     die("krt_sysctl_scan 1: %m");
-   obl = *bl;
+ #ifdef KRT_USE_SYSCTL_7
+   if (table_id >= 0)
+   {
+     mib[6] = table_id;
+     mcnt = 7;
+   }
+ #endif
  
-   while (needed > *bl) *bl *= 2;
-   while (needed < (*bl/2)) *bl /= 2;
+ #ifdef KRT_USE_SETFIB_SCAN
+   if (table_id > 0)
+     if (setfib(table_id) < 0)
+     {
+       log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
+       return;
+     }
+ #endif
  
-   if ((obl!=*bl) || !*buf)
+  try:
+   rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
+   if (rv < 0)
    {
-     if (*buf) mb_free(*buf);
-     if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc");
+     /* OpenBSD returns EINVAL for not yet used tables */
+     if ((errno == EINVAL) && (table_id > 0))
+       goto exit;
+     log(L_ERR "KRT: Route scan estimate failed: %m");
+     goto exit;
    }
  
-   if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
+   /* The table is empty */
+   if (needed == 0)
+     goto exit;
+   buf = krt_buffer_update(p, &needed);
+   rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
+   if (rv < 0)
    {
-     if (errno == ENOMEM)
-     {
-       /* The buffer size changed since last sysctl ('needed' is not changed) */
-       if (retries--)
-       goto try;
+     /* The buffer size changed since last sysctl ('needed' is not changed) */
+     if ((errno == ENOMEM) && retries--)
+       goto try;
  
-       log(L_ERR "KRT: Route scan failed");
-       return;
-     }
-     die("krt_sysctl_scan 2: %m");
+     log(L_ERR "KRT: Route scan failed: %m");
+     goto exit;
    }
  
-   for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen)
+ #ifdef KRT_USE_SETFIB_SCAN
+   if (table_id > 0)
+     if (setfib(0) < 0)
+       die("KRT: setfib(%d) failed: %m", 0);
+ #endif
+   /* Process received messages */
+   for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
    {
      m = (struct ks_msg *)next;
      krt_read_msg(p, m, 1);
  void
  krt_do_scan(struct krt_proto *p)
  {
- <<<<<<< HEAD:sysdep/bsd/krt-sock.c
-   krt_sysctl_scan(&p->p, p->krt_pool, &krt_buffer, &krt_buflen,
-                 NET_RT_DUMP, rt_to_af(p->addr_type));
 -  krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
++  krt_sysctl_scan(&p->p, NET_RT_DUMP, rt_to_af(p->addr_type), KRT_CF->sys.table_id);
  }
  
  void
  kif_do_scan(struct kif_proto *p)
  {
    if_start_update();
-   krt_sysctl_scan(&p->p, p->p.pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST, 0);
 -  krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
++  krt_sysctl_scan(&p->p, NET_RT_IFLIST, 0, -1);
    if_end_update();
  }
  
@@@ -802,31 -989,54 +1061,56 @@@ krt_sys_start(struct krt_proto *p
  }
  
  void
- krt_sys_shutdown(struct krt_proto *x UNUSED)
+ krt_sys_shutdown(struct krt_proto *p)
  {
-   if (!krt_buffer)
-     return;
+   rfree(p->sys.sk);
+   p->sys.sk = NULL;
  
-   mb_free(krt_buffer);
-   krt_buffer = NULL;
+   krt_buffer_release(&p->p);
  }
  
- static u32 tables;
+ #endif /* KRT_SHARED_SOCKET */
+ /* KRT configuration callbacks */
 -static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32];
++static u32 krt_table4_cf[(KRT_MAX_TABLES+31) / 32];
++static u32 krt_table6_cf[(KRT_MAX_TABLES+31) / 32];
+ int
+ krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
+ {
+   return n->sys.table_id == o->sys.table_id;
+ }
  
  void
  krt_sys_preconfig(struct config *c UNUSED)
  {
-   tables = 0;
+   krt_max_tables = krt_get_max_tables();
 -  bzero(&krt_table_cf, sizeof(krt_table_cf));
++  bzero(&krt_table4_cf, sizeof(krt_table4_cf));
++  bzero(&krt_table6_cf, sizeof(krt_table6_cf));
  }
  
  void
  krt_sys_postconfig(struct krt_config *x)
  {
-   u32 id = x->c.table->addr_type;
 -  u32 *tbl = krt_table_cf;
++  u32 *tbl = (x->c.table->addr_type == RT_IPV4) ? krt_table4_cf : krt_table6_cf;
+   int id = x->sys.table_id;
  
-   if (tables & (1 << id))
-     cf_error("Multiple kernel protocols defined for AF %d", id);
-   tables |= (1 << id);
+   if (tbl[id/32] & (1 << (id%32)))
+     cf_error("Multiple kernel syncers defined for table #%d", id);
+   tbl[id/32] |= (1 << (id%32));
+ }
+ void krt_sys_init_config(struct krt_config *c)
+ {
+   c->sys.table_id = 0; /* Default table */
+ }
+ void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
+ {
+   d->sys.table_id = s->sys.table_id;
  }
  
  
index 593f8c5be2721fd84b07a3dabaf6dc3a4785bd34,f61e31a5069e67e5e890328c5d90417876a832a9..5b46985892506e0b629a46730bc529514ec19655
@@@ -1134,12 -1115,11 +1134,13 @@@ krt_sys_preconfig(struct config *c UNUS
  void
  krt_sys_postconfig(struct krt_config *x)
  {
 -  int id = x->sys.table_id;
 +  u32 *tbl = (x->c.table->addr_type == RT_IPV4) ? nl_table4_cf : nl_table6_cf;
 +  u32 id = x->sys.table_id;
  
 -  if (nl_cf_table[id/8] & (1 << (id%8)))
 +  if (tbl[id/32] & (1 << (id%32)))
      cf_error("Multiple kernel syncers defined for table #%d", id);
 -  nl_cf_table[id/8] |= (1 << (id%8));
++
 +  tbl[id/32] |= (1 << (id%32));
  }
  
  void