From 8f79e6b93e32a4eb7e4dda9bd4a9d04400b79d45 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 10 Oct 2022 05:06:19 +0200 Subject: [PATCH] BGP: Add option 'next hop prefer global' Add BGP channel option 'next hop prefer global' that modifies BGP recursive next hop resolution to use global next hop IPv6 address instead of link-local next hop IPv6 address for immediate next hop of received routes. --- doc/bird.sgml | 14 ++++++++++++++ nest/rt-table.c | 5 +++-- proto/bgp/bgp.c | 5 +++++ proto/bgp/bgp.h | 4 ++++ proto/bgp/config.Y | 3 ++- proto/bgp/packets.c | 3 ++- 6 files changed, 30 insertions(+), 4 deletions(-) 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);