Dear BIRD dev-team and community,
By looking at the project code (and corroborated by this [0] earlier RFC) it seems that currently the feature of auto-discovering BGP neighbors leveraging the IPv6 ND protocol is not currently fully supported by BIRD. I would like to start working on a patch proposal to close this gap.
Many of the required pieces seem to be already in-place, like support for IPv6 link-local peer addresses and support of RFC-8950 for extended next-hop.
There is also the dynamic BGP implementation which seems useful for the purpose of achieving dynamic connections based on received RAs. The problem is that dynamic BGP works in a passive/reactive model only, as it waits for peers within a specified range to connect, an idea would be to integrate with this implementation but also trigger a peer connection on a RA arrival (after checking if the advertised IP is within the desired range).
Since I am still new to the project codebase and contributing for the first time, I would like to outline the idea for the implementation of the feature and hear what you think of it before going through the implementation. Any suggestions on best practices, style and common pitfalls would be also very welcome.
Introduce a new configuration option (e.g. automatic_lladdr_peering, or similar) to trigger this feature. This will provide a way to avoid modifying the current behavior if not needed.
The rest of the configuration will also have to contain a neighbour range of fe80::/12 and an interface for the link-local feature (both of these are already supported). The resulting configuration preamble would look something like this:
local as 65532;
neighbor range fe80::/12%eth0 as 65534;
dynamic name "link_local_";
automatic lladdr peering on;
To make the configuration tidier we could, alternatively, introduce a new value for neighbor, like “neighbor auto” or “neighbor discover” to enable the feature.
When the above configuration is found, open a L2 socket on the provided device during the bgp_startup phase. This socket will then be used to send a RS to ff02::2 (all-routers multicast) to trigger the RAs used for peer discovery on remote routers.
Another option would be to start sending out unsolicited RAs for the other peers to receive for discovery, this will make sure that we are not dependent on the peer being able to answer RSs and can rely entirely on the BGP implementation. This method would require to keep sending unsolicited RAs with a certain cadence, which could be set as a timer parameter in the added configuration option.
On the rx_hook of this socket listen for incoming ICMPv6 packets with type 134 (RA) and check if they contain a link-local address (i.e. inside the range provided in the configuration). If so, initiate a new BGP connection, using the now discovered LL remote address. This will follow the same path as if the remote peer address was statically provided in the configuration (sets remote_ip, calls bgp_active). As an added failover, we could remain listening on the L2 socket and try connecting to a new peer if a new address is discovered and we are in state BS_IDLE.
After a connection is established, if it becomes stale (after hold timer elapses) we can then trigger a new RS and relative discovery as outlined above to try and connect to a new remote LL address.
This will not be needed if using the unsolicited RAs variant.
The rest of the connection management and BGP message handling via the TCP socket will remain the same.
This idea for the implementation is the one that reuses as much of the current codebase while introducing as little new procedures as possible that I could come up with, but I think it can still be refined with more insight with the internals.
One thing that I am not sure about is the introduction of a new socket and connected logic on the BGP module, but I cannot really find an alternative. There is already an implementation of a packet engine for RAs that could maybe be reused for the processing of the ICMPv6 packets, but I think it will be easier to decouple the logic and implement everything on the BGP state machine (even if it will mean some code duplication, which is not ideal).
Another variant could be establishing a connection for every discovered address, as in the case of incoming connections for the dynamic BGP implementation. Maybe this is a more general solution, but since the current implementation expects an incoming request it will maybe introduce too much logic to try and fit it in.
Let me know your opinion on if and if it seems a proper way to proceed (and, of course, if there is any interest in having this feature upstream). Thank you in advance for your time and feedback.
Best Regards,
Matteo
0: https://bird.network.cz/pipermail/bird-users/2022-July/016233.html