Under some circumstances it might happen that the session is quickly UP in the
middle of `clear bgp ...` and `shutdown`. That leads to session be UP, and
the stale routes being cleared quickly.
Christian Hopps [Tue, 23 Jul 2024 21:42:07 +0000 (17:42 -0400)]
lib: mgmtd: fix too early daemon detach of mgmtd
Correct FRR startup counts on a daemon's vty socket to be open when the
parent process exits. The parent process waits for `frr_check_detach()`
to be called by the child before exiting. The problem is when the
`FRR_MANUAL_VTY_START` flag is set the vty socket was not opened but
`frr_check_detach()` was called anyway.
Instead add a bool option for `frr_check_detach()` to be called when the
socket is opened with `frr_vty_serv_start()`, and do so when "manually"
calling said function (i.e., when FRR_MANUAL_VTY_START is set).
The `FRR_MANUAL_VTY_START` flag is only set by mgmtd. The reason we
wait to open the vty socket is so that mgmtd can parse the various
daemon specific config files it has taken over, after the event loop has
started, but before we receive any possible new config from `vtysh`.
Rajasekar Raja [Mon, 22 Jul 2024 17:13:19 +0000 (10:13 -0700)]
bgpd: backpressure - Avoid use after free
Coverity complains there is a use after free (1598495 and 1598496)
At this point, most likely dest->refcount cannot go 1 and free up
the dest, but there might be some code path where this can happen.
Fixing this with a simple order change (no harm fix).
Dave LeRoy [Thu, 18 Jul 2024 17:19:30 +0000 (10:19 -0700)]
nhrpd: Fixes auth no redirect bug
The nhrp_peer_forward() routine was not explicitly handling the
Authentication Extension in the switch statement and instead fell
through to the default case which checked whether this was an
unhandled Compulsory extension and errored out, never forwarding
the Resolution Request.
Dave LeRoy [Wed, 17 Jul 2024 17:37:44 +0000 (10:37 -0700)]
nhrpd: Fixes auth config change bug
Freeing auth-token does not set nifp->auth_token to NULL.
Explicitly set auth_token to NULL when deleting auth config in order
for write config logic to succeed.
Loïc Sang [Wed, 17 Jul 2024 12:40:09 +0000 (14:40 +0200)]
bgpd: do not update leak label at loopback up down
The up/down state of the lo loopback interface does not determine the
availability of the default vrf-lite.
Do not update leak label at lo loopback up/down change.
Fixes: b45c5cd959 ("bgpd: update route leak when vrf state changes") Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com> Signed-off-by: Loïc Sang <loic.sang@6wind.com>
Loïc Sang [Tue, 16 Jul 2024 12:03:11 +0000 (14:03 +0200)]
bgpd: fix label lost when vrf loopback comes back
VRF-label association drops when the VRF loopback goes down, however, it
does not return once the interface is enabled again.
Logs show that when VRF loopback goes down, a label drop message is sent
to zebra and immediately resent label installation to zebra, trigged by
"vpn_leak_postchange_all()":
2024/07/16 13:26:29 BGP: [RVJ1J-J2T22] ifp down r1-cust1 vrf id 7
2024/07/16 13:26:29 BGP: [WA2QY-06STJ] vpn_leak_zebra_vrf_label_withdraw: deleting label for vrf VRF r1-cust1 (id=7)
2024/07/16 13:26:30 BGP: [S82AC-6YAC8] vpn_leak_zebra_vrf_label_update: vrf VRF r1-cust1: afi IPv4: setting label 80 for vrf id 7
Since the interface is down, the netlink message is not send to kernel.
Once the interface comes back, zebra ignore the installation assuming
the label is already seen.
To fix this, add a check for the interface status before attempting to
reinstall the label.
ospfd: fix internal ldp-sync state flags when feature is disabled
When enabling "mpls ldp-sync" under "router ospf" ospfd configures
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG) so internally knowing
that the ldp-sync feature is enabled. However the flag is not cleared when
turning of the feature using "nompls ldp-sync"!
https://github.com/FRRouting/frr/issues/16375
Signed-off-by: Christian Breunig <christian@breunig.cc>
Nathan Bahr [Mon, 24 Jun 2024 17:45:42 +0000 (12:45 -0500)]
doc: Update PIM[6] configure docs
Document 'router pim[6] [vrf NAME]' configuration.
All the commands are basically the same, just dropped the
'ip pim[6]' prefix and document them under the router pim block.
Moved all existing global/vrf PIM config to the new subnode.
Existing configuration updated to be hidden and deprecated.
Both versions of configuration still work together.
Rajasekar Raja [Wed, 10 Jul 2024 23:46:29 +0000 (16:46 -0700)]
bgpd: backpressure - fix to properly remove dest for bgp under deletion
In case of imported routes (L3vni/vrf leaks), when a bgp instance is
being deleted, the peer->bgp comparision with the incoming bgp to remove
the dest from the pending fifo is wrong. This can lead to the fifo
having stale entries resulting in crash.
Two changes are done here.
- Instead of pop/push items in list if the struct bgp doesnt match,
simply iterate the list and remove the expected ones.
- Corrected the way bgp is fetched from dest rather than relying on
path_info->peer so that it works for all kinds of routes.
bgpd: Skip automatically created BGP instances for show CMDs
When using e.g. `adverise-all-vni`, and/or `import vrf ...`, the VRF instance
is created with a default's VRF ASN and tagged as AUTO_VRF. We MUST skip them
here also.
bgpd: Mark VRF instance as auto created if import vrf is configured for this instance
If we create a new BGP instance (in this case VRF instance), it MUST be marked
as auto created, to avoid bgpd changing VRF instance's ASN to the default VRF's.
That's because of the ordering when FRR reload is happening.
Rajasekar Raja [Fri, 5 Jul 2024 23:02:12 +0000 (16:02 -0700)]
zebra: Fix to avoid two Vrfs with same table ids
During internal testing, when the following sequence is followed, two
non default vrfs end up pointing to the same table-id
- Initially vrf201 has table id 1002
- ip link add dev vrf202 type vrf table 1002
- ip link set dev vrf202 up
- ip link set dev <intrerface> master vrf202
This will ideally lead to zebra exit since this is a misconfiguration as
expected.
However if we perform a restart frr.service at this point, we end up
having two vrfs pointing to same table-id and bad things can happen.
This is because in the interface_vrf_change, we incorrectly check for
vrf_lookup_by_id() to evaluate if there is a misconfig. This works well
for a non restart case but not for the startup case.
root@mlx-3700-20:mgmt:/var/log/frr# sudo vtysh -c "sh vrf"
vrf mgmt id 37 table 1001
vrf vrf201 id 46 table 1002
vrf vrf202 id 59 table 1002 >>>>
Fix: in all cases of misconfiguration, exit zebra as expected.
Use `vtysh` with this input file:
```
ip route A nh1
ip route A nh2
ip route B nh1
ip route B nh2
```
When running "ip route B" with "nh1" and "nh2", the procedure maybe is:
1) Create the two nexthops: "nh1" and "nh2".
2) Register "nh1" with `static_zebra_nht_register()`, then the states of both
"nh1" and "nht2" are set to "STATIC_SENT_TO_ZEBRA".
3) Register "nh2" with `static_zebra_nht_register()`, then only the routes with
nexthop of "STATIC_START" will be sent to zebra.
So, send the routes with the nexthop of "STATIC_SENT_TO_ZEBRA" to zebra.
isisd: fix crash when calculating the neighbor spanning tree based on the fragmented LSP
1. When the root IS regenerates an LSP, it calls lsp_build() -> lsp_clear_data() to free the TLV memory of the first fragment and all other fragments. If the number of fragments in the regenerated LSP decreases or if no fragmentation is needed, the extra LSP fragments are not immediately deleted. Instead, lsp_seqno_update() -> lsp_purge() is called to set the remaining time to zero and start aging, while also notifying other IS nodes to age these fragments. lsp_purge() usually does not reset lsp->hdr.seqno to zero because the LSP might recover during the aging process.
2. When other IS nodes receive an LSP, they always call process_lsp() -> isis_unpack_tlvs() to allocate TLV memory for the LSP. This does not differentiate whether the received LSP has a remaining lifetime of zero. Therefore, it is rare for an LSP of a non-root IS to have empty TLVs. Of course, if an LSP with a remaining time of zero and already corrupted is received, lsp_update() -> lsp_purge() will be called to free the TLV memory of the LSP, but this scenario is rare.
3. In LFA calculations, neighbors of the root IS are traversed, and each neighbor is taken as a new root to compute the neighbor SPT. During this process, the old root IS will serve as a neighbor of the new root IS, triggering a call to isis_spf_process_lsp() to parse the LSP of the old root IS and obtain its IP vertices and neighboring IS vertices. However, isis_spf_process_lsp() only checks whether the TLVs in the first fragment of the LSP exist, and does not check the TLVs in the fragmented LSP. If the TLV memory of the fragmented LSP of the old root IS has been freed, it can lead to a null pointer access, causing the current crash.
Additionally, for the base SPT, there are only two places where the LSP of the root IS is parsed:
1. When obtaining the UP neighbors of the root IS via spf_adj_list_parse_lsp().
2. When preloading the IP vertices of the root IS via isis_lsp_iterate_ip_reach().
Both of these checks ensure that frag->tlvs is not null, and they do not subsequently call isis_spf_process_lsp() to parse the root IS's LSP. It is very rare for non-root IS LSPs to have empty TLVs unless they are corrupted LSPs awaiting deletion. If it happens, a crash will occur.
The backtrace is as follows:
(gdb) bt
#0 0x00007f3097281fe1 in raise () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007f30973a2972 in core_handler (signo=11, siginfo=0x7ffce66c2870, context=0x7ffce66c2740) at ../lib/sigevent.c:261
#2 <signal handler called>
#3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0)
at ../isisd/isis_spf.c:898
#4 0x000055dfa805743b in isis_spf_loop (spftree=0x55dfa950eee0, root_sysid=0x55dfa950ef6c "") at ../isisd/isis_spf.c:1688
#5 0x000055dfa805784f in isis_run_spf (spftree=0x55dfa950eee0) at ../isisd/isis_spf.c:1808
#6 0x000055dfa8037ff5 in isis_spf_run_neighbors (spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:1259
#7 0x000055dfa803ac17 in isis_spf_run_lfa (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:2300
#8 0x000055dfa8057964 in isis_run_spf_with_protection (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_spf.c:1827
#9 0x000055dfa8057c15 in isis_run_spf_cb (thread=0x7ffce66c38e0) at ../isisd/isis_spf.c:1889
#10 0x00007f30973bbf04 in thread_call (thread=0x7ffce66c38e0) at ../lib/thread.c:1990
#11 0x00007f309735497b in frr_run (master=0x55dfa91733c0) at ../lib/libfrr.c:1198
#12 0x000055dfa8029d5d in main (argc=5, argv=0x7ffce66c3b08, envp=0x7ffce66c3b38) at ../isisd/isis_main.c:273
(gdb) f 3
#3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0)
at ../isisd/isis_spf.c:898
898 ../isisd/isis_spf.c: No such file or directory.
(gdb) p te_neighs
$1 = (struct isis_item_list *) 0x120
(gdb) p lsp->tlvs
$2 = (struct isis_tlvs *) 0x0
(gdb) p lsp->hdr
$3 = {pdu_len = 27, rem_lifetime = 0, lsp_id = "\000\000\000\000\000\001\000\001", seqno = 4, checksum = 59918, lsp_bits = 1 '\001'}
The backtrace provided above pertains to version 8.5.4, but it seems that the same issue exists in the code of the master branch as well.
I have reviewed the process for calculating the SPT based on the LSP, and isis_spf_process_lsp() is the only function that does not check whether the TLVs in the fragments are empty. Therefore, I believe that modifying this function alone should be sufficient. If the TLVs of the current fragment are already empty, we do not need to continue processing subsequent fragments. This is consistent with the behavior where we do not process fragments if the TLVs of the first fragment are empty.
Of course, one could argue that lsp_purge() should still retain the TLV memory, freeing it and then reallocating it if needed. However, this is a debatable point because in some scenarios, it is permissible for the LSP to have empty TLVs. For example, after receiving an SNP (Sequence Number PDU) message, an empty LSP (with lsp->hdr.seqno = 0) might be created by calling lsp_new. If the corresponding LSP message is discarded due to domain or area authentication failure, the TLV memory wouldn't be allocated.
Test scenario:
In an LFA network, importing a sufficient number of static routes to cause LSP fragmentation, and then rolling back the imported static routes so that the LSP is no longer fragmented, can easily result in this issue.
David Lamparter [Wed, 10 Jul 2024 07:49:51 +0000 (09:49 +0200)]
ospfd: fix state location mixup
In the "2x2 matrix" of these, I accidentally edited "row-wise" when I
should've edited "column-wise"... *sigh*
Reported-by: github.com/rbfnet Fixes: #16349 Fixes: 110945ba0d2 ("ospfd: fix GR state location") Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
zebra, topotests: do not set nexthop's FIB flag when DUPLICATE present
The bgp_duplicate_nexthop test installs routes with nexthop's
flags set to both DUPLICATE and FIB: this should not happen.
The DUPLICATE flag of a nexthop indicates this nexthop is already
used in the same nexthop-group, and there is no need to install it
twice in the system; having the FIB flag set indicates that the
nexthop is installed in the system. This is why both flags should
not be set on the same nexthop.
This case happens at installation time, but can also happen
at update time.
- Fix this by not setting the FIB flag value when the DUPLICATE
flag is present.
- Modify the bgp_duplicate_test to check that the FIB flag is not
present on duplicated nexthops.
- Modify the bgp_peer_type_multipath_relax test.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
zebra: evpn: not coerce VTEP IP to IPv4 in nh_list
In L3 BGP-EVPN, if there are both IPv4 and IPv6 routes in the VPN, zebra
maintains two instances of `struct zebra_neigh` object: one with IPv4
address of the nexthop, and another with IPv6 address that is an IPv4
mapped to IPv6, but only one intance of `struct zebra_mac` object, that
contains a list of nexthop addresses that use this mac.
The code in `zebra_vxlan` module uses the fact that the list is empty as
the indication that the `zebra_mac` object is unused, and needs to be
dropped. However, preexisting code used nexthop address converted to
IPv4 notation for the element of this list. As a result, when two
`zebra_neigh` objects, one IPv4 and one IPv6-mapped-IPv4 were linked to
the `zebra_mac` object, only one element was added to the list.
Consequently, when one of the two `zebra_neigh` objects was dropped, the
only element in the list was removed, making it empty, and `zebra_mac`
object was dropped, and neigbrour cache elements uninstalled from the
kernel.
As a result, after the last route in _one_ family was removed from a
remote vtep, all remaining routes in the _other_ family became
unreachable, because RMAC of the vtep was removed.
This commit makes `zebra_mac` use uncoerced IP address of the `zebra_neigh`
object for the entries in the `nh_list`. This way, `zebra_mac` object no
longer loses track of `zebra_neigh` objects that need it.