2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2016-04-14 15:20:47 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 CumulusNetworks
|
|
|
|
* Donald Sharp
|
|
|
|
*
|
|
|
|
* This file is part of Quagga
|
|
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2021-10-18 22:34:02 +02:00
|
|
|
/* for basename */
|
|
|
|
#include <libgen.h>
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
#include "log.h"
|
|
|
|
#include "linklist.h"
|
2016-10-29 02:32:07 +02:00
|
|
|
#include "command.h"
|
2015-05-29 05:48:31 +02:00
|
|
|
#include "memory.h"
|
2016-12-05 20:05:30 +01:00
|
|
|
#include "srcdest_table.h"
|
2018-01-22 09:42:53 +01:00
|
|
|
#include "vrf.h"
|
2016-10-06 21:56:13 +02:00
|
|
|
#include "vty.h"
|
2018-01-22 09:42:53 +01:00
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
#include "zebra/zebra_router.h"
|
2019-03-27 10:25:13 +01:00
|
|
|
#include "zebra/rtadv.h"
|
2016-04-14 15:20:47 +02:00
|
|
|
#include "zebra/debug.h"
|
2018-04-22 22:01:20 +02:00
|
|
|
#include "zebra/zapi_msg.h"
|
2016-04-14 15:20:47 +02:00
|
|
|
#include "zebra/rib.h"
|
|
|
|
#include "zebra/zebra_vrf.h"
|
2016-10-31 18:15:16 +01:00
|
|
|
#include "zebra/zebra_rnh.h"
|
2016-04-14 15:20:47 +02:00
|
|
|
#include "zebra/router-id.h"
|
2016-10-31 18:15:16 +01:00
|
|
|
#include "zebra/interface.h"
|
2016-04-15 19:51:56 +02:00
|
|
|
#include "zebra/zebra_mpls.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "zebra/zebra_vxlan.h"
|
2018-03-13 15:26:03 +01:00
|
|
|
#include "zebra/zebra_netns_notify.h"
|
2018-10-11 19:49:34 +02:00
|
|
|
#include "zebra/zebra_routemap.h"
|
2021-08-23 22:54:12 +02:00
|
|
|
#include "zebra/zebra_vrf_clippy.c"
|
2021-07-23 16:56:28 +02:00
|
|
|
#include "zebra/table_manager.h"
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2017-12-11 23:38:15 +01:00
|
|
|
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
|
|
|
|
safi_t safi);
|
|
|
|
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
|
|
|
struct route_node *node);
|
|
|
|
|
2019-06-21 08:10:39 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF");
|
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table");
|
2019-05-07 01:42:26 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/* VRF information update. */
|
|
|
|
static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
2016-10-30 22:50:26 +01:00
|
|
|
zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf));
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2025-03-16 21:56:19 +01:00
|
|
|
frr_each (zserv_client_list, &zrouter.client_list, client) {
|
2020-03-06 16:33:40 +01:00
|
|
|
/* Do not send unsolicited messages to synchronous clients. */
|
|
|
|
if (client->synchronous)
|
|
|
|
continue;
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
zsend_vrf_add(client, zvrf);
|
2020-03-06 16:33:40 +01:00
|
|
|
}
|
2016-04-14 15:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vrf_delete_update(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct zserv *client;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
2016-10-30 22:50:26 +01:00
|
|
|
zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf));
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2025-03-16 21:56:19 +01:00
|
|
|
frr_each (zserv_client_list, &zrouter.client_list, client) {
|
2020-03-06 16:33:40 +01:00
|
|
|
/* Do not send unsolicited messages to synchronous clients. */
|
|
|
|
if (client->synchronous)
|
|
|
|
continue;
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
zsend_vrf_delete(client, zvrf);
|
2020-03-06 16:33:40 +01:00
|
|
|
}
|
2016-04-14 15:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_vrf_update_all(struct zserv *client)
|
|
|
|
{
|
|
|
|
struct vrf *vrf;
|
|
|
|
|
2017-09-15 17:47:35 +02:00
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
2017-12-22 16:02:51 +01:00
|
|
|
if (vrf->vrf_id != VRF_UNKNOWN)
|
2016-04-14 15:20:47 +02:00
|
|
|
zsend_vrf_add(client, vrf_info_lookup(vrf->vrf_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Callback upon creating a new VRF. */
|
2016-10-30 22:50:26 +01:00
|
|
|
static int zebra_vrf_new(struct vrf *vrf)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
2016-10-30 22:50:26 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2016-06-27 13:34:32 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
2019-08-23 14:28:43 +02:00
|
|
|
zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id);
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2021-04-26 15:47:39 +02:00
|
|
|
zvrf = zebra_vrf_alloc(vrf);
|
2020-12-08 12:11:05 +01:00
|
|
|
if (!vrf_is_backend_netns())
|
|
|
|
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
|
2024-12-27 14:10:27 +01:00
|
|
|
else if (vrf->vrf_id == VRF_DEFAULT) {
|
|
|
|
struct ns *ns;
|
|
|
|
|
|
|
|
strlcpy(vrf->data.l.netns_name, VRF_DEFAULT_NAME, NS_NAMSIZ);
|
|
|
|
ns = ns_lookup(NS_DEFAULT);
|
|
|
|
ns->vrf_ctxt = vrf;
|
|
|
|
vrf->ns_ctxt = ns;
|
|
|
|
}
|
2019-05-07 01:42:26 +02:00
|
|
|
|
|
|
|
otable_init(&zvrf->other_tables);
|
|
|
|
|
2017-12-22 16:21:09 +01:00
|
|
|
router_id_init(zvrf);
|
2021-07-23 16:56:28 +02:00
|
|
|
|
|
|
|
/* Initiate Table Manager per ZNS */
|
|
|
|
table_manager_enable(zvrf);
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Callback upon enabling a VRF. */
|
2016-10-30 22:50:26 +01:00
|
|
|
static int zebra_vrf_enable(struct vrf *vrf)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
2016-10-30 22:50:26 +01:00
|
|
|
struct zebra_vrf *zvrf = vrf->info;
|
2017-12-11 23:38:15 +01:00
|
|
|
struct route_table *table;
|
2016-05-04 02:04:43 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
assert(zvrf);
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
|
|
zlog_debug("VRF %s id %u is now active", zvrf_name(zvrf),
|
|
|
|
zvrf_id(zvrf));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-12-22 16:21:09 +01:00
|
|
|
if (vrf_is_backend_netns())
|
|
|
|
zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id);
|
|
|
|
else
|
|
|
|
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
|
2021-04-18 12:11:14 +02:00
|
|
|
|
2021-05-26 23:36:16 +02:00
|
|
|
rtadv_vrf_init(zvrf);
|
2019-03-27 10:25:13 +01:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Inform clients that the VRF is now active. This is an
|
|
|
|
* add for the clients.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-05 18:07:23 +01:00
|
|
|
zebra_vrf_add_update(zvrf);
|
2017-12-11 23:38:15 +01:00
|
|
|
/* Allocate tables */
|
|
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
|
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
|
|
|
zebra_vrf_table_create(zvrf, afi, safi);
|
|
|
|
|
|
|
|
table = route_table_init();
|
|
|
|
table->cleanup = zebra_rnhtable_node_cleanup;
|
|
|
|
zvrf->rnh_table[afi] = table;
|
|
|
|
|
|
|
|
table = route_table_init();
|
|
|
|
table->cleanup = zebra_rnhtable_node_cleanup;
|
2021-09-24 22:42:25 +02:00
|
|
|
zvrf->rnh_table_multicast[afi] = table;
|
2017-12-11 23:38:15 +01:00
|
|
|
}
|
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Kick off any VxLAN-EVPN processing. */
|
|
|
|
zebra_vxlan_vrf_enable(zvrf);
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
/* update the VRF ID of a routing table and their routing entries */
|
|
|
|
static void zebra_vrf_disable_update_vrfid(struct zebra_vrf *zvrf, afi_t afi, safi_t safi)
|
|
|
|
{
|
|
|
|
struct rib_table_info *info;
|
2024-08-22 11:12:29 +02:00
|
|
|
struct route_entry *re, *nre;
|
|
|
|
struct route_node *rn, *nrn;
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
bool empty_table = true;
|
2024-08-22 11:12:29 +02:00
|
|
|
bool rn_delete;
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
|
|
|
|
/* Assign the table to the default VRF.
|
|
|
|
* Although the table is not technically owned by the default VRF,
|
|
|
|
* the code assumes that unassigned routing tables are
|
|
|
|
* associated with the default VRF.
|
|
|
|
*/
|
|
|
|
info = route_table_get_info(zvrf->table[afi][safi]);
|
|
|
|
info->zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
|
|
|
|
rn = route_top(zvrf->table[afi][safi]);
|
|
|
|
if (rn)
|
|
|
|
empty_table = false;
|
|
|
|
while (rn) {
|
|
|
|
if (!rn->info) {
|
|
|
|
rn = route_next(rn);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-08-22 11:12:29 +02:00
|
|
|
/* Assign the kernel route entries to the default VRF,
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
* even though they are not actually owned by it.
|
2024-08-22 11:12:29 +02:00
|
|
|
*
|
2024-09-23 17:23:51 +02:00
|
|
|
* Remove route nodes that were created by FRR daemons,
|
|
|
|
* unless they are associated with the table rather than the VRF.
|
|
|
|
* Routes associated with the VRF are not needed once the VRF is
|
|
|
|
* disabled.
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
*/
|
2024-08-22 11:12:29 +02:00
|
|
|
rn_delete = true;
|
|
|
|
RNODE_FOREACH_RE_SAFE (rn, re, nre) {
|
2024-09-23 17:23:51 +02:00
|
|
|
if (re->type == ZEBRA_ROUTE_KERNEL ||
|
|
|
|
CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID)) {
|
2024-08-22 11:12:29 +02:00
|
|
|
nexthop_vrf_update(rn, re, VRF_DEFAULT);
|
2024-09-23 17:23:51 +02:00
|
|
|
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID))
|
|
|
|
/* reinstall routes */
|
|
|
|
rib_install_kernel(rn, re, NULL);
|
2024-08-22 11:12:29 +02:00
|
|
|
rn_delete = false;
|
|
|
|
} else
|
|
|
|
rib_unlink(rn, re);
|
|
|
|
}
|
|
|
|
if (rn_delete) {
|
|
|
|
nrn = route_next(rn);
|
|
|
|
zebra_node_info_cleanup(rn);
|
|
|
|
rn->info = NULL;
|
|
|
|
route_unlock_node(rn);
|
|
|
|
rn = nrn;
|
|
|
|
} else {
|
|
|
|
empty_table = false;
|
|
|
|
rn = route_next(rn);
|
|
|
|
}
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (empty_table)
|
|
|
|
zebra_router_release_table(zvrf, zvrf->table_id, afi, safi);
|
|
|
|
zvrf->table[afi][safi] = NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/* Callback upon disabling a VRF. */
|
2016-10-30 22:50:26 +01:00
|
|
|
static int zebra_vrf_disable(struct vrf *vrf)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
2016-10-30 22:50:26 +01:00
|
|
|
struct zebra_vrf *zvrf = vrf->info;
|
2017-12-11 23:38:15 +01:00
|
|
|
struct interface *ifp;
|
2016-05-04 02:04:43 +02:00
|
|
|
afi_t afi;
|
|
|
|
safi_t safi;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
assert(zvrf);
|
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
|
|
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
|
|
|
|
zvrf_id(zvrf));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Stop any VxLAN-EVPN processing. */
|
|
|
|
zebra_vxlan_vrf_disable(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-04-02 17:16:50 +02:00
|
|
|
rtadv_vrf_terminate(zvrf);
|
2019-03-27 10:25:13 +01:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Inform clients that the VRF is now inactive. This is a
|
|
|
|
* delete for the clients.
|
|
|
|
*/
|
2016-04-14 15:20:47 +02:00
|
|
|
zebra_vrf_delete_update(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-12-11 23:38:15 +01:00
|
|
|
/* If asked to retain routes, there's nothing more to do. */
|
|
|
|
if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Remove all routes. */
|
|
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
2019-03-08 21:38:00 +01:00
|
|
|
route_table_finish(zvrf->rnh_table[afi]);
|
|
|
|
zvrf->rnh_table[afi] = NULL;
|
2021-09-24 22:42:25 +02:00
|
|
|
route_table_finish(zvrf->rnh_table_multicast[afi]);
|
|
|
|
zvrf->rnh_table_multicast[afi] = NULL;
|
2019-03-08 21:38:00 +01:00
|
|
|
|
2017-12-11 23:38:15 +01:00
|
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
|
|
|
rib_close_table(zvrf->table[afi][safi]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup Vxlan, MPLS and PW tables. */
|
|
|
|
zebra_vxlan_cleanup_tables(zvrf);
|
|
|
|
zebra_mpls_cleanup_tables(zvrf);
|
2023-12-11 21:22:07 +01:00
|
|
|
zebra_pw_exit_vrf(zvrf);
|
2017-12-11 23:38:15 +01:00
|
|
|
|
|
|
|
/* Remove link-local IPv4 addresses created for BGP unnumbered peering.
|
|
|
|
*/
|
|
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
|
|
|
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
|
|
|
|
|
|
|
/* clean-up work queues */
|
2022-08-09 19:09:16 +02:00
|
|
|
meta_queue_free(zrouter.mq, zvrf);
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2017-12-11 23:38:15 +01:00
|
|
|
/* Cleanup (free) routing tables and NHT tables. */
|
|
|
|
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
2018-08-27 16:43:37 +02:00
|
|
|
/*
|
|
|
|
* Set the table pointer to NULL as that
|
|
|
|
* we no-longer need a copy of it, nor do we
|
|
|
|
* own this data, the zebra_router structure
|
|
|
|
* owns these tables. Once we've cleaned up the
|
|
|
|
* table, see rib_close_table above
|
|
|
|
* we no-longer need this pointer.
|
|
|
|
*/
|
2019-02-28 15:11:41 +01:00
|
|
|
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
if (!zvrf->table[afi][safi] || vrf->vrf_id == VRF_DEFAULT) {
|
|
|
|
zebra_router_release_table(zvrf, zvrf->table_id, afi, safi);
|
|
|
|
zvrf->table[afi][safi] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zebra_vrf_disable_update_vrfid(zvrf, afi, safi);
|
2019-02-28 15:11:41 +01:00
|
|
|
}
|
2016-10-31 18:15:16 +01:00
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-30 22:50:26 +01:00
|
|
|
static int zebra_vrf_delete(struct vrf *vrf)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
2016-10-30 22:50:26 +01:00
|
|
|
struct zebra_vrf *zvrf = vrf->info;
|
2019-05-07 01:42:26 +02:00
|
|
|
struct other_route_table *otable;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
assert(zvrf);
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_EVENT)
|
|
|
|
zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf),
|
|
|
|
zvrf_id(zvrf));
|
2016-10-31 18:15:16 +01:00
|
|
|
|
2021-11-04 23:54:48 +01:00
|
|
|
table_manager_disable(zvrf);
|
|
|
|
|
2016-10-31 18:15:16 +01:00
|
|
|
/* clean-up work queues */
|
2022-08-09 19:09:16 +02:00
|
|
|
meta_queue_free(zrouter.mq, zvrf);
|
2016-10-31 18:15:16 +01:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Free Vxlan and MPLS. */
|
|
|
|
zebra_vxlan_close_tables(zvrf);
|
|
|
|
zebra_mpls_close_tables(zvrf);
|
|
|
|
|
2019-05-07 01:42:26 +02:00
|
|
|
otable = otable_pop(&zvrf->other_tables);
|
|
|
|
while (otable) {
|
|
|
|
zebra_router_release_table(zvrf, otable->table_id,
|
|
|
|
otable->afi, otable->safi);
|
|
|
|
XFREE(MTYPE_OTHER_TABLE, otable);
|
|
|
|
|
|
|
|
otable = otable_pop(&zvrf->other_tables);
|
|
|
|
}
|
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
/* Cleanup EVPN states for vrf */
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_vrf_delete(zvrf);
|
2022-12-09 14:51:34 +01:00
|
|
|
zebra_routemap_vrf_delete(zvrf);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
list_delete_all_node(zvrf->rid_all_sorted_list);
|
|
|
|
list_delete_all_node(zvrf->rid_lo_sorted_list);
|
2019-05-07 01:42:26 +02:00
|
|
|
|
2020-10-20 14:48:12 +02:00
|
|
|
list_delete_all_node(zvrf->rid6_all_sorted_list);
|
|
|
|
list_delete_all_node(zvrf->rid6_lo_sorted_list);
|
|
|
|
|
2019-05-07 01:42:26 +02:00
|
|
|
otable_fini(&zvrf->other_tables);
|
2016-10-31 18:15:16 +01:00
|
|
|
XFREE(MTYPE_ZEBRA_VRF, zvrf);
|
2023-11-13 15:07:06 +01:00
|
|
|
|
|
|
|
if (vrf->ns_ctxt) {
|
|
|
|
ns_delete(vrf->ns_ctxt);
|
|
|
|
vrf->ns_ctxt = NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-30 22:50:26 +01:00
|
|
|
vrf->info = NULL;
|
2016-10-31 18:15:16 +01:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup the routing table in a VRF based on both VRF-Id and table-id.
|
2018-03-28 10:46:14 +02:00
|
|
|
* NOTE: Table-id is relevant on two modes:
|
|
|
|
* - case VRF backend is default : on default VRF only
|
|
|
|
* - case VRF backend is netns : on all VRFs
|
2016-04-14 15:20:47 +02:00
|
|
|
*/
|
2019-11-01 20:52:47 +01:00
|
|
|
struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi,
|
|
|
|
vrf_id_t vrf_id,
|
|
|
|
uint32_t table_id)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
2019-05-07 00:03:39 +02:00
|
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
2019-05-07 01:42:26 +02:00
|
|
|
struct other_route_table ort, *otable;
|
2019-05-07 00:03:39 +02:00
|
|
|
|
|
|
|
if (!zvrf)
|
|
|
|
return NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX)
|
|
|
|
return NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-07 00:03:39 +02:00
|
|
|
if (table_id == zvrf->table_id)
|
|
|
|
return zebra_vrf_table(afi, safi, vrf_id);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-07 01:42:26 +02:00
|
|
|
ort.afi = afi;
|
|
|
|
ort.safi = safi;
|
|
|
|
ort.table_id = table_id;
|
|
|
|
otable = otable_find(&zvrf->other_tables, &ort);
|
2019-11-01 20:52:47 +01:00
|
|
|
|
2019-05-07 01:42:26 +02:00
|
|
|
if (otable)
|
|
|
|
return otable->table;
|
|
|
|
|
2019-11-01 20:52:47 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi,
|
|
|
|
vrf_id_t vrf_id,
|
|
|
|
uint32_t table_id)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
|
|
|
struct other_route_table *otable;
|
|
|
|
struct route_table *table;
|
|
|
|
|
|
|
|
table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id,
|
|
|
|
table_id);
|
|
|
|
|
|
|
|
if (table)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Create it as an `other` table */
|
2019-05-07 01:42:26 +02:00
|
|
|
table = zebra_router_get_table(zvrf, table_id, afi, safi);
|
|
|
|
|
|
|
|
otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable));
|
|
|
|
otable->afi = afi;
|
|
|
|
otable->safi = safi;
|
|
|
|
otable->table_id = table_id;
|
|
|
|
otable->table = table;
|
|
|
|
otable_add(&zvrf->other_tables, otable);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-01 20:52:47 +01:00
|
|
|
done:
|
2016-04-14 15:20:47 +02:00
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
2016-12-05 20:05:30 +01:00
|
|
|
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
|
|
|
struct route_node *node)
|
2016-10-31 18:15:16 +01:00
|
|
|
{
|
|
|
|
if (node->info)
|
|
|
|
zebra_free_rnh(node->info);
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/*
|
|
|
|
* Create a routing table for the specific AFI/SAFI in the given VRF.
|
|
|
|
*/
|
|
|
|
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
|
|
|
|
safi_t safi)
|
|
|
|
{
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
vrf_id_t vrf_id = zvrf->vrf->vrf_id;
|
|
|
|
struct rib_table_info *info;
|
|
|
|
struct route_entry *re;
|
2019-02-06 20:44:44 +01:00
|
|
|
struct route_node *rn;
|
|
|
|
struct prefix p;
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
assert(!zvrf->table[afi][safi]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
/* Attempt to retrieve the Linux routing table using zvrf->table_id.
|
|
|
|
* If the table was created before the VRF, it will already exist.
|
|
|
|
* Otherwise, create a new table.
|
|
|
|
*/
|
2019-01-04 14:36:02 +01:00
|
|
|
zvrf->table[afi][safi] =
|
|
|
|
zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
|
2019-02-06 20:44:44 +01:00
|
|
|
|
zebra: fix table heap-after-free crash
Fix a heap-after-free that causes zebra to crash even without
address-sanitizer. To reproduce:
> echo "100 my_table" | tee -a /etc/iproute2/rt_tables
> ip route add blackhole default table 100
> ip route show table 100
> ip l add red type vrf table 100
> ip l del red
> ip route del blackhole default table 100
Zebra manages routing tables for all existing Linux RT tables,
regardless of whether they are assigned to a VRF interface. When a table
is not assigned to any VRF, zebra arbitrarily assigns it to the default
VRF, even though this is not strictly accurate (the code expects this
behavior).
When an RT table is created after a VRF, zebra correctly assigns the
table to the VRF. However, if a VRF interface is assigned to an existing
RT table, zebra does not update the table owner, which remains as the
default VRF. As a result, existing routing entries remain under the
default VRF, while new entries are correctly assigned to the VRF. The
VRF mismatch is unexpected in the code and creates crashes and memory
related issues.
Furthermore, Linux does not automatically delete RT tables when they are
unassigned from a VRF. It is incorrect to delete these tables from zebra.
Instead, at VRF disabling, do not release the table but reassign it to
the default VRF. At VRF enabling, change the table owner back to the
appropriate VRF.
> ==2866266==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000154f54 at pc 0x7fa32474b83f bp 0x7ffe94f67d90 sp 0x7ffe94f67d88
> READ of size 1 at 0x606000154f54 thread T0
> #0 0x7fa32474b83e in rn_hash_node_const_find lib/table.c:28
> #1 0x7fa32474bab1 in rn_hash_node_find lib/table.c:28
> #2 0x7fa32474d783 in route_node_get lib/table.c:283
> #3 0x7fa3247328dd in srcdest_rnode_get lib/srcdest_table.c:231
> #4 0x55b0e4fa8da4 in rib_find_rn_from_ctx zebra/zebra_rib.c:1957
> #5 0x55b0e4fa8e31 in rib_process_result zebra/zebra_rib.c:1988
> #6 0x55b0e4fb9d64 in rib_process_dplane_results zebra/zebra_rib.c:4894
> #7 0x7fa32476689c in event_call lib/event.c:1996
> #8 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #9 0x55b0e4e6c32a in main zebra/main.c:526
> #10 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
> #11 0x55b0e4e2d649 in _start (/usr/lib/frr/zebra+0x1a1649)
>
> 0x606000154f54 is located 20 bytes inside of 56-byte region [0x606000154f40,0x606000154f78)
> freed by thread T0 here:
> #0 0x7fa324ca9b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123
> #1 0x7fa324668d8f in qfree lib/memory.c:130
> #2 0x7fa32474c421 in route_table_free lib/table.c:126
> #3 0x7fa32474bf96 in route_table_finish lib/table.c:46
> #4 0x55b0e4fbca3a in zebra_router_free_table zebra/zebra_router.c:191
> #5 0x55b0e4fbccea in zebra_router_release_table zebra/zebra_router.c:214
> #6 0x55b0e4fd428e in zebra_vrf_disable zebra/zebra_vrf.c:219
> #7 0x7fa32476fabf in vrf_disable lib/vrf.c:326
> #8 0x7fa32476f5d4 in vrf_delete lib/vrf.c:231
> #9 0x55b0e4e4ad36 in interface_vrf_change zebra/interface.c:1478
> #10 0x55b0e4e4d5d2 in zebra_if_dplane_ifp_handling zebra/interface.c:1949
> #11 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #12 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #13 0x7fa32476689c in event_call lib/event.c:1996
> #14 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #15 0x55b0e4e6c32a in main zebra/main.c:526
> #16 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
>
> previously allocated by thread T0 here:
> #0 0x7fa324caa037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
> #1 0x7fa324668c4d in qcalloc lib/memory.c:105
> #2 0x7fa32474bf33 in route_table_init_with_delegate lib/table.c:38
> #3 0x7fa32474e73c in route_table_init lib/table.c:512
> #4 0x55b0e4fbc353 in zebra_router_get_table zebra/zebra_router.c:137
> #5 0x55b0e4fd4da0 in zebra_vrf_table_create zebra/zebra_vrf.c:358
> #6 0x55b0e4fd3d30 in zebra_vrf_enable zebra/zebra_vrf.c:140
> #7 0x7fa32476f9b2 in vrf_enable lib/vrf.c:286
> #8 0x55b0e4e4af76 in interface_vrf_change zebra/interface.c:1533
> #9 0x55b0e4e4d612 in zebra_if_dplane_ifp_handling zebra/interface.c:1968
> #10 0x55b0e4e4fb89 in zebra_if_dplane_result zebra/interface.c:2268
> #11 0x55b0e4fb9f26 in rib_process_dplane_results zebra/zebra_rib.c:4954
> #12 0x7fa32476689c in event_call lib/event.c:1996
> #13 0x7fa32463b7b2 in frr_run lib/libfrr.c:1232
> #14 0x55b0e4e6c32a in main zebra/main.c:526
> #15 0x7fa32424fd09 in __libc_start_main ../csu/libc-start.c:308
Fixes: d8612e6 ("zebra: Track tables allocated by vrf and cleanup")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2024-11-20 16:33:55 +01:00
|
|
|
/* If the table existed before the VRF was created, info->zvrf was
|
|
|
|
* referring to the default VRF.
|
|
|
|
* Assign the table to the new VRF.
|
|
|
|
* Note: FRR does not allow multiple VRF interfaces to be created with the
|
|
|
|
* same table ID.
|
|
|
|
*/
|
|
|
|
info = route_table_get_info(zvrf->table[afi][safi]);
|
|
|
|
info->zvrf = zvrf;
|
|
|
|
|
|
|
|
/* If the table existed before the VRF was created, their routing entries
|
|
|
|
* was owned by the default VRF.
|
|
|
|
* Re-assign all the routing entries to the new VRF.
|
|
|
|
*/
|
|
|
|
for (rn = route_top(zvrf->table[afi][safi]); rn; rn = route_next(rn)) {
|
|
|
|
if (!rn->info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
RNODE_FOREACH_RE (rn, re)
|
|
|
|
nexthop_vrf_update(rn, re, vrf_id);
|
|
|
|
}
|
|
|
|
|
2019-02-06 20:44:44 +01:00
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
p.family = afi2family(afi);
|
|
|
|
|
2024-08-22 11:29:11 +02:00
|
|
|
/* create a fake default route or get the existing one */
|
2019-02-06 20:44:44 +01:00
|
|
|
rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL);
|
2024-08-22 11:29:11 +02:00
|
|
|
if (!rn->info)
|
|
|
|
/* do not override the existing default route */
|
|
|
|
zebra_rib_create_dest(rn);
|
2016-04-14 15:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate new zebra VRF. */
|
2021-04-26 15:47:39 +02:00
|
|
|
struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-26 15:47:39 +02:00
|
|
|
zvrf->vrf = vrf;
|
|
|
|
vrf->info = zvrf;
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
zebra_vxlan_init_tables(zvrf);
|
2016-04-15 19:51:56 +02:00
|
|
|
zebra_mpls_init_tables(zvrf);
|
2023-12-11 21:22:07 +01:00
|
|
|
zebra_pw_init_vrf(zvrf);
|
2023-08-22 13:27:59 +02:00
|
|
|
zvrf->table_id = rt_table_main_id;
|
2018-03-28 10:46:14 +02:00
|
|
|
/* by default table ID is default one */
|
2023-08-06 19:42:47 +02:00
|
|
|
|
|
|
|
if (DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) {
|
|
|
|
zvrf->zebra_rnh_ip_default_route = true;
|
|
|
|
zvrf->zebra_rnh_ipv6_default_route = true;
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
return zvrf;
|
|
|
|
}
|
|
|
|
|
2023-04-27 05:25:27 +02:00
|
|
|
/*
|
2023-04-27 13:37:58 +02:00
|
|
|
* Pending: create an efficient table_id (in a tree/hash) based lookup)
|
2023-04-27 05:25:27 +02:00
|
|
|
*/
|
|
|
|
vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
|
|
|
|
{
|
|
|
|
struct vrf *vrf;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
|
|
|
zvrf = vrf->info;
|
2024-09-05 15:11:04 +02:00
|
|
|
|
2023-04-27 05:25:27 +02:00
|
|
|
if (zvrf == NULL)
|
|
|
|
continue;
|
|
|
|
/* case vrf with netns : match the netnsid */
|
|
|
|
if (vrf_is_backend_netns()) {
|
|
|
|
if (ns_id == zvrf_id(zvrf))
|
|
|
|
return zvrf_id(zvrf);
|
|
|
|
} else {
|
|
|
|
/* VRF is VRF_BACKEND_VRF_LITE */
|
|
|
|
if (zvrf->table_id != table_id)
|
|
|
|
continue;
|
2024-09-05 15:11:04 +02:00
|
|
|
|
2023-04-27 05:25:27 +02:00
|
|
|
return zvrf_id(zvrf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return VRF_DEFAULT;
|
|
|
|
}
|
|
|
|
|
2024-11-21 21:12:42 +01:00
|
|
|
/*
|
|
|
|
* Lookup tableid by vrfid; handle vrf-lite and vrf-netns cases
|
|
|
|
*/
|
|
|
|
int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
/* Handle vrf-lite and vrf-netns */
|
|
|
|
if (vrf_is_backend_netns())
|
|
|
|
zvrf = vrf_info_lookup(ns_id);
|
|
|
|
else
|
|
|
|
zvrf = vrf_info_lookup(vrf_id);
|
|
|
|
|
|
|
|
if (zvrf)
|
|
|
|
return zvrf->table_id;
|
|
|
|
else
|
|
|
|
return ZEBRA_ROUTE_TABLE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/* Lookup VRF by identifier. */
|
2016-11-02 15:16:58 +01:00
|
|
|
struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id)
|
2016-04-14 15:20:47 +02:00
|
|
|
{
|
|
|
|
return vrf_info_lookup(vrf_id);
|
|
|
|
}
|
|
|
|
|
2016-10-29 02:26:04 +02:00
|
|
|
/* Lookup VRF by name. */
|
2016-10-30 02:44:06 +02:00
|
|
|
struct zebra_vrf *zebra_vrf_lookup_by_name(const char *name)
|
2016-05-04 02:17:29 +02:00
|
|
|
{
|
2016-10-29 02:26:04 +02:00
|
|
|
struct vrf *vrf;
|
2016-05-04 02:17:29 +02:00
|
|
|
|
2016-05-10 14:49:28 +02:00
|
|
|
if (!name)
|
|
|
|
name = VRF_DEFAULT_NAME;
|
|
|
|
|
2016-10-30 02:44:06 +02:00
|
|
|
vrf = vrf_lookup_by_name(name);
|
2016-10-29 02:26:04 +02:00
|
|
|
if (vrf)
|
|
|
|
return ((struct zebra_vrf *)vrf->info);
|
|
|
|
|
2016-05-04 02:17:29 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/* Lookup the routing table in an enabled VRF. */
|
|
|
|
struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
|
|
|
|
|
|
|
|
if (!zvrf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return zvrf->table[afi][safi];
|
|
|
|
}
|
|
|
|
|
2021-10-18 22:34:02 +02:00
|
|
|
/* if ns_id is different and not VRF_UNKNOWN,
|
|
|
|
* then update vrf identifier, and enable VRF
|
|
|
|
*/
|
|
|
|
static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr)
|
|
|
|
{
|
|
|
|
ns_id_t vrf_id = (vrf_id_t)ns_id;
|
|
|
|
vrf_id_t old_vrf_id;
|
|
|
|
struct vrf *vrf = (struct vrf *)opaqueptr;
|
|
|
|
|
|
|
|
if (!vrf)
|
|
|
|
return;
|
|
|
|
old_vrf_id = vrf->vrf_id;
|
|
|
|
if (vrf_id == vrf->vrf_id)
|
|
|
|
return;
|
|
|
|
if (vrf->vrf_id != VRF_UNKNOWN)
|
|
|
|
RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
|
|
|
|
vrf->vrf_id = vrf_id;
|
|
|
|
RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
|
|
|
|
if (old_vrf_id == VRF_UNKNOWN)
|
|
|
|
vrf_enable(vrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
|
|
|
|
char *pathname, ns_id_t ns_id,
|
|
|
|
ns_id_t internal_ns_id,
|
|
|
|
ns_id_t rel_def_ns_id)
|
|
|
|
{
|
|
|
|
struct ns *ns = NULL;
|
|
|
|
|
|
|
|
if (!vrf)
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) {
|
|
|
|
if (vty)
|
|
|
|
vty_out(vty,
|
|
|
|
"VRF %u is already configured with VRF %s\n",
|
|
|
|
vrf->vrf_id, vrf->name);
|
|
|
|
else
|
|
|
|
zlog_info("VRF %u is already configured with VRF %s",
|
|
|
|
vrf->vrf_id, vrf->name);
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
}
|
|
|
|
if (vrf->ns_ctxt != NULL) {
|
|
|
|
ns = (struct ns *)vrf->ns_ctxt;
|
|
|
|
if (!strcmp(ns->name, pathname)) {
|
|
|
|
if (vty)
|
|
|
|
vty_out(vty,
|
|
|
|
"VRF %u already configured with NETNS %s\n",
|
|
|
|
vrf->vrf_id, ns->name);
|
|
|
|
else
|
|
|
|
zlog_info(
|
|
|
|
"VRF %u already configured with NETNS %s",
|
|
|
|
vrf->vrf_id, ns->name);
|
2022-09-07 11:14:02 +02:00
|
|
|
return CMD_WARNING;
|
2021-10-18 22:34:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ns = ns_lookup_name(pathname);
|
|
|
|
if (ns && ns->vrf_ctxt) {
|
|
|
|
struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt;
|
|
|
|
|
|
|
|
if (vrf2 == vrf)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
if (vty)
|
|
|
|
vty_out(vty,
|
|
|
|
"NS %s is already configured with VRF %u(%s)\n",
|
|
|
|
ns->name, vrf2->vrf_id, vrf2->name);
|
|
|
|
else
|
|
|
|
zlog_info("NS %s is already configured with VRF %u(%s)",
|
|
|
|
ns->name, vrf2->vrf_id, vrf2->name);
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
}
|
|
|
|
ns = ns_get_created(ns, pathname, ns_id);
|
|
|
|
ns->internal_ns_id = internal_ns_id;
|
|
|
|
ns->relative_default_ns = rel_def_ns_id;
|
|
|
|
ns->vrf_ctxt = (void *)vrf;
|
|
|
|
vrf->ns_ctxt = (void *)ns;
|
|
|
|
/* update VRF netns NAME */
|
|
|
|
strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
|
|
|
|
|
|
|
|
if (!ns_enable(ns, vrf_update_vrf_id)) {
|
|
|
|
if (vty)
|
|
|
|
vty_out(vty, "Can not associate NS %u with NETNS %s\n",
|
|
|
|
ns->ns_id, ns->name);
|
|
|
|
else
|
|
|
|
zlog_info("Can not associate NS %u with NETNS %s",
|
|
|
|
ns->ns_id, ns->name);
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-04-14 15:20:47 +02:00
|
|
|
/* Zebra VRF initialization. */
|
|
|
|
void zebra_vrf_init(void)
|
|
|
|
{
|
2018-02-05 16:30:21 +01:00
|
|
|
vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable,
|
*: rework renaming the default VRF
Currently, it is possible to rename the default VRF either by passing
`-o` option to zebra or by creating a file in `/var/run/netns` and
binding it to `/proc/self/ns/net`.
In both cases, only zebra knows about the rename and other daemons learn
about it only after they connect to zebra. This is a problem, because
daemons may read their config before they connect to zebra. To handle
this rename after the config is read, we have some special code in every
single daemon, which is not very bad but not desirable in my opinion.
But things are getting worse when we need to handle this in northbound
layer as we have to manually rewrite the config nodes. This approach is
already hacky, but still works as every daemon handles its own NB
structures. But it is completely incompatible with the central
management daemon architecture we are aiming for, as mgmtd doesn't even
have a connection with zebra to learn from it. And it shouldn't have it,
because operational state changes should never affect configuration.
To solve the problem and simplify the code, I propose to expand the `-o`
option to all daemons. By using the startup option, we let daemons know
about the rename before they read their configs so we don't need any
special code to deal with it. There's an easy way to pass the option to
all daemons by using `frr_global_options` variable.
Unfortunately, the second way of renaming by creating a file in
`/var/run/netns` is incompatible with the new mgmtd architecture.
Theoretically, we could force daemons to read their configs only after
they connect to zebra, but it means adding even more code to handle a
very specific use-case. And anyway this won't work for mgmtd as it
doesn't have a connection with zebra. So I had to remove this option.
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
2021-12-03 23:22:55 +01:00
|
|
|
zebra_vrf_delete);
|
2016-04-14 15:20:47 +02:00
|
|
|
|
2021-11-05 00:04:02 +01:00
|
|
|
hook_register(zserv_client_close, release_daemon_table_chunks);
|
2016-04-14 15:20:47 +02:00
|
|
|
}
|