]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Netlink: Allow more than 256 routing tables.
authorJan Moskyto Matejka <mq@ucw.cz>
Tue, 3 Nov 2015 13:42:41 +0000 (14:42 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Wed, 11 Nov 2015 10:40:49 +0000 (11:40 +0100)
Since 2.6.19, the netlink API defines RTA_TABLE routing attribute to
allow 32-bit routing table IDs. Using this attribute to index routing
tables at Linux, instead of 8-bit rtm_table field.

sysdep/bsd/krt-sock.c
sysdep/bsd/krt-sys.h
sysdep/linux/krt-sys.h
sysdep/linux/netlink.Y
sysdep/linux/netlink.c
sysdep/unix/krt.c
sysdep/unix/krt.h

index 064bae18fca73338e201886e3499b8c668a86181..29203d1b8168a4ea5d76637d43d7d2a73f765df9 100644 (file)
@@ -970,13 +970,15 @@ krt_sock_close_shared(void)
   }
 }
 
-void
+int
 krt_sys_start(struct krt_proto *p)
 {
   krt_table_map[KRT_CF->sys.table_id] = p;
 
   krt_sock_open_shared();
   p->sys.sk = krt_sock;
+
+  return 1;
 }
 
 void
@@ -992,10 +994,11 @@ krt_sys_shutdown(struct krt_proto *p)
 
 #else
 
-void
+int
 krt_sys_start(struct krt_proto *p)
 {
   p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
+  return 1;
 }
 
 void
index 2c6e35c537a1453c7c6b0ebe85a2c44ba3d1b2e3..a63f8caf9efe02f6757bac007985b16f8d3f650d 100644 (file)
@@ -42,6 +42,7 @@ struct krt_state {
 };
 
 
+static inline void krt_sys_io_init(void) { }
 static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
 
 static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { }
index e32e4fe1c2686b5840c92d16eb2ca7caeedbd34b..7fd5f1396c487566b140f7c49049cd2fddf3507b 100644 (file)
@@ -84,18 +84,18 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; }
 #define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3)
 
 
-
-#define NL_NUM_TABLES 256
-
 struct krt_params {
-  int table_id;                                /* Kernel table ID we sync with */
+  u32 table_id;                                /* Kernel table ID we sync with */
 };
 
 struct krt_state {
+  struct krt_proto *hash_next;
 };
 
 
 static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
+static inline void krt_sys_preconfig(struct config *c UNUSED) { }
+static inline void krt_sys_postconfig(struct krt_config *x UNUSED) { }
 
 
 #endif
index f8137e23f748daa66e479e4443c0492b6b3e9d85..e9c225a202335f06aa75f81b14730b031604400c 100644 (file)
@@ -23,8 +23,6 @@ CF_ADDTO(kern_proto, kern_proto kern_sys_item ';')
 
 kern_sys_item:
    KERNEL TABLE expr {
-       if ($3 <= 0 || $3 >= NL_NUM_TABLES)
-         cf_error("Kernel routing table number out of range");
        THIS_KRT->sys.table_id = $3;
    }
  ;
index 674d338b0221fb8c76572cf7c7809fc6760e7bde..db9989267b6cd731a28608fc3869fbf085006f24 100644 (file)
@@ -25,6 +25,7 @@
 #include "lib/krt.h"
 #include "lib/socket.h"
 #include "lib/string.h"
+#include "lib/hash.h"
 #include "conf/conf.h"
 
 #include <asm/types.h>
@@ -32,6 +33,7 @@
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
+
 #ifndef MSG_TRUNC                      /* Hack: Several versions of glibc miss this one :( */
 #define MSG_TRUNC 0x20
 #endif
 #define IFF_LOWER_UP 0x10000
 #endif
 
+#ifndef RTA_TABLE
+#define RTA_TABLE  15
+#endif
+
+
 /*
  *     Synchronous Netlink interface
  */
@@ -650,7 +657,23 @@ kif_do_scan(struct kif_proto *p UNUSED)
  *     Routes
  */
 
-static struct krt_proto *nl_table_map[NL_NUM_TABLES];
+static inline u32
+krt_table_id(struct krt_proto *p)
+{
+  return KRT_CF->sys.table_id;
+}
+
+static HASH(struct krt_proto) nl_table_map;
+
+#define RTH_FN(k)      u32_hash(k)
+#define RTH_EQ(k1,k2)  k1 == k2
+#define RTH_KEY(p)     krt_table_id(p)
+#define RTH_NEXT(p)    p->sys.hash_next
+
+#define RTH_REHASH             rth_rehash
+#define RTH_PARAMS             /8, *2, 2, 2, 6, 20
+
+HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
 
 int
 krt_capable(rte *e)
@@ -708,12 +731,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
 
   r.r.rtm_family = BIRD_AF;
   r.r.rtm_dst_len = net->n.pxlen;
-  r.r.rtm_tos = 0;
-  r.r.rtm_table = KRT_CF->sys.table_id;
   r.r.rtm_protocol = RTPROT_BIRD;
   r.r.rtm_scope = RT_SCOPE_UNIVERSE;
   nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
 
+  if (krt_table_id(p) < 256)
+    r.r.rtm_table = krt_table_id(p);
+  else
+    nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));
+
   /* For route delete, we do not specify route attributes */
   if (!new)
     return nl_exchange(&r.h);
@@ -809,11 +835,12 @@ nl_parse_route(struct nlmsghdr *h, int scan)
 {
   struct krt_proto *p;
   struct rtmsg *i;
-  struct rtattr *a[RTA_CACHEINFO+1];
+  struct rtattr *a[RTA_TABLE+1];
   int new = h->nlmsg_type == RTM_NEWROUTE;
 
   ip_addr dst = IPA_NONE;
   u32 oif = ~0;
+  u32 table;
   int src;
 
   if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))
@@ -825,6 +852,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
       (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||
 #endif
       (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||
+      (a[RTA_TABLE] && RTA_PAYLOAD(a[RTA_TABLE]) != 4) ||
       (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) ||
       (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||
       (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) ||
@@ -843,10 +871,15 @@ nl_parse_route(struct nlmsghdr *h, int scan)
   if (a[RTA_OIF])
     oif = rta_get_u32(a[RTA_OIF]);
 
-  p = nl_table_map[i->rtm_table];      /* Do we know this table? */
-  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)");
+  if (a[RTA_TABLE])
+    table = rta_get_u32(a[RTA_TABLE]);
+  else
+    table = i->rtm_table;
+
+  p = HASH_FIND(nl_table_map, RTH, table); /* Do we know this table? */
+  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, table, i->rtm_protocol, p ? p->p.name : "(none)");
   if (!p)
-    SKIP("unknown table %d\n", i->rtm_table);
+    SKIP("unknown table %d\n", table);
 
 
 #ifdef IPV6
@@ -1186,25 +1219,41 @@ nl_open_async(void)
     bug("Netlink: sk_open failed");
 }
 
+
 /*
  *     Interface to the UNIX krt module
  */
 
-static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
-
 void
+krt_sys_io_init(void)
+{
+  HASH_INIT(nl_table_map, krt_pool, 6);
+}
+
+int
 krt_sys_start(struct krt_proto *p)
 {
-  nl_table_map[KRT_CF->sys.table_id] = p;
+  struct krt_proto *old = HASH_FIND(nl_table_map, RTH, krt_table_id(p));
+
+  if (old)
+    {
+      log(L_ERR "%s: Kernel table %u already registered by %s",
+         p->p.name, krt_table_id(p), old->p.name);
+      return 0;
+    }
+
+  HASH_INSERT2(nl_table_map, RTH, krt_pool, p);
 
   nl_open();
   nl_open_async();
+
+  return 1;
 }
 
 void
-krt_sys_shutdown(struct krt_proto *p UNUSED)
+krt_sys_shutdown(struct krt_proto *p)
 {
-  nl_table_map[KRT_CF->sys.table_id] = NULL;
+  HASH_REMOVE2(nl_table_map, RTH, krt_pool, p);
 }
 
 int
@@ -1213,23 +1262,6 @@ krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt
   return n->sys.table_id == o->sys.table_id;
 }
 
-
-void
-krt_sys_preconfig(struct config *c UNUSED)
-{
-  bzero(&nl_cf_table, sizeof(nl_cf_table));
-}
-
-void
-krt_sys_postconfig(struct krt_config *x)
-{
-  int id = x->sys.table_id;
-
-  if (nl_cf_table[id/8] & (1 << (id%8)))
-    cf_error("Multiple kernel syncers defined for table #%d", id);
-  nl_cf_table[id/8] |= (1 << (id%8));
-}
-
 void
 krt_sys_init_config(struct krt_config *cf)
 {
index 2eab5cb2e46c260fdae6eb63a9acbea2fc959015..49bf9519d19e5fc606eb997f357194a9af26bb17 100644 (file)
@@ -77,6 +77,7 @@ krt_io_init(void)
   krt_pool = rp_new(&root_pool, "Kernel Syncer");
   krt_filter_lp = lp_new(krt_pool, 4080);
   init_list(&krt_proto_list);
+  krt_sys_io_init();
 }
 
 /*
@@ -1126,7 +1127,11 @@ krt_start(struct proto *P)
   krt_learn_init(p);
 #endif
 
-  krt_sys_start(p);
+  if (!krt_sys_start(p))
+  {
+    rem_node(&p->krt_node);
+    return PS_START;
+  }
 
   krt_scan_timer_start(p);
 
@@ -1150,8 +1155,10 @@ krt_shutdown(struct proto *P)
   p->ready = 0;
   p->initialized = 0;
 
-  krt_sys_shutdown(p);
+  if (p->p.proto_state == PS_START)
+    return PS_DOWN;
 
+  krt_sys_shutdown(p);
   rem_node(&p->krt_node);
 
   return PS_DOWN;
index 9d5d4e8cc16c7016e0314233f5c7cd10ecea5ca7..aea20102a891a036289bbc474f0c65c181248623 100644 (file)
@@ -119,8 +119,9 @@ struct proto_config * krt_init_config(int class);
 
 /* krt sysdep */
 
+void krt_sys_io_init(void);
 void krt_sys_init(struct krt_proto *);
-void krt_sys_start(struct krt_proto *);
+int krt_sys_start(struct krt_proto *);
 void krt_sys_shutdown(struct krt_proto *);
 int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o);