diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 596 | ||||
| -rw-r--r-- | src/libnm-platform/nm-netlink.c | 94 | ||||
| -rw-r--r-- | src/libnm-platform/nm-netlink.h | 63 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.c | 35 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.h | 3 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 482 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.h | 201 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-base.h | 15 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-global-tracker.c | 7 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-object.c | 20 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-object.h | 15 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-plobj.c | 4 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-plobj.h | 3 | ||||
| -rw-r--r-- | src/libnm-platform/tests/test-nm-platform.c | 1 |
14 files changed, 879 insertions, 660 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 484087b9..99eab9c7 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -115,7 +115,9 @@ typedef enum _nm_packed { #define IFLA_CARRIER 33 #define IFLA_PHYS_PORT_ID 34 #define IFLA_LINK_NETNSID 37 -#define __IFLA_MAX 39 +#define IFLA_GSO_MAX_SEGS 40 +#define IFLA_GSO_MAX_SIZE 41 +#define IFLA_GRO_MAX_SIZE 58 #define IFLA_INET6_TOKEN 7 #define IFLA_INET6_ADDR_GEN_MODE 8 @@ -180,6 +182,9 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); #define IFLA_BOND_SLAVE_PRIO 9 #define IFLA_BOND_PEER_NOTIF_DELAY 28 +#define IFLA_BOND_AD_LACP_ACTIVE 29 +#define IFLA_BOND_MISSED_MAX 30 +#define IFLA_BOND_NS_IP6_TARGET 31 #undef IFLA_BOND_MAX @@ -325,6 +330,10 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ +#define RESYNC_RETRIES 50 + +/*****************************************************************************/ + typedef struct { guint16 family_id; } GenlFamilyData; @@ -452,7 +461,14 @@ typedef enum _nm_packed { WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN, + + /* The receive buffer of the netlink socket has a large, but limited size. + * It can fill up, and we lose messages. When that happens, we may lose a + * response that we were waiting for. This error number indicates that we + * don't know the response due to a resync. We probably should retry the + * request. */ WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING, @@ -467,7 +483,7 @@ typedef enum _nm_packed { typedef struct { WaitForNlResponseResult *out_seq_result; - char **out_errmsg; + char **out_extack_msg; union { int *out_refresh_all_in_progress; NMPObject **out_route_get; @@ -484,9 +500,6 @@ typedef struct { typedef struct { guint32 nlh_seq_next; guint32 nlh_seq_last_seen; -#if NM_MORE_LOGGING - guint32 nlh_seq_last_handled; -#endif } NetlinkProtocolPrivData; typedef struct { @@ -711,7 +724,7 @@ wait_for_nl_response_to_nmerr(WaitForNlResponseResult seq_result) static const char * wait_for_nl_response_to_string(WaitForNlResponseResult seq_result, - const char *errmsg, + const char *extack_msg, char *buf, gsize buf_size) { @@ -737,8 +750,8 @@ wait_for_nl_response_to_string(WaitForNlResponseResult seq_result, "failure %d (%s%s%s)", -((int) seq_result), nm_strerror_native(-((int) seq_result)), - errmsg ? " - " : "", - errmsg ?: ""); + extack_msg ? " - " : "", + extack_msg ?: ""); } else nm_strbuf_append(&buf, &buf_size, "internal failure %d", (int) seq_result); break; @@ -1609,6 +1622,9 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) [IFLA_BOND_AD_ACTOR_SYSTEM] = {.minlen = sizeof(NMEtherAddr)}, [IFLA_BOND_TLB_DYNAMIC_LB] = {.type = NLA_U8}, [IFLA_BOND_PEER_NOTIF_DELAY] = {.type = NLA_U32}, + [IFLA_BOND_MISSED_MAX] = {.type = NLA_U8}, + [IFLA_BOND_AD_LACP_ACTIVE] = {.type = NLA_U8}, + [IFLA_BOND_NS_IP6_TARGET] = {.type = NLA_NESTED}, }; NMPlatformLnkBond *props; struct nlattr *tb[G_N_ELEMENTS(policy)]; @@ -1663,6 +1679,19 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) props->arp_ip_target[props->arp_ip_targets_num++] = nla_get_u32(attr); } } + if (tb[IFLA_BOND_NS_IP6_TARGET]) { + struct nlattr *attr; + int rem; + + nla_for_each_nested (attr, tb[IFLA_BOND_NS_IP6_TARGET], rem) { + if (props->ns_ip6_targets_num > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (nla_len(attr) < sizeof(struct in6_addr)) + break; + + props->ns_ip6_target[props->ns_ip6_targets_num++] = nla_get_in6_addr(attr); + } + } if (tb[IFLA_BOND_ARP_VALIDATE]) props->arp_validate = nla_get_u32(tb[IFLA_BOND_ARP_VALIDATE]); if (tb[IFLA_BOND_ARP_ALL_TARGETS]) @@ -1683,6 +1712,8 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) props->num_grat_arp = nla_get_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]); if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE]) props->all_ports_active = nla_get_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]); + if (tb[IFLA_BOND_MISSED_MAX]) + props->arp_missed_max = nla_get_u8(tb[IFLA_BOND_MISSED_MAX]); if (tb[IFLA_BOND_MIN_LINKS]) props->min_links = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]); if (tb[IFLA_BOND_LP_INTERVAL]) @@ -1691,6 +1722,10 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) props->packets_per_port = nla_get_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]); if (tb[IFLA_BOND_AD_LACP_RATE]) props->lacp_rate = nla_get_u8(tb[IFLA_BOND_AD_LACP_RATE]); + if (tb[IFLA_BOND_AD_LACP_ACTIVE]) { + props->lacp_active = nla_get_u8(tb[IFLA_BOND_AD_LACP_ACTIVE]); + props->lacp_active_has = TRUE; + } if (tb[IFLA_BOND_AD_SELECT]) props->ad_select = nla_get_u8(tb[IFLA_BOND_AD_SELECT]); if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) @@ -3265,6 +3300,9 @@ _new_from_nl_link(NMPlatform *platform, [IFLA_IFNAME] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, [IFLA_MTU] = {.type = NLA_U32}, [IFLA_TXQLEN] = {.type = NLA_U32}, + [IFLA_GSO_MAX_SIZE] = {.type = NLA_U32}, + [IFLA_GSO_MAX_SEGS] = {.type = NLA_U32}, + [IFLA_GRO_MAX_SIZE] = {.type = NLA_U32}, [IFLA_LINK] = {.type = NLA_U32}, [IFLA_WEIGHT] = {.type = NLA_U32}, [IFLA_MASTER] = {.type = NLA_U32}, @@ -3409,6 +3447,15 @@ _new_from_nl_link(NMPlatform *platform, } } + if (tb[IFLA_TXQLEN]) + obj->link.link_props.tx_queue_length = nla_get_u32(tb[IFLA_TXQLEN]); + if (tb[IFLA_GSO_MAX_SIZE]) + obj->link.link_props.gso_max_size = nla_get_u32(tb[IFLA_GSO_MAX_SIZE]); + if (tb[IFLA_GSO_MAX_SEGS]) + obj->link.link_props.gso_max_segments = nla_get_u32(tb[IFLA_GSO_MAX_SEGS]); + if (tb[IFLA_GRO_MAX_SIZE]) + obj->link.link_props.gro_max_size = nla_get_u32(tb[IFLA_GRO_MAX_SIZE]); + if (tb[IFLA_STATS64]) { const char *stats = nla_data(tb[IFLA_STATS64]); @@ -4568,15 +4615,15 @@ _new_from_nl_tfilter(NMPlatform *platform, const struct nlmsghdr *nlh, gboolean /** * nmp_object_new_from_nl: - * @platform: (allow-none): for creating certain objects, the constructor wants to check + * @platform: (nullable): for creating certain objects, the constructor wants to check * sysfs. For this the platform instance is needed. If missing, the object might not * be correctly detected. - * @cache: (allow-none): for certain objects, the netlink message doesn't contain all the information. + * @cache: (nullable): for certain objects, the netlink message doesn't contain all the information. * If a cache is given, the object is completed with information from the cache. * @nlh: the netlink message header * @id_only: whether only to create an empty object with only the ID fields set. * - * Returns: %NULL or a newly created NMPObject instance. + * Returns: (nullable): %NULL or a newly created NMPObject instance. **/ static NMPObject * nmp_object_new_from_nl(NMPlatform *platform, @@ -4735,6 +4782,17 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo nla_nest_end(msg, targets); } + if (props->ns_ip6_targets_num > 0) { + targets = nla_nest_start(msg, IFLA_BOND_NS_IP6_TARGET); + if (!targets) + goto nla_put_failure; + + for (i = 0; i < props->ns_ip6_targets_num; i++) + NLA_PUT(msg, i, sizeof(struct in6_addr), &props->ns_ip6_target[i]); + + nla_nest_end(msg, targets); + } + if (props->arp_all_targets) NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets); if (props->arp_interval) @@ -4770,6 +4828,8 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo &props->ad_actor_system); if (props->ad_select) NLA_PUT_U8(msg, IFLA_BOND_AD_SELECT, props->ad_select); + if (props->arp_missed_max) + NLA_PUT_U8(msg, IFLA_BOND_MISSED_MAX, props->arp_missed_max); NLA_PUT_U8(msg, IFLA_BOND_ALL_SLAVES_ACTIVE, props->all_ports_active); @@ -4777,6 +4837,8 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo NLA_PUT_U8(msg, IFLA_BOND_FAIL_OVER_MAC, props->fail_over_mac); if (props->lacp_rate) NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_RATE, props->lacp_rate); + if (props->lacp_active_has) + NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_ACTIVE, props->lacp_active); if (props->num_grat_arp) NLA_PUT_U8(msg, IFLA_BOND_NUM_PEER_NOTIF, props->num_grat_arp); @@ -6690,7 +6752,7 @@ delayed_action_wait_for_response_complete(NMPlatform *platform, nm_assert(NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)); nm_assert(idx < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); data = delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, idx); @@ -7041,7 +7103,7 @@ delayed_action_schedule_WAIT_FOR_RESPONSE(NMPlatform *pla NMPNetlinkProtocol netlink_protocol, guint32 seq_number, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, + char **out_extack_msg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -7050,11 +7112,13 @@ delayed_action_schedule_WAIT_FOR_RESPONSE(NMPlatform *pla .timeout_abs_nsec = nm_utils_get_monotonic_timestamp_nsec() + (200 * (NM_UTILS_NSEC_PER_SEC / 1000)), .out_seq_result = out_seq_result, - .out_errmsg = out_errmsg, + .out_extack_msg = out_extack_msg, .response_type = response_type, .response.out_data = response_out_data, }; + nm_assert(!out_seq_result || *out_seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + delayed_action_schedule( platform, nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response, @@ -7409,7 +7473,7 @@ static int _nl_send_nlmsghdr(NMPlatform *platform, struct nlmsghdr *nlhdr, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, + char **out_extack_msg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -7419,6 +7483,8 @@ _nl_send_nlmsghdr(NMPlatform *platform, nm_assert(nlhdr); + nm_assert(out_seq_result && *out_seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + seq = _nlh_seq_next_get(priv, NMP_NETLINK_ROUTE); nlhdr->nlmsg_seq = seq; @@ -7446,7 +7512,7 @@ again: errsv = errno; if (errsv == EINTR && try_count++ < 100) goto again; - _LOGD("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", + _LOGI("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", nm_strerror_native(errsv), errsv); return -nm_errno_from_native(errsv); @@ -7457,7 +7523,7 @@ again: NMP_NETLINK_ROUTE, seq, out_seq_result, - out_errmsg, + out_extack_msg, response_type, response_out_data); return 0; @@ -7468,7 +7534,7 @@ _netlink_send_nlmsg(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol, struct nl_msg *nlmsg, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, + char **out_extack_msg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -7477,13 +7543,15 @@ _netlink_send_nlmsg(NMPlatform *platform, guint32 seq; int nle; + nm_assert(!out_seq_result || *out_seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + nlhdr = nlmsg_hdr(nlmsg); seq = _nlh_seq_next_get(priv, netlink_protocol); nlhdr->nlmsg_seq = seq; nle = nl_send_auto(priv->sk_x[netlink_protocol], nlmsg); if (nle < 0) { - _LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); + _LOGI("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); return nle; } @@ -7491,7 +7559,7 @@ _netlink_send_nlmsg(NMPlatform *platform, netlink_protocol, seq, out_seq_result, - out_errmsg, + out_extack_msg, response_type, response_out_data); return 0; @@ -7501,13 +7569,13 @@ static int _netlink_send_nlmsg_rtnl(NMPlatform *platform, struct nl_msg *nlmsg, WaitForNlResponseResult *out_seq_result, - char **out_errmsg) + char **out_extack_msg) { return _netlink_send_nlmsg(platform, NMP_NETLINK_ROUTE, nlmsg, out_seq_result, - out_errmsg, + out_extack_msg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); } @@ -7778,7 +7846,7 @@ event_seq_check(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol, guint32 seq_number, WaitForNlResponseResult seq_result, - const char *msg) + const char *extack_msg) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); guint i; @@ -7789,7 +7857,7 @@ event_seq_check(NMPlatform *platform, if (!NM_FLAGS_ANY( priv->delayed_action.flags, nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) - goto out; + return; nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); @@ -7797,30 +7865,23 @@ event_seq_check(NMPlatform *platform, DelayedActionWaitForNlResponseData *data = delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); - if (data->seq_number == seq_number) { - /* We potentially receive many parts partial responses for the same sequence number. - * Thus, we only remember the result, and collect it later. */ - if (data->seq_result < 0) { - /* we already saw an error for this sequence number. - * Preserve it. */ - } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN - || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - data->seq_result = seq_result; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup(msg); - return; - } - } + if (data->seq_number != seq_number) + continue; -out: + /* We potentially receive many parts partial responses for the same sequence number. + * Thus, we only remember the result, and collect it later. */ + if (data->seq_result < 0) { + /* we already saw an error for this sequence number. + * Preserve it. */ + } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN + || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) + data->seq_result = seq_result; -#if NM_MORE_LOGGING - if (seq_number != priv->proto_data_x[netlink_protocol].nlh_seq_last_handled) - _LOGt("netlink: recvmsg: unwaited sequence number %u", seq_number); - priv->proto_data_x[netlink_protocol].nlh_seq_last_handled = seq_number; -#else - (void) 0; -#endif + if (extack_msg && data->out_extack_msg && !*data->out_extack_msg) + *data->out_extack_msg = g_strdup(extack_msg); + + return; + } } static void @@ -8056,35 +8117,41 @@ do_add_link_with_lookup(NMPlatform *platform, struct nl_msg *nlmsg, const NMPlatformLink **out_link) { - const NMPObject *obj = NULL; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + const NMPObject *obj = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; - NMPCache *cache = nm_platform_get_cache(platform); + NMPCache *cache = nm_platform_get_cache(platform); + int try_count = 0; event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", - name, - nm_link_type_to_string(link_type), - nm_strerror(nle), - -nle); - NM_SET_OUT(out_link, NULL); - return nle; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", + name, + nm_link_type_to_string(link_type), + nm_strerror(nle), + -nle); + NM_SET_OUT(out_link, NULL); + return nle; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-link[%s/%s]: %s", - name, - nm_link_type_to_string(link_type), - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, + "do-add-link[%s/%s]: %s", + name, + nm_link_type_to_string(link_type), + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); + + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); if (out_link) { obj = nmp_cache_lookup_link_full(cache, 0, name, FALSE, link_type, NULL, NULL); @@ -8098,14 +8165,17 @@ static int do_add_addrroute(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg, - gboolean suppress_netlink_failure) + gboolean suppress_netlink_failure, + char **out_extack_msg) { char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; + int try_count = 0; + nm_assert(!out_extack_msg || !*out_extack_msg); nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, @@ -8114,28 +8184,34 @@ do_add_addrroute(NMPlatform *platform, event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", - NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, - nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), - nm_strerror(nle), - -nle); - return -NME_PL_NETLINK; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", + NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, + nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), + nm_strerror(nle), + -nle); + NM_SET_OUT(out_extack_msg, g_steal_pointer(&extack_msg)); + return -NME_PL_NETLINK; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); + + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); - nm_assert(seq_result); + _NMLOG((seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + || (suppress_netlink_failure && seq_result < 0)) + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-%s[%s]: %s", + NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, + nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); - _NMLOG((seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK - || (suppress_netlink_failure && seq_result < 0)) - ? LOGL_DEBUG - : LOGL_WARN, - "do-add-%s[%s]: %s", - NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, - nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); if (NMP_OBJECT_GET_TYPE(obj_id) == NMP_OBJECT_TYPE_IP6_ADDRESS) { /* In rare cases, the object is not yet ready as we received the ACK from @@ -8149,6 +8225,7 @@ do_add_addrroute(NMPlatform *platform, do_request_one_type_by_needle_object(platform, obj_id); } + NM_SET_OUT(out_extack_msg, g_steal_pointer(&extack_msg)); return wait_for_nl_response_to_nmerr(seq_result); } @@ -8156,54 +8233,60 @@ static gboolean do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) { char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; gboolean success; const char *log_detail = ""; + int try_count = 0; event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", - NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, - nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), - nm_strerror(nle), - -nle); - return FALSE; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", + NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, + nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), + nm_strerror(nle), + -nle); + return FALSE; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + + success = TRUE; + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { + /* ok */ + } else if (NM_IN_SET(-((int) seq_result), ESRCH, ENOENT)) + log_detail = ", meaning the object was already removed"; + else if (NM_IN_SET(-((int) seq_result), ENXIO) + && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS)) { + /* On RHEL7 kernel, deleting a non existing address fails with ENXIO */ + log_detail = ", meaning the address was already removed"; + } else if (NM_IN_SET(-((int) seq_result), ENODEV)) { + log_detail = ", meaning the device was already removed"; + } else if (NM_IN_SET(-((int) seq_result), EADDRNOTAVAIL) + && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), + NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP6_ADDRESS)) + log_detail = ", meaning the address was already removed"; + else + success = FALSE; - success = TRUE; - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { - /* ok */ - } else if (NM_IN_SET(-((int) seq_result), ESRCH, ENOENT)) - log_detail = ", meaning the object was already removed"; - else if (NM_IN_SET(-((int) seq_result), ENXIO) - && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS)) { - /* On RHEL7 kernel, deleting a non existing address fails with ENXIO */ - log_detail = ", meaning the address was already removed"; - } else if (NM_IN_SET(-((int) seq_result), ENODEV)) { - log_detail = ", meaning the device was already removed"; - } else if (NM_IN_SET(-((int) seq_result), EADDRNOTAVAIL) - && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS)) - log_detail = ", meaning the address was already removed"; - else - success = FALSE; + _NMLOG(success ? LOGL_DEBUG : LOGL_WARN, + "do-delete-%s[%s]: %s%s", + NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, + nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf)), + log_detail); - _NMLOG(success ? LOGL_DEBUG : LOGL_WARN, - "do-delete-%s[%s]: %s%s", - NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, - nmp_object_to_string(obj_id, NMP_OBJECT_TO_STRING_ID, sbuf1, sizeof(sbuf1)), - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf)), - log_detail); + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); if (NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS, @@ -8232,14 +8315,15 @@ do_change_link(NMPlatform *platform, { nm_auto_pop_netns NMPNetns *netns = NULL; int nle; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; char s_buf[256]; int result; NMLogLevel log_level; const char *log_detail; gs_free char *log_detail_free = NULL; const NMPObject *obj_cache; + int try_count = 0; if (!nm_platform_netns_push(platform, &netns)) { log_level = LOGL_ERR; @@ -8249,12 +8333,13 @@ do_change_link(NMPlatform *platform, } retry: + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; result = -NME_UNSPEC; log_level = LOGL_WARN; log_detail = ""; nm_clear_g_free(&log_detail_free); - nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &extack_msg); if (nle < 0) { log_level = LOGL_ERR; log_detail_free = @@ -8269,7 +8354,7 @@ retry: delayed_action_handle_all(platform); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); if (NM_IN_SET(seq_result, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, -EEXIST, -EADDRINUSE)) { log_level = LOGL_DEBUG; @@ -8314,10 +8399,10 @@ out: _NMLOG(log_level, "do-change-link[%d]: %s%s", ifindex, - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf)), + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf)), log_detail); - if (result == -EAGAIN) + if (result == -EAGAIN && ++try_count < RESYNC_RETRIES) goto retry; return result; @@ -8404,8 +8489,10 @@ link_delete(NMPlatform *platform, int ifindex) static gboolean link_change(NMPlatform *platform, int ifindex, + NMPlatformLinkProps *props, NMPortKind port_kind, - const NMPlatformLinkPortData *port_data) + const NMPlatformLinkPortData *port_data, + NMPlatformLinkChangeFlags flags) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *nl_info; @@ -8415,6 +8502,15 @@ link_change(NMPlatform *platform, if (!nlmsg) return FALSE; + if (flags & NM_PLATFORM_LINK_CHANGE_TX_QUEUE_LENGTH) + NLA_PUT_U32(nlmsg, IFLA_TXQLEN, props->tx_queue_length); + if (flags & NM_PLATFORM_LINK_CHANGE_GSO_MAX_SIZE) + NLA_PUT_U32(nlmsg, IFLA_GSO_MAX_SIZE, props->gso_max_size); + if (flags & NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS) + NLA_PUT_U32(nlmsg, IFLA_GSO_MAX_SEGS, props->gso_max_segments); + if (flags & NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE) + NLA_PUT_U32(nlmsg, IFLA_GRO_MAX_SIZE, props->gro_max_size); + switch (port_kind) { case NM_PORT_KIND_BOND: @@ -8573,10 +8669,10 @@ link_supports_sriov(NMPlatform *platform, int ifindex) if (dirfd < 0) return FALSE; - num = - nm_platform_sysctl_get_int32(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), - -1); + num = nm_platform_sysctl_get_int32( + platform, + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_numvfs"), + -1); return num != -1; } @@ -8710,7 +8806,7 @@ link_set_sriov_params_async(NMPlatform *platform, total = nm_platform_sysctl_get_int_checked( platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_totalvfs"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_totalvfs"), 10, 0, G_MAXUINT, @@ -8728,14 +8824,14 @@ link_set_sriov_params_async(NMPlatform *platform, */ current_num = nm_platform_sysctl_get_int_checked( platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_numvfs"), 10, 0, G_MAXUINT, -1); current_autoprobe = nm_platform_sysctl_get_int_checked( platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_drivers_autoprobe"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_drivers_autoprobe"), 10, 0, 1, @@ -8755,7 +8851,7 @@ link_set_sriov_params_async(NMPlatform *platform, && current_autoprobe != autoprobe && !nm_platform_sysctl_set( platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_drivers_autoprobe"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_drivers_autoprobe"), nm_sprintf_buf(buf, "%d", (int) autoprobe))) { g_set_error(&error, NM_UTILS_ERROR, @@ -8777,7 +8873,7 @@ link_set_sriov_params_async(NMPlatform *platform, values[i++] = NULL; sysctl_set_async(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "device/sriov_numvfs"), values, callback, data, @@ -8963,6 +9059,47 @@ nla_put_failure: g_return_val_if_reached(FALSE); } +static gboolean +link_set_bridge_info(NMPlatform *platform, + int ifindex, + const NMPlatformLinkSetBridgeInfoData *bridge_info) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + const char *kind; + + nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); + if (!nlmsg) + g_return_val_if_reached(-NME_BUG); + + if (!(info = nla_nest_start(nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + kind = nm_link_type_to_rtnl_type_string(NM_LINK_TYPE_BRIDGE); + if (!kind) + goto nla_put_failure; + + NLA_PUT_STRING(nlmsg, IFLA_INFO_KIND, kind); + + if (!(data = nla_nest_start(nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (bridge_info->vlan_filtering_has) + NLA_PUT_U8(nlmsg, IFLA_BR_VLAN_FILTERING, bridge_info->vlan_filtering_val); + + if (bridge_info->vlan_default_pvid_has) + NLA_PUT_U16(nlmsg, IFLA_BR_VLAN_DEFAULT_PVID, bridge_info->vlan_default_pvid_val); + + nla_nest_end(nlmsg, data); + nla_nest_end(nlmsg, info); + + return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + static char * link_get_physical_port_id(NMPlatform *platform, int ifindex) { @@ -8972,7 +9109,7 @@ link_get_physical_port_id(NMPlatform *platform, int ifindex) dirfd = nm_platform_sysctl_open_netdir(platform, ifindex, ifname_verified); if (dirfd < 0) return NULL; - return sysctl_get(platform, NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "phys_port_id")); + return sysctl_get(platform, NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_verified, "phys_port_id")); } static guint @@ -8986,7 +9123,7 @@ link_get_dev_id(NMPlatform *platform, int ifindex) return 0; return nm_platform_sysctl_get_int_checked( platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "dev_id"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_verified, "dev_id"), 16, 0, G_MAXUINT16, @@ -9236,12 +9373,12 @@ _infiniband_partition_action(NMPlatform *platform, if (action == INFINIBAND_ACTION_CREATE_CHILD) success = nm_platform_sysctl_set(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_parent, "create_child"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_parent, "create_child"), id); else success = nm_platform_sysctl_set(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_parent, "delete_child"), + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_parent, "delete_child"), id); if (!success) { @@ -9250,7 +9387,7 @@ _infiniband_partition_action(NMPlatform *platform, return FALSE; } - nmp_utils_new_infiniband_name(name, ifname_parent, p_key); + nm_net_devname_infiniband(name, ifname_parent, p_key); do_request_link(platform, 0, name); if (action == INFINIBAND_ACTION_DELETE_CHILD) @@ -9591,7 +9728,8 @@ ip4_address_add(NMPlatform *platform, guint32 lifetime, guint32 preferred, guint32 flags, - const char *label) + const char *label, + char **out_extack_msg) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -9611,7 +9749,7 @@ ip4_address_add(NMPlatform *platform, label); nmp_object_stackinit_id_ip4_address(&obj_id, ifindex, addr, plen, peer_addr); - return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE) >= 0); + return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE, out_extack_msg) >= 0); } static gboolean @@ -9622,7 +9760,8 @@ ip6_address_add(NMPlatform *platform, struct in6_addr peer_addr, guint32 lifetime, guint32 preferred, - guint32 flags) + guint32 flags, + char **out_extack_msg) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -9642,7 +9781,7 @@ ip6_address_add(NMPlatform *platform, NULL); nmp_object_stackinit_id_ip6_address(&obj_id, ifindex, &addr); - return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE) >= 0); + return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE, out_extack_msg) >= 0); } static gboolean @@ -9704,7 +9843,7 @@ ip6_address_delete(NMPlatform *platform, int ifindex, struct in6_addr addr, guin /*****************************************************************************/ static int -ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack) +ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack, char **out_extack_msg) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -9714,7 +9853,8 @@ ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack) return do_add_addrroute(platform, obj_stack, nlmsg, - NM_FLAGS_HAS(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE)); + NM_FLAGS_HAS(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE), + out_extack_msg); } static gboolean @@ -9815,9 +9955,10 @@ ip_route_get(NMPlatform *platform, delayed_action_handle_all(platform); - /* Retry, if we failed due to a cache resync. That can happen when the netlink - * socket fills up and we lost the response. */ - } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC && ++try_count < 10); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); if (seq_result < 0) { /* negative seq_result is an errno from kernel. Map it to negative @@ -9841,29 +9982,37 @@ ip_route_get(NMPlatform *platform, static int routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutingRule *routing_rule) { - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + WaitForNlResponseResult seq_result; nm_auto_nlmsg struct nl_msg *msg = NULL; - gs_free char *errmsg = NULL; + gs_free char *extack_msg = NULL; char s_buf[256]; int nle; + int try_count = 0; msg = _nl_msg_new_routing_rule(RTM_NEWRULE, flags, routing_rule); event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-add-rule: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-add-rule: failed sending netlink request \"%s\" (%d)", + nm_strerror(nle), + -nle); + return -NME_PL_NETLINK; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); + + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); - nm_assert(seq_result); + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, "do-add-rule: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return 0; @@ -9877,11 +10026,12 @@ routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutin static int qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) { - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; - nm_auto_nlmsg struct nl_msg *msg = NULL; + nm_auto_nlmsg struct nl_msg *msg = NULL; + int try_count = 0; /* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind * is undefined. */ @@ -9890,19 +10040,26 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-add-qdisc: failed sending netlink request \"%s\" (%d)", + nm_strerror(nle), + -nle); + return -NME_PL_NETLINK; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); + + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, "do-add-qdisc: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return 0; @@ -9918,8 +10075,8 @@ tc_delete(NMPlatform *platform, guint32 parent, gboolean log_error) { - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; const char *log_tag; @@ -9928,6 +10085,7 @@ tc_delete(NMPlatform *platform, .tcm_ifindex = ifindex, .tcm_parent = parent, }; + int try_count = 0; switch (nlmsg_type) { case RTM_DELQDISC: @@ -9948,25 +10106,30 @@ tc_delete(NMPlatform *platform, event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); - if (nle < 0) { - _NMLOG(log_error ? LOGL_ERR : LOGL_DEBUG, - "%s: failed sending netlink request \"%s\" (%d)", - log_tag, - nm_strerror(nle), - -nle); - return -NME_PL_NETLINK; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &extack_msg); + if (nle < 0) { + _NMLOG(log_error ? LOGL_ERR : LOGL_DEBUG, + "%s: failed sending netlink request \"%s\" (%d)", + log_tag, + nm_strerror(nle), + -nle); + return -NME_PL_NETLINK; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); + + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); - nm_assert(seq_result); + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); _NMLOG((seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK || !log_error) ? LOGL_DEBUG : LOGL_WARN, "%s: %s", log_tag, - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return 0; @@ -9987,11 +10150,12 @@ qdisc_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_err static int tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tfilter) { - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; + WaitForNlResponseResult seq_result; + gs_free char *extack_msg = NULL; int nle; char s_buf[256]; - nm_auto_nlmsg struct nl_msg *msg = NULL; + nm_auto_nlmsg struct nl_msg *msg = NULL; + int try_count = 0; /* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind * and tfilter.action.kind is undefined. */ @@ -10000,19 +10164,26 @@ tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tf event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); - if (nle < 0) { - _LOGE("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } + do { + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &extack_msg); + if (nle < 0) { + _LOGE("do-add-tfilter: failed sending netlink request \"%s\" (%d)", + nm_strerror(nle), + -nle); + return -NME_PL_NETLINK; + } - delayed_action_handle_all(platform); + delayed_action_handle_all(platform); - nm_assert(seq_result); + nm_assert(seq_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN); - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-tfilter: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); + _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, + "do-add-tfilter: %s", + wait_for_nl_response_to_string(seq_result, extack_msg, s_buf, sizeof(s_buf))); + + } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC + && ++try_count < RESYNC_RETRIES); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return 0; @@ -10268,9 +10439,16 @@ continue_reading: int errsv; errsv = nlmsg_parse_error(msg.nm_nlh, &extack_msg); - if (errsv == 0) + if (errsv == 0) { seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - else { + if (extack_msg) { + _LOGD("%s: recvmsg: warning message from kernel: %s%s%s for request %d", + log_prefix, + NM_PRINT_FMT_QUOTE_STRING(extack_msg), + msg.nm_nlh->nlmsg_seq); + extack_msg = NULL; + } + } else { _LOGD("%s: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", log_prefix, nm_strerror(errsv), @@ -10728,9 +10906,10 @@ mptcp_addr_update(NMPlatform *platform, NMOptionBool add, const NMPlatformMptcpA return nle; } - _LOGT("mptcp: %s address %s: success", + _LOGT("mptcp: %s address %s: success%s%s%s", cmd_str, - nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf))); + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)), + NM_PRINT_FMT_QUOTED(extack_msg[0] != '\0', " Warning: \"", extack_msg, "\"", "")); return 0; @@ -11235,6 +11414,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_set_bridge_info = link_set_bridge_info; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index fc704226..5684b8cd 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -313,9 +313,6 @@ nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg) e = nlmsg_data(nlh); - if (!e->error) - return 0; - if (NM_FLAGS_HAS(nlh->nlmsg_flags, NLM_F_ACK_TLVS) && out_extack_msg && nlh->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { static const struct nla_policy policy[] = { @@ -328,11 +325,19 @@ nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg) tlvs = NM_CAST_ALIGN(struct nlattr, (((char *) e) + sizeof(*e) + e->msg.nlmsg_len - NLMSG_HDRLEN)); if (nla_parse_arr(tb, tlvs, nlh->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, policy) >= 0) { - if (tb[NLMSGERR_ATTR_MSG]) - *out_extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); + if (tb[NLMSGERR_ATTR_MSG]) { + const char *s; + + s = nla_get_string(tb[NLMSGERR_ATTR_MSG]); + if (s[0] != '\0') + *out_extack_msg = s; + } } } + if (!e->error) + return 0; + return -nm_errno_from_native(e->error); } @@ -488,44 +493,52 @@ nlmsg_put(struct nl_msg *n, } size_t -nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) +_nla_strlcpy_full(char *dst, const struct nlattr *nla, size_t dstsize, gboolean wipe_remainder) { - const char *src; + const char *src = NULL; size_t srclen; - size_t len; - - /* - Always writes @dstsize bytes to @dst - * - Copies the first non-NUL characters to @dst. - * Any characters after the first NUL bytes in @nla are ignored. - * - If the string @nla is longer than @dstsize, the string - * gets truncated. @dst will always be NUL terminated. */ - - if (G_UNLIKELY(dstsize <= 1)) { - if (dstsize == 1) - dst[0] = '\0'; - if (nla && (srclen = nla_len(nla)) > 0) - return strnlen(nla_data(nla), srclen); - return 0; - } + size_t cpylen; + + /* Behaves like strlcpy(): + * + * - returns the length of the string in nla (how much it wanted to copy). + * - will always NUL terminate dst (unless dstsize is zero). + * - if @wipe_remainder, the remaining bytes after the string are set to NUL, + * similar to what strncpy() would do. Otherwise the bytes are undefined. + * - nla is not required to contain a NUL terminated string (unlike nla_get_string()). + * - the function copies the bytes up to the first NUL character in nla. + * any remainder in nla is ignored. + * - nla may be NULL, which is treated the same as an empty string (copying zero bytes). + */ - nm_assert(dst); + nm_assert(dstsize == 0 || dst); if (nla) { srclen = nla_len(nla); if (srclen > 0) { src = nla_data(nla); srclen = strnlen(src, srclen); - if (srclen > 0) { - len = NM_MIN(dstsize - 1, srclen); - memcpy(dst, src, len); - memset(&dst[len], 0, dstsize - len); - return srclen; - } } + } else + srclen = 0; + + if (dstsize == 0) { + /* we cannot NUL terminate. This is potentially dangerous, maybe + * we should assert against this case. */ + return srclen; } - memset(dst, 0, dstsize); - return 0; + cpylen = NM_MIN(dstsize - 1u, srclen); + + nm_memcpy(dst, src, cpylen); + + if (wipe_remainder) { + /* like strncpy() would do, wipe the rest. */ + memset(&dst[cpylen], 0, dstsize - cpylen); + } else + dst[cpylen] = '\0'; + + return srclen; } size_t @@ -1024,17 +1037,6 @@ nlmsg_get_dst(struct nl_msg *msg) } int -nl_socket_set_nonblocking(const struct nl_sock *sk) -{ - nm_assert_sk(sk); - - if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nm_errno_from_native(errno); - - return 0; -} - -int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { int err; @@ -1483,13 +1485,13 @@ nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) * @nla: (out): the source address on success. * @buf: (out): pointer to the result buffer on success. This is * either @buf0 or an allocated buffer that gets returned. - * @out_creds: (out) (allow-none): optional out buffer for the credentials + * @out_creds: (out) (optional): optional out buffer for the credentials * on success. - * @out_creds_has: (out) (allow-none): result indicating whether + * @out_creds_has: (out) (optional): result indicating whether * @out_creds was filled. -* @out_pktinfo_group: (out) (allow-none): optional out buffer for NETLINK_PKTINFO +* @out_pktinfo_group: (out) (optional): optional out buffer for NETLINK_PKTINFO * group on success. - * @out_pktinfo_has: (out) (allow-none): result indicating whether + * @out_pktinfo_has: (out) (optional): result indicating whether * @out_pktinfo_group was filled. * * If @buf0_len is zero, the function will g_malloc() a new receive buffer of size diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index cdb8a81c..efd482ad 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -93,19 +93,19 @@ struct nla_policy { /* static asserts that @tb and @policy are suitable arguments to nla_parse(). */ #if _NM_CC_SUPPORT_GENERIC -#define _nl_static_assert_tb(tb, policy) \ - G_STMT_START \ - { \ - G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0); \ - \ +#define _nl_static_assert_tb(tb, policy) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0); \ + \ /* We allow @policy to be either a C array or NULL. The sizeof() * must either match the expected array size or we check that * "policy" has typeof(NULL). This isn't a perfect compile time check, - * but good enough. */ \ - G_STATIC_ASSERT_EXPR( \ - _Generic((policy), typeof(NULL) : 1, default \ - : (sizeof(policy) == G_N_ELEMENTS(tb) * sizeof(struct nla_policy)))); \ - } \ + * but good enough. */ \ + G_STATIC_ASSERT_EXPR(_Generic((policy), \ + typeof(NULL): 1, \ + default: (sizeof(policy) == G_N_ELEMENTS(tb) * sizeof(struct nla_policy)))); \ + } \ G_STMT_END #else #define _nl_static_assert_tb(tb, policy) G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0) @@ -238,10 +238,36 @@ nla_get_be64(const struct nlattr *nla) static inline char * nla_get_string(const struct nlattr *nla) { - return nla_data(nla); + char *s; + + /* nla_get_string() requires that nla contains a NUL terminated string. + * It cannot return NULL. Only use it with attributes that validate as NLA_STRING. */ + + nm_assert(nla_len(nla) > 0); + + s = nla_data(nla); + + nm_assert(memchr(s, 0, nla_len(nla))); + + return s; } -size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize); +size_t +_nla_strlcpy_full(char *dst, const struct nlattr *nla, size_t dstsize, gboolean wipe_remainder); + +static inline size_t +nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) +{ + return _nla_strlcpy_full(dst, nla, dstsize, FALSE); +} + +static inline size_t +nla_strlcpy_wipe(char *dst, const struct nlattr *nla, size_t dstsize) +{ + /* Behaves exactly like nla_strlcpy(), but (similar to strncpy()) it fills the + * remaining @dstsize bytes with NUL. */ + return _nla_strlcpy_full(dst, nla, dstsize, TRUE); +} size_t nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize); @@ -264,6 +290,17 @@ size_t nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize); } \ G_STMT_END +static inline struct in6_addr +nla_get_in6_addr(const struct nlattr *nla) +{ + struct in6_addr in6; + + nm_assert(nla_len(nla) >= sizeof(struct in6_addr)); + + nla_memcpy(&in6, nla, sizeof(in6)); + return in6; +} + int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data); static inline int @@ -568,8 +605,6 @@ int nl_socket_set_passcred(struct nl_sock *sk, int state); int nl_socket_set_pktinfo(struct nl_sock *sk, int state); -int nl_socket_set_nonblocking(const struct nl_sock *sk); - uint32_t nl_socket_get_local_port(const struct nl_sock *sk); int nl_socket_add_memberships(struct nl_sock *sk, int group, ...); diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index bebc53a8..08d82fe8 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -1955,10 +1955,10 @@ nmp_utils_ip_config_source_to_string(NMIPConfigSource source, char *buf, gsize l /** * nmp_utils_sysctl_open_netdir: * @ifindex: the ifindex for which to open "/sys/class/net/%s" - * @ifname_guess: (allow-none): optional argument, if present used as initial + * @ifname_guess: (nullable): optional argument, if present used as initial * guess as the current name for @ifindex. If guessed right, * it saves an additional if_indextoname() call. - * @out_ifname: (allow-none): if present, must be at least IFNAMSIZ + * @out_ifname: (optional): if present, must be at least IFNAMSIZ * characters. On success, this will contain the actual ifname * found while opening the directory. * @@ -2064,35 +2064,6 @@ nmp_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id) /*****************************************************************************/ -/* nmp_utils_new_infiniband_name: - * @name: the output-buffer where the value will be written. Must be - * not %NULL and point to a string buffer of at least IFNAMSIZ bytes. - * @parent_name: the parent interface name - * @p_key: the partition key. - * - * Returns: the infiniband name will be written to @name and @name - * is returned. - */ -const char * -nmp_utils_new_infiniband_name(char *name, const char *parent_name, int p_key) -{ - g_return_val_if_fail(name, NULL); - g_return_val_if_fail(parent_name && parent_name[0], NULL); - g_return_val_if_fail(strlen(parent_name) < IFNAMSIZ, NULL); - - /* technically, p_key of 0x0000 and 0x8000 is not allowed either. But we don't - * want to assert against that in nmp_utils_new_infiniband_name(). So be more - * resilient here, and accept those. */ - g_return_val_if_fail(p_key >= 0 && p_key <= 0xffff, NULL); - - /* If parent+suffix is too long, kernel would just truncate - * the name. We do the same. See ipoib_vlan_add(). */ - g_snprintf(name, IFNAMSIZ, "%s.%04x", parent_name, p_key); - return name; -} - -/*****************************************************************************/ - /** * Takes a pair @timestamp and @duration, and returns the remaining duration based * on the new timestamp @now. @@ -2209,7 +2180,7 @@ nmp_utils_modprobe(GError **error, gboolean suppress_error_logging, const char * /* construct the argument list */ argv = g_ptr_array_sized_new(4); - g_ptr_array_add(argv, "/sbin/modprobe"); + g_ptr_array_add(argv, MODPROBE_PATH); g_ptr_array_add(argv, "--use-blacklist"); g_ptr_array_add(argv, (char *) arg1); diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h index 9f17da48..14b09a79 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -77,8 +77,7 @@ int nmp_utils_if_nametoindex(const char *ifname); int nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname); -char *nmp_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id); -const char *nmp_utils_new_infiniband_name(char *name, const char *parent_name, int p_key); +char *nmp_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id); guint32 nmp_utils_lifetime_rebase_relative_time_on_now(guint32 timestamp, guint32 duration, gint32 now); diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 1c495d60..041354cf 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -1276,7 +1276,7 @@ _link_add_check_existing(NMPlatform *self, * @type: Interface type * @name: Interface name * @parent: the IFLA_LINK parameter or 0. - * @address: (allow-none): set the mac address of the link + * @address: (nullable): set the mac address of the link * @address_len: the length of the @address * @extra_data: depending on @type, additional data. * @out_link: on success, the link object @@ -2060,6 +2060,29 @@ nm_platform_link_set_bridge_vlans(NMPlatform *self, return klass->link_set_bridge_vlans(self, ifindex, on_master, vlans); } +gboolean +nm_platform_link_set_bridge_info(NMPlatform *self, + int ifindex, + const NMPlatformLinkSetBridgeInfoData *bridge_info) +{ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + if (_LOGD_ENABLED()) { + if (bridge_info->vlan_filtering_has) { + _LOG3D("link: setting bridge vlan-filtering %s", + bridge_info->vlan_filtering_val ? "on" : "off"); + } + + if (bridge_info->vlan_default_pvid_has) { + _LOG3D("link: setting bridge vlan-default-pvid %d", bridge_info->vlan_default_pvid_val); + } + } + + return klass->link_set_bridge_info(self, ifindex, bridge_info); +} + /** * nm_platform_link_change_flags_full: * @self: platform instance @@ -2146,7 +2169,11 @@ nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) } gboolean -nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port) +nm_platform_link_change(NMPlatform *self, + int ifindex, + NMPlatformLinkProps *props, + NMPlatformLinkBondPort *bond_port, + NMPlatformLinkChangeFlags flags) { char sbuf_prio[100]; @@ -2154,9 +2181,24 @@ nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *b g_return_val_if_fail(ifindex >= 0, FALSE); + nm_assert(!NM_FLAGS_ANY(flags, + NM_PLATFORM_LINK_CHANGE_TX_QUEUE_LENGTH + | NM_PLATFORM_LINK_CHANGE_GSO_MAX_SIZE + | NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS + | NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE) + || props); + if (_LOGD_ENABLED()) { nm_auto_free_gstring GString *str = g_string_new(""); + if (flags & NM_PLATFORM_LINK_CHANGE_TX_QUEUE_LENGTH) + g_string_append_printf(str, "tx-queue-length %u ", props->tx_queue_length); + if (flags & NM_PLATFORM_LINK_CHANGE_GSO_MAX_SIZE) + g_string_append_printf(str, "gso_max_size %u ", props->gso_max_size); + if (flags & NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS) + g_string_append_printf(str, "gso_max_segments %u ", props->gso_max_segments); + if (flags & NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE) + g_string_append_printf(str, "gro_max_size %u ", props->gro_max_size); if (bond_port) { nm_assert(bond_port->prio_has || bond_port->prio == 0); g_string_append_printf(str, @@ -2178,8 +2220,10 @@ nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *b return klass->link_change(self, ifindex, + props, bond_port ? NM_PORT_KIND_BOND : NM_PORT_KIND_NONE, - (const NMPlatformLinkPortData *) bond_port); + (const NMPlatformLinkPortData *) bond_port, + flags); } /** @@ -2362,7 +2406,7 @@ nm_platform_link_can_assume(NMPlatform *self, int ifindex) * @self: the platform instance * @ifindex: the link ifindex to lookup * @link_type: filter by link-type. - * @out_link: (allow-none): returns the platform link instance + * @out_link: (out) (optional) (nullable): returns the platform link instance * * If the function returns %NULL, that could mean that no such ifindex * exists, of that the link has no lnk data. You can find that out @@ -2373,7 +2417,7 @@ nm_platform_link_can_assume(NMPlatform *self, int ifindex) * object if it is present. If you set link-type, you can be sure * that only a link type of the matching type is returned (or %NULL). * - * Returns: the internal link lnk object. The returned object + * Returns: (nullable): the internal link lnk object. The returned object * is owned by the platform cache and must not be modified. Note * however, that the object is guaranteed to be immutable, so * you can safely take a reference and keep it for yourself @@ -2631,7 +2675,7 @@ nm_platform_link_wireguard_change(NMPlatform *self * @vnet_hdr: whether to set the IFF_VNET_HDR flag * @multi_queue: whether to set the IFF_MULTI_QUEUE flag * @out_link: on success, the link object - * @out_fd: (allow-none): if give, return the file descriptor for the + * @out_fd: (out) (optional): if give, return the file descriptor for the * created device. Note that when creating a non-persistent device, * this argument is mandatory, otherwise it makes no sense * to create such an interface. @@ -2727,7 +2771,7 @@ link_set_option(NMPlatform *self, path = nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option); return nm_platform_sysctl_set(self, - NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path), + NMP_SYSCTL_PATHID_NETDIR_UNSAFE_A(dirfd, ifname_verified, path), value); } @@ -2748,7 +2792,7 @@ link_get_option(NMPlatform *self, int ifindex, const char *category, const char path = nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option); return nm_platform_sysctl_get(self, - NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path)); + NMP_SYSCTL_PATHID_NETDIR_UNSAFE_A(dirfd, ifname_verified, path)); } static const char * @@ -2955,7 +2999,7 @@ _infiniband_add_add_or_delete(NMPlatform *self, if (parent_link->type != NM_LINK_TYPE_INFINIBAND) return -NME_PL_WRONG_TYPE; - nmp_utils_new_infiniband_name(name, parent_link->name, p_key); + nm_net_devname_infiniband(name, parent_link->name, p_key); if (add) { r = _link_add_check_existing(self, name, NM_LINK_TYPE_INFINIBAND, out_link); @@ -3029,7 +3073,7 @@ nm_platform_link_infiniband_get_properties(NMPlatform *self, return FALSE; contents = - nm_platform_sysctl_get(self, NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "mode")); + nm_platform_sysctl_get(self, NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_verified, "mode")); if (!contents) return FALSE; if (strstr(contents, "datagram")) @@ -3040,13 +3084,13 @@ nm_platform_link_infiniband_get_properties(NMPlatform *self, mode = NULL; g_free(contents); - p_key = - nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "pkey"), - 16, - 0, - 0xFFFF, - -1); + p_key = nm_platform_sysctl_get_int_checked( + self, + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname_verified, "pkey"), + 16, + 0, + 0xFFFF, + -1); if (p_key < 0) return FALSE; @@ -3093,7 +3137,7 @@ nm_platform_link_veth_get_properties(NMPlatform *self, int ifindex, int *out_pee * nm_platform_link_tun_get_properties: * @self: the #NMPlatform instance * @ifindex: the ifindex to look up - * @out_properties: (out) (allow-none): return the read properties + * @out_properties: (out) (optional): return the read properties * * Only recent versions of kernel export tun properties via netlink. * So, if that's the case, then we have the NMPlatformLnkTun instance @@ -3148,31 +3192,33 @@ nm_platform_link_tun_get_properties(NMPlatform *self, int ifindex, NMPlatformLnk if (dirfd < 0) return FALSE; - owner = nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "owner"), - 10, - -1, - G_MAXUINT32, - -2); + owner = + nm_platform_sysctl_get_int_checked(self, + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "owner"), + 10, + -1, + G_MAXUINT32, + -2); if (owner == -2) return FALSE; - group = nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "group"), - 10, - -1, - G_MAXUINT32, - -2); + group = + nm_platform_sysctl_get_int_checked(self, + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "group"), + 10, + -1, + G_MAXUINT32, + -2); if (group == -2) return FALSE; - flags = - nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "tun_flags"), - 16, - 0, - G_MAXINT64, - -1); + flags = nm_platform_sysctl_get_int_checked( + self, + NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, "tun_flags"), + 16, + 0, + G_MAXINT64, + -1); if (flags == -1) return FALSE; } @@ -3634,7 +3680,8 @@ nm_platform_ip4_address_add(NMPlatform *self, guint32 lifetime, guint32 preferred, guint32 flags, - const char *label) + const char *label, + char **out_extack_msg) { _CHECK_SELF(self, klass, FALSE); @@ -3644,6 +3691,7 @@ nm_platform_ip4_address_add(NMPlatform *self, g_return_val_if_fail(preferred <= lifetime, FALSE); g_return_val_if_fail(!label || strlen(label) < sizeof(((NMPlatformIP4Address *) NULL)->label), FALSE); + nm_assert(!out_extack_msg || !*out_extack_msg); if (_LOGD_ENABLED()) { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; @@ -3676,7 +3724,8 @@ nm_platform_ip4_address_add(NMPlatform *self, lifetime, preferred, flags, - label); + label, + out_extack_msg); } gboolean @@ -3687,7 +3736,8 @@ nm_platform_ip6_address_add(NMPlatform *self, struct in6_addr peer_address, guint32 lifetime, guint32 preferred, - guint32 flags) + guint32 flags, + char **out_extack_msg) { _CHECK_SELF(self, klass, FALSE); @@ -3695,6 +3745,7 @@ nm_platform_ip6_address_add(NMPlatform *self, g_return_val_if_fail(plen <= 128, FALSE); g_return_val_if_fail(lifetime > 0, FALSE); g_return_val_if_fail(preferred <= lifetime, FALSE); + nm_assert(!out_extack_msg || !*out_extack_msg); if (_LOGD_ENABLED()) { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; @@ -3715,8 +3766,15 @@ nm_platform_ip6_address_add(NMPlatform *self, nm_platform_ip6_dadfailed_set(self, ifindex, &address, FALSE); - return klass - ->ip6_address_add(self, ifindex, address, plen, peer_address, lifetime, preferred, flags); + return klass->ip6_address_add(self, + ifindex, + address, + plen, + peer_address, + lifetime, + preferred, + flags, + out_extack_msg); } gboolean @@ -4102,7 +4160,7 @@ ip6_address_scope_cmp_descending(gconstpointer p_a, gconstpointer p_b, gpointer * @known_addresses: List of addresses. The list will be modified and * expired addresses will be cleared (by calling nmp_object_unref() * on the array element). - * @addresses_prune: (allow-none): the list of addresses to delete. + * @addresses_prune: (nullable): the list of addresses to delete. * If platform has such an address configured, it will be deleted * at the beginning of the sync. Note that the array will be modified * by the function. @@ -4539,7 +4597,8 @@ next_plat:; NM_FLAGS_HAS(flags, NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE) ? IFA_F_NOPREFIXROUTE : 0, - known_address->a4.label)) + known_address->a4.label, + NULL)) success = FALSE; } else { if (!nm_platform_ip6_address_add( @@ -4553,7 +4612,8 @@ next_plat:; (NM_FLAGS_HAS(flags, NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE) ? IFA_F_NOPREFIXROUTE : 0) - | known_address->a6.n_ifa_flags)) + | known_address->a6.n_ifa_flags, + NULL)) success = FALSE; } } @@ -4594,42 +4654,6 @@ nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex) /*****************************************************************************/ -static gboolean -_err_inval_due_to_ipv6_tentative_pref_src(NMPlatform *self, const NMPObject *obj) -{ - const NMPlatformIP6Route *r; - const NMPlatformIP6Address *a; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(NMP_OBJECT_IS_VALID(obj)); - - /* trying to add an IPv6 route with pref-src fails, if the address is - * still tentative (rh#1452684). We need to hack around that. - * - * Detect it, by guessing whether that's the case. */ - - if (NMP_OBJECT_GET_TYPE(obj) != NMP_OBJECT_TYPE_IP6_ROUTE) - return FALSE; - - r = NMP_OBJECT_CAST_IP6_ROUTE(obj); - - /* we only allow this workaround for routes added manually by the user. */ - if (r->rt_source != NM_IP_CONFIG_SOURCE_USER) - return FALSE; - - if (IN6_IS_ADDR_UNSPECIFIED(&r->pref_src)) - return FALSE; - - a = nm_platform_ip6_address_get(self, r->ifindex, &r->pref_src); - if (!a) - return FALSE; - if (!NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TENTATIVE) - || NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_DADFAILED)) - return FALSE; - - return TRUE; -} - static guint _ipv6_temporary_addr_prefixes_keep_hash(gconstpointer ptr) { @@ -4951,15 +4975,15 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, * @self: the #NMPlatform instance. * @addr_family: AF_INET or AF_INET6. * @ifindex: the @ifindex for which the routes are to be added. - * @routes: (allow-none): a list of routes to configure. Must contain + * @routes: (nullable): a list of routes to configure. Must contain * NMPObject instances of routes, according to @addr_family. - * @routes_prune: (allow-none): the list of routes to delete. + * @routes_prune: (nullable): the list of routes to delete. * If platform has such a route configured, it will be deleted * at the end of the operation. Note that if @routes contains * the same route, then it will not be deleted. @routes overrules * @routes_prune list. - * @out_temporary_not_available: (allow-none) (out): routes that could - * currently not be synced. The caller shall keep them and try later again. + * @out_routes_failed: (out) (optional) (nullable): routes that could + * not be synced/added. * * Returns: %TRUE on success. */ @@ -4969,7 +4993,7 @@ nm_platform_ip_route_sync(NMPlatform *self, int ifindex, GPtrArray *routes, GPtrArray *routes_prune, - GPtrArray **out_temporary_not_available) + GPtrArray **out_routes_failed) { const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMPlatformVTableRoute *vt; @@ -4989,8 +5013,8 @@ nm_platform_ip_route_sync(NMPlatform *self, for (i_type = 0; routes && i_type < 2; i_type++) { for (i = 0; i < routes->len; i++) { - int r, r2; - gboolean gateway_route_added = FALSE; + gs_free char *extack_msg = NULL; + int r; conf_o = routes->pdata[i]; @@ -5046,143 +5070,59 @@ nm_platform_ip_route_sync(NMPlatform *self, } } -sync_route_add: r = nm_platform_ip_route_add(self, NMP_NLM_FLAG_APPEND | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - conf_o); - if (r < 0) { - if (r == -EEXIST) { - /* Don't fail for EEXIST. It's not clear that the existing route - * is identical to the one that we were about to add. However, - * above we should have deleted conflicting (non-identical) routes. */ - if (_LOGD_ENABLED()) { - plat_entry = - nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o); - if (!plat_entry) { - _LOG3D("route-sync: adding route %s failed with EEXIST, however we " - "cannot find such a route", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1))); - } else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o), - NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj), - NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - != 0) { - _LOG3D("route-sync: adding route %s failed due to existing " - "(different!) route %s", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nmp_object_to_string(plat_entry->obj, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf2, - sizeof(sbuf2))); - } - } - } else if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { - _LOG3D("route-sync: ignore failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - } else if (r == -EINVAL && out_temporary_not_available - && _err_inval_due_to_ipv6_tentative_pref_src(self, conf_o)) { - _LOG3D("route-sync: ignore failure to add IPv6 route with tentative IPv6 " - "pref-src: %s: %s", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - if (!*out_temporary_not_available) - *out_temporary_not_available = - g_ptr_array_new_full(0, (GDestroyNotify) nmp_object_unref); - g_ptr_array_add(*out_temporary_not_available, - (gpointer) nmp_object_ref(conf_o)); - } else if (!gateway_route_added - && ((r == -ENETUNREACH && vt->is_ip4 - && !!NMP_OBJECT_CAST_IP4_ROUTE(conf_o)->gateway) - || (r == -EHOSTUNREACH && !vt->is_ip4 - && !IN6_IS_ADDR_UNSPECIFIED( - &NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->gateway)))) { - NMPObject oo; - - if (vt->is_ip4) { - const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o); - - nmp_object_stackinit( - &oo, - NMP_OBJECT_TYPE_IP4_ROUTE, - &((NMPlatformIP4Route){ - .ifindex = rt->ifindex, - .network = rt->gateway, - .plen = 32, - .metric = nm_platform_ip4_route_get_effective_metric(rt), - .rt_source = rt->rt_source, - .table_coerced = nm_platform_ip_route_get_effective_table( - NM_PLATFORM_IP_ROUTE_CAST(rt)), - })); - } else { - const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o); - - nmp_object_stackinit( - &oo, - NMP_OBJECT_TYPE_IP6_ROUTE, - &((NMPlatformIP6Route){ - .ifindex = rt->ifindex, - .network = rt->gateway, - .plen = 128, - .metric = nm_platform_ip6_route_get_effective_metric(rt), - .rt_source = rt->rt_source, - .table_coerced = nm_platform_ip_route_get_effective_table( - NM_PLATFORM_IP_ROUTE_CAST(rt)), - })); - } - - _LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct " - "route to gateway %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r), - nmp_object_to_string(&oo, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf2, - sizeof(sbuf2))); - - r2 = nm_platform_ip_route_add(self, - NMP_NLM_FLAG_APPEND - | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - &oo); - - if (r2 < 0) { - _LOG3D("route-sync: failure to add gateway IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', + conf_o, + &extack_msg); + if (r == 0) { + /* success */ + } else if (r == -EEXIST) { + /* Don't fail for EEXIST. It's not clear that the existing route + * is identical to the one that we were about to add. However, + * above we should have deleted conflicting (non-identical) routes. */ + if (_LOGD_ENABLED()) { + plat_entry = + nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o); + if (!plat_entry) { + _LOG3D("route-sync: adding route %s failed with EEXIST, however we " + "cannot find such a route", + nmp_object_to_string(conf_o, + NMP_OBJECT_TO_STRING_PUBLIC, + sbuf1, + sizeof(sbuf1))); + } else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o), + NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj), + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + != 0) { + _LOG3D("route-sync: adding route %s failed due to existing " + "(different!) route %s", nmp_object_to_string(conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof(sbuf1)), - nm_strerror(r2)); + nmp_object_to_string(plat_entry->obj, + NMP_OBJECT_TO_STRING_PUBLIC, + sbuf2, + sizeof(sbuf2))); } + } + } else { + _LOG3D( + "route-sync: failure to add IPv%c route: %s: %s%s%s%s", + vt->is_ip4 ? '4' : '6', + nmp_object_to_string(conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof(sbuf1)), + nm_strerror(r), + NM_PRINT_FMT_QUOTED(extack_msg, " (", extack_msg, ")", "")); - gateway_route_added = TRUE; - goto sync_route_add; - } else { - _LOG3W("route-sync: failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - success = FALSE; + success = FALSE; + + if (out_routes_failed) { + if (!*out_routes_failed) { + *out_routes_failed = + g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + } + g_ptr_array_add(*out_routes_failed, (gpointer) nmp_object_ref(conf_o)); } } } @@ -5325,12 +5265,12 @@ nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route) } static int -_ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack) +_ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack, char **out_extack_msg) { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; int ifindex; - _CHECK_SELF(self, klass, FALSE); + _CHECK_SELF(self, klass, -NME_BUG); /* The caller already ensures that this is a stack allocated copy, that * - stays alive for the duration of the call. @@ -5341,6 +5281,7 @@ _ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack) nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_stack), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert(!out_extack_msg || !*out_extack_msg); nm_assert(NMP_OBJECT_GET_TYPE(obj_stack) != NMP_OBJECT_TYPE_IP4_ROUTE || obj_stack->ip4_route.n_nexthops <= 1u || obj_stack->_ip4_route.extra_nexthops); @@ -5362,11 +5303,14 @@ _ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack) * is stack allocated (and the potential "extra_nexthops" array is * guaranteed to stay alive too). */ - return klass->ip_route_add(self, flags, obj_stack); + return klass->ip_route_add(self, flags, obj_stack, out_extack_msg); } int -nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *obj) +nm_platform_ip_route_add(NMPlatform *self, + NMPNlmFlags flags, + const NMPObject *obj, + char **out_extack_msg) { nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; NMPObject obj_stack; @@ -5384,7 +5328,7 @@ nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *o obj_stack._ip4_route.extra_nexthops = obj->_ip4_route.extra_nexthops; } - return _ip_route_add(self, flags, &obj_stack); + return _ip_route_add(self, flags, &obj_stack, out_extack_msg); } int @@ -5416,7 +5360,7 @@ nm_platform_ip4_route_add(NMPlatform *self, &extra_nexthops_free); } - return _ip_route_add(self, flags, &obj); + return _ip_route_add(self, flags, &obj, NULL); } int @@ -5425,7 +5369,7 @@ nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformI NMPObject obj; nmp_object_stackinit(&obj, NMP_OBJECT_TYPE_IP6_ROUTE, (const NMPlatformObject *) route); - return _ip_route_add(self, flags, &obj); + return _ip_route_add(self, flags, &obj, NULL); } gboolean @@ -5951,7 +5895,7 @@ nm_platform_vlan_qos_mapping_to_string(const char *name, /** * nm_platform_link_to_string: * @route: pointer to NMPlatformLink address structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @buf: (nullable): an optional buffer. If %NULL, a static buffer is used. * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * A method for converting an link struct into a string representation. @@ -6039,6 +5983,10 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) "%s%s" /* inet6_token */ "%s%s" /* driver */ "%s%s" /* port_data */ + " tx-queue-len %u" + " gso-max-size %u" + " gso-max-segs %u" + " gro-max-size %u" " rx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT " tx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT, link->ifindex, @@ -6072,6 +6020,10 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) link->driver ? " driver " : "", link->driver ?: "", NM_PRINT_FMT_QUOTED2(str_port_data[0] != '\0', " ", str_port_data, ""), + link->link_props.tx_queue_length, + link->link_props.gso_max_size, + link->link_props.gso_max_segments, + link->link_props.gro_max_size, link->rx_packets, link->rx_bytes, link->tx_packets, @@ -6167,6 +6119,7 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le char sbuf_miimon[30]; char sbuf_updelay[30]; char sbuf_downdelay[30]; + char sbuf_lacp_active[30]; char sbuf_peer_notif_delay[60]; char sbuf_resend_igmp[30]; char sbuf_lp_interval[30]; @@ -6201,7 +6154,9 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le " xmit_hash_policy %u" " num_gray_arp %u" " all_ports_active %u" + " arp_missed_max %u" " lacp_rate %u" + "%s" /* lacp_active */ " ad_select %u" " use_carrier %d" "%s" /* tlb_dynamic_lb */, @@ -6251,7 +6206,14 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le lnk->xmit_hash_policy, lnk->num_grat_arp, lnk->all_ports_active, + lnk->arp_missed_max, lnk->lacp_rate, + lnk->lacp_active_has || lnk->lacp_active != 0 + ? nm_sprintf_buf(sbuf_lacp_active, + " lacp_active%s %u", + !lnk->lacp_active_has ? "?" : "", + lnk->lacp_active) + : "", lnk->ad_select, (int) lnk->use_carrier, lnk->tlb_dynamic_lb_has ? nm_sprintf_buf(sbuf_tlb_dynamic_lb, @@ -6269,6 +6231,15 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le nm_strbuf_append_str(&buf, &len, nm_inet4_ntop(lnk->arp_ip_target[i], target)); } } + if (lnk->ns_ip6_targets_num > 0) { + nm_strbuf_append_str(&buf, &len, " ns_ip6_target"); + for (i = 0; i < lnk->ns_ip6_targets_num; i++) { + char target[INET6_ADDRSTRLEN]; + + nm_strbuf_append_c(&buf, &len, ' '); + nm_strbuf_append_str(&buf, &len, nm_inet6_ntop(&lnk->ns_ip6_target[i], target)); + } + } return buf; } @@ -6920,11 +6891,11 @@ _rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags) /** * nm_platform_ip4_route_to_string: * @route: pointer to NMPlatformIP4Route route structure - * @extra_nexthops: (allow-none): the route might be a ECMP multihop route + * @extra_nexthops: (nullable): the route might be a ECMP multihop route * (with n_nexthops > 1). In that case, provide the list of extra hops * to print too. It is allowed for a multihop route to omit the extra hops * by passing NULL. - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @buf: (nullable): an optional buffer. If %NULL, a static buffer is used. * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * A method for converting a route struct into a string representation. @@ -6998,7 +6969,6 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route, "%s" /* rto_min */ "%s" /* quickack */ "%s" /* mtu */ - "%s" /* r_force_commit */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -7065,8 +7035,7 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route, " mtu %s%" G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu) - : "", - route->r_force_commit ? " force-commit" : ""); + : ""); if ((n_nexthops == 1 && route->ifindex > 0) || n_nexthops == 0) { /* A plain single hop route. Nothing extra to remark. */ @@ -7116,7 +7085,7 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route, /** * nm_platform_ip6_route_to_string: * @route: pointer to NMPlatformIP6Route route structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @buf: (nullable): an optional buffer. If %NULL, a static buffer is used. * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * A method for converting a route struct into a string representation. @@ -7186,7 +7155,6 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz "%s" /* quickack */ "%s" /* mtu */ "%s" /* pref */ - "%s" /* r_force_commit */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -7253,8 +7221,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz str_pref, " pref %s", nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2))) - : "", - route->r_force_commit ? " force-commit" : ""); + : ""); return buf; } @@ -7904,6 +7871,10 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) obj->arptype, obj->inet6_addr_gen_mode_inv, obj->inet6_token, + obj->link_props.tx_queue_length, + obj->link_props.gso_max_size, + obj->link_props.gso_max_segments, + obj->link_props.gro_max_size, obj->port_kind, obj->rx_packets, obj->rx_bytes, @@ -7966,6 +7937,10 @@ nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b) if (a->l_broadcast.len) NM_CMP_FIELD_MEMCMP_LEN(a, b, l_broadcast.data, a->l_broadcast.len); NM_CMP_FIELD_MEMCMP(a, b, inet6_token); + NM_CMP_FIELD(a, b, link_props.tx_queue_length); + NM_CMP_FIELD(a, b, link_props.gso_max_size); + NM_CMP_FIELD(a, b, link_props.gso_max_segments); + NM_CMP_FIELD(a, b, link_props.gro_max_size); NM_CMP_FIELD(a, b, port_kind); switch (a->port_kind) { case NM_PORT_KIND_NONE: @@ -8032,15 +8007,19 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->ad_actor_system, obj->ad_select, obj->all_ports_active, + obj->arp_missed_max, obj->arp_ip_targets_num, obj->fail_over_mac, obj->lacp_rate, + obj->lacp_active, + obj->ns_ip6_targets_num, obj->num_grat_arp, obj->mode, obj->primary_reselect, obj->xmit_hash_policy, NM_HASH_COMBINE_BOOLS(guint16, obj->downdelay_has, + obj->lacp_active_has, obj->lp_interval_has, obj->miimon_has, obj->peer_notif_delay_has, @@ -8051,6 +8030,7 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->use_carrier)); nm_hash_update(h, obj->arp_ip_target, obj->arp_ip_targets_num * sizeof(obj->arp_ip_target[0])); + nm_hash_update(h, obj->ns_ip6_target, obj->ns_ip6_targets_num * sizeof(obj->ns_ip6_target[0])); } int @@ -8069,6 +8049,11 @@ nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) { NM_CMP_SELF(a, b); NM_CMP_FIELD(a, b, arp_ip_targets_num); + NM_CMP_FIELD(a, b, ns_ip6_targets_num); + NM_CMP_FIELD_MEMCMP_LEN(a, + b, + ns_ip6_target, + a->ns_ip6_targets_num * sizeof(a->ns_ip6_target[0])); NM_CMP_FIELD_MEMCMP_LEN(a, b, arp_ip_target, @@ -8090,13 +8075,16 @@ nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) NM_CMP_FIELD_MEMCMP(a, b, ad_actor_system); NM_CMP_FIELD(a, b, ad_select); NM_CMP_FIELD(a, b, all_ports_active); + NM_CMP_FIELD(a, b, arp_missed_max); NM_CMP_FIELD(a, b, fail_over_mac); NM_CMP_FIELD(a, b, lacp_rate); + NM_CMP_FIELD(a, b, lacp_active); NM_CMP_FIELD(a, b, num_grat_arp); NM_CMP_FIELD(a, b, mode); NM_CMP_FIELD(a, b, primary_reselect); NM_CMP_FIELD(a, b, xmit_hash_policy); NM_CMP_FIELD_BOOL(a, b, downdelay_has); + NM_CMP_FIELD_BOOL(a, b, lacp_active_has); NM_CMP_FIELD_BOOL(a, b, lp_interval_has); NM_CMP_FIELD_BOOL(a, b, miimon_has); NM_CMP_FIELD_BOOL(a, b, peer_notif_delay_has); @@ -8654,8 +8642,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, - obj->lock_mss, - obj->r_force_commit)); + obj->lock_mss)); break; } } @@ -8798,8 +8785,6 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_FIELD(a, b, initrwnd); NM_CMP_FIELD(a, b, mtu); NM_CMP_FIELD(a, b, rto_min); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) - NM_CMP_FIELD_UNSAFE(a, b, r_force_commit); break; } return 0; @@ -8899,8 +8884,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, - obj->lock_mss, - obj->r_force_commit), + obj->lock_mss), obj->window, obj->cwnd, obj->initcwnd, @@ -8990,8 +8974,6 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref)); else NM_CMP_FIELD(a, b, rt_pref); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) - NM_CMP_FIELD_UNSAFE(a, b, r_force_commit); break; } return 0; @@ -9313,7 +9295,6 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, int ifindex, guint32 route_table, guint32 route_metric, - gboolean force_commit, NMPlatformIP4Route *dst) { in_addr_t network_4; @@ -9343,15 +9324,14 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, } *dst = (NMPlatformIP4Route){ - .ifindex = ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, - .network = network_4, - .plen = addr->plen, - .pref_src = addr->address, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - .scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK), - .r_force_commit = force_commit, + .ifindex = ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, + .network = network_4, + .plen = addr->plen, + .pref_src = addr->address, + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK), }; nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst); diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index d442ad9b..aeea5c42 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -150,6 +150,21 @@ GBytes *nmp_link_address_get_as_bytes(const NMPLinkAddress *addr); #define NM_PLATFORM_LINK_OTHER_NETNS (-1) +typedef struct { + guint32 tx_queue_length; + guint32 gso_max_size; + guint32 gso_max_segments; + guint32 gro_max_size; +} NMPlatformLinkProps; + +typedef enum { + NM_PLATFORM_LINK_CHANGE_NONE = 0, + NM_PLATFORM_LINK_CHANGE_TX_QUEUE_LENGTH = (1 << 0), + NM_PLATFORM_LINK_CHANGE_GSO_MAX_SIZE = (1 << 1), + NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS = (1 << 2), + NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE = (1 << 3), +} NMPlatformLinkChangeFlags; + struct _NMPlatformObjWithIfindex { __NMPlatformObjWithIfindex_COMMON; } _nm_alignas(NMPlatformObject); @@ -166,7 +181,7 @@ typedef union { struct _NMPlatformLink { __NMPlatformObjWithIfindex_COMMON; - char name[NMP_IFNAMSIZ]; + char name[NM_IFNAMSIZ]; NMLinkType type; /* rtnl_link_get_type(), IFLA_INFO_KIND. */ @@ -214,6 +229,8 @@ struct _NMPlatformLink { guint64 tx_packets; guint64 tx_bytes; + NMPlatformLinkProps link_props; + /* an interface can only hold IFLA_INFO_SLAVE_DATA for one link type */ NMPlatformLinkPortData port_data; @@ -242,13 +259,6 @@ typedef enum { guint _nm_platform_signal_id_get(NMPlatformSignalIdType signal_type); -typedef enum { - NM_PLATFORM_SIGNAL_NONE, - NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_SIGNAL_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED, -} NMPlatformSignalChangeType; - /* Default value for adding an IPv4 route. This is also what iproute2 does. * Note that contrary to IPv6, you can add routes with metric 0 and it is even * the default. @@ -535,8 +545,8 @@ typedef struct { NMFibRuleUidRange uid_range; /* FRA_UID_RANGE */ NMFibRulePortRange sport_range; /* FRA_SPORT_RANGE */ NMFibRulePortRange dport_range; /* FRA_DPORT_RANGE */ - char iifname[NMP_IFNAMSIZ]; /* FRA_IIFNAME */ - char oifname[NMP_IFNAMSIZ]; /* FRA_OIFNAME */ + char iifname[NM_IFNAMSIZ]; /* FRA_IIFNAME */ + char oifname[NM_IFNAMSIZ]; /* FRA_OIFNAME */ guint8 addr_family; /* (struct fib_rule_hdr).family */ guint8 action; /* (struct fib_rule_hdr).action */ guint8 tos; /* (struct fib_rule_hdr).tos */ @@ -725,6 +735,13 @@ typedef struct { } NMPlatformBridgeVlan; typedef struct { + guint16 vlan_default_pvid_val; + bool vlan_filtering_val : 1; + bool vlan_default_pvid_has : 1; + bool vlan_filtering_has : 1; +} NMPlatformLinkSetBridgeInfoData; + +typedef struct { guint64 mcast_last_member_interval; guint64 mcast_membership_interval; guint64 mcast_querier_interval; @@ -756,40 +773,45 @@ extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; #define NM_BOND_MAX_ARP_TARGETS 16 typedef struct { - int primary; - in_addr_t arp_ip_target[NM_BOND_MAX_ARP_TARGETS]; - guint32 arp_all_targets; - guint32 arp_interval; - guint32 arp_validate; - guint32 downdelay; - guint32 lp_interval; - guint32 miimon; - guint32 min_links; - guint32 packets_per_port; - guint32 peer_notif_delay; - guint32 resend_igmp; - guint32 updelay; - guint16 ad_actor_sys_prio; - guint16 ad_user_port_key; - NMEtherAddr ad_actor_system; - guint8 ad_select; - guint8 all_ports_active; - guint8 arp_ip_targets_num; - guint8 fail_over_mac; - guint8 lacp_rate; - guint8 num_grat_arp; - guint8 mode; - guint8 primary_reselect; - guint8 xmit_hash_policy; - bool downdelay_has : 1; - bool lp_interval_has : 1; - bool miimon_has : 1; - bool peer_notif_delay_has : 1; - bool resend_igmp_has : 1; - bool tlb_dynamic_lb : 1; - bool tlb_dynamic_lb_has : 1; - bool updelay_has : 1; - bool use_carrier : 1; + struct in6_addr ns_ip6_target[NM_BOND_MAX_ARP_TARGETS]; + int primary; + in_addr_t arp_ip_target[NM_BOND_MAX_ARP_TARGETS]; + guint32 arp_all_targets; + guint32 arp_interval; + guint32 arp_validate; + guint32 downdelay; + guint32 lp_interval; + guint32 miimon; + guint32 min_links; + guint32 packets_per_port; + guint32 peer_notif_delay; + guint32 resend_igmp; + guint32 updelay; + guint16 ad_actor_sys_prio; + guint16 ad_user_port_key; + NMEtherAddr ad_actor_system; + guint8 ad_select; + guint8 all_ports_active; + guint8 arp_missed_max; + guint8 arp_ip_targets_num; + guint8 fail_over_mac; + guint8 lacp_active; + guint8 lacp_rate; + guint8 ns_ip6_targets_num; + guint8 num_grat_arp; + guint8 mode; + guint8 primary_reselect; + guint8 xmit_hash_policy; + bool downdelay_has : 1; + bool lacp_active_has : 1; + bool lp_interval_has : 1; + bool miimon_has : 1; + bool peer_notif_delay_has : 1; + bool resend_igmp_has : 1; + bool tlb_dynamic_lb : 1; + bool tlb_dynamic_lb_has : 1; + bool updelay_has : 1; + bool use_carrier : 1; } _nm_alignas(NMPlatformObject) NMPlatformLnkBond; typedef struct { @@ -1110,8 +1132,10 @@ typedef struct { gconstpointer extra_data); gboolean (*link_change)(NMPlatform *self, int ifindex, + NMPlatformLinkProps *props, NMPortKind port_kind, - const NMPlatformLinkPortData *port_data); + const NMPlatformLinkPortData *port_data, + NMPlatformLinkChangeFlags flags); gboolean (*link_delete)(NMPlatform *self, int ifindex); gboolean (*link_refresh)(NMPlatform *self, int ifindex); gboolean (*link_set_netns)(NMPlatform *self, int ifindex, int netns_fd); @@ -1141,6 +1165,9 @@ typedef struct { int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans); + gboolean (*link_set_bridge_info)(NMPlatform *self, + int ifindex, + const NMPlatformLinkSetBridgeInfoData *bridge_info); char *(*link_get_physical_port_id)(NMPlatform *self, int ifindex); guint (*link_get_dev_id)(NMPlatform *self, int ifindex); @@ -1241,7 +1268,8 @@ typedef struct { guint32 lifetime, guint32 preferred_lft, guint32 flags, - const char *label); + const char *label, + char **out_extack_msg); gboolean (*ip6_address_add)(NMPlatform *self, int ifindex, struct in6_addr address, @@ -1249,7 +1277,8 @@ typedef struct { struct in6_addr peer_address, guint32 lifetime, guint32 preferred_lft, - guint32 flags); + guint32 flags, + char **out_extack_msg); gboolean (*ip4_address_delete)(NMPlatform *self, int ifindex, in_addr_t address, @@ -1260,7 +1289,11 @@ typedef struct { struct in6_addr address, guint8 plen); - int (*ip_route_add)(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack); + int (*ip_route_add)(NMPlatform *self, + NMPNlmFlags flags, + NMPObject *obj_stack, + char **out_extack_msg); + int (*ip_route_get)(NMPlatform *self, int addr_family, gconstpointer address, @@ -1501,23 +1534,30 @@ const char *nm_link_type_to_string(NMLinkType link_type); #define NMP_SYSCTL_PATHID_ABSOLUTE(path) ((const char *) NULL), -1, (path) -#define NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname, path) \ - nm_sprintf_buf_unsafe_a(NM_STRLEN("net:/sys/class/net//\0") + NMP_IFNAMSIZ + ({ \ - const gsize _l = strlen(path); \ - \ - nm_assert(_l < 200); \ - _l; \ - }), \ - "net:/sys/class/net/%s/%s", \ - (ifname), \ - (path)), \ +/* Uses alloca(). Use with care. + * + * Like NMP_SYSCTL_PATHID_NETDIR_A(), but "path" must not be a string literal. + * This is the "UNSAFE" part, where there is no compile time check for the + * maximum string length. It still must be reasonably short to not overflow + * the stack (the runtime assert checks for <200 chars). */ +#define NMP_SYSCTL_PATHID_NETDIR_UNSAFE_A(dirfd, ifname, path) \ + nm_sprintf_buf_unsafe_a(NM_STRLEN("net:/sys/class/net//\0") + NM_IFNAMSIZ + ({ \ + const gsize _l = strlen(path); \ + \ + nm_assert(_l < 200); \ + _l; \ + }), \ + "net:/sys/class/net/%s/%s", \ + (ifname), \ + (path)), \ (dirfd), (path) -#define NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, path) \ - nm_sprintf_bufa(NM_STRLEN("net:/sys/class/net//" path "/\0") + NMP_IFNAMSIZ, \ - "net:/sys/class/net/%s/%s", \ - (ifname), \ - path), \ +/* Uses alloca(). Use with care. */ +#define NMP_SYSCTL_PATHID_NETDIR_A(dirfd, ifname, path) \ + nm_sprintf_bufa(NM_STRLEN("net:/sys/class/net//" path "/\0") + NM_IFNAMSIZ, \ + "net:/sys/class/net/%s/%s", \ + (ifname), \ + path), \ (dirfd), ("" path "") int nm_platform_sysctl_open_netdir(NMPlatform *self, int ifindex, char *out_ifname); @@ -1939,7 +1979,11 @@ nm_platform_link_change_flags(NMPlatform *self, int ifindex, unsigned value, gbo return nm_platform_link_change_flags_full(self, ifindex, value, set ? value : 0u); } -gboolean nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port); +gboolean nm_platform_link_change(NMPlatform *self, + int ifindex, + NMPlatformLinkProps *props, + NMPlatformLinkBondPort *bond_port, + NMPlatformLinkChangeFlags flags); gboolean nm_platform_link_get_udev_property(NMPlatform *self, int ifindex, @@ -1978,6 +2022,9 @@ gboolean nm_platform_link_set_bridge_vlans(NMPlatform *se int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans); +gboolean nm_platform_link_set_bridge_info(NMPlatform *self, + int ifindex, + const NMPlatformLinkSetBridgeInfoData *bridge_info); char *nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id(NMPlatform *self, int ifindex); @@ -2161,7 +2208,8 @@ gboolean nm_platform_ip4_address_add(NMPlatform *self, guint32 lifetime, guint32 preferred_lft, guint32 flags, - const char *label); + const char *label, + char **out_extack_msg); gboolean nm_platform_ip6_address_add(NMPlatform *self, int ifindex, struct in6_addr address, @@ -2169,7 +2217,8 @@ gboolean nm_platform_ip6_address_add(NMPlatform *self, struct in6_addr peer_address, guint32 lifetime, guint32 preferred_lft, - guint32 flags); + guint32 flags, + char **out_extack_msg); gboolean nm_platform_ip4_address_delete(NMPlatform *self, int ifindex, in_addr_t address, @@ -2282,7 +2331,23 @@ nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route return &((NMPlatformIP6Route *) route)->gateway; } -int nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route); +static inline gconstpointer +nm_platform_ip_route_get_pref_src(int addr_family, const NMPlatformIPRoute *route) +{ + nm_assert_addr_family(addr_family); + + if (!route) + return NULL; + + if (NM_IS_IPv4(addr_family)) + return &((NMPlatformIP4Route *) route)->pref_src; + return &((NMPlatformIP6Route *) route)->pref_src; +} + +int nm_platform_ip_route_add(NMPlatform *self, + NMPNlmFlags flags, + const NMPObject *route, + char **out_extack_msg); int nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route, @@ -2299,7 +2364,7 @@ gboolean nm_platform_ip_route_sync(NMPlatform *self, int ifindex, GPtrArray *routes, GPtrArray *routes_prune, - GPtrArray **out_temporary_not_available); + GPtrArray **out_routes_failed); gboolean nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 80d254b2..ffe59363 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -11,12 +11,6 @@ /*****************************************************************************/ -/* IFNAMSIZ is both defined in <linux/if.h> and <net/if.h>. In the past, these - * headers conflicted, so we cannot simply include either of them in a header-file.*/ -#define NMP_IFNAMSIZ 16 - -/*****************************************************************************/ - /* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers * that don't define it. */ #define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */ @@ -28,6 +22,15 @@ /*****************************************************************************/ typedef enum { + NM_PLATFORM_SIGNAL_NONE, + NM_PLATFORM_SIGNAL_ADDED, + NM_PLATFORM_SIGNAL_CHANGED, + NM_PLATFORM_SIGNAL_REMOVED, +} NMPlatformSignalChangeType; + +/*****************************************************************************/ + +typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, NM_PLATFORM_LINK_DUPLEX_FULL, diff --git a/src/libnm-platform/nmp-global-tracker.c b/src/libnm-platform/nmp-global-tracker.c index 3fd31e4e..b06e9fe5 100644 --- a/src/libnm-platform/nmp-global-tracker.c +++ b/src/libnm-platform/nmp-global-tracker.c @@ -540,12 +540,13 @@ _track_data_untrack(NMPGlobalTracker *self, * sync. */ obj_data->config_state = CONFIG_STATE_OWNED_BY_US; } - } else if (remove_user_tag_data && c_list_length_is(&track_data->user_tag_lst, 1)) + } else if (remove_user_tag_data && c_list_is_empty_or_single(&track_data->user_tag_lst)) g_hash_table_remove(self->by_user_tag, &track_data->user_tag); /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry * around for the next sync -- so that we can undo what we did earlier. */ - if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&track_data->obj_lst, 1)) + if (obj_data->config_state == CONFIG_STATE_NONE + && c_list_is_empty_or_single(&track_data->obj_lst)) g_hash_table_remove(self->by_obj, &track_data->obj); g_hash_table_remove(self->by_data, track_data); @@ -1101,7 +1102,7 @@ nmp_global_tracker_sync(NMPGlobalTracker *self, NMPObjectType obj_type, gboolean NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj)); } else - nm_platform_ip_route_add(self->platform, NMP_NLM_FLAG_APPEND, obj_data->obj); + nm_platform_ip_route_add(self->platform, NMP_NLM_FLAG_APPEND, obj_data->obj, NULL); } } diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 9ba027ba..7e3fb1a3 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -134,7 +134,7 @@ nm_sock_addr_union_hash_update(const NMSockAddrUnion *a, NMHashState *h) * @dst: the destination #NMSockAddrUnion. It will always be fully initialized, * to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of * error). - * @src: (allow-none): the source buffer with an sockaddr to copy. It may be unaligned in + * @src: (nullable): the source buffer with an sockaddr to copy. It may be unaligned in * memory. If not %NULL, the buffer must be at least large enough to contain * sa.sa_family, and then, depending on sa.sa_family, it must be large enough * to hold struct sockaddr_in or struct sockaddr_in6. @@ -2047,10 +2047,10 @@ nmp_cache_link_connected_for_slave(int ifindex_master, const NMPObject *slave) * @cache: the platform cache * @master: the link object, that is checked whether its connected property * needs to be toggled. - * @potential_slave: (allow-none): an additional link object that is treated + * @potential_slave: (nullable): an additional link object that is treated * as if it was inside @cache. If given, it shaddows a link in the cache * with the same ifindex. - * @ignore_slave: (allow-none): if set, the check will pretend that @ignore_slave + * @ignore_slave: (nullable): if set, the check will pretend that @ignore_slave * is not in the cache. * * NMPlatformLink has two connected flags: (master->link.flags&IFF_LOWER_UP) (as reported @@ -2114,10 +2114,10 @@ nmp_cache_link_connected_needs_toggle(const NMPCache *cache, * @cache: * @master_ifindex: the ifindex of a potential master that should be checked * whether it needs toggling. - * @potential_slave: (allow-none): passed to nmp_cache_link_connected_needs_toggle(). + * @potential_slave: (nullable): passed to nmp_cache_link_connected_needs_toggle(). * It considers @potential_slave as being inside the cache, replacing an existing * link with the same ifindex. - * @ignore_slave: (allow-onne): passed to nmp_cache_link_connected_needs_toggle(). + * @ignore_slave: (nullable): passed to nmp_cache_link_connected_needs_toggle(). * * The flag obj->link.connected depends on the state of other links in the * @cache. See also nmp_cache_link_connected_needs_toggle(). Given an ifindex @@ -2833,11 +2833,11 @@ nmp_cache_remove_netlink(NMPCache *cache, * afterwards. Hence, during a dump, every update should move the object to the * end of the list, to obtain the correct order. That means, to use NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, * instead of NM_DEDUP_MULTI_IDX_MODE_APPEND. - * @out_obj_old: (allow-none) (out): return the object with same ID as @obj_hand_over, - * that was in the cache before update. If an object is returned, the caller must - * unref it afterwards. - * @out_obj_new: (allow-none) (out): return the object from the cache after update. - * The caller must unref this object. + * @out_obj_old: (out) (optional) (nullable) (transfer full): return the object + * with same ID as @obj_hand_over, that was in the cache before update. If an + * object is returned, the caller must unref it afterwards. + * @out_obj_new: (out) (optional) (nullable) (transfer full): return the object + * from the cache after update. The caller must unref this object. * * Returns: how the cache changed. * diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index 0d5f84b3..408f0318 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -1183,21 +1183,6 @@ nm_platform_lookup_object_by_addr_family(NMPlatform *platform, /*****************************************************************************/ -static inline gboolean -nmp_object_get_force_commit(const NMPObject *obj) -{ - switch (NMP_OBJECT_GET_TYPE(obj)) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - return NMP_OBJECT_CAST_IP_ADDRESS(obj)->a_force_commit; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - return NMP_OBJECT_CAST_IP_ROUTE(obj)->r_force_commit; - default: - return nm_assert_unreachable_val(FALSE); - } -} - static inline const char * nmp_object_link_get_ifname(const NMPObject *obj) { diff --git a/src/libnm-platform/nmp-plobj.c b/src/libnm-platform/nmp-plobj.c index c27aa1fc..d3643ae1 100644 --- a/src/libnm-platform/nmp-plobj.c +++ b/src/libnm-platform/nmp-plobj.c @@ -373,7 +373,7 @@ nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr) /** * nm_platform_ip4_address_to_string: * @route: pointer to NMPlatformIP4Address address structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @buf: (nullable): an optional buffer. If %NULL, a static buffer is used. * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * A method for converting an address struct into a string representation. @@ -479,7 +479,7 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf /** * nm_platform_ip6_address_to_string: * @route: pointer to NMPlatformIP6Address address structure - * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @buf: (nullable): an optional buffer. If %NULL, a static buffer is used. * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * A method for converting an address struct into a string representation. diff --git a/src/libnm-platform/nmp-plobj.h b/src/libnm-platform/nmp-plobj.h index e149150d..35c81509 100644 --- a/src/libnm-platform/nmp-plobj.h +++ b/src/libnm-platform/nmp-plobj.h @@ -113,7 +113,7 @@ struct _NMPlatformIP4Address { * See nm_platform_ip4_broadcast_address_from_addr(). */ in_addr_t broadcast_address; - char label[NMP_IFNAMSIZ]; + char label[NM_IFNAMSIZ]; /* Whether the address is ready to be configured. By default, an address is, but this * flag may indicate that the address is just for tracking purpose only, but the ACD @@ -255,7 +255,6 @@ NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatfo int ifindex, guint32 route_table, guint32 route_metric, - gboolean force_commit, NMPlatformIP4Route *dst); typedef enum { diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 90a29045..5fc8a5dd 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -117,7 +117,6 @@ test_use_symbols(void) (void (*)(void)) nl_socket_set_passcred, (void (*)(void)) nl_socket_set_msg_buf_size, (void (*)(void)) nlmsg_get_dst, - (void (*)(void)) nl_socket_set_nonblocking, (void (*)(void)) nl_socket_set_buffer_size, (void (*)(void)) nl_socket_add_memberships, (void (*)(void)) nl_wait_for_ack, |