diff options
| author | Michael Biebl <biebl@debian.org> | 2024-08-26 16:10:34 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2024-08-26 16:10:34 +0200 |
| commit | 681dfc70ef98f6ed0c05bcb0fbff00e3fc0799ea (patch) | |
| tree | de71fafaa05ed5aa070324c3b731206150098781 /src/libnm-platform/nm-linux-platform.c | |
| parent | e96d74409128c6a977e31f24fad9b267d2feb9a1 (diff) | |
New upstream version 1.48.10 upstream/1.48.10
Diffstat (limited to 'src/libnm-platform/nm-linux-platform.c')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 172 |
1 files changed, 163 insertions, 9 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index dd4be614..53f678fc 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -187,6 +187,9 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +/* Added in kernel 5.19, dated July 31, 2022 */ +#define IFLA_BOND_SLAVE_PRIO 9 + #define IFLA_BOND_ACTIVE_PORT IFLA_BOND_ACTIVE_SLAVE #define IFLA_BOND_PORT_PRIO IFLA_BOND_SLAVE_PRIO #define IFLA_BOND_ALL_PORTS_ACTIVE IFLA_BOND_ALL_SLAVES_ACTIVE @@ -353,7 +356,8 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ -#define RESYNC_RETRIES 50 +#define RESYNC_RETRIES 50 +#define RESYNC_BACKOFF_SECONDS 1 /*****************************************************************************/ @@ -9402,17 +9406,20 @@ nla_put_failure: } static gboolean -link_set_bridge_vlans(NMPlatform *platform, - int ifindex, - gboolean on_controller, - const NMPlatformBridgeVlan *const *vlans) +link_set_bridge_vlans(NMPlatform *platform, + int ifindex, + gboolean on_controller, + const NMPlatformBridgeVlan *vlans, + guint num_vlans) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *list; struct bridge_vlan_info vinfo = {}; guint i; - nlmsg = _nl_msg_new_link_full(vlans ? RTM_SETLINK : RTM_DELLINK, + nm_assert(num_vlans == 0 || vlans); + + nlmsg = _nl_msg_new_link_full(num_vlans > 0 ? RTM_SETLINK : RTM_DELLINK, 0, ifindex, NULL, @@ -9430,10 +9437,10 @@ link_set_bridge_vlans(NMPlatform *platform, IFLA_BRIDGE_FLAGS, on_controller ? BRIDGE_FLAGS_CONTROLLER : BRIDGE_FLAGS_SELF); - if (vlans) { + if (num_vlans > 0) { /* Add VLANs */ - for (i = 0; vlans[i]; i++) { - const NMPlatformBridgeVlan *vlan = vlans[i]; + for (i = 0; i < num_vlans; i++) { + const NMPlatformBridgeVlan *vlan = &vlans[i]; gboolean is_range = vlan->vid_start != vlan->vid_end; vinfo.vid = vlan->vid_start; @@ -9470,6 +9477,138 @@ nla_put_failure: g_return_val_if_reached(FALSE); } +typedef struct { + int ifindex; + GArray *vlans; +} BridgeVlanData; + +static int +get_bridge_vlans_cb(const struct nl_msg *msg, void *arg) +{ + static const struct nla_policy policy[] = { + [IFLA_AF_SPEC] = {.type = NLA_NESTED}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + gboolean is_range = FALSE; + BridgeVlanData *data = arg; + struct ifinfomsg *ifinfo; + struct nlattr *attr; + int rem; + + if (nlmsg_parse_arr(nlmsg_hdr(msg), sizeof(struct ifinfomsg), tb, policy) < 0) + return NL_SKIP; + + ifinfo = NLMSG_DATA(nlmsg_hdr(msg)); + if (ifinfo->ifi_index != data->ifindex) + return NL_SKIP; + + if (!tb[IFLA_AF_SPEC]) + return NL_SKIP; + + nla_for_each_nested (attr, tb[IFLA_AF_SPEC], rem) { + struct bridge_vlan_info vlan_info; + NMPlatformBridgeVlan vlan = {}; + + if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO) + continue; + + if (!data->vlans) + data->vlans = g_array_new(0, FALSE, sizeof(NMPlatformBridgeVlan)); + + vlan_info = *nla_data_as(struct bridge_vlan_info, attr); + + if (is_range) { + nm_g_array_index(data->vlans, NMPlatformBridgeVlan, data->vlans->len - 1).vid_end = + vlan_info.vid; + is_range = FALSE; + continue; + } else { + vlan.vid_start = vlan_info.vid; + vlan.vid_end = vlan_info.vid; + vlan.untagged = vlan_info.flags & BRIDGE_VLAN_INFO_UNTAGGED; + vlan.pvid = vlan_info.flags & BRIDGE_VLAN_INFO_PVID; + + if (vlan_info.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + is_range = TRUE; + } + + g_array_append_val(data->vlans, vlan); + } + + return NL_OK; +} + +static gboolean +link_get_bridge_vlans(NMPlatform *platform, + int ifindex, + NMPlatformBridgeVlan **out_vlans, + guint *out_num_vlans) +{ + gboolean ret = FALSE; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nl_sock *sk = NULL; + BridgeVlanData data; + int nle; + + nlmsg = _nl_msg_new_link_full(RTM_GETLINK, NLM_F_DUMP, 0, NULL, AF_BRIDGE, 0, 0, 0); + if (!nlmsg) + g_return_val_if_reached(FALSE); + + nle = nl_socket_new(&sk, NETLINK_ROUTE, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, 0, 0); + if (nle < 0) { + _LOGD("get-bridge-vlan: error opening socket: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + NLA_PUT_U32(nlmsg, IFLA_EXT_MASK, RTEXT_FILTER_BRVLAN_COMPRESSED); + + nle = nl_send_auto(sk, nlmsg); + if (nle < 0) { + _LOGD("get-bridge-vlans: failed sending request: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + data = ((BridgeVlanData){ + .ifindex = ifindex, + }); + + do { + nle = nl_recvmsgs(sk, + &((const struct nl_cb){ + .valid_cb = get_bridge_vlans_cb, + .valid_arg = &data, + })); + } while (nle == -EAGAIN); + + if (nle < 0) { + _LOGD("get-bridge-vlan: recv failed: %s (%d)", nm_strerror(nle), nle); + ret = FALSE; + goto err; + } + + if (data.vlans) { + NM_SET_OUT(out_vlans, &nm_g_array_index(data.vlans, NMPlatformBridgeVlan, 0)); + NM_SET_OUT(out_num_vlans, data.vlans->len); + } else { + NM_SET_OUT(out_vlans, NULL); + NM_SET_OUT(out_num_vlans, 0); + } + + if (data.vlans) + g_array_free(data.vlans, !out_vlans); + + ret = TRUE; +err: + if (sk) + nl_socket_free(sk); + return ret; + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + static gboolean link_set_bridge_info(NMPlatform *platform, int ifindex, @@ -10965,6 +11104,20 @@ event_handler_read_netlink(NMPlatform *platform, } _reason; })); + + if (nle == -ENOBUFS) { + /* Netlink notifications are coming faster than what + * we can process them. Backoff a bit so we give some + * time for this burst to finish, and we don't + * contribute to starve the system contending for the + * kernel's RTNL lock. + */ + _LOGI("netlink[%s]: backoff for %d seconds before the resync.", + nmp_netlink_protocol_info(netlink_protocol)->name, + RESYNC_BACKOFF_SECONDS); + sleep(RESYNC_BACKOFF_SECONDS); + } + _netlink_recv_handle(platform, netlink_protocol, FALSE); delayed_action_wait_for_nl_response_complete_all( platform, @@ -11809,6 +11962,7 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->link_set_sriov_params_async = link_set_sriov_params_async; platform_class->link_set_sriov_vfs = link_set_sriov_vfs; platform_class->link_set_bridge_vlans = link_set_bridge_vlans; + platform_class->link_get_bridge_vlans = link_get_bridge_vlans; platform_class->link_set_bridge_info = link_set_bridge_info; platform_class->link_get_physical_port_id = link_get_physical_port_id; |