summaryrefslogtreecommitdiff
path: root/sysdep/linux/netlink
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/linux/netlink')
-rw-r--r--sysdep/linux/netlink/krt-iface.h2
-rw-r--r--sysdep/linux/netlink/krt-scan.h1
-rw-r--r--sysdep/linux/netlink/krt-set.h6
-rw-r--r--sysdep/linux/netlink/netlink.Y7
-rw-r--r--sysdep/linux/netlink/netlink.c95
5 files changed, 75 insertions, 36 deletions
diff --git a/sysdep/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h
index 38177b99..b0fbdd15 100644
--- a/sysdep/linux/netlink/krt-iface.h
+++ b/sysdep/linux/netlink/krt-iface.h
@@ -19,7 +19,7 @@ struct krt_if_params {
struct krt_if_status {
};
-static inline void krt_if_preconfig(struct kif_config *c) { };
+static inline void krt_if_construct(struct kif_config *c) { };
static inline void krt_if_shutdown(struct kif_proto *p) { };
static inline void krt_if_io_init(void) { };
diff --git a/sysdep/linux/netlink/krt-scan.h b/sysdep/linux/netlink/krt-scan.h
index cd118de4..0dd3d68c 100644
--- a/sysdep/linux/netlink/krt-scan.h
+++ b/sysdep/linux/netlink/krt-scan.h
@@ -17,6 +17,7 @@
struct krt_scan_params {
int async; /* Allow asynchronous events */
+ int table_id; /* Kernel table ID we sync with */
};
struct krt_scan_status {
diff --git a/sysdep/linux/netlink/krt-set.h b/sysdep/linux/netlink/krt-set.h
index 32fdad0a..48df5ecf 100644
--- a/sysdep/linux/netlink/krt-set.h
+++ b/sysdep/linux/netlink/krt-set.h
@@ -19,8 +19,8 @@ struct krt_set_params {
struct krt_set_status {
};
-static inline void krt_set_preconfig(struct krt_config *c) { };
-static inline void krt_set_start(struct krt_proto *p) { };
-static inline void krt_set_shutdown(struct krt_proto *p) { };
+static inline void krt_set_construct(struct krt_config *c) { };
+static inline void krt_set_start(struct krt_proto *p, int first) { };
+static inline void krt_set_shutdown(struct krt_proto *p, int last) { };
#endif
diff --git a/sysdep/linux/netlink/netlink.Y b/sysdep/linux/netlink/netlink.Y
index b5c45f29..1b9b1e48 100644
--- a/sysdep/linux/netlink/netlink.Y
+++ b/sysdep/linux/netlink/netlink.Y
@@ -10,7 +10,7 @@ CF_HDR
CF_DECLS
-CF_KEYWORDS(ASYNC)
+CF_KEYWORDS(ASYNC, KERNEL, TABLE)
CF_GRAMMAR
@@ -18,6 +18,11 @@ CF_ADDTO(kern_proto, kern_proto nl_item ';')
nl_item:
ASYNC bool { THIS_KRT->scan.async = $2; }
+ | KERNEL TABLE expr {
+ if ($3 <= 0 || $3 >= 255)
+ cf_error("Kernel routing table number out of range");
+ THIS_KRT->scan.table_id = $3;
+ }
;
CF_CODE
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c
index 3daa6f8f..6682dbc2 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink/netlink.c
@@ -24,6 +24,7 @@
#include "lib/unix.h"
#include "lib/krt.h"
#include "lib/socket.h"
+#include "conf/conf.h"
#include <asm/types.h>
#include <linux/netlink.h>
@@ -403,6 +404,8 @@ krt_if_scan(struct kif_proto *p)
* Routes
*/
+static struct krt_proto *nl_table_map[256];
+
int
krt_capable(rte *e)
{
@@ -431,7 +434,7 @@ krt_capable(rte *e)
}
static void
-nl_send_route(rte *e, int new)
+nl_send_route(struct krt_proto *p, rte *e, int new)
{
net *net = e->net;
rta *a = e->attrs;
@@ -453,10 +456,10 @@ nl_send_route(rte *e, int new)
r.r.rtm_family = AF_INET;
r.r.rtm_dst_len = net->n.pxlen;
- r.r.rtm_tos = 0; /* FIXME: Non-zero TOS? */
- r.r.rtm_table = RT_TABLE_MAIN; /* FIXME: Other tables? */
+ r.r.rtm_tos = 0;
+ r.r.rtm_table = KRT_CF->scan.table_id;
r.r.rtm_protocol = RTPROT_BIRD;
- r.r.rtm_scope = RT_SCOPE_UNIVERSE; /* FIXME: Other scopes? */
+ r.r.rtm_scope = RT_SCOPE_UNIVERSE;
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
switch (a->dest)
{
@@ -489,19 +492,22 @@ krt_set_notify(struct krt_proto *p, net *n, rte *new, rte *old)
{
if (old && new)
{
- /* FIXME: Priorities and TOS should be identical as well, but we don't use them yet. */
- nl_send_route(new, 1);
+ /*
+ * We should check whether priority and TOS is identical as well,
+ * but we don't use these and default value is always equal to default value. :-)
+ */
+ nl_send_route(p, new, 1);
}
else
{
if (old)
{
if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
- nl_send_route(old, 0);
+ nl_send_route(p, old, 0);
/* else the kernel has already flushed it */
}
if (new)
- nl_send_route(new, 1);
+ nl_send_route(p, new, 1);
}
}
@@ -524,8 +530,9 @@ krt_temp_iface(struct krt_proto *p, unsigned index)
}
static void
-nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
+nl_parse_route(struct nlmsghdr *h, int scan)
{
+ struct krt_proto *p;
struct rtmsg *i;
struct rtattr *a[RTA_CACHEINFO+1];
int new = h->nlmsg_type == RTM_NEWROUTE;
@@ -549,11 +556,16 @@ nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
return;
}
- if (i->rtm_table != RT_TABLE_MAIN) /* FIXME: What about other tables? */
- return;
- if (i->rtm_tos != 0) /* FIXME: What about TOS? */
+ p = nl_table_map[i->rtm_table]; /* Do we know this table? */
+ if (!p)
return;
+ if (i->rtm_tos != 0) /* We don't support TOS */
+ {
+ DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos);
+ return;
+ }
+
if (scan && !new)
{
DBG("KRT: Ignoring route deletion\n");
@@ -572,7 +584,7 @@ nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
else
oif = ~0;
- DBG("Got %I/%d, type=%d, oif=%d\n", dst, i->rtm_dst_len, i->rtm_type, oif);
+ DBG("Got %I/%d, type=%d, oif=%d, table=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, p->p.name);
switch (i->rtm_protocol)
{
@@ -647,7 +659,7 @@ nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
return;
}
- if (i->rtm_scope != RT_SCOPE_UNIVERSE) /* FIXME: Other scopes? */
+ if (i->rtm_scope != RT_SCOPE_UNIVERSE)
{
DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);
return;
@@ -669,14 +681,14 @@ nl_parse_route(struct krt_proto *p, struct nlmsghdr *h, int scan)
}
void
-krt_scan_fire(struct krt_proto *p)
+krt_scan_fire(struct krt_proto *p) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
{
struct nlmsghdr *h;
nl_request_dump(RTM_GETROUTE);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
- nl_parse_route(p, h, 1);
+ nl_parse_route(h, 1);
else
log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
}
@@ -689,14 +701,14 @@ static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */
static byte *nl_async_rx_buffer; /* Receive buffer */
static void
-nl_async_msg(struct krt_proto *p, struct nlmsghdr *h)
+nl_async_msg(struct nlmsghdr *h)
{
switch (h->nlmsg_type)
{
case RTM_NEWROUTE:
case RTM_DELROUTE:
DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
- nl_parse_route(p, h, 0);
+ nl_parse_route(h, 0);
break;
case RTM_NEWLINK:
case RTM_DELLINK:
@@ -716,7 +728,6 @@ nl_async_msg(struct krt_proto *p, struct nlmsghdr *h)
static int
nl_async_hook(sock *sk, int size)
{
- struct krt_proto *p = sk->data;
struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
struct sockaddr_nl sa;
struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
@@ -746,7 +757,7 @@ nl_async_hook(sock *sk, int size)
}
while (NLMSG_OK(h, len))
{
- nl_async_msg(p, h);
+ nl_async_msg(h);
h = NLMSG_NEXT(h, len);
}
if (len)
@@ -755,7 +766,7 @@ nl_async_hook(sock *sk, int size)
}
static void
-nl_open_async(struct krt_proto *p)
+nl_open_async(void)
{
sock *sk;
struct sockaddr_nl sa;
@@ -766,7 +777,7 @@ nl_open_async(struct krt_proto *p)
fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0)
{
- log(L_ERR "Unable to open secondary rtnetlink socket: %m");
+ log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
return;
}
@@ -775,13 +786,12 @@ nl_open_async(struct krt_proto *p)
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
{
- log(L_ERR "Unable to bind secondary rtnetlink socket: %m");
+ log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
return;
}
- sk = nl_async_sk = sk_new(p->p.pool);
+ sk = nl_async_sk = sk_new(krt_pool);
sk->type = SK_MAGIC;
- sk->data = p;
sk->rx_hook = nl_async_hook;
sk->fd = fd;
if (sk_open(sk))
@@ -795,24 +805,47 @@ nl_open_async(struct krt_proto *p)
* Interface to the UNIX krt module
*/
+static u8 nl_cf_table[256 / 8];
+
void
-krt_scan_preconfig(struct krt_config *x)
+krt_scan_preconfig(struct config *c)
+{
+ bzero(&nl_cf_table, sizeof(nl_cf_table));
+}
+
+void
+krt_scan_postconfig(struct krt_config *x)
+{
+ int id = x->scan.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_scan_construct(struct krt_config *x)
{
x->scan.async = 1;
+ x->scan.table_id = RT_TABLE_MAIN;
/* FIXME: Use larger defaults for scanning times? */
}
void
-krt_scan_start(struct krt_proto *p)
+krt_scan_start(struct krt_proto *p, int first)
{
init_list(&p->scan.temp_ifs);
- nl_open();
- if (KRT_CF->scan.async) /* FIXME: Async is for debugging only. Get rid of it some day. */
- nl_open_async(p);
+ nl_table_map[KRT_CF->scan.table_id] = p;
+ if (first)
+ {
+ nl_open();
+ if (KRT_CF->scan.async) /* FIXME: Async is for debugging only. Get rid of it some day. */
+ nl_open_async();
+ }
}
void
-krt_scan_shutdown(struct krt_proto *p)
+krt_scan_shutdown(struct krt_proto *p, int last)
{
}