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.
This commit is contained in:
Ondrej Zajicek 2022-10-10 05:06:19 +02:00
parent 8478de8817
commit 8f79e6b93e
6 changed files with 30 additions and 4 deletions

View file

@ -2911,6 +2911,20 @@ be used in explicit configuration.
BGP session (if acceptable), or the preferred address of an associated BGP session (if acceptable), or the preferred address of an associated
interface. interface.
<tag><label id="bgp-next-hop-prefer">next hop prefer global</tag>
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 (<ref id="bgp-gateway"
name="gateway recursive">) through an IGP routing table
(<ref id="bgp-igp-table" name="igp 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.
<tag><label id="bgp-gateway">gateway direct|recursive</tag> <tag><label id="bgp-gateway">gateway direct|recursive</tag>
For received routes, their <cf/gw/ (immediate next hop) attribute is For received routes, their <cf/gw/ (immediate next hop) attribute is
computed from received <cf/bgp_next_hop/ attribute. This option computed from received <cf/bgp_next_hop/ attribute. This option

View file

@ -3603,6 +3603,7 @@ rt_update_hostcache(rtable *tab)
struct hostentry * struct hostentry *
rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
{ {
ip_addr link = ipa_zero(ll) ? a : ll;
struct hostentry *he; struct hostentry *he;
if (!tab->hostcache) if (!tab->hostcache)
@ -3611,10 +3612,10 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
u32 k = hc_hash(a, dep); u32 k = hc_hash(a, dep);
struct hostcache *hc = tab->hostcache; struct hostcache *hc = tab->hostcache;
for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next) 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; 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); rt_update_hostentry(tab, he);
return he; return he;
} }

View file

@ -2037,6 +2037,10 @@ bgp_postconfig(struct proto_config *CF)
if (!cc->gw_mode) if (!cc->gw_mode)
cc->gw_mode = cf->multihop ? GW_RECURSIVE : GW_DIRECT; 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 */ /* Defaults based on proto config */
if (cc->gr_able == 0xff) if (cc->gr_able == 0xff)
cc->gr_able = (cf->gr_mode == BGP_GR_ABLE); 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; return 0;
if ((new->gw_mode != old->gw_mode) || if ((new->gw_mode != old->gw_mode) ||
(new->next_hop_prefer != old->next_hop_prefer) ||
(new->aigp != old->aigp) || (new->aigp != old->aigp) ||
(new->cost != old->cost)) (new->cost != old->cost))
{ {

View file

@ -145,6 +145,7 @@ struct bgp_channel_config {
ip_addr next_hop_addr; /* Local address for NEXT_HOP attribute */ 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_self; /* Always set next hop to local IP address (NH_*) */
u8 next_hop_keep; /* Do not modify next hop attribute (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 mandatory; /* Channel is mandatory in capability negotiation */
u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */ 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) */ 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_DIRECT 1
#define GW_RECURSIVE 2 #define GW_RECURSIVE 2
#define NHP_GLOBAL 1
#define NHP_LOCAL 2
#define BGP_ADD_PATH_RX 1 #define BGP_ADD_PATH_RX 1
#define BGP_ADD_PATH_TX 2 #define BGP_ADD_PATH_TX 2
#define BGP_ADD_PATH_FULL 3 #define BGP_ADD_PATH_FULL 3

View file

@ -32,7 +32,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS, LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE, DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
FIRST, FREE, VALIDATE, BASE, ROLE, ROLES, PEER, PROVIDER, CUSTOMER, 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 <i> bgp_nh %type <i> bgp_nh
%type <i32> bgp_afi %type <i32> bgp_afi
@ -263,6 +263,7 @@ bgp_channel_item:
| NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; } | NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; }
| NEXT HOP SELF bgp_nh { BGP_CC->next_hop_self = $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 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; } | 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); } | 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; } | GATEWAY DIRECT { BGP_CC->gw_mode = GW_DIRECT; }

View file

@ -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"); WITHDRAW(BAD_NEXT_HOP " - zero address");
rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6; 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) if (!s->mpls)
rta_apply_hostentry(a, s->hostentry, NULL); rta_apply_hostentry(a, s->hostentry, NULL);