diff --git a/doc/bird.sgml b/doc/bird.sgml
index 648b4a1c..3dc1e294 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -2911,6 +2911,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)
@@ -3611,10 +3612,10 @@ rt_get_hostentry(rtable *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 e1e0d796..ad78d5e5 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -2037,6 +2037,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);
@@ -2167,6 +2171,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 5d0e9791..eda5d229 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 cb410a5e..2294119e 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -32,7 +32,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, BGP_AIGP, 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
@@ -263,6 +263,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 8087608a..c464e9c7 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1020,7 +1020,8 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
WITHDRAW(BAD_NEXT_HOP " - zero address");
rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6;
- s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table);
+ ip_addr lla = (c->cf->next_hop_prefer == NHP_LOCAL) ? ll : IPA_NONE;
+ s->hostentry = rt_get_hostentry(tab, gw, lla, c->c.table);
if (!s->mpls)
rta_apply_hostentry(a, s->hostentry, NULL);