Hi Ondrej, Any update/feedback regarding this latest patch? I'm opened for further discussions and adjustments if you feel they are needed.
Thanks, Mikhail 2016-02-22 13:01 GMT+01:00 Mikhail Sennikovskii < [email protected]>: > The API for configuring ECMP for IPv6 on Linux is not symmetrical. > Routes can be set via the multipath structures, but Linux kernel > splits this up into separate routes internally. > As a result, ECMP routes are retorned as separate independent > routes when queried. > This patch works around this issue by making bird collect > individual routes for the same destination in one multipath route. > It also implements deletion of multipath routes as a set of > delete operations for each route entry. > Asynchronous motification are still not supported for now. > > Signed-off-by: Mikhail Sennikovskii <[email protected] > > > --- > nest/route.h | 2 + > nest/rt-attr.c | 145 +++++++++++++++++++ > nest/rt-table.c | 41 +++++- > sysdep/linux/netlink.c | 371 > +++++++++++++++++++++++++++++++++++++++++++------ > 4 files changed, 512 insertions(+), 47 deletions(-) > > diff --git a/nest/route.h b/nest/route.h > index c435b9e..3b87a0e 100644 > --- a/nest/route.h > +++ b/nest/route.h > @@ -498,6 +498,8 @@ int mpnh__same(struct mpnh *x, struct mpnh *y); /* > Compare multipath nexthops */ > static inline int mpnh_same(struct mpnh *x, struct mpnh *y) > { return (x == y) || mpnh__same(x, y); } > struct mpnh *mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, > int max, linpool *lp); > +struct mpnh *mpnh_sub(struct mpnh *x, struct mpnh *y, linpool *lp); > +struct mpnh *mpnh_sort(struct mpnh *x, linpool *lp); > > void rta_init(void); > rta *rta_lookup(rta *); /* Get rta equivalent to > this one, uc++ */ > diff --git a/nest/rt-attr.c b/nest/rt-attr.c > index 7fa05d6..335c96e 100644 > --- a/nest/rt-attr.c > +++ b/nest/rt-attr.c > @@ -302,6 +302,151 @@ mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, > int ry, int max, linpool *lp) > return root; > } > > +/** > + * mpnh_sub - subtract one nexthop list from another. > + * I.e. returns a list of entries, that existed in list1, but did not > + * exist in list 2. > + * The input lists must be sorted and the > + * result is sorted too. > + * > + * @x: list 1 > + * @y: list 2 > + * @lp: linpool if not NULL list 1 is not reusable, > + * new entries are to be allocated using this pool. > + * list 2 is never modified. > + * > + * The argument linpool determines whether the list1 > + * consumed by the function (i.e. its nodes reused in the resulting list). > + * If NULL, the list1 is reused, otherwise the resulting list > + * is populated with the new entries, allocated using the linpool. > + * To eliminate issues with deallocation of this list, > + * the caller should use some form of bulk deallocation > + * (e.g. stack or linpool) to free these nodes when the > + * resulting list is no longer needed. > + */ > +struct mpnh * > +mpnh_sub(struct mpnh *x, struct mpnh *y, linpool *lp) > +{ > + struct mpnh *root = NULL; > + struct mpnh **n = &root; > + > + while (x || y) > + { > + int cmp = mpnh_compare_node(x, y); > + if (cmp < 0) > + { > + *n = !lp ? x : mpnh_copy_node(x, lp); > + x = x->next; > + n = &((*n)->next); > + } > + else if (cmp > 0) > + y = y->next; > + else > + { > + x = x->next; > + y = y->next; > + } > + } > + > + *n = NULL; > + > + return root; > +} > + > +/** > + * mpnh_copy_lp copies nexthop list using given linpool > + * (unlike mpnh_copy, which uses sl_alloc) > + */ > +static struct mpnh * > +mpnh_copy_lp(struct mpnh *o, linpool *lp) > +{ > + struct mpnh *first = NULL; > + struct mpnh **last = &first; > + > + for (; o; o = o->next) > + { > + struct mpnh *n = mpnh_copy_node(o, lp); > + *last = n; > + last = &(n->next); > + } > + > + return first; > +} > + > +/* > + * mpnh_sort - sort the nexthop list > + * @x: the list to be sorted > + * @lp: if not NULL - the list will be copied in case it needs to be > reordered, > + * in this case the given list always remains unchanged. > + * If however the list is ordered, the given list is just returned, > + * and no copy of the list is created. > + * If lp is NULL, the given list will be reordered directly > + */ > +struct mpnh * > +mpnh_sort(struct mpnh *x, linpool *lp) > +{ > + struct mpnh *ret = x; > + struct mpnh *cur; > + struct mpnh *prev; > + int copy_on_change = !!lp; > + > + for (cur = ret->next, prev = ret; cur; prev = cur, cur = cur->next) > + { > + int cmp = mpnh_compare_node(prev, cur); > + if (cmp <= 0) > + continue; > + > + if (copy_on_change) > + { > + /* the list needs to be copied, and prev and cur need to be made > + * pointing to the new list entries */ > + > + struct mpnh *old_prev, *new_prev; > + > + ret = mpnh_copy_lp(x, lp); > + > + for (old_prev = x, new_prev = ret; > + old_prev != prev; > + old_prev = old_prev->next, new_prev = new_prev->next); > + > + prev = new_prev; > + cur = new_prev->next; > + > + copy_on_change = 0; > + } > + > + /* promote the entry */ > + struct mpnh *cur2; > + struct mpnh **next2_ptr; > + > + for (cur2 = ret, next2_ptr = &ret; ; next2_ptr = &cur2->next, cur2 > = cur2->next) > + { > + cmp = mpnh_compare_node(cur2, cur); > + if (cmp <= 0) > + continue; > + > + /* > + * found the place, where to insert the entry > + * do the entry move > + */ > + > + /* 1. remove entry from the list */ > + prev->next = cur->next; > + > + /* 2. now insert entry to the new place */ > + *next2_ptr = cur; > + cur->next = cur2; > + > + break; > + } > + > + /* now we have everything sorted upto prev, > + * set cur to prev and proceed with the cur->next loop */ > + cur = prev; > + } > + > + return ret; > +} > > static struct mpnh * > mpnh_copy(struct mpnh *o) > diff --git a/nest/rt-table.c b/nest/rt-table.c > index 57c8b8e..0a90633 100644 > --- a/nest/rt-table.c > +++ b/nest/rt-table.c > @@ -592,8 +592,27 @@ static struct mpnh * > mpnh_merge_rta(struct mpnh *nhs, rta *a, int max) > { > struct mpnh nh = { .gw = a->gw, .iface = a->iface }; > - struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh; > - return mpnh_merge(nhs, nh2, 1, 0, max, rte_update_pool); > + struct mpnh *nh2; > + int r2 = 0; > + > + if (a->dest == RTD_MULTIPATH) > + { > + /* > + * mpnh_merge expects the nexthops list to be sorted, > + * while the nexthops returned by the protocols, > + * e.g. the "static" one, are actually not. > + * Ensures the nh2 is sorted. > + */ > + nh2 = mpnh_sort(a->nexthops, rte_update_pool); > + /* > + * If the sort was actually done, the nh2 is already copies, > + * so no need to copy it once again, set r2 to 1 in this case. > + */ > + r2 = (nh2 != a->nexthops); > + } > + else > + nh2 = &nh; > + return mpnh_merge(nhs, nh2, 1, r2, max, rte_update_pool); > } > > rte * > @@ -642,6 +661,24 @@ rt_export_merged(struct announce_hook *ah, net *net, > rte **rt_free, ea_list **tm > best->attrs->nexthops = nhs; > } > } > + else if (best->attrs->dest == RTD_MULTIPATH) > + { > + /* > + * mpnh_merge, mpnh_same and mpnh_sub expect the nexthops list > + * to be sorted, while the nexthops returned by the protocols, > + * e.g. the "static" one, are actually not. > + * This ensures the resulting entry has nexthops sorted, > + * and makes the behavior consistent and agnostic to > + * the number of elements in the best0 entries list > + * (i.e. best0->next processing above) > + */ > + nhs = mpnh_sort(best->attrs->nexthops, rte_update_pool); > + if (nhs != best->attrs->nexthops) > + { > + best = rte_cow_rta(best, rte_update_pool); > + best->attrs->nexthops = nhs; > + } > + } > > if (best != best0) > *rt_free = best; > diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c > index 640d187..ca2648b 100644 > --- a/sysdep/linux/netlink.c > +++ b/sysdep/linux/netlink.c > @@ -19,7 +19,6 @@ > #include "nest/route.h" > #include "nest/protocol.h" > #include "nest/iface.h" > -#include "lib/alloca.h" > #include "lib/timer.h" > #include "lib/unix.h" > #include "lib/krt.h" > @@ -46,6 +45,32 @@ > #define RTA_TABLE 15 > #endif > > +/* > + * nl parse route context > + * its duty is > + * 1. To maintain the entry collect state - > + * for IPv6 ECMP the nl parsing logic needs to collect > + * separate individual entries, representing the multipath > + * into one multipath entry > + * 2. To hold some temporary data used while parsing > + * (like non-cached rta) on the stack. > + * > + * Implementation note: the context actually maintain two rta entries: > + * one to be used for the current rte being processed > + * (i.e. being created as a result of the nl data parsing), > + * another is used for the current rte being collected, > + * (i.e. stored in collect_rte, and for which multipath entries are > being collected). > + * process_attrs holds the index of the attrs, being used for rte > being processed. > + * Once the rte being processed becomes the one being collected, > + * the attrs used with it become "being collected", and another attrs > become "being processed". > + */ > +typedef struct nl_parsectx > +{ > + struct krt_proto *collect_p; /* Protocol, for which entries are > currently being processed */ > + rte *collect_rte; /* Entry, for which multipath entries are currently > being collected */ > + int process_attrs; /* index in the attrs array for the entry to be used > for the "processed" entry */ > + rta attrs[2]; > +} nl_parsectx; > > /* > * Synchronous Netlink interface > @@ -62,6 +87,8 @@ struct nl_sock > > #define NL_RX_SIZE 8192 > > +static linpool *netlink_lp; > + > static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for > synchronous scan */ > static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for > requests */ > > @@ -803,7 +830,7 @@ nh_bufsize(struct mpnh *nh) > } > > static int > -nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int > new) > +nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int > new, int mp) > { > eattr *ea; > net *net = e->net; > @@ -820,7 +847,8 @@ nl_send_route(struct krt_proto *p, rte *e, struct > ea_list *eattrs, int new) > bzero(&r.r, sizeof(r.r)); > r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE; > r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); > - r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? > NLM_F_CREATE|NLM_F_EXCL : 0); > + r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK > + | (new ? NLM_F_CREATE | (!mp ? NLM_F_EXCL : 0) : 0); > > r.r.rtm_family = BIRD_AF; > r.r.rtm_dst_len = net->n.pxlen; > @@ -835,8 +863,12 @@ nl_send_route(struct krt_proto *p, rte *e, struct > ea_list *eattrs, int new) > > /* For route delete, we do not specify route attributes */ > if (!new) > - return nl_exchange(&r.h); > - > + { > + if (mp) > + goto set_dest; > + else > + goto submit; > + } > > if (ea = ea_find(eattrs, EA_KRT_METRIC)) > nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data); > @@ -864,7 +896,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct > ea_list *eattrs, int new) > > > /* a->iface != NULL checked in krt_capable() for router and device > routes */ > - > +set_dest: > switch (a->dest) > { > case RTD_ROUTER: > @@ -892,10 +924,104 @@ nl_send_route(struct krt_proto *p, rte *e, struct > ea_list *eattrs, int new) > default: > bug("krt_capable inconsistent with nl_send_route"); > } > - > +submit: > return nl_exchange(&r.h); > } > > +/* > + * this is just to unify the code for bird1.x and bird2 > + * for bird1.x it is just a define, resolving to 1 > + * for IPV6 and 0 for IPV4 > + * > + * for bird2 it is a function, making a decision based > + * on the p->p.table->addr_type > + * > + * static int > + * trk_is_use_collect_mode(struct krt_proto *p); > + */ > +#ifdef IPV6 > +#define trk_is_use_collect_mode(_p) 1 > +#else > +#define trk_is_use_collect_mode(_p) 0 > +#endif > + > +static struct mpnh * > +krt_mp_merge_rta(struct mpnh *nhs, rta *a, int max) > +{ > + struct mpnh nh = { .gw = a->gw, .iface = a->iface }; > + struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh; > + return mpnh_merge(nhs, nh2, 1, 0, max, netlink_lp); > +} > + > +static struct mpnh * > +krt_mp_sub_rte_rta(rta *ax, rta *ay) > +{ > + struct mpnh nhx = { .gw = ax->gw, .iface = ax->iface }; > + struct mpnh nhy = { .gw = ay->gw, .iface = ay->iface }; > + struct mpnh *nhpx = (ax->dest == RTD_MULTIPATH) ? ax->nexthops : &nhx; > + struct mpnh *nhpy = (ay->dest == RTD_MULTIPATH) ? ay->nexthops : &nhy; > + return mpnh_sub(nhpx, nhpy, netlink_lp); > +} > + > +static int > +krt_send_nh_multipath(struct krt_proto *p, rte *base, struct mpnh *nh, > struct ea_list *eattrs, int new) > +{ > + rte *e; > + int err = 0; > + rta ra = { > + .src= p->p.main_source, > + .source = RTS_INHERIT, > + .scope = SCOPE_UNIVERSE, > + .cast = RTC_UNICAST > + }; > + > + e = rte_get_temp(&ra); > + e->net = base->net; > + e->u.krt = base->u.krt; > + > + for (; nh; nh = nh->next) > + { > + ra.gw = nh->gw; > + ra.iface = nh->iface; > + > + err = nl_send_route(p, e, eattrs, new, 1); > + if (err < 0) > + DBG("deleting route failed %d\n", err); > + } > + > + rte_free(e); > + > + return err; > +} > + > +static int > +krt_adjust_rte_multipath(struct krt_proto *p, rte *new, rte *old, struct > ea_list *eattrs) > +{ > + struct mpnh *nhold, *nhnew; > + int err = 0; > + > + nhold = krt_mp_sub_rte_rta(old->attrs, new->attrs); > + nhnew = krt_mp_sub_rte_rta(new->attrs, old->attrs); > + > + if (nhold) > + { > + if (old->attrs->dest == RTD_MULTIPATH) > + err = krt_send_nh_multipath(p, old, nhold, NULL, 0); > + else > + err = nl_send_route(p, old, NULL, 0, 1); > + } > + > + if (nhnew) > + { > + if (new->attrs->dest == RTD_MULTIPATH) > + err |= krt_send_nh_multipath(p, new, nhnew, eattrs, 1); > + else > + err |= nl_send_route(p, new, eattrs, 1, 1); > + } > + > + return err; > +} > + > void > krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct > ea_list *eattrs) > { > @@ -909,10 +1035,27 @@ krt_replace_rte(struct krt_proto *p, net *n, rte > *new, rte *old, struct ea_list > */ > > if (old) > - nl_send_route(p, old, NULL, 0); > + { > + if (trk_is_use_collect_mode(p)) > + { > + if (new && ( new->attrs->dest == RTD_MULTIPATH > + || old->attrs->dest == RTD_MULTIPATH)) > + { > + err = krt_adjust_rte_multipath(p, new, old, eattrs); > + /* zero up "new" to ensure the below "if (new)" branch is > not triggered */ > + new = NULL; > + } > + else if (old->attrs->dest == RTD_MULTIPATH) > + krt_send_nh_multipath(p, old, old->attrs->nexthops, NULL, 0); > + else > + nl_send_route(p, old, NULL, 0, 0); > + } > + else > + nl_send_route(p, old, NULL, 0, 0); > + } > > if (new) > - err = nl_send_route(p, new, eattrs, 1); > + err = nl_send_route(p, new, eattrs, 1, 0); > > if (err < 0) > n->n.flags |= KRF_SYNC_ERROR; > @@ -920,11 +1063,138 @@ krt_replace_rte(struct krt_proto *p, net *n, rte > *new, rte *old, struct ea_list > n->n.flags &= ~KRF_SYNC_ERROR; > } > > +static int > +krt_mp_is_collectable(struct krt_proto *p, rte *e) > +{ > + if (!trk_is_use_collect_mode(p)) > + return 0; > + > + struct rta *a = e->attrs; > + > + if (a->dest != RTD_ROUTER && a->dest != RTD_DEVICE) > + return 0; > + > + return 1; > +} > + > +static int > +krt_mp_is_mergable(struct krt_proto *p, rte *e1, rte *e2) > +{ > + if (e1->net != e2->net) > + return 0; > + > + if (!rte_is_valid(e1) || !rte_is_valid(e2)) > + return 0; > + > + if (e1->pref != e2->pref) > + return 0; > + > + if (e1->attrs->src->proto->proto != e2->attrs->src->proto->proto) > + return 0; > + > + return 1; > +} > + > +static rte * > +krt_mp_collect_do_add(struct krt_proto *p, rte *mp_collect_rte, rte *e) > +{ > + struct rta *attrs = mp_collect_rte->attrs; > + > + ASSERT(!rta_is_cached(attrs)); > + > + /* sanity to check our tmp attrs selection logic works correctly */ > + ASSERT(attrs != e->attrs); > + > + if (attrs->dest != RTD_MULTIPATH) > + { > + attrs->nexthops = krt_mp_merge_rta(NULL, attrs, p->p.merge_limit); > + attrs->dest = RTD_MULTIPATH; > + } > + > + attrs->nexthops = krt_mp_merge_rta(attrs->nexthops, e->attrs, > p->p.merge_limit); > + > + return mp_collect_rte; > +} > + > +static int > +krt_mp_can_collect(struct krt_proto *p, rte *mp_collect_rte, rte *e) > +{ > + if (!krt_mp_is_collectable(p, e)) > + return 0; > + > + if (!krt_mp_is_mergable(p, mp_collect_rte, e)) > + return 0; > + > + return 1; > +} > + > +static rta* nl_parse_get_tmp_rta(nl_parsectx *ctx) > +{ > + rta *a = &ctx->attrs[ctx->process_attrs]; > + > + memset(a, 0, sizeof(*a)); > + return a; > +} > + > +static void nl_parse_collect_complete(nl_parsectx *ctx) > +{ > + if (ctx->collect_p) > + { > + DBG("KRT: collected\n"); > + krt_got_route(ctx->collect_p, ctx->collect_rte); > + ctx->collect_p = NULL; > + ctx->collect_rte = NULL; > + lp_flush(netlink_lp); > + } > +} > + > +static void > +nl_parse_collect_rte(nl_parsectx *ctx, struct krt_proto *p, rte *e) > +{ > + if (ctx->collect_p) > + { > + ASSERT(ctx->collect_rte); > + if (ctx->collect_p == p && krt_mp_can_collect(p, ctx->collect_rte, > e)) > + { > + ctx->collect_rte = krt_mp_collect_do_add(p, ctx->collect_rte, e); > + DBG("KRT: collecting[add]\n"); > + return; > + } > + > + nl_parse_collect_complete(ctx); > + } > + > + ASSERT(!ctx->collect_p); > + ASSERT(!ctx->collect_rte); > + > + if (krt_mp_is_collectable(p, e)) > + { > + ASSERT(e->attrs == &ctx->attrs[ctx->process_attrs]); > + ASSERT(!rta_is_cached(e->attrs)); > + ctx->collect_p = p; > + ctx->collect_rte = e; > + ctx->process_attrs = (ctx->process_attrs + 1) % 2; > + DBG("KRT: collecting\n"); > + return; > + } > + > + krt_got_route(p, e); > +} > + > +static void nl_parse_begin(nl_parsectx *ctx) > +{ > + memset(ctx, 0, sizeof (*ctx)); > +} > + > +static void nl_parse_end(nl_parsectx *ctx) > +{ > + nl_parse_collect_complete(ctx); > +} > > #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } > while(0) > > static void > -nl_parse_route(struct nlmsghdr *h, int scan) > +nl_parse_route(nl_parsectx *ctx, struct nlmsghdr *h, int scan) > { > struct krt_proto *p; > struct rtmsg *i; > @@ -1022,12 +1292,12 @@ nl_parse_route(struct nlmsghdr *h, int scan) > > net *net = net_get(p->p.table, dst, i->rtm_dst_len); > > - rta ra = { > - .src= p->p.main_source, > - .source = RTS_INHERIT, > - .scope = SCOPE_UNIVERSE, > - .cast = RTC_UNICAST > - }; > + rta *ra = nl_parse_get_tmp_rta(ctx); > + > + ra->src= p->p.main_source, > + ra->source = RTS_INHERIT, > + ra->scope = SCOPE_UNIVERSE, > + ra->cast = RTC_UNICAST; > > switch (i->rtm_type) > { > @@ -1035,9 +1305,9 @@ nl_parse_route(struct nlmsghdr *h, int scan) > > 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) > + ra->dest = RTD_MULTIPATH; > + 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); > @@ -1047,8 +1317,8 @@ nl_parse_route(struct nlmsghdr *h, int scan) > break; > } > > - ra.iface = if_find_by_index(oif); > - if (!ra.iface) > + 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); > @@ -1058,39 +1328,39 @@ nl_parse_route(struct nlmsghdr *h, int scan) > 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->dest = RTD_ROUTER; > + memcpy(&ra->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra->gw)); > + ipa_ntoh(ra->gw); > > #ifdef IPV6 > /* Silently skip strange 6to4 routes */ > - if (ipa_in_net(ra.gw, IPA_NONE, 96)) > + if (ipa_in_net(ra->gw, IPA_NONE, 96)) > return; > #endif > > - ng = neigh_find2(&p->p, &ra.gw, ra.iface, > + ng = neigh_find2(&p->p, &ra->gw, ra->iface, > (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : > 0); > if (!ng || (ng->scope == SCOPE_HOST)) > { > log(L_ERR "KRT: Received route %I/%d with strange next-hop > %I", > - net->n.prefix, net->n.pxlen, ra.gw); > + net->n.prefix, net->n.pxlen, ra->gw); > return; > } > } > else > { > - ra.dest = RTD_DEVICE; > + ra->dest = RTD_DEVICE; > } > > break; > case RTN_BLACKHOLE: > - ra.dest = RTD_BLACKHOLE; > + ra->dest = RTD_BLACKHOLE; > break; > case RTN_UNREACHABLE: > - ra.dest = RTD_UNREACHABLE; > + ra->dest = RTD_UNREACHABLE; > break; > case RTN_PROHIBIT: > - ra.dest = RTD_PROHIBIT; > + ra->dest = RTD_PROHIBIT; > break; > /* FIXME: What about RTN_THROW? */ > default: > @@ -1098,7 +1368,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) > return; > } > > - rte *e = rte_get_temp(&ra); > + rte *e = rte_get_temp(ra); > e->net = net; > e->u.krt.src = src; > e->u.krt.proto = i->rtm_protocol; > @@ -1114,24 +1384,24 @@ nl_parse_route(struct nlmsghdr *h, int scan) > memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps)); > ipa_ntoh(ps); > > - ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); > - ea->next = ra.eattrs; > - ra.eattrs = ea; > + ea_list *ea = lp_alloc(netlink_lp, sizeof(ea_list) + sizeof(eattr)); > + ea->next = ra->eattrs; > + ra->eattrs = ea; > ea->flags = EALF_SORTED; > ea->count = 1; > ea->attrs[0].id = EA_KRT_PREFSRC; > ea->attrs[0].flags = 0; > ea->attrs[0].type = EAF_TYPE_IP_ADDRESS; > - ea->attrs[0].u.ptr = alloca(sizeof(struct adata) + sizeof(ps)); > + ea->attrs[0].u.ptr = lp_alloc(netlink_lp, sizeof(struct adata) + > sizeof(ps)); > ea->attrs[0].u.ptr->length = sizeof(ps); > memcpy(ea->attrs[0].u.ptr->data, &ps, sizeof(ps)); > } > > if (a[RTA_FLOW]) > { > - ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); > - ea->next = ra.eattrs; > - ra.eattrs = ea; > + ea_list *ea = lp_alloc(netlink_lp, sizeof(ea_list) + sizeof(eattr)); > + ea->next = ra->eattrs; > + ra->eattrs = ea; > ea->flags = EALF_SORTED; > ea->count = 1; > ea->attrs[0].id = EA_KRT_REALM; > @@ -1143,7 +1413,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) > if (a[RTA_METRICS]) > { > u32 metrics[KRT_METRICS_MAX]; > - ea_list *ea = alloca(sizeof(ea_list) + KRT_METRICS_MAX * > sizeof(eattr)); > + ea_list *ea = lp_alloc(netlink_lp, sizeof(ea_list) + > KRT_METRICS_MAX * sizeof(eattr)); > int t, n = 0; > > if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) > < 0) > @@ -1165,15 +1435,15 @@ nl_parse_route(struct nlmsghdr *h, int scan) > > if (n > 0) > { > - ea->next = ra.eattrs; > + ea->next = ra->eattrs; > ea->flags = EALF_SORTED; > ea->count = n; > - ra.eattrs = ea; > + ra->eattrs = ea; > } > } > > if (scan) > - krt_got_route(p, e); > + nl_parse_collect_rte(ctx, p, e); > else > krt_got_route_async(p, e, new); > } > @@ -1182,13 +1452,19 @@ void > krt_do_scan(struct krt_proto *p UNUSED) /* > CONFIG_ALL_TABLES_AT_ONCE => p is NULL */ > { > struct nlmsghdr *h; > + nl_parsectx ctx; > > nl_request_dump(BIRD_AF, RTM_GETROUTE); > + > + nl_parse_begin(&ctx); > + > while (h = nl_get_scan()) > if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE) > - nl_parse_route(h, 1); > + nl_parse_route(&ctx, h, 1); > else > log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", > h->nlmsg_type); > + > + nl_parse_end(&ctx); > } > > /* > @@ -1201,12 +1477,16 @@ static byte *nl_async_rx_buffer; /* Receive > buffer */ > static void > nl_async_msg(struct nlmsghdr *h) > { > + nl_parsectx ctx; > + > switch (h->nlmsg_type) > { > case RTM_NEWROUTE: > case RTM_DELROUTE: > DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type); > - nl_parse_route(h, 0); > + nl_parse_begin(&ctx); > + nl_parse_route(&ctx, h, 0); > + nl_parse_end(&ctx); > break; > case RTM_NEWLINK: > case RTM_DELLINK: > @@ -1325,6 +1605,7 @@ void > krt_sys_io_init(void) > { > HASH_INIT(nl_table_map, krt_pool, 6); > + netlink_lp = lp_new(krt_pool, 4080); > } > > int > -- > 2.5.0 > >
