diff options
Diffstat (limited to 'sysdep/linux')
-rw-r--r-- | sysdep/linux/netlink.c | 108 |
1 files changed, 48 insertions, 60 deletions
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index ee2cd125..6e75ee53 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -20,6 +20,7 @@ #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" +#include "lib/alloca.h" #include "sysdep/unix/timer.h" #include "sysdep/unix/unix.h" #include "sysdep/unix/krt.h" @@ -303,7 +304,6 @@ 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) }, }; static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { @@ -315,7 +315,7 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { #define BIRD_RTA_MAX (RTA_TABLE+1) -static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = { +static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = { [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, }; @@ -472,7 +472,7 @@ nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh) } static void -nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct mpnh *nh) +nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh) { struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH); @@ -492,17 +492,17 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct mpnh *nh) nl_close_attr(h, a); } -static struct mpnh * +static struct nexthop * nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) { /* Temporary buffer for multicast nexthops */ - static struct mpnh *nh_buffer; + static struct nexthop *nh_buffer; static int nh_buf_size; /* in number of structures */ static int nh_buf_used; struct rtattr *a[BIRD_RTA_MAX]; struct rtnexthop *nh = RTA_DATA(ra); - struct mpnh *rv, *first, **last; + struct nexthop *rv, *first, **last; unsigned len = RTA_PAYLOAD(ra); first = NULL; @@ -518,7 +518,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) if (nh_buf_used == nh_buf_size) { nh_buf_size = nh_buf_size ? (nh_buf_size * 2) : 4; - nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct mpnh)); + nh_buffer = xrealloc(nh_buffer, nh_buf_size * sizeof(struct nexthop)); } *last = rv = nh_buffer + nh_buf_used++; rv->next = NULL; @@ -531,7 +531,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) /* Nonexistent RTNH_PAYLOAD ?? */ nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0); - nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a)); + nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a)); if (a[RTA_GATEWAY]) { rv->gw = rta_get_ipa(a[RTA_GATEWAY]); @@ -957,14 +957,14 @@ krt_capable(rte *e) switch (a->dest) { - case RTD_ROUTER: - case RTD_DEVICE: - if (a->iface == NULL) - return 0; + case RTD_UNICAST: + for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) + if (nh->iface) + return 1; + return 0; case RTD_BLACKHOLE: case RTD_UNREACHABLE: case RTD_PROHIBIT: - case RTD_MULTIPATH: break; default: return 0; @@ -973,7 +973,7 @@ krt_capable(rte *e) } static inline int -nh_bufsize(struct mpnh *nh) +nh_bufsize(struct nexthop *nh) { int rv = 0; for (; nh != NULL; nh = nh->next) @@ -982,12 +982,12 @@ nh_bufsize(struct mpnh *nh) } static int -nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int dest, ip_addr gw, struct iface *iface) +nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int dest, struct nexthop *nh) { eattr *ea; net *net = e->net; rta *a = e->attrs; - int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops); + int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh)); u32 priority = 0; struct { @@ -1043,7 +1043,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d if (ea = ea_find(eattrs, EA_KRT_SCOPE)) 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_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); @@ -1071,14 +1071,17 @@ dest: /* a->iface != NULL checked in krt_capable() for router and device routes */ switch (dest) { - case RTD_ROUTER: - 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: + case RTD_UNICAST: r->r.rtm_type = RTN_UNICAST; - nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index); + if (nh->next && !krt_ecmp6(p)) + nl_add_multipath(&r->h, rsize, nh); + else + { + nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index); + + if (ipa_nonzero(nh->gw)) + nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, nh->gw); + } break; case RTD_BLACKHOLE: r->r.rtm_type = RTN_BLACKHOLE; @@ -1089,10 +1092,6 @@ dest: case RTD_PROHIBIT: r->r.rtm_type = RTN_PROHIBIT; break; - case RTD_MULTIPATH: - r->r.rtm_type = RTN_UNICAST; - nl_add_multipath(&r->h, rsize, a->nexthops); - break; case RTD_NONE: break; default: @@ -1109,21 +1108,21 @@ nl_add_rte(struct krt_proto *p, rte *e, struct ea_list *eattrs) rta *a = e->attrs; int err = 0; - if (krt_ecmp6(p) && (a->dest == RTD_MULTIPATH)) + if (krt_ecmp6(p) && a->nh.next) { - struct mpnh *nh = a->nexthops; + struct nexthop *nh = &(a->nh); - err = nl_send_route(p, e, eattrs, NL_OP_ADD, RTD_ROUTER, nh->gw, nh->iface); + err = nl_send_route(p, e, eattrs, NL_OP_ADD, RTD_UNICAST, nh); if (err < 0) return err; for (nh = nh->next; nh; nh = nh->next) - err += nl_send_route(p, e, eattrs, NL_OP_APPEND, RTD_ROUTER, nh->gw, nh->iface); + err += nl_send_route(p, e, eattrs, NL_OP_APPEND, RTD_UNICAST, nh); return err; } - return nl_send_route(p, e, eattrs, NL_OP_ADD, a->dest, a->gw, a->iface); + return nl_send_route(p, e, eattrs, NL_OP_ADD, a->dest, &(a->nh)); } static inline int @@ -1133,7 +1132,7 @@ nl_delete_rte(struct krt_proto *p, rte *e, struct ea_list *eattrs) /* For IPv6, we just repeatedly request DELETE until we get error */ do - err = nl_send_route(p, e, eattrs, NL_OP_DELETE, RTD_NONE, IPA_NONE, NULL); + err = nl_send_route(p, e, eattrs, NL_OP_DELETE, RTD_NONE, NULL); while (krt_ecmp6(p) && !err); return err; @@ -1168,10 +1167,10 @@ krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list } -static inline struct mpnh * -nl_alloc_mpnh(struct nl_parse_state *s, ip_addr gw, struct iface *iface, byte weight) +static inline struct nexthop * +nl_alloc_nexthop(struct nl_parse_state *s, ip_addr gw, struct iface *iface, byte weight) { - struct mpnh *nh = lp_alloc(s->pool, sizeof(struct mpnh)); + struct nexthop *nh = lp_alloc(s->pool, sizeof(struct nexthop)); nh->gw = gw; nh->iface = iface; @@ -1342,7 +1341,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type)) nl_announce_route(s); - rta *ra = lp_allocz(s->pool, sizeof(rta)); + rta *ra = lp_allocz(s->pool, sizeof(rta)); // TODO: fix alloc ra->src = p->p.main_source; ra->source = RTS_INHERIT; ra->scope = SCOPE_UNIVERSE; @@ -1354,19 +1353,19 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET)) { - ra->dest = RTD_MULTIPATH; - ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH]); - if (!ra->nexthops) + struct nexthop *nh = nl_parse_multipath(p, a[RTA_MULTIPATH]); + if (!nh) { log(L_ERR "KRT: Received strange multipath route %N", net->n.addr); return; } + nexthop_link(ra, nh); break; } - ra->iface = if_find_by_index(oif); - if (!ra->iface) + ra->nh.iface = if_find_by_index(oif); + if (!ra->nh.iface) { log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif); return; @@ -1374,28 +1373,23 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (a[RTA_GATEWAY]) { - ra->dest = RTD_ROUTER; - ra->gw = rta_get_ipa(a[RTA_GATEWAY]); + ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]); /* Silently skip strange 6to4 routes */ 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)) + if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit)) return; neighbor *nbr; - nbr = neigh_find2(&p->p, &ra->gw, ra->iface, + nbr = neigh_find2(&p->p, &ra->nh.gw, ra->nh.iface, (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); if (!nbr || (nbr->scope == SCOPE_HOST)) { - log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, ra->gw); + log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, + ra->nh.gw); return; } } - else - { - ra->dest = RTD_DEVICE; - def_scope = RT_SCOPE_LINK; - } break; case RTN_BLACKHOLE: @@ -1510,13 +1504,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) /* Merge next hops with the stored route */ rta *a = s->attrs; - if (a->dest != RTD_MULTIPATH) - { - a->dest = RTD_MULTIPATH; - a->nexthops = nl_alloc_mpnh(s, a->gw, a->iface, 0); - } - - mpnh_insert(&a->nexthops, nl_alloc_mpnh(s, ra->gw, ra->iface, 0)); + nexthop_insert(&a->nh, &ra->nh); } } |