[PATCH master v2] IPv6 ECMP support fixes for linux
Mikhail Sennikovskii
mikhail.sennikovskii at profitbricks.com
Thu Mar 3 13:51:38 CET 2016
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 <
mikhail.sennikovskii at profitbricks.com>:
> 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 <mikhail.sennikovskii at profitbricks.com
> >
> ---
> 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://trubka.network.cz/pipermail/bird-users/attachments/20160303/c94da6f2/attachment.html>
More information about the Bird-users
mailing list