]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP: Add option 'next hop prefer global'
authorOndrej Zajicek <santiago@crfreenet.org>
Mon, 10 Oct 2022 03:06:19 +0000 (05:06 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 10 Oct 2022 03:06:19 +0000 (05:06 +0200)
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
nest/rt-table.c
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/bgp/packets.c

index 648b4a1ce4b8b8bad688439abbb24ba15e26cca5..3dc1e2945f9fab608ff6d69f2ccc5c1629a2cb60 100644 (file)
@@ -2911,6 +2911,20 @@ be used in explicit configuration.
        BGP session (if acceptable), or the preferred address of an associated
        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>
        For received routes, their <cf/gw/ (immediate next hop) attribute is
        computed from received <cf/bgp_next_hop/ attribute. This option
index 4127912cc690bd70d4d0c63b74818158ccc3c95c..cb8c56a611ee89e653bdf7479c8baa46f20411b1 100644 (file)
@@ -3603,6 +3603,7 @@ rt_update_hostcache(rtable *tab)
 struct hostentry *
 rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
 {
+  ip_addr link = ipa_zero(ll) ? a : ll;
   struct hostentry *he;
 
   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);
   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;
 }
index e1e0d796815a582d8c140b96213de93066f2aa44..ad78d5e54e5247de317b452e8130a861e5ffa34e 100644 (file)
@@ -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))
   {
index 5d0e9791d63f58d239a3aa86fdd3e4fdc496d914..eda5d229200066d6155aa264597ced6988c7b011 100644 (file)
@@ -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
index cb410a5e85c266155d8b9f755b1a0882a34c8753..2294119ea488a798f38cd695dc5b43142d453188 100644 (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,
        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 <i> bgp_nh
 %type <i32> 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; }
index 8087608a87c2055166c1a00b06d38e42b8070ddc..c464e9c7e60d1a434573abdd53bbf6647cb845bc 100644 (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");
 
     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);