The babel protocol normally sends all its messages as multicast packets,
but the protocol specification allows most messages to be sent as either
unicast or multicast, and the two can be mixed freely. In particular, the
babeld implementation can be configured to unicast updates to all peers
instead of sending them as unicast.
Daniel discovered that this can cause problems with the packet counter
checks in the MAC extension due to packet reordering. This happens on WiFi
networks where clients have power save enabled (which is quite common in
infrastructure networks): in this case, the access point will buffer all
multicast traffic and only send it out along with its beacons, leading to a
maximum buffering in default Linux-based access point configuration of up
to 200 ms.
This means that a Babel sender that mixes unicast and multicast messages
can have the unicast messages overtake the multicast messages because of
this buffering; when authentication is enabled, this causes the receiver to
discard the multicast message when it does arrive because it now has a
packet counter value less than the unicast message that arrived before it.
Daniel observed that this happens frequently enough that Babel ceases to
work entirely when runner over a WiFi network.
The issue has been described in draft-ietf-babel-mac-relaxed, which is
currently pending RFC publication. That also describes two mitigation
mechanisms: Keeping separate PC counters for unicast and multicast, and
using a reorder window for PC values. This patch implements the former as
that is the simplest, and resolves the particular issue seen on WiFi.
Thanks to Daniel Gröber for the bugreport.
Minor changes from committer.
The patch implements an IPv4 via IPv6 extension (RFC 9229) to the Babel
routing protocol (RFC 8966) that allows annoncing routes to an IPv4
prefix with an IPv6 next hop, which makes it possible for IPv4 traffic
to flow through interfaces that have not been assigned an IPv4 address.
The implementation is compatible with the current Babeld version.
Thanks to Toke Høiland-Jørgensen for early review on this work.
Minor changes from committer.
When creating a new babel_source object we initialise the seqno to 0. The
caller will update the source object with the right metric and seqno value,
for both newly created and old source objects. However if we initialise the
source object seqno to 0 that may actually turn out to be a valid (higher)
seqno than the one in the routing table, because of seqno wrapping. In this
case the source metric will not be set properly, which breaks feasibility
tracking for subsequent updates.
To fix this, add a new initial_seqno argument to babel_get_source() which
is used when allocating a new object, and set that to the seqno value of
the update we're sending.
Thanks to Juliusz Chroboczek for the bugreport.
Juliusz noticed there were a couple of places we were doing straight
inequality comparisons of seqnos in Babel. This is wrong because seqnos can
wrap: so we need to use the modulo-64k comparison function for these cases
as well.
Introduce a strict-inequality version of the modulo-comparison for this
purpose.
For active sessions, ignore received packets with zero local id and
mismatched remote id. That forces a session timeout instead of an
immediate session restart. It makes BFD sessions more resilient to
packet spoofing.
Thanks to André Grüneberg for the suggestion.
Protocols receive if_notify() announcements that are filtered according
to their VRF setting, but during reconfiguration, they access iface_list
directly and forgot to check VRF setting here, which leads to all
interfaces be addedd.
Fix this issue for Babel, OSPF, RAdv and RIP protocols.
Thanks to Marcel Menzel for the bugreport.
Some of these new BGP role keywords use generic names that collides with
user-defined symbols. Allow them to be redefined. Also remove duplicit
keyword definition for 'prefer'.
During backporting attribute changes from 3.0-branch, some internal
attributes (RIP iface and Babel seqno) leaked to 'show route all' output.
Allow protocols to hide specific attributes with GA_HIDDEN value.
Thanks to Nigel Kukard for the bugreport.
There were some confusion about validity and usage of pflags, which
caused incorrect usage after some flags from (now removed) protocol-
specific area were moved to pflags.
We state that pflags:
- Are secondary data used by protocol-specific hooks
- Can be changed on an existing route (in contrast to copy-on-write
for primary data)
- Are irrelevant for propagation (not propagated when changed)
- Are specific to a routing table (not propagated by pipe)
The patch did these fixes:
- Do not compare pflags in rte_same(), as they may keep cached values
like BGP_REF_STALE, causing spurious propagation.
- Initialize pflags to zero in rte_get_temp(), avoid initialization in
protocol code, fixing at least two forgotten initializations (krt
and one case in babel).
- Improve documentation about pflags
The seqno request retransmission handling was tracking the destination
that a forwarded request was being sent to and always retransmitting to
that same destination. This is unnecessary because we only need to
retransmit requests we originate ourselves, not those we forward on
behalf of others; in fact retransmitting on behalf of others can lead to
exponential multiplication of requests, which would be bad.
So rework the seqno request tracking so that instead of storing the
destination of a request, we just track whether it was a request that we
forwarded on behalf of another node, or if it was a request we originated
ourselves. Forwarded requests are not retransmitted, they are only used
for duplicate suppression, and for triggering an update when satisfied.
If we end up originating a request that we previously forwarded, we
"upgrade" the old request and restart the retransmit counter.
One complication with this is that requests sent in response to unfeasible
updates (section 3.8.2.2 of the RFC) have to be sent as unicast to a
particular peer. However, we don't really need to retransmit those as
there's no starvation when sending such a request; so we just change
such requests to be one-off unicast requests that are not subject to
retransmission or duplicate suppression. This is the same behaviour as
babeld has for such requests.
Minor changes from committer.
The effective keepalive time now scales relative to the negotiated
hold time, to maintain proportion between the keepalive time and the
hold time. This avoids issues when both keepalive and hold times
were configured, the hold time was negotiated to a smaller value,
but the keepalive time stayed the same.
Add new options 'min hold time' and 'min keepalive time', which reject
session attempts with too small hold time.
Improve validation of config options an their documentation.
Thanks to Alexander Zubkov and Sergei Goriunov for suggestions.
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.
- When next hop is reset to local IP, we should remove BGP label stack,
as it is related to original next hop
- BGP next hop or immediate next hop from one VRF should not be passed
to another VRF, as they are different IP namespaces
In principle, the channel list is a list of parent struct proto and can
contain general structures of type struct channel, That is useful e.g.
for adding MPLS channels to BGP.
Implement BGP roles as described in RFC 9234. It is a mechanism for
route leak prevention and automatic route filtering based on common BGP
topology relationships. It defines role capability (controlled by 'local
role' option) and OTC route attribute, which is used for automatic route
filtering and leak detection.
Minor changes done by commiter.
When f_line is done, we have to pop the stack frame. The old code just
removed nominal number of args/vars. Change it to use stored ventry value
modified by number of returned values. This allows to allocate variables
on a stack frame during execution of f_lines instead of just at start.
But we need to know the number of returned values for a f_line. It is 1
for term, 0 for cmd. Store that to f_line during linearization.
Passing protocol to preexport was in fact a historical relic from the
old times when channels weren't a thing. Refactoring that to match
current extensibility needs.
The Babel seqno request code keeps track of which seqno requests are
outstanding for a neighbour by putting them onto a per-neighbour list. When
reusing a seqno request, it will try to remove this node, but if the seqno
request in question was a multicast request with no neighbour attached this
will result in a crash because it tries to remove a list node that wasn't
added to any list.
Fix this by making the list remove conditional. Also fix neighbor removal
which were changing seqno requests to multicast ones instead of removing
them.
Fixes: ebd5751cde ("Babel: Seqno requests are properly decoupled from
neighbors when the underlying interface disappears").
Based on the patch from Toke Høiland-Jørgensen <toke@toke.dk>,
bug reported by Stefan Haller <stefan.haller@stha.de>, thanks.
The prefix hash table in BGP used the same hash function as the rtable.
When a batch of routes are exported during feed/flush to the BGP, they
all have similar hash values, so they are all crowded in a few slots in
the BGP prefix table (which is much smaller - around the size of the
batch - and uses higher bits from hash values), making it much slower due
to excessive collisions. Use a different hash function to avoid this.
Also, increase the batch size to fill 4k BGP packets and increase minimum
BGP bucket and prefix hash sizes to avoid back and forth resizing during
flushes.
This leads to order of magnitude faster flushes (on my test data).
When shutting down a Babel instance we send a wildcard retraction to make
sure all peers can quickly switch to other route origins. Add another small
optimisation borrowed from babeld: sending a Hello message (along with the
retraction) with a very low interval.
This will cause neighbours to modify their expiry timers for the node's
state to quickly time it out, thus conserving resources in the network.
The interface pointer was improperly converted to u32 and back. Fixing
this by explicitly allocating an adata structure for it. It's not so
memory efficient, we'll optimize this later.
Add BFD protocol option 'strict bind' to use separate listening socket
for each BFD interface bound to its address instead of using shared
listening sockets.
It is too cryptic to flush tmp_linpool in these cases and we don't want
anybody in the future to break this code by adding an allocation
somewhere which should persist over that flush.
Saving and restoring linpool state is safer.
A recent change in Babel causes ifaces to disappear after
reconfiguration. The patch fixes that.
Thanks to Johannes Kimmel for an insightful bugreport.
Implement flowspec validation procedure as described in RFC 8955 sec. 6
and RFC 9117. The Validation procedure enforces that only routers in the
forwarding path for a network can originate flowspec rules for that
network.
The patch adds new mechanism for tracking inter-table dependencies, which
is necessary as the flowspec validation depends on IP routes, and flowspec
rules must be revalidated when best IP routes change.
The validation procedure is disabled by default and requires that
relevant IP table uses trie, as it uses interval queries for subnets.
Attach a prefix trie to IP/VPN/ROA tables. Use it for net_route() and
net_roa_check(). This leads to 3-5x speedups for IPv4 and 5-10x
speedup for IPv6 of these calls.
TODO:
- Rebuild the trie during rt_prune_table()
- Better way to avoid trie_add_prefix() in net_get() for existing tables
- Make it configurable (?)
One of previous commits added error logging of invalid routes. This
also inadvertently caused error logging of route loops, which should
be ignored silently. Fix that.
Most error messages in attribute processing are in rx/decode step and
these use L_REMOTE log class. But there are few that are in tx/export
step and these should use L_ERR log class.
Use tx-specific macro (REJECT()) in tx/export code and rename field
err_withdraw to err_reject in struct bgp_export_state to ensure that
appropriate error reporting macros are called in proper contexts.
RFC 6810 and RFC 8210 specify that the "Max Length" value MUST NOT be
less than the Prefix Length element (underflow). On the other side,
overflow of the Max Length element also is possible, it being an 8-bit
unsigned integer allows for values larger than 32 or 128. This also
implicitly ensures there is no overflow of "Length" value.
When a PDU is received where the Max Length field is corrputed, the RTR
client (BIRD) should immediately terminate the session, flush all data
learned from that cache, and log an error for the operator.
Minor changes done by commiter.
Some cleanups and bugfixes to the previous patch, including:
- Fix rate limiting in index mismatch check
- Fix missing BABEL_AUTH_INDEX_LEN in auth_tx_overhead computation
- Fix missing auth_tx_overhead recalculation during reconfiguration
- Fix pseudoheader construction in babel_auth_sign() (sport vs fport)
- Fix typecasts for ptrdiffs in log messages
- Make auth log messages similar to corresponding RIP/OSPF ones
- Change auth log messages for events that happen during regular
operation to debug messages
- Switch meaning of babel_auth_check*() functions for consistency
with corresponding RIP/OSPF ones
- Remove requirement for min/max key length, only those required by
given MAC code are enforced
This implements support for MAC authentication in the Babel protocol, as
specified by RFC 8967. The implementation seeks to follow the RFC as close
as possible, with the only deliberate deviation being the addition of
support for all the HMAC algorithms already supported by Bird, as well as
the Blake2b variant of the Blake algorithm.
For description of applicability, assumptions and security properties,
see RFC 8967 sections 1.1 and 1.2.
In preparation for adding authentication checks, refactor the TLV
walking code so it can be reused for a separate pass of the packet
for authentication checks.
Routes from downed protocols stay in rtable (until next rtable prune
cycle ends) and may be even exported to another protocol. In BGP case,
source BGP protocol is examined, although dynamic parts (including
neighbor entries) are already freed. That may lead to crash under some
race conditions. Ensure that freed neighbor entry is not accessed to
avoid this issue.
When an interface disappears, all the neighbors are freed as well. Seqno
requests were anyway not decoupled from them, leading to strange
segfaults. This fix adds a proper seqno request list inside neighbors to
make sure that no pointer to neighbor is kept after free.
The babel protocol code checks whether iface supports multicast, and
whether it has a link-local address assigned. However, it doesn not give
any feedback if any of those checks fail, it just silently ignores the
interface. Fix this by explicitly logging when multicast check fails.
Based on patch from Toke Høiland-Jørgensen, thanks!
Ifaces with host address (/32) were forced to be stubby, but now they
can be used as PtP or PtMP. For these ifaces we need to:
- Do not force stub mode
- Accept packets from any IP as local
- Accept any configured neighbor as local
- Detect ifaces properly as unnumbered
- Use ONLINK flag for nexthops
As specified in RFC 2328 8.1: "On physical point-to-point networks,
the IP destination is always set to the address AllSPFRouters."
Note that this likely break setups with multiple neighbors on a network
configured as PtP, which worked before. These should be configured as
PtMP.
Thanks to Senthil Kumar Nagappan for the original patch and to Joakim
Tjernlund for suggestions.
The flag makes sense just in external representation. It is reset during
BGP export, but keeping it internally broke MRT dumps for short attributes
that used it anyways.
Thanks to Simon Marsh for the bugreport and the patch.
BGP statistics code was preliminary and i wanted to replace it by
separate 'show X stats' command. The patch hides the preliminary
output in 'show protocols all' so it is not part of the released
version.
In OSPFv3, only Hello and DBDes packets contain flags specifying whether
RFC 7166 authentication trailer is used. Other packets are processed
based on stored authentication state in neighbor structure. Update this
state with each received Hello to handle authentication change from
reconfigurations.
Thanks to Joakim Tjernlund and Kenth Eriksson for the bugreport.
This is an implementation of draft-walton-bgp-hostname-capability-02.
It is implemented since quite some time for FRR and in datacenter, this
gives a nice output to avoid using IP addresses.
It is disabled by default. The hostname is retrieved from uname(2) and
can be overriden with "hostname" option. The domain name is never set
nor displayed.
Minor changes by committer.
Flag signalling that MP-BGP mode should be used got reset after first
batch of routes, so remaining routes were processed without that, leading
to missing MP_REACH_NLRI attribute.
Thanks to Piotr Wydrych for the bugreport.
Add fake MP_REACH_NLRI attribute with BGP next hop when encoding MRT
table dumps for IPv6 routes. That is necessary to encode next hop as
NEXT_HOP attribute is not used for MP-BGP.
Thanks to Santiago Aggio for the bugreport.
Direct BFD sessions needs to be dispatched not only by IP addresses, but
also by interfaces, in order to avoid collisions between neighbors with
the same IPv6 link-local addresses.
Extend BFD session hash_ip key by interface index to handle that. Use 0
for multihop sessions.
Thanks to Sebastian Hahn for the original patch.
It was mixed-up if hostname is IPv6 address, and reporting separate
values (like port) on separate lines fits better into key-value style
of 'show protocols all' output. Also, the patch simplifies transport
identification formatting (although it is unused now).
Thanks to Alarig Le Lay for the suggestion.
The option is not implemented since transition to 2.0 and no plan to add it.
Also remove some deprecated RTS_* valus from documentation.
Thanks to Sébastien Parisot for notification.
The patch add support for per-channel debug flags, currently just
'states', 'routes', and 'filters'. Flag 'states' is used for channel
state changes, remaining two for routes passed through the channel.
The per-protocol debug flags 'routes'/'filters' still enable reporting
of routes for all channels, to keep existing behavior.
The patch causes minor changes in some log messages.
When config structures are copied due to template application,
we need to reset list node structure before calling add_tail().
Thanks to Mikael Magnusson for patches.
The babel protocol code was initialising objects returned from the slab
allocator by assigning to each of the struct members individually, but
wasn't touching the NODE member while doing so. This leads to warnings on
debug builds since commit:
baac700906 ("List expensive check.")
To fix this, introduce an sl_allocz() variant of the slab allocator which
will zero out the memory before returning it, and switch all the babel call
sites to use this version. The overhead for doing this should be negligible
for small objects, and in the case of babel, the largest object being
allocated was being zeroed anyway, so we can drop the memset in
babel_read_tlv().
Add support for proper handling of multiple routes with the same network
to the static protocol. Routes are distinguished by internal index, which
is assigned automatically (sequentially for routes within each network).
Having different route preference or igp_metric attribute is optional.
When a new link-LSA is originated, we need to notify intra-area-prefix-LSA
handling, like when a new link-LSA is received. Otherwise a new network
prefix added to a DR is not propagated immediately.
Thanks to Bala Sajja for the bugreport.
Merge multiple BFD option blocks in BGP configs instead of using the last
one. That is necessary for proper handling of templates when BFD options
are used both in a BGP template and in a BGP protocol derived from that
template.
BFD session options are configured per interface in BFD protocol. This
patch allows to specify them also per-request in protocols requesting
sessions (currently limited to BGP).
Add 'ignore max length' option to RPKI protocol, which ignores received
max length in ROA records and instead uses max value (32 or 128). This
may be useful for implementing loose RPKI check for blackholes.
Sometimes multicast OSPF packet is received when neighbor adjacency is
not established. Such packet should be ignored earlier in packet
processing as otherwise it causes strange error messages when OSPFv3
authentication is enabled.
Most commands like 'show ospf neighbors' fail when protocol is not
specified and there are multiple instances of given protocol type.
This is annoying in BIRD 2, as many protocols have IPv4 and IPv6
instances. The patch changes that by showing output from all protocol
instances of appropriate type.
Note that the patch also removes terminating cli_msg() call from these
commands and moves it to the common iterating code.
Compare the new timing parameters with the old configuration, not with
the temporary state of the current connection.
The timing values in struct rpki_cache is updated by a version 1 End Of
Data PDU, unless this behavior is suppressed by the configuration
explicitly by the "keep" keyword. Consequently, every reconfiguration
of BIRD triggers a reconnection even if it is not necessary.
If the next hop of a route is not a reachable address, the route should be
installed as onlink. This enables a configuration common in mesh networks
where the mesh interface is assigned a /32 and babel handles the routing by
installing onlink routes.
Thanks to Toke Hoiland-Jorgensen for the patch.
This issue has a long history. In 2012, we changed data field for
unnumbered PtP links from iface id (specified by RFC) to IP address based
on reports of bugs in Quagga that required it, and we used out-of-band
information to distinquish unnumberred PtPs with the same local IP
address.
Then with OSPF graceful restart implementation, we found that we can no
longer use out-of-band information, and we need to use only LSAdb info
for routing table calculation, but i forgot to finish handling of this
case, so multiple unnumbered PtPs with the same local IP addresses were
broken.
Considering that even recent Mikrotik RouterOS has broken next hop
calculation that depends on IP address in PtP link data field, we
cannot just switch back to the iface id for unnumbered PtP links.
The patch makes two changes: First, it goes back to use out-of-band
(position) info for distinguishing local interfaces in SPF when graceful
restart is not enabled, while still uses LSAdb-only approach for SPF
calculation when graceful restart is enabled.
Second, it adds OSPF interface option 'ptp address', which controls
whether IP address or iface id is used in data field. It is enabled
by default except for unnumbered PtP links with enabled graceful
restart.
Thanks to Kenth Eriksson for the bugreport and Joakim Tjernlund for
suggestions.
There are three common ways how to encode IPv6 link-local-only next hops:
(:: ll), (ll), and (ll ll). We use the first one but we should accept all
three. The patch fixes handling of the last one.
Thanks to Sebastian Hahn for the bugreport.
The RFC 5575 does not explicitly reject flowspec rules without dst part,
it just requires dst part in validation procedure for feasibility, which
we do not implement anyway. Thus flow without dst prefix is syntactically
valid, but unfeasible (if feasibilty testing is done).
Thanks to Alex D. for the bugreport.
When dynamic BGP with remote range is configured, MD5SIG needs to use
newer socket option (TCP_MD5SIG_EXT) to specify remote addres range for
listening socket.
Thanks to Adam Kułagowski for the suggestion.
Recent changes in neighbor code caused RIP to access neighbor field which
is NULL during interface/neighbor removal and caused crash when debug
messages are enabled. Use correct field to get iface from neighbor.