Hi KusakabeShi,

thank you for your patch. We are not going to merge it for several reasons, not listed in any particular order:

This issue will be handled by an upcoming rework of the filter type system, which we are expecting to continue on working in several months, after releasing EVPN support and other more pushing stuff. We do know that the current implementation is limited. We also have non-triviaĺ experience maintaining old filter language quirks, and adding a new one just adds more maintenance work long-term.

If you really need this, we may, theoretically, consider merging a patch implementing a method atop bgp_next_hop, e.g.

bgp_next_hop.set_global(3fff::);
bgp_next_hop.set_local(fe80::);

Yet, that has another list of weird problems under the hood, which will be, again, solved by the type system rework. One of the reasons why the type system rework takes so long (and didn’t start until recently) is actually this pre-existing quirk of bgp next hop for IPv6.

Thank you for your understanding.

Maria

On Tue, Apr 21, 2026 at 07:34:17PM +0800, Shi Kusakabe via Bird-users wrote:

Hi,

 

The current bgp_next_hop filter attribute only accesses nh[0] (the global address) of the BA_NEXT_HOP eattr. The link-local address stored in nh[1] is completely invisible to filters. Worse, set bgp_next_hop allocates a new 16-byte adata, silently discarding any existing link-local next hop.

 

This makes it impossible to:

 

This patch adds two new filter attributes, bgp_next_hop_global and bgp_next_hop_ll, which provide independent read/write access to nh[0] and nh[1] of the BGP next hop. Setting one does not affect other.

 

The existing bgp_next_hop behavior is completely unchanged.

 

Implementation:

 

Both new attributes map to the same BA_NEXT_HOP ea_code, differentiated by the bit field of struct f_dynamic_attr (which was previously unused for EAF_TYPE_IP_ADDRESS):

 

 

GET (FI_EA_GET):

 

SET (FI_EA_SET):

 

Usage example:

 

Read

print bgp_next_hop_global;   # 2404:f4c0:f70e:1980::202:881

print bgp_next_hop_ll;       # fe80::ff:fe20:2881

 

Modify global only, link-local preserved

bgp_next_hop_global = 2001:db8::1;

 

Modify link-local only, global preserved

bgp_next_hop_ll = fe80::99;

 

Files changed:

https://github.com/KusakabeShi/bird/commit/b5af9bc2eefbcc9e6f96432dd43fc6422f5f33c8

 

 

The patch applies against the v2.18 release branch. Feedback welcome.

 

Thanks,

KusakabeShi

On Wed, Apr 22, 2026 at 08:50:25AM +0000, KSKB SHI wrote: > Hi, >
> The current bgp_next_hop filter attribute only accesses nh[0] (the global address) of the BA_NEXT_HOP eattr. > The link-local address stored in nh[1] is completely invisible to filters. >
> see this image: > https://upload.cc/i1/2026/04/22/0Nj4E8.png >
> Worse, set bgp_next_hop allocates a new 16-byte adata, silently discarding any existing link-local next hop. >
> This makes it impossible to: > - Inspect the link-local next hop in a filter > - Modify only the global next hop while preserving the link-local > - Set a link-local next hop independently >
> This patch adds two new filter attributes, bgp_next_hop_global and bgp_next_hop_ll, which provide independent read/write access to nh[0] and nh[1] of the BGP next hop. Setting one does not affect other. >
> The existing bgp_next_hop behavior is completely unchanged. >
> Implementation: >
> Both new attributes map to the same BA_NEXT_HOP ea_code, differentiated by the bit field of struct f_dynamic_attr (which was previously unused for EAF_TYPE_IP_ADDRESS): >
> - bgp_next_hop — bit=0, original behavior (default from zero-init) > - bgp_next_hop_global — bit=1, reads/writes nh[0] > - bgp_next_hop_ll — bit=2, reads/writes nh[1] >
> GET (FI_EA_GET): > - bit=2: returns nh[1] if adata->length >= 32, otherwise IPA_NONE > - bit=0,1: returns nh[0] (same as before) >
> SET (FI_EA_SET): > - bit=0: allocates new 16-byte adata with only the assigned IP (original behavior, nh[1] is lost) > - bit=1,2: read-modify-write — reads the existing BA_NEXT_HOP from eattrs, updates only the target slot, preserves the other. If nh[1] is zero after the update, length is set to 16; otherwise 32. >
> Usage example: >
> # Read > print bgp_next_hop_global; # 2404:f4c0:f70e:1980::202:881 > print bgp_next_hop_ll; # fe80::ff:fe20:2881 >
> # Modify global only, link-local preserved > bgp_next_hop_global = 2001:db8::1; >
> # Modify link-local only, global preserved > bgp_next_hop_ll = fe80::99; >
> Files changed: > https://github.com/KusakabeShi/bird/commit/b5af9bc2eefbcc9e6f96432dd43fc6422f5f33c8 >
> - proto/bgp/config.Y — new keywords and dynamic_attr rules > - filter/f-inst.c — GET/SET handling for partial next hop access >
> The patch applies against the v2.18 release branch. Feedback welcome. >
> Thanks, > KusakabeShi


Maria Matejka (she/her) | BIRD Team Leader | CZ.NIC, z.s.p.o.