diff options
| author | Michael Biebl <biebl@debian.org> | 2024-12-25 20:36:29 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2024-12-25 20:36:29 +0100 |
| commit | e465722b908aa870bdc293b9a417d3c15294aa6d (patch) | |
| tree | 7c959d3b73f427d6c40522a7464eaa4531ef2f05 /src/libnm-platform | |
| parent | 56928734cbcf1d3a02fae4f152a541df1b04e04a (diff) | |
New upstream version 1.50.1 upstream/1.50.1
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 123 | ||||
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.h | 3 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 86 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.h | 5 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-base.h | 10 |
5 files changed, 216 insertions, 11 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index bd495fe2..90a34102 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -323,6 +323,10 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); #define IFLA_VF_VLAN_INFO_UNSPEC 0 #define IFLA_VF_VLAN_INFO 1 +/*****************************************************************************/ + +#define NDA_CONTROLLER NDA_MASTER + /* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */ struct _ifla_vf_setting { guint32 vf; @@ -10352,6 +10356,125 @@ link_get_driver_info(NMPlatform *platform, /*****************************************************************************/ +typedef struct { + int ifindexes_len; + int *ifindexes; + GHashTable *out_fdb_addrs; +} FdbData; + +static int +parse_fdb_cb(const struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct ndmsg *ndmsg = NLMSG_DATA(nlh); + int from_ifindex = ndmsg->ndm_ifindex; + bool match = FALSE; + + static const struct nla_policy policy[] = { + [NDA_LLADDR] = {.minlen = ETH_ALEN, .maxlen = ETH_ALEN}, + [NDA_CONTROLLER] = {.type = NLA_U32}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + FdbData *data = arg; + int fdb_controller = -1; + + if (nlmsg_parse_arr(nlh, sizeof(*ndmsg), tb, policy) < 0) + return NL_SKIP; + + if (tb[NDA_CONTROLLER]) + fdb_controller = nla_get_u32(tb[NDA_CONTROLLER]); + + for (int i = 0; i < data->ifindexes_len; i++) { + int current_ifindex = data->ifindexes[i]; + + if (NM_IN_SET(current_ifindex, from_ifindex, fdb_controller)) { + match = TRUE; + break; + } + } + + if (!match) + return NL_SKIP; + + if (tb[NDA_LLADDR]) { + NMEtherAddr *hwaddr = g_new(NMEtherAddr, 1); + memcpy(hwaddr, nla_data(tb[NDA_LLADDR]), ETH_ALEN); + g_hash_table_add(data->out_fdb_addrs, hwaddr); + } + + return NL_OK; +} + +NMEtherAddr ** +nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len) +{ + int nle; + struct nl_sock *sk = NULL; + nm_auto_nlmsg struct nl_msg *msg = NULL; + gs_unref_hashtable GHashTable *fdb_addrs = NULL; + FdbData data; + const struct ndmsg ndm = { + .ndm_family = AF_BRIDGE, + }; + gpointer *ret = NULL; + + nm_assert(ifindexes); + nm_assert(ifindexes_len >= 1); + + fdb_addrs = g_hash_table_new_full((GHashFunc) nm_ether_addr_hash, + (GEqualFunc) nm_ether_addr_equal, + g_free, + NULL); + + msg = nlmsg_alloc_new(0, RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP); + + if (nlmsg_append_struct(msg, &ndm) < 0) + goto err; + + nle = nl_socket_new(&sk, NETLINK_ROUTE, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, 0, 0); + if (nle < 0) { + _LOGD("get-link-fdb: error opening socket: %s (%d)", nm_strerror(nle), nle); + goto err; + } + + nle = nl_send_auto(sk, msg); + if (nle < 0) { + _LOGD("get-link-fdb: failed sending request: %s (%d)", nm_strerror(nle), nle); + goto err; + } + + data = ((FdbData) { + .ifindexes_len = ifindexes_len, + .ifindexes = ifindexes, + .out_fdb_addrs = fdb_addrs, + }); + + do { + nle = nl_recvmsgs(sk, + &((const struct nl_cb) { + .valid_cb = parse_fdb_cb, + .valid_arg = &data, + })); + } while (nle == -EAGAIN); + + if (nle < 0) { + _LOGD("get-link-fdb: recv failed: %s (%d)", nm_strerror(nle), nle); + goto err; + } + + ret = g_hash_table_get_keys_as_array(fdb_addrs, NULL); + g_hash_table_steal_all(fdb_addrs); + nl_socket_free(sk); + return NM_CAST_ALIGN(NMEtherAddr *, ret); + +err: + if (sk) + nl_socket_free(sk); + return NULL; +} + +/*****************************************************************************/ + static gboolean ip4_address_add(NMPlatform *platform, int ifindex, diff --git a/src/libnm-platform/nm-linux-platform.h b/src/libnm-platform/nm-linux-platform.h index 08135a4a..3f591b7f 100644 --- a/src/libnm-platform/nm-linux-platform.h +++ b/src/libnm-platform/nm-linux-platform.h @@ -25,6 +25,9 @@ GType nm_linux_platform_get_type(void); struct _NMDedupMultiIndex; +NMEtherAddr ** +nm_linux_platform_get_link_fdb_table(NMPlatform *platform, int *ifindexes, guint ifindexes_len); + NMPlatform *nm_linux_platform_new(struct _NMDedupMultiIndex *multi_idx, gboolean log_with_ptr, gboolean netns_support, diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index af04f29f..658efadb 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -61,6 +61,8 @@ G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == _NM_UTILS_H G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UTILS_HWADDR_LEN_MAX); G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX); +static int _route_objs_cmp_values(gconstpointer a, gconstpointer b, gpointer user_data); + static const char * _nmp_link_port_data_to_string(NMPortKind port_kind, const NMPlatformLinkPortData *port_data, @@ -4872,11 +4874,24 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, return result; } +static gboolean +_route_obj_find_bsearch(GPtrArray *sorted_routes_objs, const NMPObject *route_obj) +{ + gssize pos = + nm_ptrarray_find_bsearch((gconstpointer *) sorted_routes_objs->pdata, + sorted_routes_objs->len, + route_obj, + _route_objs_cmp_values, + GINT_TO_POINTER((int) NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)); + return pos >= 0; +} + GPtrArray * nm_platform_ip_route_get_prune_list(NMPlatform *self, int addr_family, int ifindex, - NMIPRouteTableSyncMode route_table_sync) + NMIPRouteTableSyncMode route_table_sync, + GPtrArray *sorted_old_routes_objs) { NMPLookup lookup; GPtrArray *routes_prune = NULL; @@ -4890,10 +4905,21 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); 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_EXCEPT_LOCAL, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); + if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES) { + nm_assert(sorted_old_routes_objs); + nm_assert(nm_utils_ptrarray_is_sorted( + (gconstpointer *) sorted_old_routes_objs->pdata, + sorted_old_routes_objs->len, + FALSE, + _route_objs_cmp_values, + GINT_TO_POINTER((int) NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY))); + } + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex); @@ -4915,7 +4941,12 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, 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: + case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES: + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx)) + && !_route_obj_find_bsearch(sorted_old_routes_objs, obj)) + continue; + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) continue; break; @@ -5284,7 +5315,8 @@ 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_PRUNE); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, + NULL); success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); } if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { @@ -5293,7 +5325,8 @@ 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_PRUNE); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, + NULL); success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); } return success; @@ -6533,9 +6566,9 @@ nm_platform_lnk_infiniband_to_string(const NMPlatformLnkInfiniband *lnk, char *b const char * nm_platform_lnk_ip6tnl_to_string(const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len) { - char str_local[30]; + char str_local[30 + NM_INET_ADDRSTRLEN]; char str_local1[NM_INET_ADDRSTRLEN]; - char str_remote[30]; + char str_remote[30 + NM_INET_ADDRSTRLEN]; char str_remote1[NM_INET_ADDRSTRLEN]; char str_ttl[30]; char str_tclass[30]; @@ -8767,6 +8800,45 @@ nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformL return 0; } +static int +_route_objs_cmp_values(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const NMPObject *a_obj = a; + const NMPObject *b_obj = b; + NMPlatformIPRouteCmpType cmp_type = GPOINTER_TO_INT(user_data); + + nm_assert(a_obj && b_obj); + nm_assert(NMP_OBJECT_CAST_IP_ROUTE(a_obj) && NMP_OBJECT_CAST_IP_ROUTE(b_obj)); + + if (NMP_OBJECT_GET_ADDR_FAMILY(a_obj) != NMP_OBJECT_GET_ADDR_FAMILY(b_obj)) { + return NMP_OBJECT_GET_ADDR_FAMILY(a_obj) == AF_INET ? 1 : -1; + } else if (NMP_OBJECT_GET_ADDR_FAMILY(a_obj) == AF_INET) { + return nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(a_obj), + NMP_OBJECT_CAST_IP4_ROUTE(b_obj), + cmp_type); + } else { + return nm_platform_ip6_route_cmp(NMP_OBJECT_CAST_IP6_ROUTE(a_obj), + NMP_OBJECT_CAST_IP6_ROUTE(b_obj), + cmp_type); + } +} + +static int +_route_objs_cmp(gconstpointer a, gconstpointer b, gpointer user_data) +{ + nm_assert(a && b); + + return _route_objs_cmp_values(*((const NMPObject **) a), *((const NMPObject **) b), user_data); +} + +void +nm_platform_route_objs_sort(GPtrArray *routes_objs, NMPlatformIPRouteCmpType cmp_type) +{ + nm_assert(routes_objs); + + g_ptr_array_sort_with_data(routes_objs, _route_objs_cmp, GINT_TO_POINTER((int) cmp_type)); +} + void nm_platform_ip4_rt_nexthop_hash_update(const NMPlatformIP4RtNextHop *obj, gboolean for_id, diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index e33be813..22bf0fdb 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2389,7 +2389,8 @@ int nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatf GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform *self, int addr_family, int ifindex, - NMIPRouteTableSyncMode route_table_sync); + NMIPRouteTableSyncMode route_table_sync, + GPtrArray *old_routes_objs); gboolean nm_platform_ip_route_sync(NMPlatform *self, int addr_family, @@ -2495,6 +2496,8 @@ int nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatf GHashTable *nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex); +void nm_platform_route_objs_sort(GPtrArray *routes_objs, NMPlatformIPRouteCmpType cmp_type); + int nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, NMPlatformIPRouteCmpType cmp_type); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index c7d487e2..3784a78e 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -211,8 +211,11 @@ nmp_object_type_to_flags(NMPObjectType obj_type) * @NM_IP_ROUTE_TABLE_SYNC_MODE_NONE: indicate an invalid setting. * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all * other tables, NM won't delete any extra routes. - * @NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: NM will sync all tables, except the - * local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES: only the main table is synced, + * plus individual routes in other tables added by NM, leaving routes that + * were not added by NM untouched. + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: NM will sync all tables, except + * the 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 @@ -222,7 +225,8 @@ nmp_object_type_to_flags(NMPObjectType obj_type) typedef enum { 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_MAIN_AND_NM_ROUTES, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, } NMIPRouteTableSyncMode; |