summaryrefslogtreecommitdiff
path: root/sysdep/linux/netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/linux/netlink.c')
-rw-r--r--sysdep/linux/netlink.c470
1 files changed, 290 insertions, 180 deletions
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 22313f43..554f2c97 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -6,6 +6,7 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
+#include <alloca.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
@@ -19,9 +20,9 @@
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
-#include "lib/timer.h"
-#include "lib/unix.h"
-#include "lib/krt.h"
+#include "sysdep/unix/timer.h"
+#include "sysdep/unix/unix.h"
+#include "sysdep/unix/krt.h"
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/hash.h"
@@ -50,11 +51,7 @@
#endif
-#ifdef IPV6
-#define krt_ecmp6(X) 1
-#else
-#define krt_ecmp6(X) 0
-#endif
+#define krt_ecmp6(p) ((p)->af == AF_INET6)
/*
* Structure nl_parse_state keeps state of received route processing. Ideally,
@@ -302,20 +299,18 @@ static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
#define BIRD_IFA_MAX (IFA_FLAGS+1)
-#ifndef IPV6
static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = {
[IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) },
[IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) },
[IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
[IFA_FLAGS] = { 1, 1, sizeof(u32) },
};
-#else
+
static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
[IFA_ADDRESS] = { 1, 1, sizeof(ip6_addr) },
[IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) },
[IFA_FLAGS] = { 1, 1, sizeof(u32) },
};
-#endif
#define BIRD_RTA_MAX (RTA_TABLE+1)
@@ -324,7 +319,6 @@ static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
};
-#ifndef IPV6
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
[RTA_DST] = { 1, 1, sizeof(ip4_addr) },
[RTA_OIF] = { 1, 1, sizeof(u32) },
@@ -336,7 +330,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
};
-#else
+
static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
[RTA_DST] = { 1, 1, sizeof(ip6_addr) },
[RTA_IIF] = { 1, 1, sizeof(u32) },
@@ -348,7 +342,6 @@ static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
};
-#endif
static int
@@ -364,7 +357,7 @@ nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k,
if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
{
- log(L_ERR "nl_parse_attrs: Malformed message received");
+ log(L_ERR "nl_parse_attrs: Malformed attribute received");
return 0;
}
@@ -389,6 +382,13 @@ static inline ip4_addr rta_get_ip4(struct rtattr *a)
static inline ip6_addr rta_get_ip6(struct rtattr *a)
{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
+static inline ip_addr rta_get_ipa(struct rtattr *a)
+{
+ if (RTA_PAYLOAD(a) == sizeof(ip4_addr))
+ return ipa_from_ip4(rta_get_ip4(a));
+ else
+ return ipa_from_ip6(rta_get_ip6(a));
+}
struct rtattr *
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
@@ -411,16 +411,32 @@ nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint
}
static inline void
-nl_add_attr_u32(struct nlmsghdr *h, unsigned bufsize, int code, u32 data)
+nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
{
nl_add_attr(h, bufsize, code, &data, 4);
}
static inline void
-nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
+nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4)
+{
+ ip4 = ip4_hton(ip4);
+ nl_add_attr(h, bufsize, code, &ip4, sizeof(ip4));
+}
+
+static inline void
+nl_add_attr_ip6(struct nlmsghdr *h, uint bufsize, int code, ip6_addr ip6)
{
- ipa_hton(ipa);
- nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
+ ip6 = ip6_hton(ip6);
+ nl_add_attr(h, bufsize, code, &ip6, sizeof(ip6));
+}
+
+static inline void
+nl_add_attr_ipa(struct nlmsghdr *h, uint bufsize, int code, ip_addr ipa)
+{
+ if (ipa_is_ip4(ipa))
+ nl_add_attr_ip4(h, bufsize, code, ipa_to_ip4(ipa));
+ else
+ nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa));
}
static inline struct rtattr *
@@ -456,7 +472,7 @@ nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
}
static void
-nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
+nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct mpnh *nh)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
@@ -518,12 +534,12 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a));
if (a[RTA_GATEWAY])
{
- memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ip_addr));
- ipa_ntoh(rv->gw);
+ rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
- neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
- (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
- if (!ng || (ng->scope == SCOPE_HOST))
+ neighbor *nbr;
+ nbr = neigh_find2(&p->p, &rv->gw, rv->iface,
+ (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
return NULL;
}
else
@@ -658,52 +674,131 @@ nl_parse_link(struct nlmsghdr *h, int scan)
}
static void
-nl_parse_addr(struct nlmsghdr *h, int scan)
+nl_parse_addr4(struct ifaddrmsg *i, int scan, int new)
{
- struct ifaddrmsg *i;
struct rtattr *a[BIRD_IFA_MAX];
- int new = h->nlmsg_type == RTM_NEWADDR;
- struct ifa ifa;
struct iface *ifi;
- int scope;
u32 ifa_flags;
+ int scope;
- if (!(i = nl_checkin(h, sizeof(*i))))
+ if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
return;
- switch (i->ifa_family)
+ if (!a[IFA_LOCAL])
{
-#ifndef IPV6
- case AF_INET:
- if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
- return;
- if (!a[IFA_LOCAL])
- {
- log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
- return;
- }
- break;
-#else
- case AF_INET6:
- if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
- return;
- break;
-#endif
- default:
- return;
+ log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
+ return;
}
-
if (!a[IFA_ADDRESS])
{
log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
return;
}
+ ifi = if_find_by_index(i->ifa_index);
+ if (!ifi)
+ {
+ log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
+ return;
+ }
+
if (a[IFA_FLAGS])
ifa_flags = rta_get_u32(a[IFA_FLAGS]);
else
ifa_flags = i->ifa_flags;
+ struct ifa ifa;
+ bzero(&ifa, sizeof(ifa));
+ ifa.iface = ifi;
+ if (ifa_flags & IFA_F_SECONDARY)
+ ifa.flags |= IA_SECONDARY;
+
+ ifa.ip = rta_get_ipa(a[IFA_LOCAL]);
+
+ if (i->ifa_prefixlen > IP4_MAX_PREFIX_LENGTH)
+ {
+ log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
+ new = 0;
+ }
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH)
+ {
+ ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
+ net_fill_ip4(&ifa.prefix, rta_get_ip4(a[IFA_ADDRESS]), i->ifa_prefixlen);
+
+ /* It is either a host address or a peer address */
+ if (ipa_equal(ifa.ip, ifa.brd))
+ ifa.flags |= IA_HOST;
+ else
+ {
+ ifa.flags |= IA_PEER;
+ ifa.opposite = ifa.brd;
+ }
+ }
+ else
+ {
+ net_fill_ip4(&ifa.prefix, ipa_to_ip4(ifa.ip), i->ifa_prefixlen);
+ net_normalize(&ifa.prefix);
+
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 1)
+ ifa.opposite = ipa_opposite_m1(ifa.ip);
+
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 2)
+ ifa.opposite = ipa_opposite_m2(ifa.ip);
+
+ if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
+ {
+ ip4_addr xbrd = rta_get_ip4(a[IFA_BROADCAST]);
+ ip4_addr ybrd = ip4_or(ipa_to_ip4(ifa.ip), ip4_not(ip4_mkmask(i->ifa_prefixlen)));
+
+ if (ip4_equal(xbrd, net4_prefix(&ifa.prefix)) || ip4_equal(xbrd, ybrd))
+ ifa.brd = ipa_from_ip4(xbrd);
+ else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
+ {
+ log(L_ERR "KIF: Invalid broadcast address %I4 for %s", xbrd, ifi->name);
+ ifa.brd = ipa_from_ip4(ybrd);
+ }
+ }
+ }
+
+ scope = ipa_classify(ifa.ip);
+ if (scope < 0)
+ {
+ log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
+ return;
+ }
+ ifa.scope = scope & IADDR_SCOPE_MASK;
+
+ DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
+ ifi->index, ifi->name,
+ new ? "added" : "removed",
+ ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
+
+ if (new)
+ ifa_update(&ifa);
+ else
+ ifa_delete(&ifa);
+
+ if (!scan)
+ if_end_partial_update(ifi);
+}
+
+static void
+nl_parse_addr6(struct ifaddrmsg *i, int scan, int new)
+{
+ struct rtattr *a[BIRD_IFA_MAX];
+ struct iface *ifi;
+ u32 ifa_flags;
+ int scope;
+
+ if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
+ return;
+
+ if (!a[IFA_ADDRESS])
+ {
+ log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
+ return;
+ }
+
ifi = if_find_by_index(i->ifa_index);
if (!ifi)
{
@@ -711,65 +806,50 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
return;
}
+ if (a[IFA_FLAGS])
+ ifa_flags = rta_get_u32(a[IFA_FLAGS]);
+ else
+ ifa_flags = i->ifa_flags;
+
+ struct ifa ifa;
bzero(&ifa, sizeof(ifa));
ifa.iface = ifi;
if (ifa_flags & IFA_F_SECONDARY)
ifa.flags |= IA_SECONDARY;
-#ifdef IPV6
/* Ignore tentative addresses silently */
if (ifa_flags & IFA_F_TENTATIVE)
return;
-#endif
/* IFA_LOCAL can be unset for IPv6 interfaces */
- memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
- ipa_ntoh(ifa.ip);
- ifa.pxlen = i->ifa_prefixlen;
- if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
+ ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_ADDRESS]);
+
+ if (i->ifa_prefixlen > IP6_MAX_PREFIX_LENGTH)
{
log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
new = 0;
}
- if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
+ if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH)
{
- ip_addr addr;
- memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr));
- ipa_ntoh(addr);
- ifa.prefix = ifa.brd = addr;
+ ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
+ net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen);
/* It is either a host address or a peer address */
- if (ipa_equal(ifa.ip, addr))
+ if (ipa_equal(ifa.ip, ifa.brd))
ifa.flags |= IA_HOST;
else
{
ifa.flags |= IA_PEER;
- ifa.opposite = addr;
+ ifa.opposite = ifa.brd;
}
}
else
{
- ip_addr netmask = ipa_mkmask(ifa.pxlen);
- ifa.prefix = ipa_and(ifa.ip, netmask);
- ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
- if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
- ifa.opposite = ipa_opposite_m1(ifa.ip);
+ net_fill_ip6(&ifa.prefix, ipa_to_ip6(ifa.ip), i->ifa_prefixlen);
+ net_normalize(&ifa.prefix);
-#ifndef IPV6
- if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
- ifa.opposite = ipa_opposite_m2(ifa.ip);
-
- if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
- {
- ip_addr xbrd;
- memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
- ipa_ntoh(xbrd);
- if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
- ifa.brd = xbrd;
- else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
- log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
- }
-#endif
+ if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH - 1)
+ ifa.opposite = ipa_opposite_m1(ifa.ip);
}
scope = ipa_classify(ifa.ip);
@@ -780,10 +860,10 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
}
ifa.scope = scope & IADDR_SCOPE_MASK;
- DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
+ DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
ifi->index, ifi->name,
new ? "added" : "removed",
- ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
+ ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
if (new)
ifa_update(&ifa);
@@ -794,6 +874,26 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
if_end_partial_update(ifi);
}
+static void
+nl_parse_addr(struct nlmsghdr *h, int scan)
+{
+ struct ifaddrmsg *i;
+
+ if (!(i = nl_checkin(h, sizeof(*i))))
+ return;
+
+ int new = (h->nlmsg_type == RTM_NEWADDR);
+
+ switch (i->ifa_family)
+ {
+ case AF_INET:
+ return nl_parse_addr4(i, scan, new);
+
+ case AF_INET6:
+ return nl_parse_addr6(i, scan, new);
+ }
+}
+
void
kif_do_scan(struct kif_proto *p UNUSED)
{
@@ -808,7 +908,14 @@ kif_do_scan(struct kif_proto *p UNUSED)
else
log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
- nl_request_dump(BIRD_AF, RTM_GETADDR);
+ nl_request_dump(AF_INET, RTM_GETADDR);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
+ nl_parse_addr(h, 1);
+ else
+ log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
+
+ nl_request_dump(AF_INET6, RTM_GETADDR);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
nl_parse_addr(h, 1);
@@ -830,10 +937,10 @@ krt_table_id(struct krt_proto *p)
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_KEY(p) p->af, krt_table_id(p)
+#define RTH_NEXT(p) p->sys.hash_next
+#define RTH_EQ(a1,i1,a2,i2) a1 == a2 && i1 == i2
+#define RTH_FN(a,i) a ^ u32_hash(i)
#define RTH_REHASH rth_rehash
#define RTH_PARAMS /8, *2, 2, 2, 6, 20
@@ -880,27 +987,31 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
eattr *ea;
net *net = e->net;
rta *a = e->attrs;
+ int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops);
u32 priority = 0;
struct {
struct nlmsghdr h;
struct rtmsg r;
- char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
- } r;
+ char buf[0];
+ } *r;
+
+ int rsize = sizeof(*r) + bufsize;
+ r = alloca(rsize);
- DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op);
+ DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op);
- bzero(&r.h, sizeof(r.h));
- bzero(&r.r, sizeof(r.r));
- r.h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
- r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- r.h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
+ bzero(&r->h, sizeof(r->h));
+ bzero(&r->r, sizeof(r->r));
+ r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
+ r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
- r.r.rtm_family = BIRD_AF;
- r.r.rtm_dst_len = net->n.pxlen;
- r.r.rtm_protocol = RTPROT_BIRD;
- r.r.rtm_scope = RT_SCOPE_NOWHERE;
- nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
+ r->r.rtm_family = p->af;
+ r->r.rtm_dst_len = net_pxlen(net->n.addr);
+ r->r.rtm_protocol = RTPROT_BIRD;
+ r->r.rtm_scope = RT_SCOPE_UNIVERSE;
+ nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
/*
* Strange behavior for RTM_DELROUTE:
@@ -910,9 +1021,9 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
*/
if (krt_table_id(p) < 256)
- r.r.rtm_table = krt_table_id(p);
+ r->r.rtm_table = krt_table_id(p);
else
- nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));
+ nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p));
if (a->source == RTS_DUMMY)
priority = e->u.krt.metric;
@@ -922,7 +1033,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
priority = ea->u.data;
if (priority)
- nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority);
+ nl_add_attr_u32(&r->h, sizeof(r), RTA_PRIORITY, priority);
/* For route delete, we do not specify remaining route attributes */
if (op == NL_OP_DELETE)
@@ -930,15 +1041,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
/* Default scope is LINK for device routes, UNIVERSE otherwise */
if (ea = ea_find(eattrs, EA_KRT_SCOPE))
- r.r.rtm_scope = ea->u.data;
+ r->r.rtm_scope = ea->u.data;
else
- r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
+ r->r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
- nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
+ nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
if (ea = ea_find(eattrs, EA_KRT_REALM))
- nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
+ nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
u32 metrics[KRT_METRICS_MAX];
@@ -953,7 +1064,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
}
if (metrics[0])
- nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
+ nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX);
dest:
@@ -961,26 +1072,26 @@ dest:
switch (dest)
{
case RTD_ROUTER:
- r.r.rtm_type = RTN_UNICAST;
- nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
- nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, gw);
+ r->r.rtm_type = RTN_UNICAST;
+ nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
+ nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, gw);
break;
case RTD_DEVICE:
- r.r.rtm_type = RTN_UNICAST;
- nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
+ r->r.rtm_type = RTN_UNICAST;
+ nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
break;
case RTD_BLACKHOLE:
- r.r.rtm_type = RTN_BLACKHOLE;
+ r->r.rtm_type = RTN_BLACKHOLE;
break;
case RTD_UNREACHABLE:
- r.r.rtm_type = RTN_UNREACHABLE;
+ r->r.rtm_type = RTN_UNREACHABLE;
break;
case RTD_PROHIBIT:
- r.r.rtm_type = RTN_PROHIBIT;
+ r->r.rtm_type = RTN_PROHIBIT;
break;
case RTD_MULTIPATH:
- r.r.rtm_type = RTN_UNICAST;
- nl_add_multipath(&r.h, sizeof(r), a->nexthops);
+ r->r.rtm_type = RTN_UNICAST;
+ nl_add_multipath(&r->h, rsize, a->nexthops);
break;
case RTD_NONE:
break;
@@ -989,7 +1100,7 @@ dest:
}
/* Ignore missing for DELETE */
- return nl_exchange(&r.h, (op == NL_OP_DELETE));
+ return nl_exchange(&r->h, (op == NL_OP_DELETE));
}
static inline int
@@ -1137,9 +1248,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
struct rtattr *a[BIRD_RTA_MAX];
int new = h->nlmsg_type == RTM_NEWROUTE;
- ip_addr dst = IPA_NONE;
+ net_addr dst;
u32 oif = ~0;
- u32 table;
+ u32 table_id;
u32 priority = 0;
u32 def_scope = RT_SCOPE_UNIVERSE;
int src;
@@ -1149,47 +1260,48 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
switch (i->rtm_family)
{
-#ifndef IPV6
- case AF_INET:
- if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a)))
- return;
- break;
-#else
- case AF_INET6:
- if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
- return;
- break;
-#endif
- default:
+ case AF_INET:
+ if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a)))
return;
- }
- if (a[RTA_DST])
- {
- memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
- ipa_ntoh(dst);
+ if (a[RTA_DST])
+ net_fill_ip4(&dst, rta_get_ip4(a[RTA_DST]), i->rtm_dst_len);
+ else
+ net_fill_ip4(&dst, IP4_NONE, 0);
+ break;
+
+ case AF_INET6:
+ if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
+ return;
+
+ if (a[RTA_DST])
+ net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
+ else
+ net_fill_ip6(&dst, IP6_NONE, 0);
+ break;
+
+ default:
+ return;
}
if (a[RTA_OIF])
oif = rta_get_u32(a[RTA_OIF]);
if (a[RTA_TABLE])
- table = rta_get_u32(a[RTA_TABLE]);
+ table_id = rta_get_u32(a[RTA_TABLE]);
else
- table = i->rtm_table;
+ table_id = 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)");
+ /* Do we know this table? */
+ p = HASH_FIND(nl_table_map, RTH, i->rtm_family, table_id);
if (!p)
SKIP("unknown table %d\n", table);
-#ifdef IPV6
if (a[RTA_IIF])
SKIP("IIF set\n");
-#else
+
if (i->rtm_tos != 0) /* We don't support TOS */
SKIP("TOS %02x\n", i->rtm_tos);
-#endif
if (s->scan && !new)
SKIP("RTM_DELROUTE in scan\n");
@@ -1197,7 +1309,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_PRIORITY])
priority = rta_get_u32(a[RTA_PRIORITY]);
- int c = ipa_classify_net(dst);
+ int c = net_classify(&dst);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
SKIP("strange class/scope\n");
@@ -1225,7 +1337,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
src = KRT_SRC_ALIEN;
}
- net *net = net_get(p->p.table, dst, i->rtm_dst_len);
+ net *net = net_get(p->p.main_channel->table, &dst);
if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
nl_announce_route(s);
@@ -1246,8 +1358,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]);
if (!ra->nexthops)
{
- log(L_ERR "KRT: Received strange multipath route %I/%d",
- net->n.prefix, net->n.pxlen);
+ log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
return;
}
@@ -1257,30 +1368,26 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ra->iface = if_find_by_index(oif);
if (!ra->iface)
{
- log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
- net->n.prefix, net->n.pxlen, oif);
+ log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
return;
}
if (a[RTA_GATEWAY])
{
- neighbor *ng;
ra->dest = RTD_ROUTER;
- memcpy(&ra->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra->gw));
- ipa_ntoh(ra->gw);
+ ra->gw = rta_get_ipa(a[RTA_GATEWAY]);
-#ifdef IPV6
/* Silently skip strange 6to4 routes */
- if (ipa_in_net(ra->gw, IPA_NONE, 96))
+ const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
+ if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->gw, (net_addr *) &sit))
return;
-#endif
- ng = neigh_find2(&p->p, &ra->gw, ra->iface,
- (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
- if (!ng || (ng->scope == SCOPE_HOST))
+ neighbor *nbr;
+ nbr = neigh_find2(&p->p, &ra->gw, ra->iface,
+ (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
{
- log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
- net->n.prefix, net->n.pxlen, ra->gw);
+ log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, ra->gw);
return;
}
}
@@ -1321,9 +1428,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_PREFSRC])
{
- ip_addr ps;
- memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
- ipa_ntoh(ps);
+ ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
ea->next = ra->eattrs;
@@ -1359,8 +1464,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
{
- log(L_ERR "KRT: Received route %I/%d with strange RTA_METRICS attribute",
- net->n.prefix, net->n.pxlen);
+ log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
return;
}
@@ -1422,15 +1526,22 @@ krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NUL
struct nlmsghdr *h;
struct nl_parse_state s;
- nl_parse_begin(&s, 1, krt_ecmp6(p));
-
- nl_request_dump(BIRD_AF, RTM_GETROUTE);
+ nl_parse_begin(&s, 1, 0);
+ nl_request_dump(AF_INET, RTM_GETROUTE);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
nl_parse_route(&s, h);
else
log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
+ nl_parse_end(&s);
+ nl_parse_begin(&s, 1, 1);
+ nl_request_dump(AF_INET6, RTM_GETROUTE);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
+ nl_parse_route(&s, h);
+ else
+ log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
nl_parse_end(&s);
}
@@ -1553,11 +1664,10 @@ nl_open_async(void)
bzero(&sa, sizeof(sa));
sa.nl_family = AF_NETLINK;
-#ifdef IPV6
- sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
-#else
- sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
-#endif
+ sa.nl_groups = RTMGRP_LINK |
+ RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
+ RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
+
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
{
log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
@@ -1591,7 +1701,7 @@ krt_sys_io_init(void)
int
krt_sys_start(struct krt_proto *p)
{
- struct krt_proto *old = HASH_FIND(nl_table_map, RTH, krt_table_id(p));
+ struct krt_proto *old = HASH_FIND(nl_table_map, RTH, p->af, krt_table_id(p));
if (old)
{