From 4e276a8920ed0496836f002f144943ab42f120f6 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Fri, 6 May 2016 15:48:35 +0200 Subject: 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. --- nest/route.h | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'nest/route.h') 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++ */ -- cgit v1.2.3 From 5b208e296fed0beddce16188478c5119df610d89 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Tue, 7 Jun 2016 11:46:07 +0200 Subject: Removing (struct rta)->cast. Never used. --- filter/config.Y | 3 +-- filter/filter.c | 1 - filter/filter.h | 7 +++---- nest/config.Y | 1 - nest/route.h | 11 ++++------- nest/rt-attr.c | 13 ++++++------- nest/rt-dev.c | 1 - proto/bgp/packets.c | 1 - proto/ospf/rt.c | 1 - proto/rip/rip.c | 1 - proto/rpki/rpki.c | 1 - proto/static/static.c | 11 +++++------ sysdep/bsd/krt-sock.c | 2 -- sysdep/linux/netlink.c | 4 ---- 14 files changed, 19 insertions(+), 39 deletions(-) (limited to 'nest/route.h') diff --git a/filter/config.Y b/filter/config.Y index 7b4178be..94a7e307 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -397,7 +397,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, - FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, + FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, PREFERENCE, ROA_CHECK, ASN, LEN, MAXLEN, @@ -854,7 +854,6 @@ static_attr: | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; } | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; } | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; } - | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; } | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; } | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; } | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; } diff --git a/filter/filter.c b/filter/filter.c index 926316ac..bc80997f 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -905,7 +905,6 @@ interpret(struct f_inst *what) 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->nh.iface ? rta->nh.iface->name : ""; break; case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break; diff --git a/filter/filter.h b/filter/filter.h index a4808731..0482b83b 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -174,10 +174,9 @@ void val_format(struct f_val v, buffer *buf); #define SA_PROTO 4 #define SA_SOURCE 5 #define SA_SCOPE 6 -#define SA_CAST 7 -#define SA_DEST 8 -#define SA_IFNAME 9 -#define SA_IFINDEX 10 +#define SA_DEST 8 +#define SA_IFNAME 9 +#define SA_IFINDEX 10 struct f_tree { diff --git a/nest/config.Y b/nest/config.Y index 95ce59cd..511936ef 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -78,7 +78,6 @@ CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, 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_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT) CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID) diff --git a/nest/route.h b/nest/route.h index 37c9abfb..154e027e 100644 --- a/nest/route.h +++ b/nest/route.h @@ -358,13 +358,10 @@ typedef struct rta { struct hostentry *hostentry; /* Hostentry for recursive next-hops */ ip_addr from; /* Advertising router */ u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */ - 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; + u8 source; /* Route source (RTS_...) */ + u8 scope; /* Route scope (SCOPE_... -- see ip.h) */ + u8 dest; /* Route destination type (RTD_...) */ + u8 aflags; struct nexthop nh; /* Next hop */ } rta; diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 0eacfe3f..e575ba4a 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1008,7 +1008,9 @@ rta_hash(rta *a) MIX(hostentry); MIX(from); MIX(igp_metric); - mem_hash_mix(&h, a->bf, sizeof(u32)); + MIX(source); + MIX(scope); + MIX(dest); #undef MIX return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs); @@ -1020,7 +1022,6 @@ rta_same(rta *x, rta *y) return (x->src == y->src && x->source == y->source && x->scope == y->scope && - x->cast == y->cast && x->dest == y->dest && x->igp_metric == y->igp_metric && ipa_equal(x->nh.gw, y->nh.gw) && @@ -1163,11 +1164,10 @@ rta_dump(rta *a) "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; - static char *rtc[] = { "", " BC", " MC", " AC" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; - debug("p=%s uc=%d %s %s%s%s h=%04x", - a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast], + debug("p=%s uc=%d %s %s%s h=%04x", + a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtd[a->dest], a->hash_key); if (!(a->aflags & RTAF_CACHED)) debug(" !CACHED"); @@ -1213,10 +1213,9 @@ rta_show(struct cli *c, rta *a, ea_list *eal) { static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect", "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" }; - static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" }; int i; - cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope)); + cli_printf(c, -1008, "\tType: %s %s", src_names[a->source], ip_scope_text(a->scope)); if (!eal) eal = a->eattrs; for(; eal; eal=eal->next) diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 43628af8..5edd1c5d 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -78,7 +78,6 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) .src = src, .source = RTS_DEVICE, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST, .dest = RTD_UNICAST, .nh = { .iface = ad->iface diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 0baa84c9..9c59e6d8 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1439,7 +1439,6 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; - a->cast = RTC_UNICAST; a->dest = RTD_UNREACHABLE; a->from = s->proto->cf->remote_ip; a->eattrs = ea; diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 09cc5776..d28d463b 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1951,7 +1951,6 @@ again1: .src = p->p.main_source, .source = nf->n.type, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST }; nexthop_link(&a0, nf->n.nhs); diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 8b09330c..9bed9249 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -147,7 +147,6 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .src = p->p.main_source, .source = RTS_RIP, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST }; u8 rt_metric = rt->metric; diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 6360dbaf..81268e83 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -124,7 +124,6 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_ .src = p->p.main_source, .source = RTS_RPKI, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST, .dest = RTD_BLACKHOLE, }; diff --git a/proto/static/static.c b/proto/static/static.c index f3cfec01..a63d4d29 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -71,7 +71,6 @@ static_install(struct proto *p, struct static_route *r) a.src = p->main_source; 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; if (r->dest == RTD_UNICAST) { @@ -210,13 +209,13 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) } if (count) - static_install(p, r, NULL); + static_install(p, r); break; } default: - static_install(p, r, NULL); + static_install(p, r); } } @@ -300,7 +299,7 @@ static_update_rte(struct proto *p, struct static_route *r) return; if (static_decide((struct static_config *) p->cf, r)) - static_install(p, r, r->neigh->iface); + static_install(p, r); else static_remove(p, r); } @@ -367,7 +366,7 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) { WALK_LIST(r, c->iface_routes) if (!strcmp(r->if_name, i->name)) - static_install(p, r, i); + static_install(p, r); } else if (flags & IF_CHANGE_DOWN) { @@ -535,7 +534,7 @@ static_reconfigure(struct proto *p, struct proto_config *CF) { struct iface *ifa; if ((ifa = if_find_by_name(r->if_name)) && (ifa->flags & IF_UP)) - static_install(p, r, ifa); + static_install(p, r); } WALK_LIST(r, n->other_routes) static_add(p, n, r); diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index fbaa8e32..2e0f194b 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -147,7 +147,6 @@ krt_capable(rte *e) rta *a = e->attrs; return - a->cast == RTC_UNICAST && ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */ #ifdef RTF_REJECT || a->dest == RTD_UNREACHABLE @@ -470,7 +469,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) .src = p->p.main_source, .source = RTS_INHERIT, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST }; /* reject/blackhole routes have also set RTF_GATEWAY, diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 6e75ee53..c9a30719 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -952,9 +952,6 @@ krt_capable(rte *e) { rta *a = e->attrs; - if (a->cast != RTC_UNICAST) - return 0; - switch (a->dest) { case RTD_UNICAST: @@ -1345,7 +1342,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) ra->src = p->p.main_source; ra->source = RTS_INHERIT; ra->scope = SCOPE_UNIVERSE; - ra->cast = RTC_UNICAST; switch (i->rtm_type) { -- cgit v1.2.3 From ec5e5d23faa482495c84163c4ae38d9a31bdc00f Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Fri, 10 Jun 2016 14:34:41 +0200 Subject: Nexthop: Support for label stack in nest --- nest/route.h | 9 +++++- nest/rt-attr.c | 82 ++++++++++++++++++++++++++++++++++++++------------- nest/rt-table.c | 2 +- proto/ospf/rt.c | 1 + proto/pipe/pipe.c | 17 ++++++----- proto/static/static.c | 1 + 6 files changed, 83 insertions(+), 29 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index 154e027e..d9a1737b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -338,6 +338,8 @@ struct nexthop { struct iface *iface; /* Outgoing interface */ struct nexthop *next; byte weight; + byte labels; /* Number of labels appended */ + u32 label[0]; }; struct rte_src { @@ -510,16 +512,21 @@ 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); +#define NEXTHOP_MAX_LABEL_STACK 8 + +static inline size_t nexthop_size(const struct nexthop *nh) +{ return sizeof(struct nexthop) + sizeof(u32)*nh->labels; } 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; } +{ memcpy(&a->nh, from, nexthop_size(from)); } void nexthop_insert(struct nexthop *n, struct nexthop *y); int nexthop_is_sorted(struct nexthop *x); void rta_init(void); +static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; } rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; } static inline rta *rta_clone(rta *r) { r->uc++; return r; } diff --git a/nest/rt-attr.c b/nest/rt-attr.c index e575ba4a..d3671a53 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -60,8 +60,8 @@ pool *rta_pool; -static slab *rta_slab; -static slab *nexthop_slab; +static slab *rta_slab_[4]; +static slab *nexthop_slab_[4]; static slab *rte_src_slab; static struct idm src_ids; @@ -148,7 +148,11 @@ nexthop_hash(struct nexthop *x) { u32 h = 0; for (; x; x = x->next) - h ^= ipa_hash(x->gw); + { + h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9); + for (int i=0; ilabels; i++) + h ^= x->label[i] ^ (h << 6) ^ (h >> 7); + } return h; } @@ -157,10 +161,15 @@ int 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)) + { + if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels)) return 0; + for (int i=0; ilabels; i++) + if (x->label[i] != y->label[i]) + return 0; + } - return x == y; + return 1; } static int @@ -182,17 +191,28 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y) if (r) return r; + r = ((int) y->labels) - ((int) x->labels); + if (r) + return r; + + for (int i=0; ilabels; i++) + { + r = ((int) y->label[i]) - ((int) x->label[i]); + if (r) + return r; + } + return ((int) x->iface->index) - ((int) y->iface->index); } static inline struct nexthop * nexthop_copy_node(const struct nexthop *src, linpool *lp) { - struct nexthop *n = lp_alloc(lp, sizeof(struct nexthop)); - n->gw = src->gw; - n->iface = src->iface; + struct nexthop *n = lp_alloc(lp, nexthop_size(src)); + + memcpy(n, src, nexthop_size(src)); n->next = NULL; - n->weight = src->weight; + return n; } @@ -291,6 +311,12 @@ nexthop_is_sorted(struct nexthop *x) return 1; } +static inline slab * +nexthop_slab(struct nexthop *nh) +{ + return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels]; +} + static struct nexthop * nexthop_copy(struct nexthop *o) { @@ -299,7 +325,7 @@ nexthop_copy(struct nexthop *o) for (; o; o = o->next) { - struct nexthop *n = sl_alloc(nexthop_slab); + struct nexthop *n = sl_alloc(nexthop_slab(o)); n->gw = o->gw; n->iface = o->iface; n->next = NULL; @@ -320,7 +346,7 @@ nexthop_free(struct nexthop *o) while (o) { n = o->next; - sl_free(nexthop_slab, o); + sl_free(nexthop_slab(o), o); o = n; } } @@ -1024,20 +1050,24 @@ rta_same(rta *x, rta *y) x->scope == y->scope && x->dest == y->dest && x->igp_metric == y->igp_metric && - ipa_equal(x->nh.gw, y->nh.gw) && ipa_equal(x->from, y->from) && - x->nh.iface == y->nh.iface && x->hostentry == y->hostentry && nexthop_same(&(x->nh), &(y->nh)) && ea_same(x->eattrs, y->eattrs)); } +static inline slab * +rta_slab(rta *a) +{ + return rta_slab_[a->nh.labels > 2 ? 3 : a->nh.labels]; +} + static rta * rta_copy(rta *o) { - rta *r = sl_alloc(rta_slab); + rta *r = sl_alloc(rta_slab(o)); - memcpy(r, o, sizeof(rta)); + memcpy(r, o, rta_size(o)); r->uc = 1; r->nh.next = nexthop_copy(o->nh.next); r->eattrs = ea_list_copy(o->eattrs); @@ -1138,14 +1168,14 @@ rta__free(rta *a) if (a->nh.next) nexthop_free(a->nh.next); ea_free(a->eattrs); - sl_free(rta_slab, a); + sl_free(rta_slab(a), a); } rta * rta_do_cow(rta *o, linpool *lp) { - rta *r = lp_alloc(lp, sizeof(rta)); - memcpy(r, o, sizeof(rta)); + rta *r = lp_alloc(lp, rta_size(o)); + memcpy(r, o, rta_size(o)); r->aflags = 0; r->uc = 0; return r; @@ -1176,6 +1206,9 @@ rta_dump(rta *a) for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) { if (ipa_nonzero(nh->gw)) debug(" ->%I", nh->gw); + if (nh->labels) debug(" L %d", nh->label[0]); + for (int i=1; ilabels; i++) + debug("/%d", nh->label[i]); debug(" [%s]", nh->iface ? nh->iface->name : "???"); } if (a->eattrs) @@ -1233,8 +1266,17 @@ void rta_init(void) { rta_pool = rp_new(&root_pool, "Attributes"); - rta_slab = sl_new(rta_pool, sizeof(rta)); - nexthop_slab = sl_new(rta_pool, sizeof(struct nexthop)); + + rta_slab_[0] = sl_new(rta_pool, sizeof(rta)); + rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)); + rta_slab_[2] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*2); + rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK); + + nexthop_slab_[0] = sl_new(rta_pool, sizeof(struct nexthop)); + nexthop_slab_[1] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)); + nexthop_slab_[2] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*2); + nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*NEXTHOP_MAX_LABEL_STACK); + rta_alloc_hash(); rte_src_init(); } diff --git a/nest/rt-table.c b/nest/rt-table.c index 46857d0d..a7ceddb8 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1782,7 +1782,7 @@ static inline rte * rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) { rta a; - memcpy(&a, old->attrs, sizeof(rta)); + memcpy(&a, old->attrs, rta_size(old->attrs)); rta_apply_hostentry(&a, old->attrs->hostentry); a.aflags = 0; diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index d28d463b..74f47810 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -37,6 +37,7 @@ static inline struct nexthop * new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) { struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop)); + nh->labels = 0; nh->gw = gw; nh->iface = iface; nh->next = NULL; diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 8924c200..a4d371fe 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -43,6 +43,8 @@ #include "pipe.h" +#include + static void pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs) { @@ -51,7 +53,7 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o struct rte_src *src; rte *e; - rta a; + rta *a; if (!new && !old) return; @@ -65,12 +67,13 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o if (new) { - memcpy(&a, new->attrs, sizeof(rta)); + a = alloca(rta_size(new->attrs)); + memcpy(a, new->attrs, rta_size(new->attrs)); - a.aflags = 0; - a.eattrs = attrs; - a.hostentry = NULL; - e = rte_get_temp(&a); + a->aflags = 0; + a->eattrs = attrs; + a->hostentry = NULL; + e = rte_get_temp(a); e->pflags = 0; /* Copy protocol specific embedded attributes. */ @@ -78,7 +81,7 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o e->pref = new->pref; e->pflags = new->pflags; - src = a.src; + src = a->src; } else { diff --git a/proto/static/static.c b/proto/static/static.c index a63d4d29..9ecf6df8 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -88,6 +88,7 @@ static_install(struct proto *p, struct static_route *r) nh->gw = r2->via; nh->iface = r2->neigh->iface; nh->weight = r2->weight; + nh->labels = 0; if (a.nh.next) nexthop_insert(&(a.nh), nh); r2->state |= STS_INSTALLED; -- cgit v1.2.3 From f2010f9c65ca69584c34c762fb3e5e957958478e Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Mon, 13 Jun 2016 15:49:53 +0200 Subject: Static: Protocol rework wrt. struct nexthop changes; MPLS label support --- conf/confbase.Y | 18 +++++ doc/bird.sgml | 14 ++-- nest/route.h | 2 + nest/rt-attr.c | 9 +++ nest/rt-table.c | 28 ++++--- proto/static/config.Y | 95 +++++++++++----------- proto/static/static.c | 213 +++++++++++++++++++++++++++++++++++--------------- proto/static/static.h | 17 ++-- 8 files changed, 259 insertions(+), 137 deletions(-) (limited to 'nest/route.h') diff --git a/conf/confbase.Y b/conf/confbase.Y index aec4aeb4..11393fe2 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -64,6 +64,7 @@ CF_DECLS struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; + u32 *lbl; } %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT @@ -82,6 +83,7 @@ CF_DECLS %type ipa %type net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type net_ net_any net_roa4_ net_roa6_ net_roa_ +%type label_stack_start label_stack %type text opttext @@ -266,6 +268,22 @@ net_or_ipa: } ; +label_stack_start: NUM +{ + $$ = cfg_allocz(sizeof(u32) * (NEXTHOP_MAX_LABEL_STACK+1)); + $$[0] = 1; + $$[1] = $1; +}; + +label_stack: + label_stack_start + | label_stack '/' NUM { + if ($1[0] >= NEXTHOP_MAX_LABEL_STACK) + cf_error("Too many labels in stack."); + $1[++$1[0]] = $3; + $$ = $1; + } +; datetime: TEXT { diff --git a/doc/bird.sgml b/doc/bird.sgml index 999fa294..23026eae 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -4141,8 +4141,8 @@ specific destination for them and you don't want to send them out through the default route to prevent routing loops).

There are five types of static routes: `classical' routes telling to forward -packets to a neighboring router, multipath routes specifying several (possibly -weighted) neighboring routers, device routes specifying forwarding to hosts on a +packets to a neighboring router (single path or multipath, possibly weighted), +device routes specifying forwarding to hosts on a directly connected network, recursive routes computing their nexthops by doing route table lookups for a given IP, and special routes (sink, blackhole etc.) which specify a special action to be done instead of forwarding the packet. @@ -4174,14 +4174,14 @@ definition of the protocol contains mainly a list of static routes.

Route definitions (each may also contain a block of per-route options): -

There are five types of static routes: `classical' routes telling to forward +

There are four types of static routes: `classical' routes telling to forward packets to a neighboring router (single path or multipath, possibly weighted), -device routes specifying forwarding to hosts on a -directly connected network, recursive routes computing their nexthops by doing -route table lookups for a given IP, and special routes (sink, blackhole etc.) -which specify a special action to be done instead of forwarding the packet. +device routes specifying forwarding to hosts on a directly connected network, +recursive routes computing their nexthops by doing route table lookups for a +given IP, and special routes (sink, blackhole etc.) which specify a special +action to be done instead of forwarding the packet.

When the particular destination is not available (the interface is down or the next hop of the route is not a neighbor at the moment), Static just diff --git a/filter/filter.h b/filter/filter.h index 0482b83b..855219ec 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -174,9 +174,9 @@ void val_format(struct f_val v, buffer *buf); #define SA_PROTO 4 #define SA_SOURCE 5 #define SA_SCOPE 6 -#define SA_DEST 8 -#define SA_IFNAME 9 -#define SA_IFINDEX 10 +#define SA_DEST 7 +#define SA_IFNAME 8 +#define SA_IFINDEX 9 struct f_tree { diff --git a/lib/alloca.h b/lib/alloca.h index f0d61bb4..e5557cdb 100644 --- a/lib/alloca.h +++ b/lib/alloca.h @@ -15,4 +15,6 @@ #include #endif +#define allocz(len) ({ void *_x = alloca(len); memset(_x, 0, len); _x; }) + #endif diff --git a/lib/net.c b/lib/net.c index e46be8b2..74cea277 100644 --- a/lib/net.c +++ b/lib/net.c @@ -69,21 +69,20 @@ net_format(const net_addr *N, char *buf, int buflen) case NET_VPN4: switch (n->vpn4.rd >> 48) { - case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen); - case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); - case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); + case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen); + case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); + case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); + default: return bsnprintf(buf, buflen, "X:%08x:%08x %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen); } - return bsnprintf(buf, buflen, "X: %016x %I4/%d", (n->vpn4.rd), n->vpn4.prefix, n->vpn4.pxlen); - - /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4. */ case NET_VPN6: + /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4 */ switch (n->vpn6.rd >> 48) { - case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen); - case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); - case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); + case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen); + case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); + case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); + default: return bsnprintf(buf, buflen, "X:%08x:%08x %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen); } - return bsnprintf(buf, buflen, "X: %016x %I6/%d", (n->vpn6.rd), n->vpn6.prefix, n->vpn6.pxlen); case NET_ROA4: return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn); case NET_ROA6: diff --git a/lib/net.h b/lib/net.h index 7c124fc0..7144bcb9 100644 --- a/lib/net.h +++ b/lib/net.h @@ -306,6 +306,9 @@ static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4 static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) { return net_equal((const net_addr *) a, (const net_addr *) b); } +static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b) +{ return !memcmp(a, b, sizeof(net_addr_mpls)); } + static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b) { return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } @@ -313,8 +316,6 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) { return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } -static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b) -{ return !memcmp(a, b, sizeof(net_addr_mpls)); } static inline int net_zero_ip4(const net_addr_ip4 *a) { return !a->pxlen && ip4_zero(a->prefix); } @@ -404,16 +405,17 @@ static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src) { memcpy(dst, src, sizeof(net_addr_mpls)); } + +/* XXXX */ +static inline u32 u64_hash(u64 a) +{ return u32_hash(a); } + static inline u32 net_hash_ip4(const net_addr_ip4 *n) { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); } static inline u32 net_hash_ip6(const net_addr_ip6 *n) { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); } -/* XXXX */ -static inline u32 u64_hash(u64 a) -{ return u32_hash(a); } - static inline u32 net_hash_vpn4(const net_addr_vpn4 *n) { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); } @@ -452,7 +454,7 @@ static inline int net_validate_ip6(const net_addr_ip6 *n) static inline int net_validate_mpls(const net_addr_mpls *n) { - return n->label < (1<<20); + return n->label < (1 << 20); } int net_validate(const net_addr *N); diff --git a/nest/route.h b/nest/route.h index eb98b609..1e0a14bc 100644 --- a/nest/route.h +++ b/nest/route.h @@ -390,11 +390,11 @@ typedef struct rta { #define RTC_MULTICAST 2 #define RTC_ANYCAST 3 /* IPv6 Anycast */ -#define RTD_UNICAST 0 /* Next hop is neighbor router */ +#define RTD_NONE 0 /* Undefined next hop */ +#define RTD_UNICAST 1 /* 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_NONE 6 /* Invalid RTD */ /* Flags for net->n.flags, used by kernel syncer */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ @@ -408,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_UNICAST); } +{ return r->attrs->dest == RTD_UNICAST; } /* @@ -523,7 +523,7 @@ static inline int nexthop_same(struct nexthop *x, struct nexthop *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) { memcpy(&a->nh, from, nexthop_size(from)); } -void nexthop_insert(struct nexthop *n, struct nexthop *y); +void nexthop_insert(struct nexthop **n, struct nexthop *y); int nexthop_is_sorted(struct nexthop *x); void rta_init(void); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 120a8e24..afc97e22 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -150,7 +150,8 @@ nexthop_hash(struct nexthop *x) for (; x; x = x->next) { h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9); - for (int i=0; ilabels; i++) + + for (int i = 0; i < x->labels; i++) h ^= x->label[i] ^ (h << 6) ^ (h >> 7); } @@ -164,12 +165,13 @@ nexthop__same(struct nexthop *x, struct nexthop *y) { if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels)) return 0; - for (int i=0; ilabels; i++) + + for (int i = 0; i < x->labels; i++) if (x->label[i] != y->label[i]) return 0; } - return 1; + return x == y; } static int @@ -195,7 +197,7 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y) if (r) return r; - for (int i=0; ilabels; i++) + for (int i = 0; i < y->labels; i++) { r = ((int) y->label[i]) - ((int) x->label[i]); if (r) @@ -271,34 +273,22 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin } void -nexthop_insert(struct nexthop *n, struct nexthop *x) +nexthop_insert(struct nexthop **n, struct nexthop *x) { - struct nexthop tmp; - memcpy(&tmp, n, sizeof(struct nexthop)); - if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */ - { - 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)) + for (; *n; n = &((*n)->next)) { - int cmp = nexthop_compare_node(*nn, x); + int cmp = nexthop_compare_node(*n, x); if (cmp < 0) continue; - - if (cmp > 0) - { - x->next = *nn; - *nn = x; - } - - return; + else if (cmp > 0) + break; + else + return; } + x->next = *n; + *n = x; } int @@ -314,7 +304,7 @@ nexthop_is_sorted(struct nexthop *x) static inline slab * nexthop_slab(struct nexthop *nh) { - return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels]; + return nexthop_slab_[MIN(nh->labels, 3)]; } static struct nexthop * diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 5edd1c5d..9993da24 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -79,9 +79,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) .source = RTS_DEVICE, .scope = SCOPE_UNIVERSE, .dest = RTD_UNICAST, - .nh = { - .iface = ad->iface - } + .nh.iface = ad->iface, }; a = rta_lookup(&a0); diff --git a/nest/rt-table.c b/nest/rt-table.c index ef402f28..a33b7909 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1768,7 +1768,6 @@ static inline void rta_apply_hostentry(rta *a, struct hostentry *he) { a->hostentry = he; - a->dest = he->dest; a->igp_metric = he->igp_metric; @@ -1810,14 +1809,14 @@ rta_apply_hostentry(rta *a, struct hostentry *he) static inline rte * rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) { - rta *ap = alloca(RTA_MAX_SIZE); - memcpy(ap, old->attrs, rta_size(old->attrs)); - rta_apply_hostentry(ap, old->attrs->hostentry); - ap->aflags = 0; + rta *a = alloca(RTA_MAX_SIZE); + memcpy(a, old->attrs, rta_size(old->attrs)); + rta_apply_hostentry(a, old->attrs->hostentry); + a->aflags = 0; rte *e = sl_alloc(rte_slab); memcpy(e, old, sizeof(rte)); - e->attrs = rta_lookup(ap); + e->attrs = rta_lookup(a); return e; } @@ -2373,7 +2372,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) } if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next) - { /* We have singlepath device route */ + { + /* 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 */ @@ -2389,7 +2389,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) else { /* The host is reachable through some route entry */ - he->nh = (&a->nh); + he->nh = &(a->nh); he->dest = a->dest; } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 11666f30..1b124a17 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1461,8 +1461,7 @@ bgp_get_neighbor(rte *r) static inline int rte_resolvable(rte *rt) { - int rd = rt->attrs->dest; - return (rd == RTD_UNICAST); + return rt->attrs->dest == RTD_UNICAST; } int diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 9c59e6d8..9380f999 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -700,9 +700,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll) WITHDRAW(BAD_NEXT_HOP); a->dest = RTD_UNICAST; - a->nh.gw = nbr->addr; - a->nh.iface = nbr->iface; - a->nh.next = NULL; + a->nh = (struct nexthop){ .gw = nbr->addr, .iface = nbr->iface }; a->hostentry = NULL; a->igp_metric = 0; } @@ -749,8 +747,8 @@ bgp_use_gateway(struct bgp_export_state *s) if (s->channel->cf->next_hop_self) return 0; - /* We need valid global gateway */ - if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw)) + /* We need one valid global gateway */ + 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 */ @@ -1434,12 +1432,10 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis if (ea) { - a = alloca(sizeof(struct rta)); - memset(a, 0, sizeof(struct rta)); + a = allocz(sizeof(struct rta)); a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; - a->dest = RTD_UNREACHABLE; a->from = s->proto->cf->remote_ip; a->eattrs = ea; diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 74f47810..1b0ac5e9 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -36,11 +36,9 @@ unresolved_vlink(ort *ort) static inline struct nexthop * new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) { - struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop)); - nh->labels = 0; + struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop)); nh->gw = gw; nh->iface = iface; - nh->next = NULL; nh->weight = weight; return nh; } @@ -1907,7 +1905,6 @@ 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->nh.iface != or->nh.iface) || !ipa_equal(nr->nh.gw, or->nh.gw) || !nexthop_same(&(nr->nh), &(or->nh)); } @@ -1952,11 +1949,10 @@ again1: .src = p->p.main_source, .source = nf->n.type, .scope = SCOPE_UNIVERSE, + .dest = RTD_UNICAST, + .nh = *(nf->n.nhs), }; - nexthop_link(&a0, nf->n.nhs); - a0.dest = RTD_UNICAST; - if (reload || ort_changed(nf, &a0)) { rta *a = rta_lookup(&a0); diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index a4d371fe..310f3c01 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -43,8 +43,6 @@ #include "pipe.h" -#include - static void pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs) { diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 9bed9249..157093aa 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -147,20 +147,16 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .src = p->p.main_source, .source = RTS_RIP, .scope = SCOPE_UNIVERSE, + .dest = RTD_UNICAST, }; u8 rt_metric = rt->metric; u16 rt_tag = rt->tag; - struct rip_rte *rt2 = rt->next; - /* Find second valid rte */ - while (rt2 && !rip_valid_rte(rt2)) - rt2 = rt2->next; - - a0.dest = RTD_UNICAST; - if (p->ecmp && rt2) + if (p->ecmp) { /* ECMP route */ + struct nexthop *nhs = NULL; int num = 0; for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next) @@ -168,28 +164,27 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) if (!rip_valid_rte(rt)) continue; - struct nexthop *nh = (a0.nh.next ? &(a0.nh) : alloca(sizeof(struct nexthop))); + struct nexthop *nh = allocz(sizeof(struct nexthop)); nh->gw = rt->next_hop; nh->iface = rt->from->nbr->iface; nh->weight = rt->from->ifa->cf->ecmp_weight; - if (a0.nh.next) - nexthop_insert(&(a0.nh), nh); - + nexthop_insert(&nhs, nh); num++; if (rt->tag != rt_tag) rt_tag = 0; } + + a0.nh = *nhs; } else { /* Unipath route */ - a0.nh.next = NULL; + a0.from = rt->from->nbr->addr; a0.nh.gw = rt->next_hop; a0.nh.iface = rt->from->nbr->iface; - a0.from = rt->from->nbr->addr; } rta *a = rta_lookup(&a0); diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 81268e83..497edd3c 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -124,7 +124,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_ .src = p->p.main_source, .source = RTS_RPKI, .scope = SCOPE_UNIVERSE, - .dest = RTD_BLACKHOLE, + .dest = RTD_NONE, }; rta *a = rta_lookup(&a0); diff --git a/proto/static/config.Y b/proto/static/config.Y index 2fb54448..16c276ce 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -13,9 +13,33 @@ CF_HDR CF_DEFINES #define STATIC_CFG ((struct static_config *) this_proto) -static struct static_route *this_srt, *last_srt; +static struct static_route *this_srt, *this_snh; static struct f_inst **this_srt_last_cmd; +static struct static_route * +static_nexthop_new(void) +{ + struct static_route *nh; + + if (!this_snh) + { + /* First next hop */ + nh = this_srt; + rem_node(&this_srt->n); + } + else + { + /* Additional next hop */ + nh = cfg_allocz(sizeof(struct static_route)); + nh->net = this_srt->net; + this_snh->mp_next = nh; + } + + nh->dest = RTD_UNICAST; + nh->mp_head = this_srt; + return nh; +}; + static void static_route_finish(void) { } @@ -45,48 +69,35 @@ static_proto: | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } ; -stat_nexthop_via: VIA -{ - if (last_srt) - { - last_srt = (last_srt->mp_next = cfg_allocz(sizeof(struct static_route))); - last_srt->net = this_srt->net; - } - else - { - last_srt = this_srt; - rem_node(&this_srt->n); - } - - last_srt->mp_head = this_srt; - last_srt->dest = RTD_UNICAST; -}; - -stat_nexthop_ident: - stat_nexthop_via ipa ipa_scope { - last_srt->via = $2; - last_srt->iface = $3; - add_tail(&STATIC_CFG->neigh_routes, &last_srt->n); +stat_nexthop: + VIA ipa ipa_scope { + this_snh = static_nexthop_new(); + this_snh->via = $2; + this_snh->iface = $3; + add_tail(&STATIC_CFG->neigh_routes, &this_snh->n); } - | stat_nexthop_via TEXT { - last_srt->via = IPA_NONE; - last_srt->if_name = $2; - add_tail(&STATIC_CFG->iface_routes, &last_srt->n); + | VIA TEXT { + this_snh = static_nexthop_new(); + this_snh->via = IPA_NONE; + this_snh->if_name = $2; + add_tail(&STATIC_CFG->iface_routes, &this_snh->n); } - | stat_nexthop_ident MPLS label_stack { - last_srt->label_count = $3[0]; - last_srt->label_stack = &($3[1]); + | stat_nexthop MPLS label_stack { + this_snh->label_count = $3[0]; + this_snh->label_stack = &($3[1]); } - | stat_nexthop_ident WEIGHT expr { - last_srt->weight = $3 - 1; + | stat_nexthop WEIGHT expr { + this_snh->weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); } - | stat_nexthop_ident BFD bool { last_srt->use_bfd = $3; cf_check_bfd($3); } + | stat_nexthop BFD bool { + this_snh->use_bfd = $3; cf_check_bfd($3); + } ; -stat_nexthop: - stat_nexthop_ident - | stat_nexthop stat_nexthop_ident +stat_nexthops: + stat_nexthop + | stat_nexthops stat_nexthop ; stat_route0: ROUTE net_any { @@ -95,12 +106,12 @@ stat_route0: ROUTE net_any { this_srt->net = $2; this_srt_last_cmd = &(this_srt->cmds); this_srt->mp_next = NULL; - last_srt = NULL; + this_snh = NULL; } ; stat_route: - stat_route0 stat_nexthop + stat_route0 stat_nexthops | 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 3e03708c..e5251bf6 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -60,54 +60,44 @@ p_igp_table(struct proto *p) static void static_install(struct proto *p, struct static_route *r) { - rta *ap = alloca(RTA_MAX_SIZE); + rta *ap = allocz(RTA_MAX_SIZE); rte *e; if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST) goto drop; DBG("Installing static route %N, rtd=%d\n", r->net, r->dest); - bzero(ap, RTA_MAX_SIZE); ap->src = p->main_source; - ap->source = ((r->dest == RTD_UNICAST) && ipa_zero(r->via)) ? RTS_STATIC_DEVICE : RTS_STATIC; + ap->source = RTS_STATIC; ap->scope = SCOPE_UNIVERSE; ap->dest = r->dest; if (r->dest == RTD_UNICAST) { + struct nexthop *nhs = NULL; struct static_route *r2; - int num = 0, update = 0; + int update = 0; + r = r->mp_head; for (r2 = r; r2; r2 = r2->mp_next) { - if ((r2->state & STS_FORCE) || (!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT))) update++; if (r2->state & STS_WANT) - { - struct nexthop *nh = (ap->nh.next) ? alloca(NEXTHOP_MAX_SIZE) : &(ap->nh); - if (ipa_zero(r2->via)) // Device nexthop - { - nh->gw = IPA_NONE; - nh->iface = r2->iface; - } - else // Router nexthop - { - nh->gw = r2->via; - nh->iface = r2->neigh->iface; - } - nh->weight = r2->weight; - nh->labels = r2->label_count; - for (int i=0; ilabels; i++) - nh->label[i] = r2->label_stack[i]; - - if (ap->nh.next) - nexthop_insert(&(ap->nh), nh); - r2->state |= STS_INSTALLED; - num++; - } + { + struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE); + + nh->gw = r2->via; + nh->iface = r2->neigh ? r2->neigh->iface : r2->iface; + nh->weight = r2->weight; + nh->labels = r2->label_count; + memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32)); + + r2->state |= STS_INSTALLED; + nexthop_insert(&nhs, nh); + } else r2->state = 0; } @@ -115,18 +105,19 @@ static_install(struct proto *p, struct static_route *r) if (!update) // Nothing changed return; - r = r->mp_head; - - if (!num) // No nexthop to install + if (!nhs) // No nexthop to install { drop: rte_update(p, r->net, NULL); return; } + + ap->dest = RTD_UNICAST; + nexthop_link(ap, nhs); } else r->state |= STS_INSTALLED; - + if (r->dest == RTDX_RECURSIVE) { ap->nh.labels_append = ap->nh.labels = r->label_count; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 2e0f194b..c65cba65 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -193,7 +193,6 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) struct ks_msg msg; char *body = (char *)msg.buf; sockaddr gate, mask, dst; - ip_addr gw; DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw); @@ -223,14 +222,12 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) msg.rtm.rtm_flags |= RTF_BLACKHOLE; #endif - /* This is really very nasty, but I'm not able - * to add "(reject|blackhole)" route without - * gateway set + /* + * This is really very nasty, but I'm not able to add reject/blackhole route + * without gateway address. */ - if(!i) + if (!i) { - i = HEAD(iface_list); - WALK_LIST(j, iface_list) { if (j->flags & IF_LOOPBACK) @@ -239,13 +236,13 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) break; } } - } - gw = a->nh.gw; - - /* Embed interface ID to link-local address */ - if (ipa_is_link_local(gw)) - _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff); + if (!i) + { + log(L_ERR "KRT: Cannot find loopback iface"); + return -1; + } + } int af = AF_UNSPEC; @@ -261,45 +258,51 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) return -1; } - sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0); sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0); - sockaddr_fill(&gate, af, gw, NULL, 0); switch (a->dest) { - 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 + case RTD_UNICAST: + if (ipa_nonzero(a->nh.gw)) + { + ip_addr gw = a->nh.gw; - 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; - } + /* Embed interface ID to link-local address */ + if (ipa_is_link_local(gw)) + _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff); + + sockaddr_fill(&gate, af, gw, NULL, 0); + msg.rtm.rtm_flags |= RTF_GATEWAY; + msg.rtm.rtm_addrs |= RTA_GATEWAY; break; + } #ifdef RTF_REJECT - case RTD_UNREACHABLE: + case RTD_UNREACHABLE: #endif #ifdef RTF_BLACKHOLE - case RTD_BLACKHOLE: + case RTD_BLACKHOLE: #endif - default: - bug("krt-sock: unknown flags, but not filtered"); + { + /* Fallback for all other valid cases */ + if (!i->addr) + { + log(L_ERR "KRT: interface %s has no IP addess", i->name); + return -1; + } + +#ifdef RTF_CLONING + if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */ + msg.rtm.rtm_flags |= RTF_CLONING; +#endif + + sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); + msg.rtm.rtm_addrs |= RTA_GATEWAY; + } + + default: + bug("krt-sock: unknown flags, but not filtered"); } msg.rtm.rtm_index = i->index; @@ -497,7 +500,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) } a.dest = RTD_UNICAST; - a.nh.next = NULL; if (flags & RTF_GATEWAY) { neighbor *ng; @@ -520,8 +522,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) return; } } - else - a.nh.gw = IPA_NONE; done: e = rte_get_temp(&a); diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 23431172..80439c47 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -320,6 +320,7 @@ 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] = { @@ -543,18 +544,17 @@ nl_add_attr_via(struct nlmsghdr *h, uint bufsize, ip_addr ipa) h->nlmsg_len += sizeof(*via); - if (ipa_is_ip4(ipa)) { - ip4_addr ip4 = ipa_to_ip4(ipa); - ip4 = ip4_hton(ip4); + if (ipa_is_ip4(ipa)) + { via->rtvia_family = AF_INET; - memcpy(via->rtvia_addr, &ip4, sizeof(ip4)); - h->nlmsg_len += sizeof(ip4); - } else { - ip6_addr ip6 = ipa_to_ip6(ipa); - ip6 = ip6_hton(ip6); + put_ip4(via->rtvia_addr, ipa_to_ip4(ipa)); + h->nlmsg_len += sizeof(ip4_addr); + } + else + { via->rtvia_family = AF_INET6; - memcpy(via->rtvia_addr, &ip6, sizeof(ip6)); - h->nlmsg_len += sizeof(ip6); + put_ip6(via->rtvia_addr, ipa_to_ip6(ipa)); + h->nlmsg_len += sizeof(ip6_addr); } nl_close_attr(h, nest); @@ -669,6 +669,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) } else rv->gw = IPA_NONE; + if (a[RTA_ENCAP_TYPE]) { if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) { @@ -1092,20 +1093,16 @@ krt_capable(rte *e) rta *a = e->attrs; switch (a->dest) - { + { 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: - break; + return 1; + default: return 0; - } - return 1; + } } static inline int @@ -1210,7 +1207,6 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d dest: - /* a->iface != NULL checked in krt_capable() for router and device routes */ switch (dest) { case RTD_UNICAST: @@ -1502,6 +1498,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) switch (i->rtm_type) { case RTN_UNICAST: + ra->dest = RTD_UNICAST; if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET)) { @@ -1512,7 +1509,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } - nexthop_link(ra, nh); + ra->nh = *nh; break; } @@ -1698,9 +1695,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) else { /* Merge next hops with the stored route */ - rta *a = s->attrs; + rta *oa = s->attrs; - nexthop_insert(&a->nh, &ra->nh); + struct nexthop *nhs = &oa->nh; + nexthop_insert(&nhs, &ra->nh); + + /* Perhaps new nexthop is inserted at the first position */ + if (nhs == &ra->nh) + { + /* Swap rtas */ + s->attrs = ra; + + /* Keep old eattrs */ + ra->eattrs = oa->eattrs; + } } } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index c273cb10..c6ff6275 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -984,7 +984,7 @@ krt_store_tmp_attrs(rte *rt, struct ea_list *attrs) static int krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED) { - struct krt_proto *p = (struct krt_proto *) P; + // struct krt_proto *p = (struct krt_proto *) P; rte *e = *new; if (e->attrs->src->proto == P) @@ -1005,17 +1005,6 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct li 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; -- cgit v1.2.3 From 93f50ca31757fc8e416093e0c73681e070294a3d Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Wed, 22 Feb 2017 14:02:03 +0100 Subject: Nest: names for nhu_state values It took too much time to analyze what's the meaning of nhu_state values so I spent less than the same amount of time documenting it. --- nest/route.h | 5 +++++ nest/rt-table.c | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index c16b2643..928a022d 100644 --- a/nest/route.h +++ b/nest/route.h @@ -168,6 +168,11 @@ typedef struct rtable { struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */ } rtable; +#define NHU_CLEAN 0 +#define NHU_SCHEDULED 1 +#define NHU_RUNNING 2 +#define NHU_DIRTY 3 + typedef struct network { struct rte *routes; /* Available routes for this network */ struct fib_node n; /* FIB flags reserved for kernel syncer */ diff --git a/nest/rt-table.c b/nest/rt-table.c index a33b7909..1e1dde25 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1561,11 +1561,14 @@ rt_schedule_hcu(rtable *tab) static inline void rt_schedule_nhu(rtable *tab) { - if (tab->nhu_state == 0) + if (tab->nhu_state == NHU_CLEAN) ev_schedule(tab->rt_event); - /* state change 0->1, 2->3 */ - tab->nhu_state |= 1; + /* state change: + * NHU_CLEAN -> NHU_SCHEDULED + * NHU_RUNNING -> NHU_DIRTY + */ + tab->nhu_state |= NHU_SCHEDULED; } void @@ -1897,13 +1900,13 @@ rt_next_hop_update(rtable *tab) struct fib_iterator *fit = &tab->nhu_fit; int max_feed = 32; - if (tab->nhu_state == 0) + if (tab->nhu_state == NHU_CLEAN) return; - if (tab->nhu_state == 1) + if (tab->nhu_state == NHU_SCHEDULED) { FIB_ITERATE_INIT(fit, &tab->fib); - tab->nhu_state = 2; + tab->nhu_state = NHU_RUNNING; } FIB_ITERATE_START(&tab->fib, fit, net, n) @@ -1918,10 +1921,13 @@ rt_next_hop_update(rtable *tab) } FIB_ITERATE_END; - /* state change 2->0, 3->1 */ + /* State change: + * NHU_DIRTY -> NHU_SCHEDULED + * NHU_RUNNING -> NHU_CLEAN + */ tab->nhu_state &= 1; - if (tab->nhu_state > 0) + if (tab->nhu_state != NHU_CLEAN) ev_schedule(tab->rt_event); } -- cgit v1.2.3 From 039a65d0e4f33f8432caae78cd919d2fd2052eea Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Fri, 24 Feb 2017 14:05:11 +0100 Subject: Nexthop: Fixed hostentry --- nest/route.h | 6 +-- nest/rt-attr.c | 2 +- nest/rt-table.c | 105 ++++++++++++++++++++++++-------------------------- proto/bgp/packets.c | 2 +- proto/static/static.c | 2 +- 5 files changed, 57 insertions(+), 60 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index 928a022d..98bef1fd 100644 --- a/nest/route.h +++ b/nest/route.h @@ -200,8 +200,8 @@ struct hostentry { unsigned hash_key; /* Hash key */ unsigned uc; /* Use count */ struct rta *src; /* Source rta entry */ - struct nexthop *nh; /* Chosen next hop */ byte dest; /* Chosen route destination type (RTD_...) */ + byte nexthop_linkable; /* Nexthop list is completely non-device */ u32 igp_metric; /* Chosen route IGP metric */ }; @@ -344,8 +344,8 @@ struct nexthop { struct iface *iface; /* Outgoing interface */ struct nexthop *next; byte weight; - byte labels_append; /* Number of labels before hostentry was applied */ - byte labels; /* Number of labels prepended */ + byte labels_orig; /* Number of labels before hostentry was applied */ + byte labels; /* Number of all labels */ u32 label[0]; }; diff --git a/nest/rt-attr.c b/nest/rt-attr.c index afc97e22..2c8ee7db 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1155,12 +1155,12 @@ rta__free(rta *a) *a->pprev = a->next; if (a->next) a->next->pprev = a->pprev; - a->aflags = 0; /* Poison the entry */ rt_unlock_hostentry(a->hostentry); rt_unlock_source(a->src); if (a->nh.next) nexthop_free(a->nh.next); ea_free(a->eattrs); + a->aflags = 0; /* Poison the entry */ sl_free(rta_slab(a), a); } diff --git a/nest/rt-table.c b/nest/rt-table.c index 1e1dde25..8765d293 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1764,7 +1764,7 @@ rta_next_hop_outdated(rta *a) return a->dest != RTD_UNREACHABLE; return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) || - !nexthop_same(&(a->nh), he->nh); + (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh)); } static inline void @@ -1774,39 +1774,49 @@ rta_apply_hostentry(rta *a, struct hostentry *he) a->dest = he->dest; a->igp_metric = he->igp_metric; - if (a->nh.labels_append == 0) + if ((a->nh.labels_orig == 0) && (!a->nh.next) && he->nexthop_linkable) { - a->nh = *(he->nh); - a->nh.labels_append = 0; + a->nh = he->src->nh; return; } - int labels_append = a->nh.labels_append; - u32 label_stack[MPLS_MAX_LABEL_STACK]; - memcpy(label_stack, a->nh.label, labels_append * sizeof(u32)); - - struct nexthop *nhp = NULL; - for (struct nexthop *nh = he->nh; nh; nh = nh->next) + struct nexthop *nhp = alloca(NEXTHOP_MAX_SIZE); + + for (struct nexthop *nhe = &(a->nh); nhe; nhe = nhe->next) { - nhp = nhp ? (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh); - nhp->gw = ipa_nonzero(nh->gw) ? nh->gw : he->link; - nhp->iface = nh->iface; /* FIXME: This is at least strange, if not utter nonsense. */ - nhp->weight = nh->weight; - nhp->labels = nh->labels + labels_append; - nhp->labels_append = labels_append; - if (nhp->labels <= MPLS_MAX_LABEL_STACK) - { - memcpy(nhp->label, nh->label, nh->labels * sizeof(u32)); - memcpy(&(nhp->label[nh->labels]), label_stack, labels_append * sizeof(u32)); - } - else + int labels_orig = nhe->labels_orig; /* Number of labels (at the bottom of stack) */ + u32 label_stack[MPLS_MAX_LABEL_STACK]; + memcpy(label_stack, nhe->label, labels_orig * sizeof(u32)); + + for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next) { - log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)", - nh->labels, labels_append, nhp->labels, MPLS_MAX_LABEL_STACK); - a->dest = RTD_UNREACHABLE; - break; + nhp->iface = nh->iface; + nhp->weight = nh->weight; /* FIXME: Ignoring the recursive nexthop's weight */ + nhp->labels = nh->labels + labels_orig; + nhp->labels_orig = labels_orig; + if (nhp->labels <= MPLS_MAX_LABEL_STACK) + { + memcpy(nhp->label, nh->label, nh->labels * sizeof(u32)); /* First the hostentry labels */ + memcpy(&(nhp->label[nh->labels]), label_stack, labels_orig * sizeof(u32)); /* Then the bottom labels */ + } + else + { + log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)", + nh->labels, labels_orig, nhp->labels, MPLS_MAX_LABEL_STACK); + continue; + } + if (ipa_nonzero(nh->gw)) + nhp->gw = nh->gw; /* Router nexthop */ + else if (ipa_nonzero(he->link)) + nhp->gw = he->link; /* Device nexthop with link-local address known */ + else + nhp->gw = he->addr; /* Device nexthop with link-local address unknown */ + + nhp = (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE)); } } + + memcpy(&(a->nh), nhp, nexthop_size(nhp)); } static inline rte * @@ -2231,12 +2241,12 @@ hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsig { struct hostentry *he = sl_alloc(hc->slab); - he->addr = a; - he->link = ll; - he->tab = dep; - he->hash_key = k; - he->uc = 0; - he->src = NULL; + *he = (struct hostentry) { + .addr = a, + .link = ll, + .tab = dep, + .hash_key = k, + }; add_tail(&hc->hostentries, &he->ln); hc_insert(hc, he); @@ -2357,6 +2367,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) /* Reset the hostentry */ he->src = NULL; + he->nexthop_linkable = 0; he->dest = RTD_UNREACHABLE; he->igp_metric = 0; @@ -2377,28 +2388,14 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - 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->nh.iface->name); - goto done; - } - - /* The host is directly reachable, use link as a gateway */ - he->nh = NULL; - he->dest = RTD_UNICAST; - } - else - { - /* The host is reachable through some route entry */ - he->nh = &(a->nh); - he->dest = a->dest; - } - + he->nexthop_linkable = 1; + for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) + if (ipa_zero(nh->gw)) + { + he->nexthop_linkable = 0; + break; + } + he->src = rta_clone(a); he->igp_metric = rt_get_igp_metric(e); } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 2106e0d1..bee9248a 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1705,7 +1705,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis if (ea) { - a = allocz(sizeof(struct rta)); + a = allocz(RTA_MAX_SIZE); a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; diff --git a/proto/static/static.c b/proto/static/static.c index e5251bf6..63ee2518 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -120,7 +120,7 @@ drop: if (r->dest == RTDX_RECURSIVE) { - ap->nh.labels_append = ap->nh.labels = r->label_count; + ap->nh.labels_orig = ap->nh.labels = r->label_count; memcpy(ap->nh.label, r->label_stack, r->label_count * sizeof(u32)); rta_set_recursive_next_hop(p->main_channel->table, ap, p_igp_table(p), r->via, IPA_NONE); } -- cgit v1.2.3 From 665be7f6bdbf1fd8dbac45cef533bd4b1df35d4d Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 8 Mar 2017 16:27:18 +0100 Subject: Nest: Minor fixes in show route --- nest/route.h | 6 ++++++ nest/rt-attr.c | 8 ++++++++ nest/rt-table.c | 49 +++++++++++++++++-------------------------------- proto/static/static.c | 9 --------- 4 files changed, 31 insertions(+), 41 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index 98bef1fd..65711138 100644 --- a/nest/route.h +++ b/nest/route.h @@ -401,6 +401,7 @@ typedef struct rta { #define RTD_BLACKHOLE 2 /* Silently drop packets */ #define RTD_UNREACHABLE 3 /* Reject as unreachable */ #define RTD_PROHIBIT 4 /* Administratively prohibited */ +#define RTD_MAX 5 /* Flags for net->n.flags, used by kernel syncer */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ @@ -412,6 +413,11 @@ typedef struct rta { protocol-specific metric is availabe */ +const char * rta_dest_names[RTD_MAX]; + +static inline const char *rta_dest_name(uint n) +{ return (n < RTD_MAX) ? rta_dest_names[n] : "???"; } + /* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */ static inline int rte_is_reachable(rte *r) { return r->attrs->dest == RTD_UNICAST; } diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 2c8ee7db..1b7f5836 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -58,6 +58,14 @@ #include +const char * rta_dest_names[RTD_MAX] = { + [RTD_NONE] = "", + [RTD_UNICAST] = "unicast", + [RTD_BLACKHOLE] = "blackhole", + [RTD_UNREACHABLE] = "unreachable", + [RTD_PROHIBIT] = "prohibited", +}; + pool *rta_pool; static slab *rta_slab_[4]; diff --git a/nest/rt-table.c b/nest/rt-table.c index 8765d293..92db6cc8 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -50,7 +50,6 @@ static linpool *rte_update_pool; static list routing_tables; -static byte *rt_format_via(rte *e); static void rt_free_hostcache(rtable *tab); static void rt_notify_hostcache(rtable *tab, net *net); static void rt_update_hostcache(rtable *tab); @@ -346,7 +345,7 @@ rte_mergable(rte *pri, rte *sec) static void rte_trace(struct proto *p, rte *e, int dir, char *msg) { - log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rt_format_via(e)); + log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rta_dest_name(e->attrs->dest)); } static inline void @@ -2395,12 +2394,12 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) he->nexthop_linkable = 0; break; } - + he->src = rta_clone(a); he->igp_metric = rt_get_igp_metric(e); } - done: +done: /* Add a prefix range to the trie */ trie_add_prefix(tab->hostcache->trie, &he_addr, pxlen, he_addr.pxlen); @@ -2465,25 +2464,6 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr * CLI commands */ -static byte * -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->nh.iface->name)+16]; - - switch (a->dest) - { - case RTD_UNICAST: bsprintf(via, "unicast"); break; - case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break; - case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; - case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; - default: bsprintf(via, "???"); - } - return via; -} - static void rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa) { @@ -2515,26 +2495,31 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm get_route_info(e, info, tmpa); else 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->nh); nh; nh = nh->next) + + cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest), + a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); + + if (a->dest == RTD_UNICAST) + for (nh = &(a->nh); nh; nh = nh->next) { - char ls[MPLS_MAX_LABEL_STACK*8 + 5]; char *lsp = ls; + char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls; + if (nh->labels) - { + { lsp += bsprintf(lsp, " mpls %d", nh->label[0]); for (int i=1;ilabels; i++) lsp += bsprintf(lsp, "/%d", nh->label[i]); - *lsp++ = '\0'; } + *lsp = '\0'; + if (a->nh.next) - cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, (nh->labels ? ls : ""), nh->iface->name, nh->weight + 1); + cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, mpls, nh->iface->name, nh->weight + 1); else - cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, (nh->labels ? ls : ""), nh->iface->name); + cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, mpls, nh->iface->name); } + if (d->verbose) rta_show(c, a, tmpa); - } static void diff --git a/proto/static/static.c b/proto/static/static.c index dbe490f9..55fd957c 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -570,15 +570,6 @@ static_copy_config(struct proto_config *dest, struct proto_config *src) } } - -static const char * rta_dest_names[] = { - [RTD_NONE] = "", - [RTD_UNICAST] = "unicast", - [RTD_BLACKHOLE] = "blackhole", - [RTD_UNREACHABLE] = "unreachable", - [RTD_PROHIBIT] = "prohibited", -}; - static void static_show_rt(struct static_route *r) { -- cgit v1.2.3 From 3c74416465d77c0e79eeaaeb988e471663484b5d Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Fri, 17 Mar 2017 15:48:09 +0100 Subject: Nexthop: Fixed recursive route mpls label merging --- conf/confbase.Y | 15 ++++--- lib/ip.h | 5 +++ nest/route.h | 2 +- nest/rt-table.c | 107 ++++++++++++++++++++++++++++++++++---------------- proto/bgp/bgp.h | 2 + proto/bgp/packets.c | 2 +- proto/static/config.Y | 6 +-- proto/static/static.c | 37 +++++++++++------ proto/static/static.h | 3 +- 9 files changed, 119 insertions(+), 60 deletions(-) (limited to 'nest/route.h') diff --git a/conf/confbase.Y b/conf/confbase.Y index 291dc6a0..d6a6951f 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -65,7 +65,7 @@ CF_DECLS struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; - u32 *lbl; + mpls_label_stack *mls; } %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT @@ -85,7 +85,7 @@ CF_DECLS %type ipa %type net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ -%type label_stack_start label_stack +%type label_stack_start label_stack %type text opttext @@ -288,18 +288,17 @@ net_or_ipa: label_stack_start: NUM { - $$ = cfg_allocz(sizeof(u32) * (MPLS_MAX_LABEL_STACK+1)); - $$[0] = 1; - $$[1] = $1; + $$ = cfg_allocz(sizeof(mpls_label_stack)); + $$->len = 1; + $$->stack[0] = $1; }; label_stack: label_stack_start | label_stack '/' NUM { - if ($1[0] >= MPLS_MAX_LABEL_STACK) + if ($1->len >= MPLS_MAX_LABEL_STACK) cf_error("Too many labels in stack"); - $1[0]++; - $1[*$1] = $3; + $1->stack[$1->len++] = $3; $$ = $1; } ; diff --git a/lib/ip.h b/lib/ip.h index ab90bee7..5cfce1f1 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -326,6 +326,11 @@ static inline ip6_addr ip6_ntoh(ip6_addr a) { return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } #define MPLS_MAX_LABEL_STACK 8 +typedef struct mpls_label_stack { + uint len; + u32 stack[MPLS_MAX_LABEL_STACK]; +} mpls_label_stack; + static inline int mpls_get(const char *buf, int buflen, u32 *stack) { diff --git a/nest/route.h b/nest/route.h index 65711138..546b04c4 100644 --- a/nest/route.h +++ b/nest/route.h @@ -551,7 +551,7 @@ static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta void rta_dump(rta *); void rta_dump_all(void); void rta_show(struct cli *, rta *, ea_list *); -void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll); +void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls); /* * rta_set_recursive_next_hop() acquires hostentry from hostcache and fills diff --git a/nest/rt-table.c b/nest/rt-table.c index 92db6cc8..f8baf572 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1767,55 +1767,80 @@ rta_next_hop_outdated(rta *a) } static inline void -rta_apply_hostentry(rta *a, struct hostentry *he) +rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls) { a->hostentry = he; a->dest = he->dest; a->igp_metric = he->igp_metric; - if ((a->nh.labels_orig == 0) && (!a->nh.next) && he->nexthop_linkable) + if (a->dest != RTD_UNICAST) { - a->nh = he->src->nh; + /* No nexthop */ +no_nexthop: + a->nh = (struct nexthop) {}; + if (mls) + { /* Store the label stack for later changes */ + a->nh.labels_orig = a->nh.labels = mls->len; + memcpy(a->nh.label, mls->stack, mls->len * sizeof(u32)); + } return; } - struct nexthop *nhp = alloca(NEXTHOP_MAX_SIZE); + if (((!mls) || (!mls->len)) && he->nexthop_linkable) + { /* Just link the nexthop chain, no label append happens. */ + memcpy(&(a->nh), &(he->src->nh), nexthop_size(&(he->src->nh))); + return; + } + + struct nexthop *nhp = NULL, *nhr = NULL; + int skip_nexthop = 0; - for (struct nexthop *nhe = &(a->nh); nhe; nhe = nhe->next) + for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next) { - int labels_orig = nhe->labels_orig; /* Number of labels (at the bottom of stack) */ - u32 label_stack[MPLS_MAX_LABEL_STACK]; - memcpy(label_stack, nhe->label, labels_orig * sizeof(u32)); + if (skip_nexthop) + skip_nexthop--; + else + { + nhr = nhp; + nhp = (nhp ? (nhp->next = lp_allocz(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh)); + } - for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next) + nhp->iface = nh->iface; + nhp->weight = nh->weight; + if (mls) { - nhp->iface = nh->iface; - nhp->weight = nh->weight; /* FIXME: Ignoring the recursive nexthop's weight */ - nhp->labels = nh->labels + labels_orig; - nhp->labels_orig = labels_orig; + nhp->labels = nh->labels + mls->len; + nhp->labels_orig = mls->len; if (nhp->labels <= MPLS_MAX_LABEL_STACK) { memcpy(nhp->label, nh->label, nh->labels * sizeof(u32)); /* First the hostentry labels */ - memcpy(&(nhp->label[nh->labels]), label_stack, labels_orig * sizeof(u32)); /* Then the bottom labels */ + memcpy(&(nhp->label[nh->labels]), mls->stack, mls->len * sizeof(u32)); /* Then the bottom labels */ } else { log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)", - nh->labels, labels_orig, nhp->labels, MPLS_MAX_LABEL_STACK); + nh->labels, mls->len, nhp->labels, MPLS_MAX_LABEL_STACK); + skip_nexthop++; continue; } - if (ipa_nonzero(nh->gw)) - nhp->gw = nh->gw; /* Router nexthop */ - else if (ipa_nonzero(he->link)) - nhp->gw = he->link; /* Device nexthop with link-local address known */ - else - nhp->gw = he->addr; /* Device nexthop with link-local address unknown */ - - nhp = (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE)); } + if (ipa_nonzero(nh->gw)) + nhp->gw = nh->gw; /* Router nexthop */ + else if (ipa_nonzero(he->link)) + nhp->gw = he->link; /* Device nexthop with link-local address known */ + else + nhp->gw = he->addr; /* Device nexthop with link-local address unknown */ } - memcpy(&(a->nh), nhp, nexthop_size(nhp)); + if (skip_nexthop) + if (nhr) + nhr->next = NULL; + else + { + a->dest = RTD_UNREACHABLE; + log(L_WARN "No valid nexthop remaining, setting route unreachable"); + goto no_nexthop; + } } static inline rte * @@ -1823,7 +1848,11 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) { rta *a = alloca(RTA_MAX_SIZE); memcpy(a, old->attrs, rta_size(old->attrs)); - rta_apply_hostentry(a, old->attrs->hostentry); + + mpls_label_stack mls = { .len = a->nh.labels_orig }; + memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32)); + + rta_apply_hostentry(a, old->attrs->hostentry, &mls); a->aflags = 0; rte *e = sl_alloc(rte_slab); @@ -2387,13 +2416,25 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } + he->dest = a->dest; he->nexthop_linkable = 1; - for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) - if (ipa_zero(nh->gw)) - { - he->nexthop_linkable = 0; - break; - } + if (he->dest == RTD_UNICAST) + { + for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) + if (ipa_zero(nh->gw)) + { + if (if_local_addr(he->addr, 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, nh->iface->name); + goto done; + } + + he->nexthop_linkable = 0; + break; + } + } he->src = rta_clone(a); he->igp_metric = rt_get_igp_metric(e); @@ -2454,9 +2495,9 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) } void -rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll) +rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls) { - rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ipa_zero(ll) ? gw : ll, dep)); + rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ipa_zero(ll) ? gw : ll, dep), mls); } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 5d2539d5..e7647625 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -337,6 +337,8 @@ struct bgp_parse_state { u32 mp_reach_af; u32 mp_unreach_af; + mpls_label_stack mls; + uint attr_len; uint ip_reach_len; uint ip_unreach_len; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index bee9248a..f7366804 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -753,7 +753,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll) if (ipa_zero(gw)) WITHDRAW(BAD_NEXT_HOP); - rta_set_recursive_next_hop(c->c.table, a, c->igp_table, gw, ll); + rta_set_recursive_next_hop(c->c.table, a, c->igp_table, gw, ll, &(s->mls)); } } diff --git a/proto/static/config.Y b/proto/static/config.Y index 86fcedec..cd8bfcec 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -75,8 +75,7 @@ stat_nexthop: this_snh->iface = if_get_by_name($2); } | stat_nexthop MPLS label_stack { - this_snh->label_count = $3[0]; - this_snh->label_stack = &($3[1]); + this_snh->mls = $3; } | stat_nexthop WEIGHT expr { this_snh->weight = $3 - 1; @@ -111,8 +110,7 @@ stat_route: | stat_route0 RECURSIVE ipa MPLS label_stack { this_srt->dest = RTDX_RECURSIVE; this_srt->via = $3; - this_srt->label_count = $5[0]; - this_srt->label_stack = &($5[1]); + this_srt->mls = $5; } | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } diff --git a/proto/static/static.c b/proto/static/static.c index 55fd957c..adefa0b2 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -79,8 +79,11 @@ static_announce_rte(struct static_proto *p, struct static_route *r) nh->gw = r2->via; nh->iface = r2->neigh->iface; nh->weight = r2->weight; - nh->labels = r2->label_count; - memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32)); + if (r2->mls) + { + nh->labels = r2->mls->len; + memcpy(nh->label, r2->mls->stack, r2->mls->len * sizeof(u32)); + } nexthop_insert(&nhs, nh); } @@ -92,11 +95,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r) } if (r->dest == RTDX_RECURSIVE) - { - a->nh.labels_orig = a->nh.labels = r->label_count; - memcpy(a->nh.label, r->label_stack, r->label_count * sizeof(u32)); - rta_set_recursive_next_hop(p->p.main_channel->table, a, p_igp_table(p), r->via, IPA_NONE); - } + rta_set_recursive_next_hop(p->p.main_channel->table, a, p_igp_table(p), r->via, IPA_NONE, r->mls); /* Already announced */ if (r->state == SRS_CLEAN) @@ -274,17 +273,33 @@ static_same_dest(struct static_route *x, struct static_route *y) (x->iface != y->iface) || (x->use_bfd != y->use_bfd) || (x->weight != y->weight) || - (x->label_count != y->label_count)) + (!x->mls != !y->mls) || + ((x->mls) && (y->mls) && (x->mls->len != y->mls->len))) return 0; - for (int i = 0; i < x->label_count; i++) - if (x->label_stack[i] != y->label_stack[i]) + if (!x->mls) + continue; + + for (uint i = 0; i < x->mls->len; i++) + if (x->mls->stack[i] != y->mls->stack[i]) return 0; } return !x && !y; case RTDX_RECURSIVE: - return ipa_equal(x->via, y->via); + if (!ipa_equal(x->via, y->via) || + (!x->mls != !y->mls) || + ((x->mls) && (y->mls) && (x->mls->len != y->mls->len))) + return 0; + + if (!x->mls) + return 1; + + for (uint i = 0; i < x->mls->len; i++) + if (x->mls->stack[i] != y->mls->stack[i]) + return 0; + + return 1; default: return 1; diff --git a/proto/static/static.h b/proto/static/static.h index bfcbd8c3..0976a9c9 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -42,9 +42,8 @@ struct static_route { byte active; /* Next hop is active (nbr/iface/BFD available) */ byte weight; /* Multipath next hop weight */ byte use_bfd; /* Configured to use BFD */ - byte label_count; /* Number of labels in stack */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */ - u32 *label_stack; /* Label stack if label_count > 0 */ + mpls_label_stack *mls; /* MPLS label stack; may be NULL */ }; /* -- cgit v1.2.3