From 4e276a8920ed0496836f002f144943ab42f120f6 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Fri, 6 May 2016 15:48:35 +0200 Subject: [PATCH] Merged multipath and single-path data structures. Dropped struct mpnh and mpnh_*() Now struct nexthop exists, nexthop_*(), and also included struct nexthop into struct rta. Also converted RTD_DEVICE and RTD_ROUTER to RTD_UNICAST. If it is needed to distinguish between these two cases, RTD_DEVICE is equivalent to IPA_ZERO(a->nh.gw), RTD_ROUTER is then IPA_NONZERO(a->nh.gw). From now on, we also explicitely want C99 compatible compiler. We assume that this 20-year norm should be known almost everywhere. --- configure.in | 1 + filter/filter.c | 20 +-- nest/config.Y | 2 +- nest/route.h | 45 +++---- nest/rt-attr.c | 119 +++++++++-------- nest/rt-dev.c | 6 +- nest/rt-table.c | 73 +++++----- proto/bgp/attrs.c | 2 +- proto/bgp/packets.c | 13 +- proto/ospf/ospf.c | 2 +- proto/ospf/rt.c | 62 ++++----- proto/ospf/rt.h | 2 +- proto/ospf/topology.c | 4 +- proto/ospf/topology.h | 2 +- proto/rip/rip.c | 25 ++-- proto/static/config.Y | 43 +++--- proto/static/static.c | 295 ++++++++++++++++------------------------- proto/static/static.h | 9 +- sysdep/bsd/krt-sock.c | 70 +++++----- sysdep/linux/netlink.c | 108 +++++++-------- sysdep/unix/krt.c | 30 ++--- 21 files changed, 434 insertions(+), 499 deletions(-) diff --git a/configure.in b/configure.in index 32344d1f..d5ddb2a5 100644 --- a/configure.in +++ b/configure.in @@ -57,6 +57,7 @@ if test "$ac_test_CFLAGS" != set ; then bird_cflags_default=yes fi +AC_PROG_CC AC_PROG_CC_C99 if test -z "$GCC" ; then AC_MSG_ERROR([This program requires the GNU C Compiler.]) diff --git a/filter/filter.c b/filter/filter.c index 4ec04554..926316ac 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -900,15 +900,15 @@ interpret(struct f_inst *what) switch (what->a2.i) { case SA_FROM: res.val.ip = rta->from; break; - case SA_GW: res.val.ip = rta->gw; break; + case SA_GW: res.val.ip = rta->nh.gw; break; case SA_NET: res.val.net = (*f_rte)->net->n.addr; break; case SA_PROTO: res.val.s = rta->src->proto->name; break; case SA_SOURCE: res.val.i = rta->source; break; case SA_SCOPE: res.val.i = rta->scope; break; case SA_CAST: res.val.i = rta->cast; break; case SA_DEST: res.val.i = rta->dest; break; - case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break; - case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break; + case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break; + case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break; default: bug("Invalid static attribute access (%x)", res.type); @@ -938,10 +938,10 @@ interpret(struct f_inst *what) if (!n || (n->scope == SCOPE_HOST)) runtime( "Invalid gw address" ); - rta->dest = RTD_ROUTER; - rta->gw = ip; - rta->iface = n->iface; - rta->nexthops = NULL; + rta->dest = RTD_UNICAST; + rta->nh.gw = ip; + rta->nh.iface = n->iface; + rta->nh.next = NULL; rta->hostentry = NULL; } break; @@ -956,9 +956,9 @@ interpret(struct f_inst *what) runtime( "Destination can be changed only to blackhole, unreachable or prohibit" ); rta->dest = i; - rta->gw = IPA_NONE; - rta->iface = NULL; - rta->nexthops = NULL; + rta->nh.gw = IPA_NONE; + rta->nh.iface = NULL; + rta->nh.next = NULL; rta->hostentry = NULL; break; diff --git a/nest/config.Y b/nest/config.Y index 23d6a452..95ce59cd 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -79,7 +79,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIREC RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL) CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED) CF_ENUM(T_ENUM_RTC, RTC_, UNICAST, BROADCAST, MULTICAST, ANYCAST) -CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULTIPATH) +CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT) CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID) %type idval diff --git a/nest/route.h b/nest/route.h index d652ca15..37c9abfb 100644 --- a/nest/route.h +++ b/nest/route.h @@ -195,7 +195,7 @@ struct hostentry { unsigned hash_key; /* Hash key */ unsigned uc; /* Use count */ struct rta *src; /* Source rta entry */ - ip_addr gw; /* Chosen next hop */ + struct nexthop *nh; /* Chosen next hop */ byte dest; /* Chosen route destination type (RTD_...) */ u32 igp_metric; /* Chosen route IGP metric */ }; @@ -332,11 +332,11 @@ void rt_show(struct rt_show_data *); * construction of BGP route attribute lists. */ -/* Multipath next-hop */ -struct mpnh { +/* Nexthop structure */ +struct nexthop { ip_addr gw; /* Next hop */ struct iface *iface; /* Outgoing interface */ - struct mpnh *next; + struct nexthop *next; byte weight; }; @@ -353,20 +353,19 @@ typedef struct rta { struct rta *next, **pprev; /* Hash chain */ u32 uc; /* Use count */ u32 hash_key; /* Hash over important fields */ - struct mpnh *nexthops; /* Next-hops for multipath routes */ struct ea_list *eattrs; /* Extended Attribute chain */ struct rte_src *src; /* Route source that created the route */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ - struct iface *iface; /* Outgoing interface */ - ip_addr gw; /* Next hop */ ip_addr from; /* Advertising router */ u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */ - byte source; /* Route source (RTS_...) */ - byte scope; /* Route scope (SCOPE_... -- see ip.h) */ - byte cast; /* Casting type (RTC_...) */ - byte dest; /* Route destination type (RTD_...) */ - byte flags; /* Route flags (RTF_...), now unused */ - byte aflags; /* Attribute cache flags (RTAF_...) */ + u32 bf[0]; + u32 source:6; /* Route source (RTS_...) */ + u32 scope:6; /* Route scope (SCOPE_... -- see ip.h) */ + u32 cast:6; /* Casting type (RTC_...) */ + u32 dest:6; /* Route destination type (RTD_...) */ +// u32 eflags:8; /* Flags (RTAF_...) */ + u32 aflags:8; + struct nexthop nh; /* Next hop */ } rta; #define RTS_DUMMY 0 /* Dummy route to be removed soon */ @@ -391,12 +390,10 @@ typedef struct rta { #define RTC_MULTICAST 2 #define RTC_ANYCAST 3 /* IPv6 Anycast */ -#define RTD_ROUTER 0 /* Next hop is neighbor router */ -#define RTD_DEVICE 1 /* Points to device */ +#define RTD_UNICAST 0 /* Next hop is neighbor router */ #define RTD_BLACKHOLE 2 /* Silently drop packets */ #define RTD_UNREACHABLE 3 /* Reject as unreachable */ #define RTD_PROHIBIT 4 /* Administratively prohibited */ -#define RTD_MULTIPATH 5 /* Multipath route (nexthops != NULL) */ #define RTD_NONE 6 /* Invalid RTD */ /* Flags for net->n.flags, used by kernel syncer */ @@ -411,7 +408,7 @@ typedef struct rta { /* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */ static inline int rte_is_reachable(rte *r) -{ uint d = r->attrs->dest; return (d == RTD_ROUTER) || (d == RTD_DEVICE) || (d == RTD_MULTIPATH); } +{ uint d = r->attrs->dest; return (d == RTD_UNICAST); } /* @@ -516,12 +513,14 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */ ea_list *ea_append(ea_list *to, ea_list *what); void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max); -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); -void mpnh_insert(struct mpnh **n, struct mpnh *y); -int mpnh_is_sorted(struct mpnh *x); +int nexthop__same(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops */ +static inline int nexthop_same(struct nexthop *x, struct nexthop *y) +{ return (x == y) || nexthop__same(x, y); } +struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp); +static inline void nexthop_link(struct rta *a, struct nexthop *from) +{ a->nh.gw = from->gw; a->nh.iface = from->iface; a->nh.weight = from->weight; a->nh.next = from->next; } +void nexthop_insert(struct nexthop *n, struct nexthop *y); +int nexthop_is_sorted(struct nexthop *x); 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 94f25de8..0eacfe3f 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -61,7 +61,7 @@ pool *rta_pool; static slab *rta_slab; -static slab *mpnh_slab; +static slab *nexthop_slab; static slab *rte_src_slab; static struct idm src_ids; @@ -144,7 +144,7 @@ rt_prune_sources(void) */ static inline u32 -mpnh_hash(struct mpnh *x) +nexthop_hash(struct nexthop *x) { u32 h = 0; for (; x; x = x->next) @@ -154,7 +154,7 @@ mpnh_hash(struct mpnh *x) } int -mpnh__same(struct mpnh *x, struct mpnh *y) +nexthop__same(struct nexthop *x, struct nexthop *y) { for (; x && y; x = x->next, y = y->next) if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight)) @@ -164,7 +164,7 @@ mpnh__same(struct mpnh *x, struct mpnh *y) } static int -mpnh_compare_node(struct mpnh *x, struct mpnh *y) +nexthop_compare_node(struct nexthop *x, struct nexthop *y) { int r; @@ -185,10 +185,10 @@ mpnh_compare_node(struct mpnh *x, struct mpnh *y) return ((int) x->iface->index) - ((int) y->iface->index); } -static inline struct mpnh * -mpnh_copy_node(const struct mpnh *src, linpool *lp) +static inline struct nexthop * +nexthop_copy_node(const struct nexthop *src, linpool *lp) { - struct mpnh *n = lp_alloc(lp, sizeof(struct mpnh)); + struct nexthop *n = lp_alloc(lp, sizeof(struct nexthop)); n->gw = src->gw; n->iface = src->iface; n->next = NULL; @@ -197,7 +197,7 @@ mpnh_copy_node(const struct mpnh *src, linpool *lp) } /** - * mpnh_merge - merge nexthop lists + * nexthop_merge - merge nexthop lists * @x: list 1 * @y: list 2 * @rx: reusability of list @x @@ -205,7 +205,7 @@ mpnh_copy_node(const struct mpnh *src, linpool *lp) * @max: max number of nexthops * @lp: linpool for allocating nexthops * - * The mpnh_merge() function takes two nexthop lists @x and @y and merges them, + * The nexthop_merge() function takes two nexthop lists @x and @y and merges them, * eliminating possible duplicates. The input lists must be sorted and the * result is sorted too. The number of nexthops in result is limited by @max. * New nodes are allocated from linpool @lp. @@ -218,28 +218,28 @@ mpnh_copy_node(const struct mpnh *src, linpool *lp) * resulting list is no longer needed. When reusability is not set, the * corresponding lists are not modified nor linked from the resulting list. */ -struct mpnh * -mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp) +struct nexthop * +nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp) { - struct mpnh *root = NULL; - struct mpnh **n = &root; + struct nexthop *root = NULL; + struct nexthop **n = &root; while ((x || y) && max--) { - int cmp = mpnh_compare_node(x, y); + int cmp = nexthop_compare_node(x, y); if (cmp < 0) { - *n = rx ? x : mpnh_copy_node(x, lp); + *n = rx ? x : nexthop_copy_node(x, lp); x = x->next; } else if (cmp > 0) { - *n = ry ? y : mpnh_copy_node(y, lp); + *n = ry ? y : nexthop_copy_node(y, lp); y = y->next; } else { - *n = rx ? x : (ry ? y : mpnh_copy_node(x, lp)); + *n = rx ? x : (ry ? y : nexthop_copy_node(x, lp)); x = x->next; y = y->next; } @@ -251,43 +251,55 @@ mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp) } void -mpnh_insert(struct mpnh **n, struct mpnh *x) +nexthop_insert(struct nexthop *n, struct nexthop *x) { - for (; *n; n = &((*n)->next)) + struct nexthop tmp; + memcpy(&tmp, n, sizeof(struct nexthop)); + if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */ { - int cmp = mpnh_compare_node(*n, x); + memcpy(n, x, sizeof(struct nexthop)); + memcpy(x, &tmp, sizeof(struct nexthop)); + n->next = x; + return; + } + + for (struct nexthop **nn = &(n->next); *nn; nn = &((*nn)->next)) + { + int cmp = nexthop_compare_node(*nn, x); if (cmp < 0) continue; - else if (cmp > 0) - break; - else - return; + + if (cmp > 0) + { + x->next = *nn; + *nn = x; + } + + return; } - x->next = *n; - *n = x; } int -mpnh_is_sorted(struct mpnh *x) +nexthop_is_sorted(struct nexthop *x) { for (; x && x->next; x = x->next) - if (mpnh_compare_node(x, x->next) >= 0) + if (nexthop_compare_node(x, x->next) >= 0) return 0; return 1; } -static struct mpnh * -mpnh_copy(struct mpnh *o) +static struct nexthop * +nexthop_copy(struct nexthop *o) { - struct mpnh *first = NULL; - struct mpnh **last = &first; + struct nexthop *first = NULL; + struct nexthop **last = &first; for (; o; o = o->next) { - struct mpnh *n = sl_alloc(mpnh_slab); + struct nexthop *n = sl_alloc(nexthop_slab); n->gw = o->gw; n->iface = o->iface; n->next = NULL; @@ -301,14 +313,14 @@ mpnh_copy(struct mpnh *o) } static void -mpnh_free(struct mpnh *o) +nexthop_free(struct nexthop *o) { - struct mpnh *n; + struct nexthop *n; while (o) { n = o->next; - sl_free(mpnh_slab, o); + sl_free(nexthop_slab, o); o = n; } } @@ -994,19 +1006,12 @@ rta_hash(rta *a) #define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f)); MIX(src); MIX(hostentry); - MIX(iface); - MIX(gw); MIX(from); MIX(igp_metric); - MIX(source); - MIX(scope); - MIX(cast); - MIX(dest); - MIX(flags); - MIX(aflags); + mem_hash_mix(&h, a->bf, sizeof(u32)); #undef MIX - return mem_hash_value(&h) ^ mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs); + return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs); } static inline int @@ -1017,13 +1022,12 @@ rta_same(rta *x, rta *y) x->scope == y->scope && x->cast == y->cast && x->dest == y->dest && - x->flags == y->flags && x->igp_metric == y->igp_metric && - ipa_equal(x->gw, y->gw) && + ipa_equal(x->nh.gw, y->nh.gw) && ipa_equal(x->from, y->from) && - x->iface == y->iface && + x->nh.iface == y->nh.iface && x->hostentry == y->hostentry && - mpnh_same(x->nexthops, y->nexthops) && + nexthop_same(&(x->nh), &(y->nh)) && ea_same(x->eattrs, y->eattrs)); } @@ -1034,7 +1038,7 @@ rta_copy(rta *o) memcpy(r, o, sizeof(rta)); r->uc = 1; - r->nexthops = mpnh_copy(o->nexthops); + r->nh.next = nexthop_copy(o->nh.next); r->eattrs = ea_list_copy(o->eattrs); return r; } @@ -1130,7 +1134,8 @@ rta__free(rta *a) a->aflags = 0; /* Poison the entry */ rt_unlock_hostentry(a->hostentry); rt_unlock_source(a->src); - mpnh_free(a->nexthops); + if (a->nh.next) + nexthop_free(a->nh.next); ea_free(a->eattrs); sl_free(rta_slab, a); } @@ -1167,10 +1172,12 @@ rta_dump(rta *a) if (!(a->aflags & RTAF_CACHED)) debug(" !CACHED"); debug(" <-%I", a->from); - if (a->dest == RTD_ROUTER) - debug(" ->%I", a->gw); - if (a->dest == RTD_DEVICE || a->dest == RTD_ROUTER) - debug(" [%s]", a->iface ? a->iface->name : "???" ); + if (a->dest == RTD_UNICAST) + for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) + { + if (ipa_nonzero(nh->gw)) debug(" ->%I", nh->gw); + debug(" [%s]", nh->iface ? nh->iface->name : "???"); + } if (a->eattrs) { debug(" EA: "); @@ -1228,7 +1235,7 @@ rta_init(void) { rta_pool = rp_new(&root_pool, "Attributes"); rta_slab = sl_new(rta_pool, sizeof(rta)); - mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh)); + nexthop_slab = sl_new(rta_pool, sizeof(struct nexthop)); rta_alloc_hash(); rte_src_init(); } diff --git a/nest/rt-dev.c b/nest/rt-dev.c index d98cd79f..43628af8 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -79,8 +79,10 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) .source = RTS_DEVICE, .scope = SCOPE_UNIVERSE, .cast = RTC_UNICAST, - .dest = RTD_DEVICE, - .iface = ad->iface + .dest = RTD_UNICAST, + .nh = { + .iface = ad->iface + } }; a = rta_lookup(&a0); diff --git a/nest/rt-table.c b/nest/rt-table.c index 8c429874..46857d0d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -708,19 +708,17 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang } -static struct mpnh * -mpnh_merge_rta(struct mpnh *nhs, rta *a, linpool *pool, int max) +static struct nexthop * +nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, 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, pool); + return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool); } rte * rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent) { // struct proto *p = c->proto; - struct mpnh *nhs = NULL; + struct nexthop *nhs = NULL; rte *best0, *best, *rt0, *rt, *tmp; best0 = net->routes; @@ -745,7 +743,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin continue; if (rte_is_reachable(rt)) - nhs = mpnh_merge_rta(nhs, rt->attrs, pool, c->merge_limit); + nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit); if (tmp) rte_free(tmp); @@ -753,13 +751,12 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin if (nhs) { - nhs = mpnh_merge_rta(nhs, best->attrs, pool, c->merge_limit); + nhs = nexthop_merge_rta(nhs, best->attrs, pool, c->merge_limit); if (nhs->next) { best = rte_cow_rta(best, pool); - best->attrs->dest = RTD_MULTIPATH; - best->attrs->nexthops = nhs; + nexthop_link(best->attrs, nhs); } } @@ -922,7 +919,7 @@ rte_validate(rte *e) return 0; } - if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops)) + if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh))) { log(L_WARN "Ignoring unsorted multipath route %N received via %s", n->n.addr, e->sender->proto->name); @@ -1763,20 +1760,22 @@ rta_next_hop_outdated(rta *a) if (!he->src) return a->dest != RTD_UNREACHABLE; - return (a->iface != he->src->iface) || !ipa_equal(a->gw, he->gw) || - (a->dest != he->dest) || (a->igp_metric != he->igp_metric) || - !mpnh_same(a->nexthops, he->src->nexthops); + return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) || + !nexthop_same(&(a->nh), he->nh); } static inline void rta_apply_hostentry(rta *a, struct hostentry *he) { a->hostentry = he; - a->iface = he->src ? he->src->iface : NULL; - a->gw = he->gw; + + a->nh.gw = ipa_nonzero(he->nh->gw) ? he->nh->gw : he->link; + a->nh.iface = he->nh->iface; + a->nh.weight = he->nh->weight; + a->nh.next = he->nh->next; + a->dest = he->dest; a->igp_metric = he->igp_metric; - a->nexthops = he->src ? he->src->nexthops : NULL; } static inline rte * @@ -2310,8 +2309,7 @@ rt_get_igp_metric(rte *rt) return rt->u.rip.metric; #endif - /* Device routes */ - if ((a->dest != RTD_ROUTER) && (a->dest != RTD_MULTIPATH)) + if (a->source == RTS_DEVICE) return 0; return IGP_METRIC_UNKNOWN; @@ -2325,7 +2323,6 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) /* Reset the hostentry */ he->src = NULL; - he->gw = IPA_NONE; he->dest = RTD_UNREACHABLE; he->igp_metric = 0; @@ -2346,24 +2343,24 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - if (a->dest == RTD_DEVICE) - { - if (if_local_addr(he->addr, a->iface)) + if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next) + { /* We have singlepath device route */ + if (if_local_addr(he->addr, a->nh.iface)) { /* The host address is a local address, this is not valid */ log(L_WARN "Next hop address %I is a local address of iface %s", - he->addr, a->iface->name); + he->addr, a->nh.iface->name); goto done; } /* The host is directly reachable, use link as a gateway */ - he->gw = he->link; - he->dest = RTD_ROUTER; + he->nh = NULL; + he->dest = RTD_UNICAST; } else { /* The host is reachable through some route entry */ - he->gw = a->gw; + he->nh = (&a->nh); he->dest = a->dest; } @@ -2442,16 +2439,21 @@ rt_format_via(rte *e) rta *a = e->attrs; /* Max text length w/o IP addr and interface name is 16 */ - static byte via[IPA_MAX_TEXT_LENGTH+sizeof(a->iface->name)+16]; + static byte via[IPA_MAX_TEXT_LENGTH+sizeof(a->nh.iface->name)+16]; switch (a->dest) { - case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break; - case RTD_DEVICE: bsprintf(via, "dev %s", a->iface->name); break; + case RTD_UNICAST: if (a->nh.next) + bsprintf(via, "multipath"); + else + { + if (ipa_nonzero(a->nh.gw)) bsprintf(via, "via %I ", a->nh.gw); + bsprintf(via, "dev %s", a->nh.iface->name); + } + break; case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; - case RTD_MULTIPATH: bsprintf(via, "multipath"); break; default: bsprintf(via, "???"); } return via; @@ -2466,10 +2468,10 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm int primary = (e->net->routes == e); int sync_error = (e->net->n.flags & KRF_SYNC_ERROR); void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); - struct mpnh *nh; + struct nexthop *nh; tm_format_datetime(tm, &config->tf_route, e->lastmod); - if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw)) + if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw)) bsprintf(from, " from %I", a->from); else from[0] = 0; @@ -2490,8 +2492,9 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm bsprintf(info, " (%d)", e->pref); cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rt_format_via(e), a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); - for (nh = a->nexthops; nh; nh = nh->next) - cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1); + if (a->nh.next) + for (nh = &(a->nh); nh; nh = nh->next) + cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1); if (d->verbose) rta_show(c, a, tmpa); } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 52b56efa..11666f30 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1462,7 +1462,7 @@ static inline int rte_resolvable(rte *rt) { int rd = rt->attrs->dest; - return (rd == RTD_ROUTER) || (rd == RTD_DEVICE) || (rd == RTD_MULTIPATH); + return (rd == RTD_UNICAST); } int diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 66561ee4..0baa84c9 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -699,9 +699,10 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll) if (!nbr || (nbr->scope == SCOPE_HOST)) WITHDRAW(BAD_NEXT_HOP); - a->dest = RTD_ROUTER; - a->gw = nbr->addr; - a->iface = nbr->iface; + a->dest = RTD_UNICAST; + a->nh.gw = nbr->addr; + a->nh.iface = nbr->iface; + a->nh.next = NULL; a->hostentry = NULL; a->igp_metric = 0; } @@ -749,7 +750,7 @@ bgp_use_gateway(struct bgp_export_state *s) return 0; /* We need valid global gateway */ - if ((ra->dest != RTD_ROUTER) || ipa_zero(ra->gw) || ipa_is_link_local(ra->gw)) + if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw)) return 0; /* Use it when exported to internal peers */ @@ -757,7 +758,7 @@ bgp_use_gateway(struct bgp_export_state *s) return 1; /* Use it when forwarded to single-hop BGP peer on on the same iface */ - return p->neigh && (p->neigh->iface == ra->iface); + return p->neigh && (p->neigh->iface == ra->nh.iface); } static void @@ -767,7 +768,7 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to) { if (bgp_use_gateway(s)) { - ip_addr nh[1] = { s->route->attrs->gw }; + ip_addr nh[1] = { s->route->attrs->nh.gw }; bgp_set_attr_data(to, s->pool, BA_NEXT_HOP, 0, nh, 16); } else diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index d074600a..daf76ff2 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -235,7 +235,7 @@ ospf_start(struct proto *P) p->lsab_size = 256; p->lsab_used = 0; p->lsab = mb_alloc(P->pool, p->lsab_size); - p->nhpool = lp_new(P->pool, 12*sizeof(struct mpnh)); + p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop)); init_list(&(p->iface_list)); init_list(&(p->area_list)); fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6, diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 054841ca..09cc5776 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -22,7 +22,7 @@ static inline void reset_ri(ort *ort) } static inline int -nh_is_vlink(struct mpnh *nhs) +nh_is_vlink(struct nexthop *nhs) { return !nhs->iface; } @@ -33,10 +33,10 @@ unresolved_vlink(ort *ort) return ort->n.nhs && nh_is_vlink(ort->n.nhs); } -static inline struct mpnh * +static inline struct nexthop * new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) { - struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh)); + struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop)); nh->gw = gw; nh->iface = iface; nh->next = NULL; @@ -46,7 +46,7 @@ new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) /* Returns true if there are device nexthops in n */ static inline int -has_device_nexthops(const struct mpnh *n) +has_device_nexthops(const struct nexthop *n) { for (; n; n = n->next) if (ipa_zero(n->gw)) @@ -56,13 +56,13 @@ has_device_nexthops(const struct mpnh *n) } /* Replace device nexthops with nexthops to gw */ -static struct mpnh * -fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw) +static struct nexthop * +fix_device_nexthops(struct ospf_proto *p, const struct nexthop *n, ip_addr gw) { - struct mpnh *root1 = NULL; - struct mpnh *root2 = NULL; - struct mpnh **nn1 = &root1; - struct mpnh **nn2 = &root2; + struct nexthop *root1 = NULL; + struct nexthop *root2 = NULL; + struct nexthop **nn1 = &root1; + struct nexthop **nn2 = &root2; if (!p->ecmp) return new_nexthop(p, gw, n->iface, n->weight); @@ -73,7 +73,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw) for (; n; n = n->next) { - struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight); + struct nexthop *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight); if (ipa_zero(n->gw)) { @@ -87,7 +87,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw) } } - return mpnh_merge(root1, root2, 1, 1, p->ecmp, p->nhpool); + return nexthop_merge(root1, root2, 1, 1, p->ecmp, p->nhpool); } @@ -283,7 +283,7 @@ ort_merge(struct ospf_proto *p, ort *o, const orta *new) if (old->nhs != new->nhs) { - old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, + old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, p->ecmp, p->nhpool); old->nhs_reuse = 1; } @@ -299,7 +299,7 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new) if (old->nhs != new->nhs) { - old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, + old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, p->ecmp, p->nhpool); old->nhs_reuse = 1; } @@ -1673,18 +1673,18 @@ ospf_rt_spf(struct ospf_proto *p) static inline int -inherit_nexthops(struct mpnh *pn) +inherit_nexthops(struct nexthop *pn) { /* Proper nexthops (with defined GW) or dummy vlink nexthops (without iface) */ return pn && (ipa_nonzero(pn->gw) || !pn->iface); } -static struct mpnh * +static struct nexthop * calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par, int pos) { struct ospf_proto *p = oa->po; - struct mpnh *pn = par->nhs; + struct nexthop *pn = par->nhs; struct ospf_iface *ifa; u32 rid = en->lsa.rt; @@ -1812,7 +1812,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (!link_back(oa, en, par)) return; - struct mpnh *nhs = calc_next_hop(oa, en, par, pos); + struct nexthop *nhs = calc_next_hop(oa, en, par, pos); if (!nhs) { log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", @@ -1850,7 +1850,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, /* Merge old and new */ int new_reuse = (par->nhs != nhs); - en->nhs = mpnh_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool); + en->nhs = nexthop_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool); en->nhs_reuse = 1; return; } @@ -1906,8 +1906,8 @@ ort_changed(ort *nf, rta *nr) (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) || (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) || (nr->source != or->source) || (nr->dest != or->dest) || - (nr->iface != or->iface) || !ipa_equal(nr->gw, or->gw) || - !mpnh_same(nr->nexthops, or->nexthops); + (nr->nh.iface != or->nh.iface) || !ipa_equal(nr->nh.gw, or->nh.gw) || + !nexthop_same(&(nr->nh), &(or->nh)); } static void @@ -1931,7 +1931,7 @@ again1: /* Sanity check of next-hop addresses, failure should not happen */ if (nf->n.type) { - struct mpnh *nh; + struct nexthop *nh; for (nh = nf->n.nhs; nh; nh = nh->next) if (ipa_nonzero(nh->gw)) { @@ -1954,22 +1954,8 @@ again1: .cast = RTC_UNICAST }; - if (nf->n.nhs->next) - { - a0.dest = RTD_MULTIPATH; - a0.nexthops = nf->n.nhs; - } - else if (ipa_nonzero(nf->n.nhs->gw)) - { - a0.dest = RTD_ROUTER; - a0.iface = nf->n.nhs->iface; - a0.gw = nf->n.nhs->gw; - } - else - { - a0.dest = RTD_DEVICE; - a0.iface = nf->n.nhs->iface; - } + nexthop_link(&a0, nf->n.nhs); + a0.dest = RTD_UNICAST; if (reload || ort_changed(nf, &a0)) { diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index 959d12e9..842792f0 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -53,7 +53,7 @@ typedef struct orta struct ospf_area *oa; struct ospf_area *voa; /* Used when route is replaced in ospf_rt_sum_tr(), NULL otherwise */ - struct mpnh *nhs; /* Next hops computed during SPF */ + struct nexthop *nhs; /* Next hops computed during SPF */ struct top_hash_entry *en; /* LSA responsible for this orta */ } orta; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index aaaf2e8e..ce77f57a 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1288,8 +1288,8 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte ip_addr fwd = IPA_NONE; - if ((a->dest == RTD_ROUTER) && use_gw_for_fwaddr(p, a->gw, a->iface)) - fwd = a->gw; + if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface)) + fwd = a->nh.gw; /* NSSA-LSA with P-bit set must have non-zero forwarding address */ if (oa && ipa_zero(fwd)) diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 38447fdf..d1682c54 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -28,7 +28,7 @@ struct top_hash_entry u16 next_lsa_opts; /* For postponed LSA origination */ bird_clock_t inst_time; /* Time of installation into DB */ struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */ - struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ + struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */ u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */ u32 dist; /* Distance from the root */ diff --git a/proto/rip/rip.c b/proto/rip/rip.c index d87a078c..8b09330c 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -158,10 +158,10 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) while (rt2 && !rip_valid_rte(rt2)) rt2 = rt2->next; + a0.dest = RTD_UNICAST; if (p->ecmp && rt2) { /* ECMP route */ - struct mpnh *nhs = NULL; int num = 0; for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next) @@ -169,33 +169,34 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) if (!rip_valid_rte(rt)) continue; - struct mpnh *nh = alloca(sizeof(struct mpnh)); + struct nexthop *nh = (a0.nh.next ? &(a0.nh) : alloca(sizeof(struct nexthop))); + nh->gw = rt->next_hop; nh->iface = rt->from->nbr->iface; nh->weight = rt->from->ifa->cf->ecmp_weight; - mpnh_insert(&nhs, nh); + + if (a0.nh.next) + nexthop_insert(&(a0.nh), nh); + num++; if (rt->tag != rt_tag) rt_tag = 0; } - - a0.dest = RTD_MULTIPATH; - a0.nexthops = nhs; } else { /* Unipath route */ - a0.dest = RTD_ROUTER; - a0.gw = rt->next_hop; - a0.iface = rt->from->nbr->iface; + a0.nh.next = NULL; + a0.nh.gw = rt->next_hop; + a0.nh.iface = rt->from->nbr->iface; a0.from = rt->from->nbr->addr; } rta *a = rta_lookup(&a0); rte *e = rte_get_temp(a); - e->u.rip.from = a0.iface; + e->u.rip.from = a0.nh.iface; e->u.rip.metric = rt_metric; e->u.rip.tag = rt_tag; @@ -345,8 +346,8 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s en->metric = rt_metric; en->tag = rt_tag; en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL; - en->iface = new->attrs->iface; - en->next_hop = new->attrs->gw; + en->iface = new->attrs->nh.iface; + en->next_hop = new->attrs->nh.gw; } else { diff --git a/proto/static/config.Y b/proto/static/config.Y index 86359f0b..8103166d 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -13,7 +13,7 @@ CF_HDR CF_DEFINES #define STATIC_CFG ((struct static_config *) this_proto) -static struct static_route *this_srt, *this_srt_nh, *last_srt_nh; +static struct static_route *this_srt, *last_srt; static struct f_inst **this_srt_last_cmd; static void @@ -22,10 +22,9 @@ static_route_finish(void) struct static_route *r; /* Update undefined use_bfd entries in multipath nexthops */ - if (this_srt->dest == RTD_MULTIPATH) - for (r = this_srt->mp_next; r; r = r->mp_next) - if (r->use_bfd < 0) - r->use_bfd = this_srt->use_bfd; + for (r = this_srt->mp_next; r; r = r->mp_next) + if (r->use_bfd < 0) + r->use_bfd = this_srt->use_bfd; } CF_DECLS @@ -58,48 +57,50 @@ stat_route0: ROUTE net_any { add_tail(&STATIC_CFG->other_routes, &this_srt->n); this_srt->net = $2; this_srt_last_cmd = &(this_srt->cmds); + this_srt->mp_next = NULL; + last_srt = NULL; } ; stat_multipath1: VIA ipa ipa_scope { - last_srt_nh = this_srt_nh; - this_srt_nh = cfg_allocz(sizeof(struct static_route)); - this_srt_nh->dest = RTD_NONE; - this_srt_nh->via = $2; - this_srt_nh->via_if = $3; - this_srt_nh->if_name = (void *) this_srt; /* really */ - this_srt_nh->use_bfd = -1; /* undefined */ + last_srt = last_srt ? last_srt->mp_next = cfg_allocz(sizeof(struct static_route)) : this_srt; + + last_srt->dest = RTD_UNICAST; + last_srt->via = $2; + last_srt->via_if = $3; + last_srt->if_name = (void *) this_srt; /* really */ + last_srt->use_bfd = -1; /* undefined */ + last_srt->mp_next = NULL; } | stat_multipath1 WEIGHT expr { - this_srt_nh->weight = $3 - 1; + last_srt->weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); } | stat_multipath1 BFD bool { - this_srt_nh->use_bfd = $3; cf_check_bfd($3); + last_srt->use_bfd = $3; cf_check_bfd($3); } ; stat_multipath: - stat_multipath1 { this_srt->mp_next = this_srt_nh; } - | stat_multipath stat_multipath1 { last_srt_nh->mp_next = this_srt_nh; } + stat_multipath1 + | stat_multipath stat_multipath1 ; stat_route: stat_route0 VIA ipa ipa_scope { - this_srt->dest = RTD_ROUTER; + this_srt->dest = RTD_UNICAST; this_srt->via = $3; this_srt->via_if = $4; } | stat_route0 VIA TEXT { - this_srt->dest = RTD_DEVICE; + this_srt->dest = RTD_UNICAST; + this_srt->via = IPA_NONE; this_srt->if_name = $3; rem_node(&this_srt->n); add_tail(&STATIC_CFG->iface_routes, &this_srt->n); } - | stat_route0 MULTIPATH stat_multipath { - this_srt->dest = RTD_MULTIPATH; - } + | stat_route0 MULTIPATH stat_multipath | stat_route0 RECURSIVE ipa { this_srt->dest = RTDX_RECURSIVE; this_srt->via = $3; diff --git a/proto/static/static.c b/proto/static/static.c index fb547537..f3cfec01 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -58,49 +58,53 @@ p_igp_table(struct proto *p) } static void -static_install(struct proto *p, struct static_route *r, struct iface *ifa) +static_install(struct proto *p, struct static_route *r) { rta a; rte *e; - if (r->installed > 0) + if (!(r->state & STS_WANT) && r->dest != RTD_UNICAST) return; DBG("Installing static route %N, rtd=%d\n", r->net, r->dest); bzero(&a, sizeof(a)); a.src = p->main_source; - a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC; + a.source = ((r->dest == RTD_UNICAST) && ipa_zero(r->via)) ? RTS_STATIC_DEVICE : RTS_STATIC; a.scope = SCOPE_UNIVERSE; a.cast = RTC_UNICAST; a.dest = r->dest; - a.gw = r->via; - a.iface = ifa; - - if (r->dest == RTD_MULTIPATH) + if (r->dest == RTD_UNICAST) { struct static_route *r2; - struct mpnh *nhs = NULL; + int num = 0; - for (r2 = r->mp_next; r2; r2 = r2->mp_next) - if (r2->installed) + for (r2 = r; r2; r2 = r2->mp_next) + { + if ((r2->state & STS_INSTALLED) && !(r2->state & STS_FORCE)) + continue; + + if (r2->state & STS_WANT) { - struct mpnh *nh = alloca(sizeof(struct mpnh)); + struct nexthop *nh = (a.nh.next) ? alloca(sizeof(struct nexthop)) : &(a.nh); nh->gw = r2->via; nh->iface = r2->neigh->iface; nh->weight = r2->weight; - mpnh_insert(&nhs, nh); + if (a.nh.next) + nexthop_insert(&(a.nh), nh); + r2->state |= STS_INSTALLED; + num++; } + else + r2->state = 0; + } - /* There is at least one nexthop */ - if (!nhs->next) - { - /* Fallback to unipath route for exactly one nexthop */ - a.dest = RTD_ROUTER; - a.gw = nhs->gw; - a.iface = nhs->iface; - } - else - a.nexthops = nhs; + if (!num) // No nexthop to install + { + if (r->state & STS_INSTALLED_ANY) + rte_update(p, r->net, NULL); + + return; + } } if (r->dest == RTDX_RECURSIVE) @@ -115,7 +119,6 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) f_eval_rte(r->cmds, &e, static_lp); rte_update(p, r->net, e); - r->installed = 1; if (r->cmds) lp_flush(static_lp); @@ -124,12 +127,13 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) static void static_remove(struct proto *p, struct static_route *r) { - if (!r->installed) + if (!(r->state & STS_INSTALLED_ANY)) return; DBG("Removing static route %N via %I\n", r->net, r->via); rte_update(p, r->net, NULL); - r->installed = 0; + + r->state &= ~(STS_INSTALLED | STS_INSTALLED_ANY); } static void @@ -180,38 +184,12 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) DBG("static_add(%N,%d)\n", r->net, r->dest); switch (r->dest) { - case RTD_ROUTER: - { - struct neighbor *n = neigh_find2(p, &r->via, r->via_if, NEF_STICKY); - if (n) - { - r->chain = n->data; - n->data = r; - r->neigh = n; - - static_update_bfd(p, r); - if (static_decide(cf, r)) - static_install(p, r, n->iface); - else - static_remove(p, r); - } - else - { - log(L_ERR "Static route destination %I is invalid. Ignoring.", r->via); - static_remove(p, r); - } - break; - } - - case RTD_DEVICE: - break; - - case RTD_MULTIPATH: + case RTD_UNICAST: { int count = 0; struct static_route *r2; - for (r2 = r->mp_next; r2; r2 = r2->mp_next) + for (r2 = r; r2; r2 = r2->mp_next) { struct neighbor *n = neigh_find2(p, &r2->via, r2->via_if, NEF_STICKY); if (n) @@ -221,20 +199,19 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) r2->neigh = n; static_update_bfd(p, r2); - r2->installed = static_decide(cf, r2); - count += r2->installed; + r2->state = static_decide(cf,r2) ? STS_WANT : 0; + count++; } else { log(L_ERR "Static route destination %I is invalid. Ignoring.", r2->via); - r2->installed = 0; + r2->state = 0; } } if (count) static_install(p, r, NULL); - else - static_remove(p, r); + break; } @@ -247,20 +224,13 @@ static void static_rte_cleanup(struct proto *p UNUSED, struct static_route *r) { struct static_route *r2; - - if (r->bfd_req) - { - rfree(r->bfd_req); - r->bfd_req = NULL; - } - - if (r->dest == RTD_MULTIPATH) - for (r2 = r->mp_next; r2; r2 = r2->mp_next) - if (r2->bfd_req) - { - rfree(r2->bfd_req); - r2->bfd_req = NULL; - } + + for (r2 = r; r2; r2 = r2->mp_next) + if (r2->bfd_req) + { + rfree(r2->bfd_req); + r2->bfd_req = NULL; + } } static int @@ -293,11 +263,11 @@ static_shutdown(struct proto *p) /* Just reset the flag, the routes will be flushed by the nest */ WALK_LIST(r, cf->iface_routes) - r->installed = 0; + r->state = 0; WALK_LIST(r, cf->other_routes) { static_rte_cleanup(p, r); - r->installed = 0; + r->state = 0; } /* Handle failure during channel reconfigure */ @@ -306,9 +276,9 @@ static_shutdown(struct proto *p) if (cf) { WALK_LIST(r, cf->iface_routes) - r->installed = 0; + r->state = 0; WALK_LIST(r, cf->other_routes) - r->installed = 0; + r->state = 0; } return PS_DOWN; @@ -326,40 +296,13 @@ static_cleanup(struct proto *p) static void static_update_rte(struct proto *p, struct static_route *r) { - switch (r->dest) - { - case RTD_ROUTER: - if (static_decide((struct static_config *) p->cf, r)) - static_install(p, r, r->neigh->iface); - else - static_remove(p, r); - break; + if (r->dest != RTD_UNICAST) + return; - case RTD_NONE: /* a part of multipath route */ - { - int decision = static_decide((struct static_config *) p->cf, r); - if (decision == r->installed) - break; /* no change */ - r->installed = decision; - - struct static_route *r1, *r2; - int count = 0; - r1 = (void *) r->if_name; /* really */ - for (r2 = r1->mp_next; r2; r2 = r2->mp_next) - count += r2->installed; - - if (count) - { - /* Set of nexthops changed - force reinstall */ - r1->installed = 0; - static_install(p, r1, NULL); - } - else - static_remove(p, r1); - - break; - } - } + if (static_decide((struct static_config *) p->cf, r)) + static_install(p, r, r->neigh->iface); + else + static_remove(p, r); } static void @@ -391,18 +334,13 @@ static void static_dump_rt(struct static_route *r) { debug("%-1N: ", r->net); - switch (r->dest) - { - case RTD_ROUTER: - debug("via %I\n", r->via); - break; - case RTD_DEVICE: + if (r->dest == RTD_UNICAST) + if (ipa_zero(r->via)) debug("dev %s\n", r->if_name); - break; - default: - debug("rtd %d\n", r->dest); - break; - } + else + debug("via %I\n", r->via); + else + debug("rtd %d\n", r->dest); } static void @@ -496,22 +434,27 @@ static_same_dest(struct static_route *x, struct static_route *y) switch (x->dest) { - case RTD_ROUTER: - return ipa_equal(x->via, y->via) && (x->via_if == y->via_if); - - case RTD_DEVICE: - return !strcmp(x->if_name, y->if_name); - - case RTD_MULTIPATH: - for (x = x->mp_next, y = y->mp_next; - x && y; - x = x->mp_next, y = y->mp_next) - if (!ipa_equal(x->via, y->via) || - (x->via_if != y->via_if) || - (x->use_bfd != y->use_bfd) || - (x->weight != y->weight)) - return 0; - return !x && !y; + case RTD_UNICAST: + { + struct static_route *xc, *yc; + for (xc = x, yc = y; xc && yc; xc = xc->mp_next, yc = yc->mp_next) + { + if (ipa_nonzero(xc->via) && ipa_nonzero(yc->via)) + { + if (!ipa_equal(x->via, y->via) || + (x->via_if != y->via_if) || + (x->use_bfd != y->use_bfd) || + (x->weight != y->weight)) + return 0; + } + else + if (strcmp(x->if_name, y->if_name) || + (x->use_bfd != y->use_bfd) || + (x->weight != y->weight)) + return 0; + } + return 1; + } case RTDX_RECURSIVE: return ipa_equal(x->via, y->via); @@ -556,10 +499,10 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) found: /* If destination is different, force reinstall */ - if ((r->installed > 0) && !static_same_rte(r, t)) - t->installed = -1; + if (r->state && !static_same_rte(r, t)) + t->state = r->state | STS_WANT | STS_FORCE; else - t->installed = r->installed; + t->state = r->state; } static inline rtable * @@ -606,37 +549,24 @@ static_reconfigure(struct proto *p, struct proto_config *CF) static void static_copy_routes(list *dlst, list *slst) { - struct static_route *dr, *sr; + struct static_route *sr; init_list(dlst); WALK_LIST(sr, *slst) { - /* copy one route */ - dr = cfg_alloc(sizeof(struct static_route)); - memcpy(dr, sr, sizeof(struct static_route)); + struct static_route *srr, *drr = NULL; + for (srr = sr; srr; srr = srr->mp_next) + { + /* copy one route */ + struct static_route *dr = cfg_alloc(sizeof(struct static_route)); + if (drr) + drr->mp_next = dr; + else + add_tail(dlst, &(dr->n)); - /* This fn is supposed to be called on fresh src routes, which have 'live' - fields (like .chain, .neigh or .installed) zero, so no need to zero them */ - - /* We need to copy multipath chain, because there are backptrs in 'if_name' */ - if (dr->dest == RTD_MULTIPATH) - { - struct static_route *md, *ms, **mp_last; - - mp_last = &(dr->mp_next); - for (ms = sr->mp_next; ms; ms = ms->mp_next) - { - md = cfg_alloc(sizeof(struct static_route)); - memcpy(md, ms, sizeof(struct static_route)); - md->if_name = (void *) dr; /* really */ - - *mp_last = md; - mp_last = &(md->mp_next); - } - *mp_last = NULL; - } - - add_tail(dlst, (node *) dr); + memcpy(dr, sr, sizeof(struct static_route)); + drr = dr; + } } } @@ -668,30 +598,39 @@ struct protocol proto_static = { .copy_config = static_copy_config }; -static void -static_show_rt(struct static_route *r) +static byte * +static_format_via(struct static_route *r) { - byte via[IPA_MAX_TEXT_LENGTH + 25]; + static byte via[IPA_MAX_TEXT_LENGTH + 25]; switch (r->dest) { - case RTD_ROUTER: bsprintf(via, "via %I%J", r->via, r->via_if); break; - case RTD_DEVICE: bsprintf(via, "dev %s", r->if_name); break; + case RTD_UNICAST: if (ipa_zero(r->via)) bsprintf(via, "dev %s", r->if_name); + else bsprintf(via, "via %I%J", r->via, r->via_if); + break; case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; - case RTD_MULTIPATH: bsprintf(via, "multipath"); break; case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break; default: bsprintf(via, "???"); } - cli_msg(-1009, "%N %s%s%s", r->net, via, - r->bfd_req ? " (bfd)" : "", r->installed ? "" : " (dormant)"); + return via; +} - struct static_route *r2; - if (r->dest == RTD_MULTIPATH) - for (r2 = r->mp_next; r2; r2 = r2->mp_next) - cli_msg(-1009, "\tvia %I%J weight %d%s%s", r2->via, r2->via_if, r2->weight + 1, - r2->bfd_req ? " (bfd)" : "", r2->installed ? "" : " (dormant)"); +static void +static_show_rt(struct static_route *r) +{ + if (r->mp_next) + { + cli_msg(-1009, "%N", r->net); + struct static_route *r2; + for (r2 = r; r2; r2 = r2->mp_next) + cli_msg(-1009, "\t%s weight %d%s%s", static_format_via(r2), r2->weight + 1, + r2->bfd_req ? " (bfd)" : "", (r2->state & STS_INSTALLED) ? "" : " (dormant)"); + } + else + cli_msg(-1009, "%N %s%s%s", r->net, static_format_via(r), + r->bfd_req ? " (bfd)" : "", (r->state & STS_INSTALLED) ? "" : " (dormant)"); } void diff --git a/proto/static/static.h b/proto/static/static.h index 51486e83..418b3076 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -32,14 +32,19 @@ struct static_route { struct iface *via_if; /* Destination iface, for link-local vias */ struct neighbor *neigh; byte *if_name; /* Name for RTD_DEVICE routes */ - struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ + struct static_route *mp_next; /* Nexthops for multipath routes */ struct f_inst *cmds; /* List of commands for setting attributes */ - int installed; /* Installed in rt table, -1 for reinstall */ + u32 state; /* Current state: STS_* */ int use_bfd; /* Configured to use BFD */ int weight; /* Multipath next hop weight */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */ }; +#define STS_INSTALLED 0x1 +#define STS_INSTALLED_ANY 0x2 +#define STS_WANT 0x4 +#define STS_FORCE 0x8 + /* Dummy nodes (parts of multipath route) abuses masklen field for weight and if_name field for a ptr to the master (RTD_MULTIPATH) node. */ diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index d2372a3d..fbaa8e32 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -148,8 +148,7 @@ krt_capable(rte *e) return a->cast == RTC_UNICAST && - (a->dest == RTD_ROUTER - || a->dest == RTD_DEVICE + ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */ #ifdef RTF_REJECT || a->dest == RTD_UNREACHABLE #endif @@ -190,7 +189,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) net *net = e->net; rta *a = e->attrs; static int msg_seq; - struct iface *j, *i = a->iface; + struct iface *j, *i = a->nh.iface; int l; struct ks_msg msg; char *body = (char *)msg.buf; @@ -243,7 +242,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) } } - gw = a->gw; + gw = a->nh.gw; /* Embed interface ID to link-local address */ if (ipa_is_link_local(gw)) @@ -270,9 +269,28 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) switch (a->dest) { - case RTD_ROUTER: - msg.rtm.rtm_flags |= RTF_GATEWAY; - msg.rtm.rtm_addrs |= RTA_GATEWAY; + case RTD_UNICAST: + if (ipa_zero(gw)) + { + if(i) + { +#ifdef RTF_CLONING + if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */ + msg.rtm.rtm_flags |= RTF_CLONING; +#endif + + if(!i->addr) { + log(L_ERR "KRT: interface %s has no IP addess", i->name); + return -1; + } + + sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); + msg.rtm.rtm_addrs |= RTA_GATEWAY; + } + } else { + msg.rtm.rtm_flags |= RTF_GATEWAY; + msg.rtm.rtm_addrs |= RTA_GATEWAY; + } break; #ifdef RTF_REJECT @@ -281,23 +299,6 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) #ifdef RTF_BLACKHOLE case RTD_BLACKHOLE: #endif - case RTD_DEVICE: - if(i) - { -#ifdef RTF_CLONING - if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */ - msg.rtm.rtm_flags |= RTF_CLONING; -#endif - - if(!i->addr) { - log(L_ERR "KRT: interface %s has no IP addess", i->name); - return -1; - } - - sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); - msg.rtm.rtm_addrs |= RTA_GATEWAY; - } - break; default: bug("krt-sock: unknown flags, but not filtered"); } @@ -489,39 +490,40 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) } #endif - a.iface = if_find_by_index(msg->rtm.rtm_index); - if (!a.iface) + a.nh.iface = if_find_by_index(msg->rtm.rtm_index); + if (!a.nh.iface) { log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, msg->rtm.rtm_index); return; } + a.dest = RTD_UNICAST; + a.nh.next = NULL; if (flags & RTF_GATEWAY) { neighbor *ng; - a.dest = RTD_ROUTER; - a.gw = igate; + a.nh.gw = igate; /* Clean up embedded interface ID returned in link-local address */ - if (ipa_is_link_local(a.gw)) - _I0(a.gw) = 0xfe800000; + if (ipa_is_link_local(a.nh.gw)) + _I0(a.nh.gw) = 0xfe800000; - ng = neigh_find2(&p->p, &a.gw, a.iface, 0); + ng = neigh_find2(&p->p, &a.nh.gw, a.nh.iface, 0); if (!ng || (ng->scope == SCOPE_HOST)) { /* Ignore routes with next-hop 127.0.0.1, host routes with such next-hop appear on OpenBSD for address aliases. */ - if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST)) + if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST)) return; log(L_ERR "KRT: Received route %N with strange next-hop %I", - net->n.addr, a.gw); + net->n.addr, a.nh.gw); return; } } else - a.dest = RTD_DEVICE; + a.nh.gw = IPA_NONE; done: e = rte_get_temp(&a); 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: + case RTD_UNICAST: 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, 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); } } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index e899671d..9f66d2f4 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -645,17 +645,11 @@ krt_same_dest(rte *k, rte *e) if (ka->dest != ea->dest) return 0; - switch (ka->dest) - { - case RTD_ROUTER: - return ipa_equal(ka->gw, ea->gw); - case RTD_DEVICE: - return !strcmp(ka->iface->name, ea->iface->name); - case RTD_MULTIPATH: - return mpnh_same(ka->nexthops, ea->nexthops); - default: - return 1; - } + + if (ka->dest == RTD_UNICAST) + return nexthop_same(&(ka->nh), &(ea->nh)); + + return 1; } /* @@ -1011,10 +1005,16 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct li return -1; } - if (!KRT_CF->devroutes && - (e->attrs->dest == RTD_DEVICE) && - (e->attrs->source != RTS_STATIC_DEVICE)) - return -1; + if (!KRT_CF->devroutes && (e->attrs->source != RTS_STATIC_DEVICE)) + { + struct nexthop *nh = &(e->attrs->nh); + for (; nh; nh = nh->next) + if (ipa_nonzero(nh->gw)) + break; + + if (!nh) /* Gone through all the nexthops and no explicit GW found */ + return -1; + } if (!krt_capable(e)) return -1;