);
}
++
+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))
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;
}
#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);
}
}
+
+ /* 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();
}
}
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;
}