From: Ondrej Zajicek (work) Date: Tue, 4 Jul 2017 21:36:21 +0000 (+0200) Subject: Implement onlink flag for nexthops X-Git-Tag: v2.0.0~61 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a1f5e514ef091b82754f38f0e583af40778c7d97;p=thirdparty%2Fbird.git Implement onlink flag for nexthops Add proper support for per-nexthop onlink flag in routes to handle next hop addresses that are not covered by interface IP ranges. Supported by kernel and static protocols. Thanks to Vincent Bernat for the idea. --- diff --git a/nest/route.h b/nest/route.h index 6c9b00c23..c1a60ccc6 100644 --- a/nest/route.h +++ b/nest/route.h @@ -366,12 +366,16 @@ struct nexthop { ip_addr gw; /* Next hop */ struct iface *iface; /* Outgoing interface */ struct nexthop *next; + byte flags; byte weight; byte labels_orig; /* Number of labels before hostentry was applied */ byte labels; /* Number of all labels */ u32 label[0]; }; +#define RNF_ONLINK 0x1 /* Gateway is onlink regardless of IP ranges */ + + struct rte_src { struct rte_src *next; /* Hash chain */ struct proto *proto; /* Protocol the source is based on */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 1b7f5836c..761ba9fe8 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -171,7 +171,9 @@ 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) || (x->labels != y->labels)) + if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || + (x->flags != y->flags) || (x->weight != y->weight) || + (x->labels != y->labels)) return 0; for (int i = 0; i < x->labels; i++) @@ -193,6 +195,8 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y) if (!y) return -1; + /* Should we also compare flags ? */ + r = ((int) y->weight) - ((int) x->weight); if (r) return r; diff --git a/nest/rt-show.c b/nest/rt-show.c index 3f5ef04d1..afde2810f 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -70,6 +70,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm for (nh = &(a->nh); nh; nh = nh->next) { char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls; + char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : ""; if (nh->labels) { @@ -80,9 +81,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm *lsp = '\0'; if (a->nh.next) - cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, mpls, nh->iface->name, nh->weight + 1); + cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d", + nh->gw, mpls, nh->iface->name, onlink, nh->weight + 1); else - cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, mpls, nh->iface->name); + cli_printf(c, -1007, "\tvia %I%s on %s%s", + nh->gw, mpls, nh->iface->name, onlink); } if (d->verbose) diff --git a/nest/rt-table.c b/nest/rt-table.c index 85a951b86..2bb78cf2d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1819,7 +1819,10 @@ no_nexthop: } } if (ipa_nonzero(nh->gw)) - nhp->gw = nh->gw; /* Router nexthop */ + { + nhp->gw = nh->gw; /* Router nexthop */ + nhp->flags |= (nh->flags & RNF_ONLINK); + } else if (ipa_nonzero(he->link)) nhp->gw = he->link; /* Device nexthop with link-local address known */ else diff --git a/proto/static/config.Y b/proto/static/config.Y index 66ae3c980..66e5ea4c2 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -44,7 +44,7 @@ static_route_finish(void) CF_DECLS CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) -CF_KEYWORDS(WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS) +CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS) CF_GRAMMAR @@ -87,6 +87,9 @@ stat_nexthop: | stat_nexthop MPLS label_stack { this_snh->mls = $3; } + | stat_nexthop ONLINK bool { + this_snh->onlink = $3; + } | stat_nexthop WEIGHT expr { this_snh->weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); diff --git a/proto/static/static.c b/proto/static/static.c index bb1501a5b..ede4c7345 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -71,6 +71,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r) struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE); nh->gw = r2->via; nh->iface = r2->neigh->iface; + nh->flags = r2->onlink ? RNF_ONLINK : 0; nh->weight = r2->weight; if (r2->mls) { @@ -205,7 +206,8 @@ static_add_rte(struct static_proto *p, struct static_route *r) for (r2 = r; r2; r2 = r2->mp_next) { n = ipa_nonzero(r2->via) ? - neigh_find2(&p->p, &r2->via, r2->iface, NEF_STICKY) : + neigh_find2(&p->p, &r2->via, r2->iface, + NEF_STICKY | (r2->onlink ? NEF_ONLINK : 0)) : neigh_find_iface(&p->p, r2->iface); if (!n) @@ -267,8 +269,9 @@ static_same_dest(struct static_route *x, struct static_route *y) { if (!ipa_equal(x->via, y->via) || (x->iface != y->iface) || - (x->use_bfd != y->use_bfd) || + (x->onlink != y->onlink) || (x->weight != y->weight) || + (x->use_bfd != y->use_bfd) || (!x->mls != !y->mls) || ((x->mls) && (y->mls) && (x->mls->len != y->mls->len))) return 0; @@ -614,11 +617,13 @@ static_show_rt(struct static_route *r) for (r2 = r; r2; r2 = r2->mp_next) { if (r2->iface && ipa_zero(r2->via)) - cli_msg(-1009, "\tdev %s%s%s", r2->iface->name, - r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)"); + cli_msg(-1009, "\tdev %s%s", r2->iface->name, + r2->active ? "" : " (dormant)"); else - cli_msg(-1009, "\tvia %I%J%s%s", r2->via, r2->iface, - r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)"); + cli_msg(-1009, "\tvia %I%J%s%s%s", r2->via, r2->iface, + r2->onlink ? " onlink" : "", + r2->bfd_req ? " (bfd)" : "", + r2->active ? "" : " (dormant)"); } break; } diff --git a/proto/static/static.h b/proto/static/static.h index c84dfa98f..b202c0b1d 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -43,6 +43,7 @@ struct static_route { byte dest; /* Destination type (RTD_*) */ byte state; /* State of route announcement (SRS_*) */ byte active; /* Next hop is active (nbr/iface/BFD available) */ + byte onlink; /* Gateway is onlink regardless of IP ranges */ byte weight; /* Multipath next hop weight */ byte use_bfd; /* Configured to use BFD */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */ diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 40d1196ea..2b7b13fb9 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -622,6 +622,9 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af) nl_add_nexthop(h, bufsize, nh, af); + if (nh->flags & RNF_ONLINK) + rtnh->rtnh_flags |= RTNH_F_ONLINK; + nl_close_nexthop(h, rtnh); } @@ -660,6 +663,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) rv->next = NULL; last = &(rv->next); + rv->flags = 0; rv->weight = nh->rtnh_hops; rv->iface = if_find_by_index(nh->rtnh_ifindex); if (!rv->iface) @@ -672,9 +676,12 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra) { rv->gw = rta_get_ipa(a[RTA_GATEWAY]); + if (nh->rtnh_flags & RTNH_F_ONLINK) + rv->flags |= RNF_ONLINK; + neighbor *nbr; nbr = neigh_find2(&p->p, &rv->gw, rv->iface, - (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); + (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0); if (!nbr || (nbr->scope == SCOPE_HOST)) return NULL; } @@ -1228,6 +1235,9 @@ dest: { nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index); nl_add_nexthop(&r->h, rsize, nh, p->af); + + if (nh->flags & RNF_ONLINK) + r->r.rtm_flags |= RTNH_F_ONLINK; } break; case RTD_BLACKHOLE: @@ -1543,9 +1553,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit)) return; + if (i->rtm_flags & RTNH_F_ONLINK) + ra->nh.flags |= RNF_ONLINK; + neighbor *nbr; nbr = neigh_find2(&p->p, &(ra->nh.gw), ra->nh.iface, - (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); + (ra->nh.flags & RNF_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,