diff --git a/doc/bird.sgml b/doc/bird.sgml index 0cfe19c4..8c882ee6 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2938,6 +2938,20 @@ be used in explicit configuration. BGP session (if acceptable), or the preferred address of an associated interface. + + Prefer global IPv6 address to link-local IPv6 address for immediate next + hops of received routes. For IPv6 routes, the Next Hop attribute may + contain both a global IP address and a link-local IP address. For IBGP + sessions, the global IP address is resolved () through an IGP routing table + () to get an immediate next + hop. If the resulting IGP route is a direct route (i.e., the next hop is + a direct neighbor), then the link-local IP address from the Next Hop + attribute is used as the immediate next hop. This option change it to + use the global IP address instead. Note that even with this option + enabled a route may end with a link-local immediate next hop when the + IGP route has one. Default: disabled. + For received routes, their hostcache) @@ -4748,10 +4749,10 @@ rt_get_hostentry(struct rtable_private *tab, ip_addr a, ip_addr ll, rtable *dep) u32 k = hc_hash(a, dep); struct hostcache *hc = tab->hostcache; for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next) - if (ipa_equal(he->addr, a) && (he->tab == dep)) + if (ipa_equal(he->addr, a) && ipa_equal(he->link, link) && (he->tab == dep)) return he; - he = hc_new_hostentry(hc, tab->rp, a, ipa_zero(ll) ? a : ll, dep, k); + he = hc_new_hostentry(hc, tab->rp, a, link, dep, k); rt_update_hostentry(tab, he); return he; } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f8655d47..2f8da1af 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -2105,6 +2105,10 @@ bgp_postconfig(struct proto_config *CF) if (!cc->gw_mode) cc->gw_mode = cf->multihop ? GW_RECURSIVE : GW_DIRECT; + /* Different default for next_hop_prefer */ + if (!cc->next_hop_prefer) + cc->next_hop_prefer = (cc->gw_mode == GW_DIRECT) ? NHP_GLOBAL : NHP_LOCAL; + /* Defaults based on proto config */ if (cc->gr_able == 0xff) cc->gr_able = (cf->gr_mode == BGP_GR_ABLE); @@ -2235,6 +2239,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor return 0; if ((new->gw_mode != old->gw_mode) || + (new->next_hop_prefer != old->next_hop_prefer) || (new->aigp != old->aigp) || (new->cost != old->cost)) { diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index c7b8e40b..b87e0fc4 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -145,6 +145,7 @@ struct bgp_channel_config { ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */ u8 next_hop_self; /* Always set next hop to local IP address (NH_*) */ u8 next_hop_keep; /* Do not modify next hop attribute (NH_*) */ + u8 next_hop_prefer; /* Prefer global or link-local next hop (NHP_*) */ u8 mandatory; /* Channel is mandatory in capability negotiation */ u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */ u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */ @@ -187,6 +188,9 @@ struct bgp_channel_config { #define GW_DIRECT 1 #define GW_RECURSIVE 2 +#define NHP_GLOBAL 1 +#define NHP_LOCAL 2 + #define BGP_ADD_PATH_RX 1 #define BGP_ADD_PATH_TX 2 #define BGP_ADD_PATH_FULL 3 diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 9f0d2306..b4edf2c5 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -31,7 +31,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS, DYNAMIC, RANGE, NAME, DIGITS, AIGP, ORIGINATE, COST, ENFORCE, FIRST, FREE, VALIDATE, BASE, ROLE, ROLES, PEER, PROVIDER, CUSTOMER, - RS_SERVER, RS_CLIENT, REQUIRE, BGP_OTC) + RS_SERVER, RS_CLIENT, REQUIRE, BGP_OTC, PREFER, GLOBAL) %type bgp_nh %type bgp_afi @@ -264,6 +264,7 @@ bgp_channel_item: | NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; } | NEXT HOP SELF bgp_nh { BGP_CC->next_hop_self = $4; } | NEXT HOP KEEP bgp_nh { BGP_CC->next_hop_keep = $4; } + | NEXT HOP PREFER GLOBAL { BGP_CC->next_hop_prefer = NHP_GLOBAL; } | MANDATORY bool { BGP_CC->mandatory = $2; } | MISSING LLADDR bgp_lladdr { log(L_WARN "%s.%s: Missing lladdr option is deprecated and ignored, remove it", this_proto->name, this_channel->name); } | GATEWAY DIRECT { BGP_CC->gw_mode = GW_DIRECT; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index f9c1da41..506268c9 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1028,13 +1028,15 @@ bgp_apply_next_hop(struct bgp_parse_state *s, ea_list **to, ip_addr gw, ip_addr WITHDRAW(BAD_NEXT_HOP " - zero address"); rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6; + ip_addr lla = (c->cf->next_hop_prefer == NHP_LOCAL) ? ll : IPA_NONE; + if (s->mpls) { u32 labels[BGP_MPLS_MAX]; - ea_set_hostentry(to, c->c.table, tab, gw, ll, BGP_MPLS_MAX, labels); + ea_set_hostentry(to, c->c.table, tab, gw, lla, BGP_MPLS_MAX, labels); } else - ea_set_hostentry(to, c->c.table, tab, gw, ll, 0, NULL); + ea_set_hostentry(to, c->c.table, tab, gw, lla, 0, NULL); } }