Commit 9ddbfbdd authored by Jan Moskyto Matejka's avatar Jan Moskyto Matejka Committed by Ondrej Zajicek (work)
Browse files

Netlink: Allow more than 256 routing tables.

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.
parent 86b4e170
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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) { }
+4 −4
Original line number Diff line number Diff line
@@ -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
+0 −2
Original line number Diff line number Diff line
@@ -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;
   }
 ;
+61 −29
Original line number Diff line number Diff line
@@ -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
@@ -40,6 +42,11 @@
#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)
{
Loading