From 5da8c073efd67f12292c1c5c67ada64b9c9f5a6c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Mar 2021 17:48:43 +0100 Subject: [PATCH 1/6] core: avoid logging pointer value in nm_device_set_ip_config() --- src/core/devices/nm-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 9d44757c08..421a219023 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -13496,10 +13496,10 @@ nm_device_set_ip_config(NMDevice * self, nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: update (commit=%d, new-config=%p)", + "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT")", nm_utils_addr_family_to_char(addr_family), commit, - new_config); + NM_HASH_OBFUSCATE_PTR(new_config)); /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { From f6db2c6261b560ec34b56eeeb3766c9165f5619b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Mar 2021 17:56:37 +0100 Subject: [PATCH 2/6] core: log route-table-sync-mode in nm_device_set_ip_config() --- src/core/devices/nm-device.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 421a219023..8b976227cc 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -13478,12 +13478,13 @@ nm_device_set_ip_config(NMDevice * self, gboolean commit, GPtrArray * ip4_dev_route_blacklist) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMIPConfig * old_config; - gboolean has_changes = FALSE; - gboolean success = TRUE; - NMSettingsConnection *settings_connection; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMIPConfig * old_config; + gboolean has_changes = FALSE; + gboolean success = TRUE; + NMSettingsConnection * settings_connection; + NMIPRouteTableSyncMode route_table_sync_mode; nm_assert_addr_family(addr_family); nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family); @@ -13495,11 +13496,18 @@ nm_device_set_ip_config(NMDevice * self, }))); nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); + if (commit && new_config) + route_table_sync_mode = _get_route_table_sync_mode_stateful(self, addr_family); + else + route_table_sync_mode = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE; + _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT")", + "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT + ", route-table-sync-mode=%d)", nm_utils_addr_family_to_char(addr_family), commit, - NM_HASH_OBFUSCATE_PTR(new_config)); + NM_HASH_OBFUSCATE_PTR(new_config), + (int) route_table_sync_mode); /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { @@ -13508,7 +13516,7 @@ nm_device_set_ip_config(NMDevice * self, if (IS_IPv4) { success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET)); + route_table_sync_mode); nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), nm_ip_config_get_ifindex(new_config), ip4_dev_route_blacklist); @@ -13517,7 +13525,7 @@ nm_device_set_ip_config(NMDevice * self, success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET6), + route_table_sync_mode, &temporary_not_available); if (!_rt6_temporary_not_available_set(self, temporary_not_available)) From e226b5eb829e5e8c623948e35d406e815cd05089 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Mar 2021 17:31:35 +0100 Subject: [PATCH 3/6] core: add NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE mode When we deactivate a device, we flush all IP addresses and routes. Thus, have yet another sync mode for that. It will sync more than "ALL". --- src/libnm-platform/nm-platform.c | 29 +++++++++++++++++++---------- src/libnm-platform/nmp-base.h | 12 ++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index fd5820cce9..06b7af8d77 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -4318,7 +4318,8 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, nm_assert(NM_IN_SET(route_table_sync, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL)); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex); head_entry = nm_platform_lookup(self, &lookup); @@ -4330,16 +4331,24 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, c_list_for_each (iter, &head_entry->lst_entries_head) { const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; - if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) { - if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) - == RT_TABLE_LOCAL) - continue; - } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) { + switch (route_table_sync) { + case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: if (!nm_platform_route_table_is_main( nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)))) continue; - } else - nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: + if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) + == RT_TABLE_LOCAL) + continue; + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: + break; + default: + nm_assert_not_reached(); + break; + } g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj)); } @@ -4634,7 +4643,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) routes_prune = nm_platform_ip_route_get_prune_list(self, AF_INET, ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); } if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { @@ -4643,7 +4652,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) routes_prune = nm_platform_ip_route_get_prune_list(self, AF_INET6, ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); } return success; diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 8a53f97c1d..f7dc63747e 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -168,12 +168,16 @@ nmp_object_type_to_flags(NMPObjectType obj_type) * local table (255). * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the * local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: NM will sync all tables (including + * the local table). It will thereby remove all addresses, that is during + * deactivation. */ typedef enum { - NM_IP_ROUTE_TABLE_SYNC_MODE_NONE = 0, - NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 1, - NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 2, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL = 3, + NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, } NMIPRouteTableSyncMode; #endif /* __NMP_FWD_H__ */ From c29d995000a147cecbe1dbaa9607936c1844ba10 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Mar 2021 21:43:47 +0100 Subject: [PATCH 4/6] core: don't add ff00::/8 unicast route to nm_ip6_config_add_dependent_routes() This effectively reverts commit cd89026c5f4f ('core: add dependent multicast route configured by kernel for IPv6'). It's not clear to me why this was done or why it would be correct. True, kernel automatically adds multicast route like multicast ff00::/8 dev $IFACE table local proto kernel metric 256 pref medium But NetworkManager ignores all multicast routes for now. So the dependent routes cannot contain multicast routes as they are not handled. Also, the code added a unicast route, so I don't understand why the comment is talking about multicast. This seems just wrong. Drop it. --- src/core/nm-ip6-config.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index a5a885f44f..5c33f2ba3c 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -396,23 +396,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, * * For manually added IPv6 routes, add the device routes explicitly. */ - /* Pre-generate multicast route */ - { - nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP6Route * route; - - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network.s6_addr[0] = 0xffu; - route->plen = 8; - route->table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL); - route->type_coerced = nm_platform_route_type_coerce(RTN_UNICAST); - route->metric = 256; - - _add_route(self, r, NULL, NULL); - } - nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { NMPlatformIP6Route *route; gboolean has_peer; From fe1bf4c907c29997cbc6a28bc0781bfc419cb07f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Mar 2021 10:05:30 +0100 Subject: [PATCH 5/6] core: minor cleanup in nm_platform_ip_route_get_prune_list() --- src/libnm-platform/nm-platform.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 06b7af8d77..e3f8be9cc7 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -4329,22 +4329,22 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPObject * obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPlatformIPXRoute *rt = NMP_OBJECT_CAST_IPX_ROUTE(obj); switch (route_table_sync) { case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: - if (!nm_platform_route_table_is_main( - nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)))) + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx))) continue; break; case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: - if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) - == RT_TABLE_LOCAL) + if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) continue; break; case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: break; + default: nm_assert_not_reached(); break; From 557644f5e03a77b3ebe09ceba672217959cf3bdc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Mar 2021 21:20:52 +0100 Subject: [PATCH 6/6] core: don't add dependent local route for addresses When adding an IPv4 address, kernel automatically adds a local route. This is done by fib_add_ifaddr(). Note that if the address is IFA_F_SECONDARY, then the "src" is the primary address. That means, with nmcli connection add con-name t type ethernet ifname t autoconnect no \ ipv4.method manual ipv6.method disabled \ ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' we get two routes: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10" Our code would only generate instead: "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10" "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11" Afterwards, this artificial route will be leaked: #!/bin/bash set -vx nmcli connection delete t || : ip link delete t || : ip link add name t type veth peer t-veth nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled nmcli connection up t ip route show table all dev t | grep --color '^\|192.168.77.11' sleep 1 nmcli device modify t -ipv4.addresses 192.168.77.11/24 ip route show table all dev t | grep --color '^\|192.168.77.11' ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src" It will also be leaked because in the example above ipv4.route-table is unset, so we are not in full route sync mode and the local table is not synced. This was introduced by commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'), but it's unclear to me why we really need this. Drop it again and effectively revert commit 3e5fc04df320 ('core: add dependent local routes configured by kernel'). I think this "solution" is still bad. We need to improve our route sync approach with L3Cfg rework. For now, it's probably good enough. https://bugzilla.redhat.com/show_bug.cgi?id=1907661 --- src/core/nm-ip4-config.c | 15 ------ src/core/nm-ip6-config.c | 16 ------ src/libnm-platform/nm-platform.c | 91 ++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 31 deletions(-) diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c index e2e4251fe3..9f8238841f 100644 --- a/src/core/nm-ip4-config.c +++ b/src/core/nm-ip4-config.c @@ -649,21 +649,6 @@ nm_ip4_config_add_dependent_routes(NMIP4Config *self, if (my_addr->external) continue; - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP4_ROUTE(r); - route->ifindex = ifindex; - route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; - route->network = my_addr->address; - route->plen = 32; - route->pref_src = my_addr->address; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST); - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - nm_clear_pointer(&r, nmp_object_unref); - if (nm_utils_ip4_address_is_zeronet(network)) { /* Kernel doesn't add device-routes for destinations that * start with 0.x.y.z. Skip them. */ diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index 5c33f2ba3c..155594c8fc 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -404,22 +404,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, if (my_addr->external) continue; - { - nm_auto_nmpobj NMPObject *r = NULL; - - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network = my_addr->address; - route->plen = 128; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->metric = 0; - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - } - if (NM_FLAGS_HAS(my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; if (my_addr->plen == 0) diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index e3f8be9cc7..9eee50fdbe 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -4312,6 +4312,11 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, GPtrArray * routes_prune; const NMDedupMultiHeadEntry *head_entry; CList * iter; + NMPlatformIP4Route rt_local4; + NMPlatformIP6Route rt_local6; + const NMPlatformLink * pllink; + const NMPlatformLnkVrf * lnk_vrf; + guint32 local_table; nm_assert(NM_IS_PLATFORM(self)); nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); @@ -4326,6 +4331,14 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, if (!head_entry) return NULL; + lnk_vrf = nm_platform_link_get_lnk_vrf(self, ifindex, &pllink); + if (!lnk_vrf && pllink && pllink->master > 0) + lnk_vrf = nm_platform_link_get_lnk_vrf(self, pllink->master, NULL); + local_table = lnk_vrf ? lnk_vrf->table : RT_TABLE_LOCAL; + + rt_local4.plen = 0; + rt_local6.plen = 0; + routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); c_list_for_each (iter, &head_entry->lst_entries_head) { @@ -4342,6 +4355,84 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, continue; break; case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: + + /* FIXME: we should better handle routes that are automatically added by kernel. + * + * For now, make a good guess which are those routes and exclude them from + * pruning them. */ + + if (NM_IS_IPv4(addr_family)) { + /* for each IPv4 address kernel adds a route like + * + * local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR + * + * Check whether route could be of that kind. */ + if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table + && rt->rx.plen == 32 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + && rt->rx.metric == 0 + && rt->r4.scope_inv == nm_platform_route_scope_inv(RT_SCOPE_HOST) + && rt->r4.gateway == INADDR_ANY) { + if (rt_local4.plen == 0) { + rt_local4 = (NMPlatformIP4Route){ + .ifindex = ifindex, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, + .metric = 0, + .table_coerced = nm_platform_route_table_coerce(local_table), + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .gateway = INADDR_ANY, + }; + } + + /* the possible "network" depends on the addresses we have. We don't check that + * carefully. If the other parameters match, we assume that this route is the one + * generated by kernel. */ + rt_local4.network = rt->r4.network; + rt_local4.pref_src = rt->r4.pref_src; + + /* to be more confident about comparing the value, use our nm_platform_ip4_route_cmp() + * implementation. That will also consider parameters that we leave unspecified here. */ + if (nm_platform_ip4_route_cmp(&rt->r4, + &rt_local4, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) + continue; + } + } else { + /* for each IPv6 address (that is no longer tentative) kernel adds a route like + * + * local $ADDR dev $IFACE table local proto kernel metric 0 pref medium + * + * Same as for the IPv4 case. */ + if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table + && rt->rx.plen == 128 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + && rt->rx.metric == 0 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM + && IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) { + if (rt_local6.plen == 0) { + rt_local6 = (NMPlatformIP6Route){ + .ifindex = ifindex, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .plen = 128, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, + .metric = 0, + .table_coerced = nm_platform_route_table_coerce(local_table), + .rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM, + .gateway = IN6ADDR_ANY_INIT, + }; + } + + rt_local6.network = rt->r6.network; + + if (nm_platform_ip6_route_cmp(&rt->r6, + &rt_local6, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) + continue; + } + } + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: break;