diff --git a/nest/route.h b/nest/route.h index 6c9b00c2..c1a60ccc 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 1b7f5836..761ba9fe 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 3f5ef04d..afde2810 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 85a951b8..2bb78cf2 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 66ae3c98..66e5ea4c 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 bb1501a5..ede4c734 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 c84dfa98..b202c0b1 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 40d1196e..2b7b13fb 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,