diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 282 | ||||
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.h | 2 | ||||
| -rw-r--r-- | src/libnm-platform/nm-netlink.c | 65 | ||||
| -rw-r--r-- | src/libnm-platform/nm-netlink.h | 52 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.c | 18 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 747 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.h | 99 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-netns.c | 20 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-object.c | 93 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-object.h | 99 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-wext.c | 2 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils.c | 2 |
12 files changed, 844 insertions, 637 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index bcf94200..78df53e7 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -80,7 +80,7 @@ enum { TCA_DEF_UNSPEC, TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, TCA_DEF_PAD, __T /*****************************************************************************/ #ifndef IFLA_PROMISCUITY - #define IFLA_PROMISCUITY 30 +#define IFLA_PROMISCUITY 30 #endif #define IFLA_NUM_TX_QUEUES 31 #define IFLA_NUM_RX_QUEUES 32 @@ -114,7 +114,7 @@ enum { TCA_DEF_UNSPEC, TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, TCA_DEF_PAD, __T #define IFLA_IPTUN_PMTUDISC 10 #define __IFLA_IPTUN_MAX 19 #ifndef IFLA_IPTUN_MAX - #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #endif #define IFLA_TUN_UNSPEC 0 @@ -136,7 +136,7 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); #define RTA_MAX (MAX((__RTA_MAX - 1), RTA_PREF)) #ifndef MACVLAN_FLAG_NOPROMISC - #define MACVLAN_FLAG_NOPROMISC 1 +#define MACVLAN_FLAG_NOPROMISC 1 #endif #define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000 @@ -145,11 +145,13 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); #define IFLA_BR_VLAN_STATS_ENABLED 41 +#define IFLA_PERM_ADDRESS 54 + /*****************************************************************************/ /* Appeared in the kernel prior to 3.13 dated 19 January, 2014 */ #ifndef ARPHRD_6LOWPAN - #define ARPHRD_6LOWPAN 825 +#define ARPHRD_6LOWPAN 825 #endif /*****************************************************************************/ @@ -267,8 +269,8 @@ struct _ifla_vf_vlan_info { /* Appeared in the kernel 4.0 dated April 12, 2015 */ #ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN - #define BRIDGE_VLAN_INFO_RANGE_BEGIN (1 << 3) /* VLAN is start of vlan range */ - #define BRIDGE_VLAN_INFO_RANGE_END (1 << 4) /* VLAN is end of vlan range */ +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1 << 3) /* VLAN is start of vlan range */ +#define BRIDGE_VLAN_INFO_RANGE_END (1 << 4) /* VLAN is end of vlan range */ #endif /*****************************************************************************/ @@ -582,25 +584,25 @@ wait_for_nl_response_to_string(WaitForNlResponseResult seq_result, switch (seq_result) { case WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN: - nm_utils_strbuf_append_str(&buf, &buf_size, "unknown"); + nm_strbuf_append_str(&buf, &buf_size, "unknown"); break; case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK: - nm_utils_strbuf_append_str(&buf, &buf_size, "success"); + nm_strbuf_append_str(&buf, &buf_size, "success"); break; case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN: - nm_utils_strbuf_append_str(&buf, &buf_size, "failure"); + nm_strbuf_append_str(&buf, &buf_size, "failure"); break; default: if (seq_result < 0) { - nm_utils_strbuf_append(&buf, - &buf_size, - "failure %d (%s%s%s)", - -((int) seq_result), - nm_strerror_native(-((int) seq_result)), - errmsg ? " - " : "", - errmsg ?: ""); + nm_strbuf_append(&buf, + &buf_size, + "failure %d (%s%s%s)", + -((int) seq_result), + nm_strerror_native(-((int) seq_result)), + errmsg ? " - " : "", + errmsg ?: ""); } else - nm_utils_strbuf_append(&buf, &buf_size, "internal failure %d", (int) seq_result); + nm_strbuf_append(&buf, &buf_size, "internal failure %d", (int) seq_result); break; } return buf0; @@ -1277,15 +1279,6 @@ _parse_af_inet6(NMPlatform * platform, token_valid = TRUE; } - /* Hack to detect support addrgenmode of the kernel. We only parse - * netlink messages that we receive from kernel, hence this check - * is valid. */ - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { - /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, - tb[IFLA_INET6_ADDR_GEN_MODE] ? 1 : -1); - } - if (tb[IFLA_INET6_ADDR_GEN_MODE]) { i6_addr_gen_mode_inv = _nm_platform_uint8_inv(nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE])); if (i6_addr_gen_mode_inv == 0) { @@ -2305,7 +2298,7 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg) { static const struct nla_policy policy[] = { [WGDEVICE_A_IFINDEX] = {.type = NLA_U32}, - [WGDEVICE_A_IFNAME] = {.type = NLA_NUL_STRING, .maxlen = IFNAMSIZ}, + [WGDEVICE_A_IFNAME] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, [WGDEVICE_A_PRIVATE_KEY] = {}, [WGDEVICE_A_PUBLIC_KEY] = {}, [WGDEVICE_A_FLAGS] = {.type = NLA_U32}, @@ -2935,6 +2928,7 @@ _new_from_nl_link(NMPlatform * platform, [IFLA_NET_NS_PID] = {.type = NLA_U32}, [IFLA_NET_NS_FD] = {.type = NLA_U32}, [IFLA_LINK_NETNSID] = {}, + [IFLA_PERM_ADDRESS] = {.type = NLA_UNSPEC}, }; const struct ifinfomsg *ifi; struct nlattr * tb[G_N_ELEMENTS(policy)]; @@ -2945,12 +2939,13 @@ _new_from_nl_link(NMPlatform * platform, gboolean * completed_from_cache = cache ? &completed_from_cache_val : NULL; const NMPObject * link_cached = NULL; const NMPObject * lnk_data = NULL; - gboolean address_complete_from_cache = TRUE; - gboolean broadcast_complete_from_cache = TRUE; - gboolean lnk_data_complete_from_cache = TRUE; - gboolean need_ext_data = FALSE; - gboolean af_inet6_token_valid = FALSE; - gboolean af_inet6_addr_gen_mode_valid = FALSE; + gboolean address_complete_from_cache = TRUE; + gboolean perm_address_complete_from_cache = TRUE; + gboolean broadcast_complete_from_cache = TRUE; + gboolean lnk_data_complete_from_cache = TRUE; + gboolean need_ext_data = FALSE; + gboolean af_inet6_token_valid = FALSE; + gboolean af_inet6_addr_gen_mode_valid = FALSE; if (!nlmsg_valid_hdr(nlh, sizeof(*ifi))) return NULL; @@ -3053,6 +3048,20 @@ _new_from_nl_link(NMPlatform * platform, address_complete_from_cache = FALSE; } + if (tb[IFLA_PERM_ADDRESS]) { + if (!_nm_platform_kernel_support_detected( + NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS)) { + /* support for IFLA_PERM_ADDRESS was added in f74877a5457d34d604dba6dbbb13c4c05bac8b93, + * kernel 5.6, 30 March 2020. + * + * We can only detect support if the attribute is present. A missing attribute + * is not conclusive. */ + _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS, 1); + } + _nmp_link_address_set(&obj->link.l_perm_address, tb[IFLA_PERM_ADDRESS]); + perm_address_complete_from_cache = FALSE; + } + if (tb[IFLA_BROADCAST]) { _nmp_link_address_set(&obj->link.l_broadcast, tb[IFLA_BROADCAST]); broadcast_complete_from_cache = FALSE; @@ -3135,8 +3144,8 @@ _new_from_nl_link(NMPlatform * platform, if (completed_from_cache && (lnk_data_complete_from_cache || need_ext_data || address_complete_from_cache - || broadcast_complete_from_cache || !af_inet6_token_valid - || !af_inet6_addr_gen_mode_valid || !tb[IFLA_STATS64])) { + || perm_address_complete_from_cache || broadcast_complete_from_cache + || !af_inet6_token_valid || !af_inet6_addr_gen_mode_valid || !tb[IFLA_STATS64])) { _lookup_cached_link(cache, obj->link.ifindex, completed_from_cache, &link_cached); if (link_cached && link_cached->_link.netlink.is_in_netlink) { if (lnk_data_complete_from_cache && link_cached->link.type == obj->link.type @@ -3160,6 +3169,8 @@ _new_from_nl_link(NMPlatform * platform, if (address_complete_from_cache) obj->link.l_address = link_cached->link.l_address; + if (perm_address_complete_from_cache) + obj->link.l_perm_address = link_cached->link.l_perm_address; if (broadcast_complete_from_cache) obj->link.l_broadcast = link_cached->link.l_broadcast; if (!af_inet6_token_valid) @@ -3572,13 +3583,6 @@ rta_multipath_done:; obj->ip_route.lock_mtu = NM_FLAGS_HAS(lock, 1 << RTAX_MTU); if (!is_v4) { - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)) { - /* Detect support for RTA_PREF by inspecting the netlink message. - * RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, - tb[RTA_PREF] ? 1 : -1); - } - if (tb[RTA_PREF]) obj->ip6_route.rt_pref = nla_get_u8(tb[RTA_PREF]); } @@ -3876,6 +3880,9 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) const struct tcmsg *tcm; nm_auto_nmpobj NMPObject *obj = NULL; + if (!nm_platform_get_cache_tc(platform)) + return NULL; + if (nlmsg_parse_arr(nlh, sizeof(*tcm), tb, policy) < 0) return NULL; @@ -3976,7 +3983,7 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) } static NMPObject * -_new_from_nl_tfilter(struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = {.type = NLA_STRING}, @@ -3985,6 +3992,9 @@ _new_from_nl_tfilter(struct nlmsghdr *nlh, gboolean id_only) NMPObject * obj = NULL; const struct tcmsg *tcm; + if (!nm_platform_get_cache_tc(platform)) + return NULL; + if (nlmsg_parse_arr(nlh, sizeof(*tcm), tb, policy) < 0) return NULL; @@ -4055,7 +4065,7 @@ nmp_object_new_from_nl(NMPlatform * platform, case RTM_NEWTFILTER: case RTM_DELTFILTER: case RTM_GETTFILTER: - return _new_from_nl_tfilter(msghdr, id_only); + return _new_from_nl_tfilter(platform, msghdr, id_only); default: return NULL; } @@ -4064,7 +4074,7 @@ nmp_object_new_from_nl(NMPlatform * platform, /*****************************************************************************/ static gboolean -_nl_msg_new_link_set_afspec(struct nl_msg *msg, int addr_gen_mode, NMUtilsIPv6IfaceId *iid) +_nl_msg_new_link_set_afspec(struct nl_msg *msg, int addr_gen_mode, const NMUtilsIPv6IfaceId *iid) { struct nlattr *af_spec; struct nlattr *af_attr; @@ -4082,11 +4092,9 @@ _nl_msg_new_link_set_afspec(struct nl_msg *msg, int addr_gen_mode, NMUtilsIPv6If NLA_PUT_U8(msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode); if (iid) { - struct in6_addr i6_token = {.s6_addr = { - 0, - }}; + struct in6_addr i6_token = IN6ADDR_ANY_INIT; - nm_utils_ipv6_addr_set_interface_identifier(&i6_token, *iid); + nm_utils_ipv6_addr_set_interface_identifier(&i6_token, iid); NLA_PUT(msg, IFLA_INET6_TOKEN, sizeof(struct in6_addr), &i6_token); } @@ -5811,13 +5819,13 @@ delayed_action_to_string_full(DelayedActionType action_type, char * buf0 = buf; const DelayedActionWaitForNlResponseData *data; - nm_utils_strbuf_append_str(&buf, &buf_size, delayed_action_to_string(action_type)); + nm_strbuf_append_str(&buf, &buf_size, delayed_action_to_string(action_type)); switch (action_type) { case DELAYED_ACTION_TYPE_MASTER_CONNECTED: - nm_utils_strbuf_append(&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT(user_data)); + nm_strbuf_append(&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT(user_data)); break; case DELAYED_ACTION_TYPE_REFRESH_LINK: - nm_utils_strbuf_append(&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT(user_data)); + nm_strbuf_append(&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT(user_data)); break; case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: data = user_data; @@ -5826,7 +5834,7 @@ delayed_action_to_string_full(DelayedActionType action_type, gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_nsec(); char b[255]; - nm_utils_strbuf_append( + nm_strbuf_append( &buf, &buf_size, " (seq %u, timeout in %s%" G_GINT64_FORMAT ".%09" G_GINT64_FORMAT @@ -5841,7 +5849,7 @@ delayed_action_to_string_full(DelayedActionType action_type, ? wait_for_nl_response_to_string(data->seq_result, NULL, b, sizeof(b)) : ""); } else - nm_utils_strbuf_append_str(&buf, &buf_size, " (any)"); + nm_strbuf_append_str(&buf, &buf_size, " (any)"); break; default: nm_assert(!user_data); @@ -5934,7 +5942,7 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform * platf guint i; guint32 next_seq_number = 0; gint64 next_timeout_abs_ns = 0; - int now_ns = 0; + gint64 now_ns = 0; for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len;) { const DelayedActionWaitForNlResponseData *data = @@ -6904,27 +6912,6 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events msghdr = nlmsg_hdr(msg); - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS) - && msghdr->nlmsg_type == RTM_NEWADDR) { - /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, - * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (nlmsg_valid_hdr(msghdr, sizeof(struct ifaddrmsg)) - && NM_IN_SET(((struct ifaddrmsg *) nlmsg_data(msghdr))->ifa_family, - AF_INET, - AF_INET6)) { - /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, - * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR - * and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14, - * dated 30 March, 2014. - * - * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy - * way to detect kernel support. */ - _nm_platform_kernel_support_init( - NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS, - !!nlmsg_find_attr(msghdr, sizeof(struct ifaddrmsg), IFA_FLAGS) ? 1 : -1); - } - } - if (!handle_events) return; @@ -7487,19 +7474,14 @@ link_change_flags(NMPlatform *platform, int ifindex, unsigned flags_mask, unsign } static int -link_set_user_ipv6ll_enabled(NMPlatform *platform, int ifindex, gboolean enabled) +link_set_inet6_addr_gen_mode(NMPlatform *platform, int ifindex, guint8 mode) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64; + char sbuf[100]; _LOGD("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s", ifindex, - nm_platform_link_inet6_addrgenmode2str(mode, NULL, 0)); - - if (!nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { - _LOGD("link: change %d: user-ipv6ll: not supported", ifindex); - return -NME_PL_OPNOTSUPP; - } + nm_platform_link_inet6_addrgenmode2str(mode, sbuf, sizeof(sbuf))); nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); if (!nlmsg || !_nl_msg_new_link_set_afspec(nlmsg, mode, NULL)) @@ -7509,7 +7491,7 @@ link_set_user_ipv6ll_enabled(NMPlatform *platform, int ifindex, gboolean enabled } static gboolean -link_set_token(NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid) +link_set_token(NMPlatform *platform, int ifindex, const NMUtilsIPv6IfaceId *iid) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; char sbuf[NM_UTILS_INET_ADDRSTRLEN]; @@ -7519,7 +7501,7 @@ link_set_token(NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid) nm_utils_inet6_interface_identifier_to_token(iid, sbuf)); nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg || !_nl_msg_new_link_set_afspec(nlmsg, -1, &iid)) + if (!nlmsg || !_nl_msg_new_link_set_afspec(nlmsg, -1, iid)) g_return_val_if_reached(FALSE); return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); @@ -7625,14 +7607,21 @@ nla_put_failure: } static gboolean -link_get_permanent_address(NMPlatform *platform, int ifindex, guint8 *buf, size_t *length) +link_get_permanent_address_ethtool(NMPlatform *platform, int ifindex, NMPLinkAddress *out_address) { nm_auto_pop_netns NMPNetns *netns = NULL; + guint8 buffer[_NM_UTILS_HWADDR_LEN_MAX]; + gsize len; if (!nm_platform_netns_push(platform, &netns)) return FALSE; - return nmp_utils_ethtool_get_permanent_address(ifindex, buf, length); + if (!nmp_utils_ethtool_get_permanent_address(ifindex, buffer, &len)) + return FALSE; + nm_assert(len <= _NM_UTILS_HWADDR_LEN_MAX); + memcpy(out_address->data, buffer, len); + out_address->len = len; + return TRUE; } static int @@ -8867,7 +8856,79 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) return -NME_UNSPEC; } -/*****************************************************************************/ +static int +tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboolean log_error) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + gs_free char * errmsg = NULL; + int nle; + char s_buf[256]; + const char * log_tag; + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct tcmsg tcm = { + .tcm_ifindex = ifindex, + .tcm_parent = parent, + }; + + switch (nlmsgtype) { + case RTM_DELQDISC: + log_tag = "do-delete-qdisc"; + break; + case RTM_DELTFILTER: + log_tag = "do-delete-tfilter"; + break; + default: + nm_assert_not_reached(); + log_tag = "do-delete-tc"; + } + + msg = nlmsg_alloc_simple(nlmsgtype, NMP_NLM_FLAG_F_ECHO); + + if (nlmsg_append_struct(msg, &tcm) < 0) + goto nla_put_failure; + + event_handler_read_netlink(platform, FALSE); + + nle = _nl_send_nlmsg(platform, + msg, + &seq_result, + &errmsg, + DELAYED_ACTION_RESPONSE_TYPE_VOID, + NULL); + 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, FALSE); + + nm_assert(seq_result); + + _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))); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + return 0; + if (seq_result < 0) + return seq_result; + return -NME_UNSPEC; + +nla_put_failure: + g_return_val_if_reached(-NME_UNSPEC); +} + +static int +qdisc_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_error) +{ + return tc_delete(platform, RTM_DELQDISC, ifindex, parent, log_error); +} static int tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tfilter) @@ -8910,6 +8971,12 @@ tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tf return -NME_UNSPEC; } +static int +tfilter_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_error) +{ + return tc_delete(platform, RTM_DELTFILTER, ifindex, parent, log_error); +} + /*****************************************************************************/ static gboolean @@ -9405,7 +9472,7 @@ constructed(GObject *_object) priv->udev_client = nm_udev_client_new(NM_MAKE_STRV("net"), handle_udev_event, platform); } - _LOGD("create (%s netns, %s, %s udev)", + _LOGD("create (%s netns, %s, %s udev, %s tc-cache)", !platform->_netns ? "ignore" : "use", !platform->_netns && nmp_netns_is_initial() ? "initial netns" @@ -9416,7 +9483,8 @@ constructed(GObject *_object) nmp_netns_get_current(), nmp_netns_get_current() == nmp_netns_get_initial() ? "/main" : "")), - nm_platform_get_use_udev(platform) ? "use" : "no"); + nm_platform_get_use_udev(platform) ? "use" : "no", + nm_platform_get_cache_tc(platform) ? "use" : "no"); priv->genl = nl_socket_alloc(); g_assert(priv->genl); @@ -9462,10 +9530,14 @@ constructed(GObject *_object) RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE, RTNLGRP_LINK, - RTNLGRP_TC, 0); g_assert(!nle); + if (nm_platform_get_cache_tc(platform)) { + nle = nl_socket_add_memberships(priv->nlh, RTNLGRP_TC, 0); + nm_assert(!nle); + } + fd = nl_socket_get_fd(priv->nlh); _LOGD("Netlink socket for events established: port=%u, fd=%d", @@ -9549,7 +9621,7 @@ path_is_read_only_fs(const char *path) } NMPlatform * -nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support) +nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean cache_tc) { gboolean use_udev = FALSE; @@ -9563,6 +9635,8 @@ nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support) use_udev, NM_PLATFORM_NETNS_SUPPORT, netns_support, + NM_PLATFORM_CACHE_TC, + cache_tc, NULL); } @@ -9639,16 +9713,16 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->link_change_flags = link_change_flags; - platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled; + platform_class->link_set_inet6_addr_gen_mode = link_set_inet6_addr_gen_mode; platform_class->link_set_token = link_set_token; - platform_class->link_set_address = link_set_address; - platform_class->link_get_permanent_address = link_get_permanent_address; - platform_class->link_set_mtu = link_set_mtu; - platform_class->link_set_name = link_set_name; - 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_address = link_set_address; + platform_class->link_get_permanent_address_ethtool = link_get_permanent_address_ethtool; + platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_name = link_set_name; + platform_class->link_set_sriov_params_async = link_set_sriov_params_async; + platform_class->link_set_sriov_vfs = link_set_sriov_vfs; + platform_class->link_set_bridge_vlans = link_set_bridge_vlans; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; @@ -9704,8 +9778,10 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->routing_rule_add = routing_rule_add; - platform_class->qdisc_add = qdisc_add; - platform_class->tfilter_add = tfilter_add; + platform_class->qdisc_add = qdisc_add; + platform_class->qdisc_delete = qdisc_delete; + platform_class->tfilter_add = tfilter_add; + platform_class->tfilter_delete = tfilter_delete; platform_class->process_events = process_events; } diff --git a/src/libnm-platform/nm-linux-platform.h b/src/libnm-platform/nm-linux-platform.h index 26c31e3e..85e06934 100644 --- a/src/libnm-platform/nm-linux-platform.h +++ b/src/libnm-platform/nm-linux-platform.h @@ -23,6 +23,6 @@ typedef struct _NMLinuxPlatformClass NMLinuxPlatformClass; GType nm_linux_platform_get_type(void); -NMPlatform *nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support); +NMPlatform *nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean cache_tc); #endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */ diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index e92c4dfe..56cde50c 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -13,7 +13,7 @@ /*****************************************************************************/ #ifndef SOL_NETLINK - #define SOL_NETLINK 270 +#define SOL_NETLINK 270 #endif /*****************************************************************************/ @@ -24,7 +24,7 @@ #define NL_NO_AUTO_ACK (1 << 5) #ifndef NETLINK_EXT_ACK - #define NETLINK_EXT_ACK 11 +#define NETLINK_EXT_ACK 11 #endif struct nl_msg { @@ -162,28 +162,28 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) } if (s) - nm_utils_strbuf_append_str(&buf, &len, s); + nm_strbuf_append_str(&buf, &len, s); else - nm_utils_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); + nm_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); flags = hdr->nlmsg_flags; if (!flags) { - nm_utils_strbuf_append_str(&buf, &len, ", flags 0"); + nm_strbuf_append_str(&buf, &len, ", flags 0"); goto flags_done; } -#define _F(f, n) \ - G_STMT_START \ - { \ - if (NM_FLAGS_ALL(flags, f)) { \ - flags &= ~(f); \ - nm_utils_strbuf_append(&buf, &len, "%s%s", prefix, n); \ - if (!flags) \ - goto flags_done; \ - prefix = ","; \ - } \ - } \ +#define _F(f, n) \ + G_STMT_START \ + { \ + if (NM_FLAGS_ALL(flags, f)) { \ + flags &= ~(f); \ + nm_strbuf_append(&buf, &len, "%s%s", prefix, n); \ + if (!flags) \ + goto flags_done; \ + prefix = ","; \ + } \ + } \ G_STMT_END prefix = ", flags "; @@ -225,11 +225,11 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) if (flags_before != flags) prefix = ";"; - nm_utils_strbuf_append(&buf, &len, "%s0x%04x", prefix, flags); + nm_strbuf_append(&buf, &len, "%s0x%04x", prefix, flags); flags_done: - nm_utils_strbuf_append(&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); + nm_strbuf_append(&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); return b; } @@ -585,21 +585,21 @@ nla_nest_end(struct nl_msg *msg, struct nlattr *start) return _nest_end(msg, start, 0); } -static const uint16_t nla_attr_minlen[NLA_TYPE_MAX + 1] = { +static const uint8_t nla_attr_minlen[NLA_TYPE_MAX + 1] = { [NLA_U8] = sizeof(uint8_t), [NLA_U16] = sizeof(uint16_t), [NLA_U32] = sizeof(uint32_t), [NLA_U64] = sizeof(uint64_t), [NLA_STRING] = 1, - [NLA_FLAG] = 0, }; static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy) { const struct nla_policy *pt; - unsigned int minlen = 0; - int type = nla_type(nla); + uint8_t minlen; + uint16_t len; + int type = nla_type(nla); if (type < 0 || type > maxtype) return 0; @@ -609,25 +609,30 @@ validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *pol if (pt->type > NLA_TYPE_MAX) g_return_val_if_reached(-NME_BUG); - if (pt->minlen) + if (pt->minlen > 0) minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) + else minlen = nla_attr_minlen[pt->type]; - if (nla_len(nla) < minlen) + len = nla_len(nla); + + if (len < minlen) return -NME_UNSPEC; - if (pt->maxlen && nla_len(nla) > pt->maxlen) + if (pt->maxlen > 0 && len > pt->maxlen) return -NME_UNSPEC; - if (pt->type == NLA_STRING) { - const char *data; + switch (pt->type) { + case NLA_STRING: + { + const char *data = nla_data(nla); nm_assert(minlen > 0); - data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') + if (data[len - 1u] != '\0') return -NME_UNSPEC; + break; + } } return 0; diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index ab355f74..00d817cd 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -21,7 +21,7 @@ #define NLMSGERR_ATTR_MAX 3 #ifndef NLM_F_ACK_TLVS - #define NLM_F_ACK_TLVS 0x200 +#define NLM_F_ACK_TLVS 0x200 #endif /*****************************************************************************/ @@ -35,15 +35,7 @@ enum { NLA_U64, /* 64 bit integer */ NLA_STRING, /* NUL terminated character string */ NLA_FLAG, /* Flag */ - NLA_MSECS, /* Micro seconds (64bit) */ NLA_NESTED, /* Nested attributes */ - NLA_NESTED_COMPAT, - NLA_NUL_STRING, - NLA_BINARY, - NLA_S8, - NLA_S16, - NLA_S32, - NLA_S64, __NLA_TYPE_MAX, }; @@ -63,10 +55,10 @@ const char *nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) struct nla_policy { /* Type of attribute or NLA_UNSPEC */ - uint16_t type; + uint8_t type; /* Minimal length of payload required */ - uint16_t minlen; + uint8_t minlen; /* Maximal length of payload allowed */ uint16_t maxlen; @@ -75,18 +67,24 @@ struct nla_policy { /*****************************************************************************/ /* static asserts that @tb and @policy are suitable arguments to nla_parse(). */ -#define _nl_static_assert_tb(tb, policy) \ - G_STMT_START \ - { \ - G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0); \ - \ +#if _NM_CC_SUPPORT_GENERIC +#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 the sizeof(NULL), - * but not both. */ \ - G_STATIC_ASSERT_EXPR((sizeof(policy) == G_N_ELEMENTS(tb) * sizeof(struct nla_policy)) \ - ^ (sizeof(policy) == sizeof(NULL))); \ - } \ + * 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)))); \ + } \ G_STMT_END +#else +#define _nl_static_assert_tb(tb, policy) G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0) +#endif /*****************************************************************************/ @@ -112,28 +110,24 @@ nla_padlen(int payload) struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen); -static inline int +static inline uint16_t nla_len(const struct nlattr *nla) { nm_assert(nla); nm_assert(nla->nla_len >= NLA_HDRLEN); - return ((int) nla->nla_len) - NLA_HDRLEN; + return nla->nla_len - ((uint16_t) NLA_HDRLEN); } static inline int nla_type(const struct nlattr *nla) { - nm_assert(nla_len(nla) >= 0); - return nla->nla_type & NLA_TYPE_MASK; } static inline void * nla_data(const struct nlattr *nla) { - nm_assert(nla_len(nla) >= 0); - return &(((char *) nla)[NLA_HDRLEN]); } @@ -219,9 +213,7 @@ nla_get_be64(const struct nlattr *nla) static inline char * nla_get_string(const struct nlattr *nla) { - nm_assert(nla_len(nla) >= 0); - - return (char *) nla_data(nla); + return nla_data(nla); } size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize); diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index ce847451..f0522736 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -308,14 +308,14 @@ _ethtool_edata_to_string(gpointer edata, gsize edata_size, char *sbuf, gsize sbu /*****************************************************************************/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - #define ethtool_cmd_speed(pedata) ((pedata)->speed) - - #define ethtool_cmd_speed_set(pedata, speed) \ - G_STMT_START \ - { \ - (pedata)->speed = (guint16) (speed); \ - } \ - G_STMT_END +#define ethtool_cmd_speed(pedata) ((pedata)->speed) + +#define ethtool_cmd_speed_set(pedata, speed) \ + G_STMT_START \ + { \ + (pedata)->speed = (guint16) (speed); \ + } \ + G_STMT_END #endif static int @@ -554,7 +554,7 @@ _ASSERT_ethtool_feature_infos(void) for (k = 0; k < inf->n_kernel_names; k++) { const char *name = inf->kernel_names[k]; - g_assert(nm_utils_strv_find_first((char **) inf->kernel_names, k, name) < 0); + g_assert(nm_strv_find_first(inf->kernel_names, k, name) < 0); /* these offload features are only informational and cannot be set from user-space * (NETIF_F_NEVER_CHANGE). We should not track them in _ethtool_feature_infos. */ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index b7a65df5..5d4ec037 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -56,6 +56,7 @@ G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIPXAdd G_STATIC_ASSERT(sizeof(((NMPLinkAddress *) NULL)->data) == _NM_UTILS_HWADDR_LEN_MAX); G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == _NM_UTILS_HWADDR_LEN_MAX); +G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UTILS_HWADDR_LEN_MAX); G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX); static const char * @@ -175,12 +176,14 @@ enum { PROP_NETNS_SUPPORT, PROP_USE_UDEV, PROP_LOG_WITH_PTR, + PROP_CACHE_TC, LAST_PROP, }; typedef struct _NMPlatformPrivate { bool use_udev : 1; bool log_with_ptr : 1; + bool cache_tc : 1; guint ip4_dev_route_blacklist_check_id; guint ip4_dev_route_blacklist_gc_timeout_id; @@ -211,6 +214,12 @@ nm_platform_get_log_with_ptr(NMPlatform *self) return NM_PLATFORM_GET_PRIVATE(self)->log_with_ptr; } +gboolean +nm_platform_get_cache_tc(NMPlatform *self) +{ + return NM_PLATFORM_GET_PRIVATE(self)->cache_tc; +} + /*****************************************************************************/ guint @@ -299,24 +308,6 @@ static const struct { const char *name; const char *desc; } _nm_platform_kernel_support_info[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = { - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS] = - { - .compile_time_default = TRUE, - .name = "EXTENDED_IFA_FLAGS", - .desc = "IPv6 temporary addresses support", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL] = - { - .compile_time_default = TRUE, - .name = "USER_IPV6LL", - .desc = "IFLA_INET6_ADDR_GEN_MODE support", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF] = - { - .compile_time_default = (RTA_MAX >= 20 /* RTA_PREF */), - .name = "RTA_PREF", - .desc = "ability to set router preference for IPv6 routes", - }, [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV] = { .compile_time_default = (FRA_MAX >= 19 /* FRA_L3MDEV */), @@ -348,6 +339,12 @@ static const struct { .name = "IFLA_BR_VLAN_STATS_ENABLE", .desc = "IFLA_BR_VLAN_STATS_ENABLE bridge link attribute", }, + [NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS] = + { + .compile_time_default = (IFLA_MAX >= 54 /* IFLA_PERM_ADDRESS */), + .name = "IFLA_PERM_ADDRESS", + .desc = "IFLA_PERM_ADDRESS netlink attribute", + }, }; int @@ -1229,25 +1226,25 @@ nm_platform_link_add(NMPlatform * self, switch (type) { case NM_LINK_TYPE_BRIDGE: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_bridge_to_string((const NMPlatformLnkBridge *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_VLAN: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_vlan_to_string((const NMPlatformLnkVlan *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_VRF: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_vrf_to_string((const NMPlatformLnkVrf *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_VXLAN: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_vxlan_to_string((const NMPlatformLnkVxlan *) extra_data, buf_p, buf_len); @@ -1257,13 +1254,13 @@ nm_platform_link_add(NMPlatform * self, break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_gre_to_string((const NMPlatformLnkGre *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_SIT: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_sit_to_string((const NMPlatformLnkSit *) extra_data, buf_p, buf_len); @@ -1271,26 +1268,26 @@ nm_platform_link_add(NMPlatform * self, case NM_LINK_TYPE_IP6TNL: case NM_LINK_TYPE_IP6GRE: case NM_LINK_TYPE_IP6GRETAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_ip6tnl_to_string((const NMPlatformLnkIp6Tnl *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_IPIP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_ipip_to_string((const NMPlatformLnkIpIp *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_MACSEC: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_macsec_to_string((const NMPlatformLnkMacsec *) extra_data, buf_p, buf_len); break; case NM_LINK_TYPE_MACVLAN: case NM_LINK_TYPE_MACVTAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_strbuf_append_str(&buf_p, &buf_len, ", "); nm_platform_lnk_macvlan_to_string((const NMPlatformLnkMacvlan *) extra_data, buf_p, buf_len); @@ -1611,7 +1608,7 @@ nm_platform_link_uses_arp(NMPlatform *self, int ifindex) * Returns: %TRUE a tokenized identifier was available */ gboolean -nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid) +nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid) { _CHECK_SELF(self, klass, FALSE); @@ -1649,47 +1646,20 @@ nm_platform_link_get_udev_device(NMPlatform *self, int ifindex) return obj_cache ? obj_cache->_link.udev.device : NULL; } -/** - * nm_platform_link_get_user_ip6vll_enabled: - * @self: platform instance - * @ifindex: Interface index - * - * Check whether NM handles IPv6LL address creation for the link. If the - * platform or OS doesn't support changing the IPv6LL address mode, this call - * will fail and return %FALSE. - * - * Returns: %TRUE if NM handles the IPv6LL address for @ifindex - */ -gboolean -nm_platform_link_get_user_ipv6ll_enabled(NMPlatform *self, int ifindex) +int +nm_platform_link_get_inet6_addr_gen_mode(NMPlatform *self, int ifindex) { - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - if (pllink && pllink->inet6_addr_gen_mode_inv) - return _nm_platform_uint8_inv(pllink->inet6_addr_gen_mode_inv) == NM_IN6_ADDR_GEN_MODE_NONE; - return FALSE; + return _nm_platform_link_get_inet6_addr_gen_mode(nm_platform_link_get(self, ifindex)); } -/** - * nm_platform_link_set_user_ip6vll_enabled: - * @self: platform instance - * @ifindex: Interface index - * - * Set whether NM handles IPv6LL address creation for the link. If the - * platform or OS doesn't support changing the IPv6LL address mode, this call - * will fail and return %FALSE. - * - * Returns: the negative nm-error on failure. - */ int -nm_platform_link_set_user_ipv6ll_enabled(NMPlatform *self, int ifindex, gboolean enabled) +nm_platform_link_set_inet6_addr_gen_mode(NMPlatform *self, int ifindex, guint8 mode) { _CHECK_SELF(self, klass, -NME_BUG); g_return_val_if_fail(ifindex > 0, -NME_BUG); - return klass->link_set_user_ipv6ll_enabled(self, ifindex, enabled); + return klass->link_set_inet6_addr_gen_mode(self, ifindex, mode); } /** @@ -1736,7 +1706,7 @@ nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length) } /** - * nm_platform_link_get_permanent_address: + * nm_platform_link_get_permanent_address_ethtool: * @self: platform instance * @ifindex: Interface index * @buf: buffer of at least %_NM_UTILS_HWADDR_LEN_MAX bytes, on success @@ -1747,23 +1717,48 @@ nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length) * address. */ gboolean -nm_platform_link_get_permanent_address(NMPlatform *self, int ifindex, guint8 *buf, size_t *length) +nm_platform_link_get_permanent_address_ethtool(NMPlatform * self, + int ifindex, + NMPLinkAddress *out_address) { _CHECK_SELF(self, klass, FALSE); - if (length) - *length = 0; + if (out_address) + out_address->len = 0; g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(buf, FALSE); - g_return_val_if_fail(length, FALSE); + g_return_val_if_fail(out_address, FALSE); - if (klass->link_get_permanent_address) - return klass->link_get_permanent_address(self, ifindex, buf, length); + if (klass->link_get_permanent_address_ethtool) + return klass->link_get_permanent_address_ethtool(self, ifindex, out_address); return FALSE; } gboolean +nm_platform_link_get_permanent_address(NMPlatform * self, + const NMPlatformLink *plink, + NMPLinkAddress * out_address) +{ + _CHECK_SELF(self, klass, FALSE); + nm_assert(out_address); + + if (!plink) + return FALSE; + if (plink->l_perm_address.len > 0) { + *out_address = plink->l_perm_address; + return TRUE; + } + if (nm_platform_kernel_support_get_full(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS, + FALSE) + == NM_OPTION_BOOL_TRUE) { + /* kernel supports the netlink API IFLA_PERM_ADDRESS, but we don't have the + * address cached. There is no need to fallback to ethtool ioctl. */ + return FALSE; + } + return nm_platform_link_get_permanent_address_ethtool(self, plink->ifindex, out_address); +} + +gboolean nm_platform_link_supports_carrier_detect(NMPlatform *self, int ifindex) { _CHECK_SELF(self, klass, FALSE); @@ -2336,13 +2331,13 @@ nm_platform_link_wireguard_change(NMPlatform * self gsize len = sizeof(buf_peers); guint i; - nm_utils_strbuf_append_str(&b, &len, " { "); + nm_strbuf_append_str(&b, &len, " { "); for (i = 0; i < peers_len; i++) { - nm_utils_strbuf_append_str(&b, &len, " { "); + nm_strbuf_append_str(&b, &len, " { "); nm_platform_wireguard_peer_to_string(&peers[i], b, len); - nm_utils_strbuf_seek_end(&b, &len); + nm_strbuf_seek_end(&b, &len); if (peer_flags) { - nm_utils_strbuf_append( + nm_strbuf_append( &b, &len, " (%s)", @@ -2350,9 +2345,9 @@ nm_platform_link_wireguard_change(NMPlatform * self buf_change_flags, sizeof(buf_change_flags))); } - nm_utils_strbuf_append_str(&b, &len, " } "); + nm_strbuf_append_str(&b, &len, " } "); } - nm_utils_strbuf_append_str(&b, &len, "}"); + nm_strbuf_append_str(&b, &len, "}"); } _LOG3D("link: change wireguard ifindex %d, %s, (%s), %u peers%s", @@ -2531,6 +2526,8 @@ slave_category(NMPlatform *self, int slave) switch (nm_platform_link_get_type(self, master)) { case NM_LINK_TYPE_BRIDGE: return "brport"; + case NM_LINK_TYPE_BOND: + return "bonding_slave"; default: return NULL; } @@ -2620,30 +2617,30 @@ nm_platform_link_vlan_change(NMPlatform * self, len = sizeof(buf); if (flags_mask) - nm_utils_strbuf_append(&b, - &len, - " flags 0x%x/0x%x", - (unsigned) flags_set, - (unsigned) flags_mask); + nm_strbuf_append(&b, + &len, + " flags 0x%x/0x%x", + (unsigned) flags_set, + (unsigned) flags_mask); if (ingress_reset_all || n_ingress_map) { - nm_utils_strbuf_append_str(&b, &len, " ingress-qos-map"); + nm_strbuf_append_str(&b, &len, " ingress-qos-map"); nm_platform_vlan_qos_mapping_to_string("", ingress_map, n_ingress_map, b, len); i = strlen(b); b += i; len -= i; if (ingress_reset_all) - nm_utils_strbuf_append_str(&b, &len, " (reset-all)"); + nm_strbuf_append_str(&b, &len, " (reset-all)"); } if (egress_reset_all || n_egress_map) { - nm_utils_strbuf_append_str(&b, &len, " egress-qos-map"); + nm_strbuf_append_str(&b, &len, " egress-qos-map"); nm_platform_vlan_qos_mapping_to_string("", egress_map, n_egress_map, b, len); i = strlen(b); b += i; len -= i; if (egress_reset_all) - nm_utils_strbuf_append_str(&b, &len, " (reset-all)"); + nm_strbuf_append_str(&b, &len, " (reset-all)"); } _LOG3D("link: change vlan %s", buf); @@ -3668,7 +3665,7 @@ _addr_array_clean_expired(int addr_family, } #endif - if (!NM_IS_IPv4(addr_family) && NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TEMPORARY)) { + if (!NM_IS_IPv4(addr_family) && NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_SECONDARY)) { /* temporary addresses are never added explicitly by NetworkManager but * kernel adds them via mngtempaddr flag. * @@ -3913,7 +3910,6 @@ nm_platform_ip_address_sync(NMPlatform *self, gs_unref_hashtable GHashTable *known_addresses_idx = NULL; GPtrArray * plat_addresses; GHashTable * known_subnets = NULL; - guint32 ifa_flags; guint i_plat; guint i_know; guint i; @@ -4140,10 +4136,6 @@ next_plat:; if (IS_IPv4) ip4_addr_subnets_destroy_index(known_subnets, known_addresses); - ifa_flags = nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS) - ? IFA_F_NOPREFIXROUTE - : 0; - /* Add missing addresses. New addresses are added by kernel with top * priority. */ @@ -4178,7 +4170,7 @@ next_plat:; nm_platform_ip4_broadcast_address_from_addr(&known_address->a4), lifetime, preferred, - ifa_flags, + IFA_F_NOPREFIXROUTE, known_address->a4.label)) { /* ignore error, for unclear reasons. */ } @@ -4190,7 +4182,7 @@ next_plat:; known_address->a6.peer_address, lifetime, preferred, - ifa_flags | known_address->a6.n_ifa_flags)) + IFA_F_NOPREFIXROUTE | known_address->a6.n_ifa_flags)) return FALSE; } } @@ -4278,7 +4270,7 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, if (!IS_IPv4) { if (exclude_ipv6_temporary_addrs - && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ADDRESS(obj)->n_ifa_flags, IFA_F_TEMPORARY)) + && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ADDRESS(obj)->n_ifa_flags, IFA_F_SECONDARY)) continue; } @@ -5311,92 +5303,13 @@ nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc return klass->qdisc_add(self, flags, qdisc); } -/** - * nm_platform_qdisc_sync: - * @self: the #NMPlatform instance - * @ifindex: the ifindex where to configure the qdiscs. - * @known_qdiscs: the list of qdiscs (#NMPObject). - * - * The function promises not to take any reference to the qdisc - * instances from @known_qdiscs, nor to keep them around after - * the function returns. This is important, because it allows the - * caller to pass NMPlatformQdisc instances which "kind" string - * have a limited lifetime. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_qdisc_sync(NMPlatform *self, int ifindex, GPtrArray *known_qdiscs) +int +nm_platform_qdisc_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error) { - gs_unref_ptrarray GPtrArray *plat_qdiscs = NULL; - NMPLookup lookup; - guint i; - gboolean success = TRUE; - gs_unref_hashtable GHashTable *known_qdiscs_idx = NULL; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex > 0); - - known_qdiscs_idx = - g_hash_table_new((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); - if (known_qdiscs) { - for (i = 0; i < known_qdiscs->len; i++) { - const NMPObject *q = g_ptr_array_index(known_qdiscs, i); - - if (!g_hash_table_insert(known_qdiscs_idx, (gpointer) q, (gpointer) q)) { - _LOGW("duplicate qdisc %s", nm_platform_qdisc_to_string(&q->qdisc, NULL, 0)); - return FALSE; - } - } - } - - plat_qdiscs = - nm_platform_lookup_clone(self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_QDISC, ifindex), - NULL, - NULL); - if (plat_qdiscs) { - for (i = 0; i < plat_qdiscs->len; i++) { - const NMPObject *p = g_ptr_array_index(plat_qdiscs, i); - const NMPObject *k; - - /* look up known qdisc with same parent */ - k = g_hash_table_lookup(known_qdiscs_idx, p); - - if (k) { - const NMPlatformQdisc *qdisc_k = NMP_OBJECT_CAST_QDISC(k); - const NMPlatformQdisc *qdisc_p = NMP_OBJECT_CAST_QDISC(p); - - /* check other fields */ - if (nm_platform_qdisc_cmp_full(qdisc_k, qdisc_p, FALSE) != 0 - || (qdisc_k->handle != qdisc_p->handle && qdisc_k != 0)) { - k = NULL; - } - } - - if (k) { - g_hash_table_remove(known_qdiscs_idx, k); - } else { - /* can't delete qdisc with zero handle */ - if (TC_H_MAJ(p->qdisc.handle) != 0) { - success &= nm_platform_object_delete(self, p); - } - } - } - } - - if (known_qdiscs) { - for (i = 0; i < known_qdiscs->len; i++) { - const NMPObject *q = g_ptr_array_index(known_qdiscs, i); - - if (g_hash_table_contains(known_qdiscs_idx, q)) { - success &= - (nm_platform_qdisc_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_QDISC(q)) >= 0); - } - } - } + _CHECK_SELF(self, klass, -NME_BUG); - return success; + _LOG3D("deleting a qdisc: parent 0x%08x", parent); + return klass->qdisc_delete(self, ifindex, parent, log_error); } /*****************************************************************************/ @@ -5414,55 +5327,58 @@ nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfi return klass->tfilter_add(self, flags, tfilter); } +int +nm_platform_tfilter_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error) +{ + _CHECK_SELF(self, klass, -NME_BUG); + + _LOG3D("deleting a tfilter: parent 0x%08x", parent); + return klass->tfilter_delete(self, ifindex, parent, log_error); +} + /** - * nm_platform_qdisc_sync: + * nm_platform_tc_sync: * @self: the #NMPlatform instance - * @ifindex: the ifindex where to configure the qdiscs. + * @ifindex: the ifindex where to configure qdiscs and filters. + * @known_qdiscs: the list of qdiscs (#NMPObject). * @known_tfilters: the list of tfilters (#NMPObject). * - * The function promises not to take any reference to the tfilter - * instances from @known_tfilters, nor to keep them around after - * the function returns. This is important, because it allows the - * caller to pass NMPlatformTfilter instances which "kind" string - * have a limited lifetime. + * The function promises not to take any reference to the + * instances from @known_qdiscs and @known_tfilters, nor to + * keep them around after the function returns. This is important, + * because it allows the caller to pass NMPlatformQdisc and + * NMPlatformTfilter instances which "kind" string have a limited + * lifetime. * * Returns: %TRUE on success. */ gboolean -nm_platform_tfilter_sync(NMPlatform *self, int ifindex, GPtrArray *known_tfilters) +nm_platform_tc_sync(NMPlatform *self, + int ifindex, + GPtrArray * known_qdiscs, + GPtrArray * known_tfilters) { - gs_unref_ptrarray GPtrArray *plat_tfilters = NULL; - NMPLookup lookup; - guint i; - gboolean success = TRUE; - gs_unref_hashtable GHashTable *known_tfilters_idx = NULL; + guint i; + gboolean success = TRUE; nm_assert(NM_IS_PLATFORM(self)); nm_assert(ifindex > 0); - known_tfilters_idx = - g_hash_table_new((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); - - if (known_tfilters) { - for (i = 0; i < known_tfilters->len; i++) { - const NMPObject *q = g_ptr_array_index(known_tfilters, i); - - g_hash_table_insert(known_tfilters_idx, (gpointer) q, (gpointer) q); - } - } + nm_platform_qdisc_delete(self, ifindex, TC_H_ROOT, FALSE); + nm_platform_qdisc_delete(self, ifindex, TC_H_INGRESS, FALSE); - plat_tfilters = - nm_platform_lookup_clone(self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_TFILTER, ifindex), - NULL, - NULL); + /* At this point we can only have a root default qdisc + * (which can't be deleted). Ensure it doesn't have any + * filters attached. + */ + nm_platform_tfilter_delete(self, ifindex, TC_H_ROOT, FALSE); - if (plat_tfilters) { - for (i = 0; i < plat_tfilters->len; i++) { - const NMPObject *q = g_ptr_array_index(plat_tfilters, i); + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index(known_qdiscs, i); - if (!g_hash_table_lookup(known_tfilters_idx, q)) - success &= nm_platform_object_delete(self, q); + success &= + (nm_platform_qdisc_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_QDISC(q)) >= 0); } } @@ -5493,7 +5409,7 @@ nm_platform_vlan_qos_mapping_to_string(const char * name, nm_utils_to_string_buffer_init(&buf, &len); if (!n_map) { - nm_utils_strbuf_append_str(&buf, &len, ""); + nm_strbuf_append_str(&buf, &len, ""); return buf; } @@ -5503,14 +5419,14 @@ nm_platform_vlan_qos_mapping_to_string(const char * name, b = buf; if (name) { - nm_utils_strbuf_append_str(&b, &len, name); - nm_utils_strbuf_append_str(&b, &len, " {"); + nm_strbuf_append_str(&b, &len, name); + nm_strbuf_append_str(&b, &len, " {"); } else - nm_utils_strbuf_append_c(&b, &len, '{'); + nm_strbuf_append_c(&b, &len, '{'); for (i = 0; i < n_map; i++) - nm_utils_strbuf_append(&b, &len, " %u:%u", map[i].from, map[i].to); - nm_utils_strbuf_append_str(&b, &len, " }"); + nm_strbuf_append(&b, &len, " %u:%u", map[i].from, map[i].to); + nm_strbuf_append_str(&b, &len, " }"); return buf; } @@ -5566,6 +5482,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) gsize l; char str_addrmode[30]; char str_address[_NM_UTILS_HWADDR_LEN_MAX * 3]; + char str_perm_address[_NM_UTILS_HWADDR_LEN_MAX * 3]; char str_broadcast[_NM_UTILS_HWADDR_LEN_MAX * 3]; char str_inet6_token[NM_UTILS_INET_ADDRSTRLEN]; const char *str_link_type; @@ -5576,13 +5493,13 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) s = str_highlighted_flags; l = sizeof(str_highlighted_flags); if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_NOARP)) - nm_utils_strbuf_append_str(&s, &l, "NOARP,"); + nm_strbuf_append_str(&s, &l, "NOARP,"); if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_UP)) - nm_utils_strbuf_append_str(&s, &l, "UP"); + nm_strbuf_append_str(&s, &l, "UP"); else - nm_utils_strbuf_append_str(&s, &l, "DOWN"); + nm_strbuf_append_str(&s, &l, "DOWN"); if (link->connected) - nm_utils_strbuf_append_str(&s, &l, ",LOWER_UP"); + nm_strbuf_append_str(&s, &l, ",LOWER_UP"); nm_assert(s > str_highlighted_flags && l > 0); if (link->n_ifi_flags) { @@ -5604,6 +5521,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) parent[0] = 0; _nmp_link_address_to_string(&link->l_address, str_address); + _nmp_link_address_to_string(&link->l_perm_address, str_perm_address); _nmp_link_address_to_string(&link->l_broadcast, str_broadcast); str_link_type = nm_link_type_to_string(link->type); @@ -5623,6 +5541,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) "%s" /* is-in-udev */ "%s%s" /* addr-gen-mode */ "%s%s" /* l_address */ + "%s%s" /* l_perm_address */ "%s%s" /* l_broadcast */ "%s%s" /* inet6_token */ "%s%s" /* driver */ @@ -5648,11 +5567,13 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) : "", str_address[0] ? " addr " : "", str_address[0] ? str_address : "", + str_perm_address[0] ? " permaddr " : "", + str_perm_address[0] ? str_perm_address : "", str_broadcast[0] ? " brd " : "", str_broadcast[0] ? str_broadcast : "", link->inet6_token.id ? " inet6token " : "", link->inet6_token.id - ? nm_utils_inet6_interface_identifier_to_token(link->inet6_token, str_inet6_token) + ? nm_utils_inet6_interface_identifier_to_token(&link->inet6_token, str_inet6_token) : "", link->driver ? " driver " : "", link->driver ?: "", @@ -6067,9 +5988,9 @@ nm_platform_lnk_vlan_to_string(const NMPlatformLnkVlan *lnk, char *buf, gsize le b = buf; - nm_utils_strbuf_append(&b, &len, "vlan %u", lnk->id); + nm_strbuf_append(&b, &len, "vlan %u", lnk->id); if (lnk->flags) - nm_utils_strbuf_append(&b, &len, " flags 0x%x", lnk->flags); + nm_strbuf_append(&b, &len, " flags 0x%x", lnk->flags); return buf; } @@ -6083,7 +6004,7 @@ nm_platform_lnk_vrf_to_string(const NMPlatformLnkVrf *lnk, char *buf, gsize len) b = buf; - nm_utils_strbuf_append(&b, &len, "table %u", lnk->table); + nm_strbuf_append(&b, &len, "table %u", lnk->table); return buf; } @@ -6208,36 +6129,36 @@ nm_platform_wireguard_peer_to_string(const NMPWireGuardPeer *peer, char *buf, gs } else s_endpoint[0] = '\0'; - nm_utils_strbuf_append( - &buf, - &len, - "public-key %s" - "%s" /* preshared-key */ - "%s" /* endpoint */ - " rx %" G_GUINT64_FORMAT " tx %" G_GUINT64_FORMAT "%s" /* persistent-keepalive */ - "%s", /* allowed-ips */ - public_key_b64, - nm_utils_memeqzero_secret(peer->preshared_key, sizeof(peer->preshared_key)) - ? "" - : " preshared-key (hidden)", - s_endpoint, - peer->rx_bytes, - peer->tx_bytes, - peer->persistent_keepalive_interval > 0 - ? nm_sprintf_buf(s_keepalive, - " keepalive %u", - (guint) peer->persistent_keepalive_interval) - : "", - peer->allowed_ips_len > 0 ? " allowed-ips" : ""); + nm_strbuf_append(&buf, + &len, + "public-key %s" + "%s" /* preshared-key */ + "%s" /* endpoint */ + " rx %" G_GUINT64_FORMAT " tx %" G_GUINT64_FORMAT + "%s" /* persistent-keepalive */ + "%s", /* allowed-ips */ + public_key_b64, + nm_utils_memeqzero_secret(peer->preshared_key, sizeof(peer->preshared_key)) + ? "" + : " preshared-key (hidden)", + s_endpoint, + peer->rx_bytes, + peer->tx_bytes, + peer->persistent_keepalive_interval > 0 + ? nm_sprintf_buf(s_keepalive, + " keepalive %u", + (guint) peer->persistent_keepalive_interval) + : "", + peer->allowed_ips_len > 0 ? " allowed-ips" : ""); for (i = 0; i < peer->allowed_ips_len; i++) { const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i]; - nm_utils_strbuf_append(&buf, - &len, - " %s/%u", - nm_utils_inet_ntop(allowed_ip->family, &allowed_ip->addr, s_addr), - allowed_ip->mask); + nm_strbuf_append(&buf, + &len, + " %s/%u", + nm_utils_inet_ntop(allowed_ip->family, &allowed_ip->addr, s_addr), + allowed_ip->mask); } return buf0; @@ -6353,7 +6274,8 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf "%s" /* label */ " src %s" "%s" /* external */ - "%s" /* ip4acd_not_ready */ + "%s" /* a_acd_not_ready */ + "%s" /* a_assume_config_once */ "", s_address, address->plen, @@ -6372,7 +6294,8 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf str_label, nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), address->external ? " ext" : "", - address->ip4acd_not_ready ? " ip4acd-not-ready" : ""); + address->a_acd_not_ready ? " ip4acd-not-ready" : "", + address->a_assume_config_once ? " assume-config-once" : ""); g_free(str_peer); return buf; } @@ -6406,17 +6329,22 @@ NM_UTILS_ENUM2STR_DEFINE(nm_platform_link_inet6_addrgenmode2str, NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY, "stable-privacy"), NM_UTILS_ENUM2STR(NM_IN6_ADDR_GEN_MODE_RANDOM, "random"), ); +G_STATIC_ASSERT(IFA_F_SECONDARY == IFA_F_TEMPORARY); + NM_UTILS_FLAGS2STR_DEFINE(nm_platform_addr_flags2str, unsigned, NM_UTILS_FLAGS2STR(IFA_F_SECONDARY, "secondary"), NM_UTILS_FLAGS2STR(IFA_F_NODAD, "nodad"), NM_UTILS_FLAGS2STR(IFA_F_OPTIMISTIC, "optimistic"), + NM_UTILS_FLAGS2STR(IFA_F_DADFAILED, "dadfailed"), NM_UTILS_FLAGS2STR(IFA_F_HOMEADDRESS, "homeaddress"), NM_UTILS_FLAGS2STR(IFA_F_DEPRECATED, "deprecated"), + NM_UTILS_FLAGS2STR(IFA_F_TENTATIVE, "tentative"), NM_UTILS_FLAGS2STR(IFA_F_PERMANENT, "permanent"), NM_UTILS_FLAGS2STR(IFA_F_MANAGETEMPADDR, "mngtmpaddr"), NM_UTILS_FLAGS2STR(IFA_F_NOPREFIXROUTE, "noprefixroute"), - NM_UTILS_FLAGS2STR(IFA_F_TENTATIVE, "tentative"), ); + NM_UTILS_FLAGS2STR(IFA_F_MCAUTOJOIN, "mcautojoin"), + NM_UTILS_FLAGS2STR(IFA_F_STABLE_PRIVACY, "stable-privacy"), ); NM_UTILS_ENUM2STR_DEFINE(nm_platform_route_scope2str, int, @@ -6486,7 +6414,10 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf g_snprintf( buf, len, - "%s/%d lft %s pref %s%s%s%s%s src %s%s", + "%s/%d lft %s pref %s%s%s%s%s src %s" + "%s" /* external */ + "%s" /* a_assume_config_once */ + "", s_address, address->plen, str_lft_p, @@ -6496,7 +6427,8 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf str_dev, _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->external ? " ext" : ""); + address->external ? " external" : "", + address->a_assume_config_once ? " assume-config-once" : ""); g_free(str_peer); return buf; } @@ -6529,7 +6461,7 @@ _rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags) if (!rtm_flags) return ""; - nm_utils_strbuf_append_str(&buf, &buf_size, " rtm_flags "); + nm_strbuf_append_str(&buf, &buf_size, " rtm_flags "); _rtm_flags_to_string(rtm_flags, buf, buf_size); nm_assert(strlen(buf) < buf_size); return buf0; @@ -6588,6 +6520,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz "%s" /* initrwnd */ "%s" /* mtu */ "%s" /* is_external */ + "%s" /* r_assume_config_once */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -6644,7 +6577,8 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz route->lock_mtu ? "lock " : "", route->mtu) : "", - route->is_external ? " (E)" : ""); + route->is_external ? " is-external" : "", + route->r_assume_config_once ? " assume-config-once" : ""); return buf; } @@ -6715,6 +6649,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz "%s" /* mtu */ "%s" /* pref */ "%s" /* is_external */ + "%s" /* r_assume_config_once */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -6775,7 +6710,8 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz " pref %s", nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2))) : "", - route->is_external ? " (E)" : ""); + route->is_external ? " is-external" : "", + route->r_assume_config_once ? " assume-config-once" : ""); return buf; } @@ -6801,18 +6737,18 @@ _routing_rule_addr_to_string(char ** buf, if (plen == 0 && is_zero) { if (is_src) - nm_utils_strbuf_append_str(buf, len, " from all"); + nm_strbuf_append_str(buf, len, " from all"); else - nm_utils_strbuf_append_str(buf, len, ""); + nm_strbuf_append_str(buf, len, ""); return; } - nm_utils_strbuf_append_str(buf, len, is_src ? " from " : " to "); + nm_strbuf_append_str(buf, len, is_src ? " from " : " to "); - nm_utils_strbuf_append_str(buf, len, nm_utils_inet_ntop(addr_family, addr, s_addr)); + nm_strbuf_append_str(buf, len, nm_utils_inet_ntop(addr_family, addr, s_addr)); if (plen != (addr_size * 8)) - nm_utils_strbuf_append(buf, len, "/%u", plen); + nm_strbuf_append(buf, len, "/%u", plen); } static void @@ -6822,11 +6758,11 @@ _routing_rule_port_range_to_string(char ** buf, const char * name) { if (port_range->start == 0 && port_range->end == 0) - nm_utils_strbuf_append_str(buf, len, ""); + nm_strbuf_append_str(buf, len, ""); else { - nm_utils_strbuf_append(buf, len, " %s %u", name, port_range->start); + nm_strbuf_append(buf, len, " %s %u", name, port_range->start); if (port_range->start != port_range->end) - nm_utils_strbuf_append(buf, len, "-%u", port_range->end); + nm_strbuf_append(buf, len, "-%u", port_range->end); } } @@ -6853,14 +6789,14 @@ nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, ch rr_flags = routing_rule->flags; rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_INVERT); - nm_utils_strbuf_append(&buf, - &len, - "[%c] " /* addr-family */ - "%u:" /* priority */ - "%s", /* not/FIB_RULE_INVERT */ - nm_utils_addr_family_to_char(routing_rule->addr_family), - routing_rule->priority, - (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_INVERT) ? " not" : "")); + nm_strbuf_append(&buf, + &len, + "[%c] " /* addr-family */ + "%u:" /* priority */ + "%s", /* not/FIB_RULE_INVERT */ + nm_utils_addr_family_to_char(routing_rule->addr_family), + routing_rule->priority, + (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_INVERT) ? " not" : "")); _routing_rule_addr_to_string(&buf, &len, @@ -6877,53 +6813,53 @@ nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, ch FALSE); if (routing_rule->tos) - nm_utils_strbuf_append(&buf, &len, " tos 0x%02x", routing_rule->tos); + nm_strbuf_append(&buf, &len, " tos 0x%02x", routing_rule->tos); if (routing_rule->fwmark != 0 || routing_rule->fwmask != 0) { - nm_utils_strbuf_append(&buf, &len, " fwmark %#x", (unsigned) routing_rule->fwmark); + nm_strbuf_append(&buf, &len, " fwmark %#x", (unsigned) routing_rule->fwmark); if (routing_rule->fwmark != 0xFFFFFFFFu) - nm_utils_strbuf_append(&buf, &len, "/%#x", (unsigned) routing_rule->fwmask); + nm_strbuf_append(&buf, &len, "/%#x", (unsigned) routing_rule->fwmask); } if (routing_rule->iifname[0]) { - nm_utils_strbuf_append(&buf, &len, " iif %s", routing_rule->iifname); + nm_strbuf_append(&buf, &len, " iif %s", routing_rule->iifname); rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_IIF_DETACHED); if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_IIF_DETACHED)) - nm_utils_strbuf_append_str(&buf, &len, " [detached]"); + nm_strbuf_append_str(&buf, &len, " [detached]"); } if (routing_rule->oifname[0]) { - nm_utils_strbuf_append(&buf, &len, " oif %s", routing_rule->oifname); + nm_strbuf_append(&buf, &len, " oif %s", routing_rule->oifname); rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_OIF_DETACHED); if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_OIF_DETACHED)) - nm_utils_strbuf_append_str(&buf, &len, " [detached]"); + nm_strbuf_append_str(&buf, &len, " [detached]"); } if (routing_rule->l3mdev != 0) { if (routing_rule->l3mdev == 1) - nm_utils_strbuf_append_str(&buf, &len, " lookup [l3mdev-table]"); + nm_strbuf_append_str(&buf, &len, " lookup [l3mdev-table]"); else { - nm_utils_strbuf_append(&buf, - &len, - " lookup [l3mdev-table/%u]", - (unsigned) routing_rule->l3mdev); + nm_strbuf_append(&buf, + &len, + " lookup [l3mdev-table/%u]", + (unsigned) routing_rule->l3mdev); } } if (routing_rule->uid_range_has || routing_rule->uid_range.start || routing_rule->uid_range.end) { - nm_utils_strbuf_append(&buf, - &len, - " uidrange %u-%u%s", - routing_rule->uid_range.start, - routing_rule->uid_range.end, - routing_rule->uid_range_has ? "" : "(?)"); + nm_strbuf_append(&buf, + &len, + " uidrange %u-%u%s", + routing_rule->uid_range.start, + routing_rule->uid_range.end, + routing_rule->uid_range_has ? "" : "(?)"); } if (routing_rule->ip_proto != 0) { /* we don't call getprotobynumber(), just print the numeric value. * This differs from what ip-rule prints. */ - nm_utils_strbuf_append(&buf, &len, " ipproto %u", routing_rule->ip_proto); + nm_strbuf_append(&buf, &len, " ipproto %u", routing_rule->ip_proto); } _routing_rule_port_range_to_string(&buf, &len, &routing_rule->sport_range, "sport"); @@ -6931,25 +6867,25 @@ nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, ch _routing_rule_port_range_to_string(&buf, &len, &routing_rule->dport_range, "dport"); if (routing_rule->tun_id != 0) { - nm_utils_strbuf_append(&buf, &len, " tun_id %" G_GUINT64_FORMAT, routing_rule->tun_id); + nm_strbuf_append(&buf, &len, " tun_id %" G_GUINT64_FORMAT, routing_rule->tun_id); } if (routing_rule->table != 0) { - nm_utils_strbuf_append(&buf, &len, " lookup %u", routing_rule->table); + nm_strbuf_append(&buf, &len, " lookup %u", routing_rule->table); } if (routing_rule->suppress_prefixlen_inverse != 0) { - nm_utils_strbuf_append(&buf, - &len, - " suppress_prefixlen %d", - (int) (~routing_rule->suppress_prefixlen_inverse)); + nm_strbuf_append(&buf, + &len, + " suppress_prefixlen %d", + (int) (~routing_rule->suppress_prefixlen_inverse)); } if (routing_rule->suppress_ifgroup_inverse != 0) { - nm_utils_strbuf_append(&buf, - &len, - " suppress_ifgroup %d", - (int) (~routing_rule->suppress_ifgroup_inverse)); + nm_strbuf_append(&buf, + &len, + " suppress_ifgroup %d", + (int) (~routing_rule->suppress_ifgroup_inverse)); } if (routing_rule->flow) { @@ -6958,7 +6894,7 @@ nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, ch * * We don't follow the style how ip-rule prints flow/realms. It's confusing. Just * print the value hex. */ - nm_utils_strbuf_append(&buf, &len, " realms 0x%08x", routing_rule->flow); + nm_strbuf_append(&buf, &len, " realms 0x%08x", routing_rule->flow); } if (routing_rule->action == RTN_NAT) { @@ -6966,36 +6902,36 @@ nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, ch /* NAT is deprecated for many years. We don't support RTA_GATEWAY/FRA_UNUSED2 * for the gateway, and so do recent kernels ignore that parameter. */ - nm_utils_strbuf_append_str(&buf, &len, " masquerade"); + nm_strbuf_append_str(&buf, &len, " masquerade"); } else if (routing_rule->action == FR_ACT_GOTO) { if (routing_rule->goto_target != 0) - nm_utils_strbuf_append(&buf, &len, " goto %u", routing_rule->goto_target); + nm_strbuf_append(&buf, &len, " goto %u", routing_rule->goto_target); else - nm_utils_strbuf_append_str(&buf, &len, " goto none"); + nm_strbuf_append_str(&buf, &len, " goto none"); rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_UNRESOLVED); if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_UNRESOLVED)) - nm_utils_strbuf_append_str(&buf, &len, " unresolved"); + nm_strbuf_append_str(&buf, &len, " unresolved"); } else if (routing_rule->action != FR_ACT_TO_TBL) { char ss_buf[60]; - nm_utils_strbuf_append(&buf, - &len, - " %s", - nm_net_aux_rtnl_rtntype_n2a(routing_rule->action) - ?: nm_sprintf_buf(ss_buf, "action-%u", routing_rule->action)); + nm_strbuf_append(&buf, + &len, + " %s", + nm_net_aux_rtnl_rtntype_n2a(routing_rule->action) + ?: nm_sprintf_buf(ss_buf, "action-%u", routing_rule->action)); } if (routing_rule->protocol != RTPROT_UNSPEC) - nm_utils_strbuf_append(&buf, &len, " protocol %u", routing_rule->protocol); + nm_strbuf_append(&buf, &len, " protocol %u", routing_rule->protocol); if (routing_rule->goto_target != 0 && routing_rule->action != FR_ACT_GOTO) { /* a trailing target is set for an unexpected action. Print it. */ - nm_utils_strbuf_append(&buf, &len, " goto-target %u", routing_rule->goto_target); + nm_strbuf_append(&buf, &len, " goto-target %u", routing_rule->goto_target); } if (rr_flags != 0) { /* we have some flags we didn't print about yet. */ - nm_utils_strbuf_append(&buf, &len, " remaining-flags %x", rr_flags); + nm_strbuf_append(&buf, &len, " remaining-flags %x", rr_flags); } return buf0; @@ -7012,53 +6948,53 @@ nm_platform_qdisc_to_string(const NMPlatformQdisc *qdisc, char *buf, gsize len) buf0 = buf; - nm_utils_strbuf_append(&buf, - &len, - "%s%s family %u handle %x parent %x info %x", - qdisc->kind, - _to_string_dev(NULL, qdisc->ifindex, str_dev, sizeof(str_dev)), - qdisc->addr_family, - qdisc->handle, - qdisc->parent, - qdisc->info); + nm_strbuf_append(&buf, + &len, + "%s%s family %u handle %x parent %x info %x", + qdisc->kind, + _to_string_dev(NULL, qdisc->ifindex, str_dev, sizeof(str_dev)), + qdisc->addr_family, + qdisc->handle, + qdisc->parent, + qdisc->info); if (nm_streq0(qdisc->kind, "fq_codel")) { if (qdisc->fq_codel.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", qdisc->fq_codel.limit); + nm_strbuf_append(&buf, &len, " limit %u", qdisc->fq_codel.limit); if (qdisc->fq_codel.flows) - nm_utils_strbuf_append(&buf, &len, " flows %u", qdisc->fq_codel.flows); + nm_strbuf_append(&buf, &len, " flows %u", qdisc->fq_codel.flows); if (qdisc->fq_codel.target) - nm_utils_strbuf_append(&buf, &len, " target %u", qdisc->fq_codel.target); + nm_strbuf_append(&buf, &len, " target %u", qdisc->fq_codel.target); if (qdisc->fq_codel.interval) - nm_utils_strbuf_append(&buf, &len, " interval %u", qdisc->fq_codel.interval); + nm_strbuf_append(&buf, &len, " interval %u", qdisc->fq_codel.interval); if (qdisc->fq_codel.quantum) - nm_utils_strbuf_append(&buf, &len, " quantum %u", qdisc->fq_codel.quantum); + nm_strbuf_append(&buf, &len, " quantum %u", qdisc->fq_codel.quantum); if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) - nm_utils_strbuf_append(&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold); + nm_strbuf_append(&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold); if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET) - nm_utils_strbuf_append(&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit); + nm_strbuf_append(&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit); if (qdisc->fq_codel.ecn) - nm_utils_strbuf_append(&buf, &len, " ecn"); + nm_strbuf_append(&buf, &len, " ecn"); } else if (nm_streq0(qdisc->kind, "sfq")) { if (qdisc->sfq.quantum) - nm_utils_strbuf_append(&buf, &len, " quantum %u", qdisc->sfq.quantum); + nm_strbuf_append(&buf, &len, " quantum %u", qdisc->sfq.quantum); if (qdisc->sfq.perturb_period) - nm_utils_strbuf_append(&buf, &len, " perturb %d", qdisc->sfq.perturb_period); + nm_strbuf_append(&buf, &len, " perturb %d", qdisc->sfq.perturb_period); if (qdisc->sfq.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", (guint) qdisc->sfq.limit); + nm_strbuf_append(&buf, &len, " limit %u", (guint) qdisc->sfq.limit); if (qdisc->sfq.divisor) - nm_utils_strbuf_append(&buf, &len, " divisor %u", qdisc->sfq.divisor); + nm_strbuf_append(&buf, &len, " divisor %u", qdisc->sfq.divisor); if (qdisc->sfq.flows) - nm_utils_strbuf_append(&buf, &len, " flows %u", qdisc->sfq.flows); + nm_strbuf_append(&buf, &len, " flows %u", qdisc->sfq.flows); if (qdisc->sfq.depth) - nm_utils_strbuf_append(&buf, &len, " depth %u", qdisc->sfq.depth); + nm_strbuf_append(&buf, &len, " depth %u", qdisc->sfq.depth); } else if (nm_streq0(qdisc->kind, "tbf")) { - nm_utils_strbuf_append(&buf, &len, " rate %" G_GUINT64_FORMAT, qdisc->tbf.rate); - nm_utils_strbuf_append(&buf, &len, " burst %u", qdisc->tbf.burst); + nm_strbuf_append(&buf, &len, " rate %" G_GUINT64_FORMAT, qdisc->tbf.rate); + nm_strbuf_append(&buf, &len, " burst %u", qdisc->tbf.burst); if (qdisc->tbf.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", qdisc->tbf.limit); + nm_strbuf_append(&buf, &len, " limit %u", qdisc->tbf.limit); if (qdisc->tbf.latency) - nm_utils_strbuf_append(&buf, &len, " latency %uns", qdisc->tbf.latency); + nm_strbuf_append(&buf, &len, " latency %uns", qdisc->tbf.latency); } return buf0; @@ -7153,11 +7089,11 @@ nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize p = act_buf; l = sizeof(act_buf); - nm_utils_strbuf_append(&p, &l, " \"%s\"", tfilter->action.kind); + nm_strbuf_append(&p, &l, " \"%s\"", tfilter->action.kind); if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { gs_free char *t = NULL; - nm_utils_strbuf_append( + nm_strbuf_append( &p, &l, " (\"%s\")", @@ -7166,14 +7102,14 @@ nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, &t)); } else if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { - nm_utils_strbuf_append(&p, - &l, - "%s%s%s%s dev %d", - tfilter->action.mirred.ingress ? " ingress" : "", - tfilter->action.mirred.egress ? " egress" : "", - tfilter->action.mirred.mirror ? " mirror" : "", - tfilter->action.mirred.redirect ? " redirect" : "", - tfilter->action.mirred.ifindex); + nm_strbuf_append(&p, + &l, + "%s%s%s%s dev %d", + tfilter->action.mirred.ingress ? " ingress" : "", + tfilter->action.mirred.egress ? " egress" : "", + tfilter->action.mirred.mirror ? " mirror" : "", + tfilter->action.mirred.redirect ? " redirect" : "", + tfilter->action.mirred.ifindex); } } else act_buf[0] = '\0'; @@ -7345,6 +7281,9 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) obj->l_address.data, NM_MIN(obj->l_address.len, sizeof(obj->l_address.data))); nm_hash_update_mem(h, + obj->l_perm_address.data, + NM_MIN(obj->l_perm_address.len, sizeof(obj->l_perm_address.data))); + nm_hash_update_mem(h, obj->l_broadcast.data, NM_MIN(obj->l_broadcast.len, sizeof(obj->l_broadcast.data))); } @@ -7364,12 +7303,15 @@ nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b) NM_CMP_FIELD_BOOL(a, b, initialized); NM_CMP_FIELD(a, b, arptype); NM_CMP_FIELD(a, b, l_address.len); + NM_CMP_FIELD(a, b, l_perm_address.len); NM_CMP_FIELD(a, b, l_broadcast.len); NM_CMP_FIELD(a, b, inet6_addr_gen_mode_inv); NM_CMP_FIELD_STR_INTERNED(a, b, kind); NM_CMP_FIELD_STR_INTERNED(a, b, driver); if (a->l_address.len) NM_CMP_FIELD_MEMCMP_LEN(a, b, l_address.data, a->l_address.len); + if (a->l_perm_address.len) + NM_CMP_FIELD_MEMCMP_LEN(a, b, l_perm_address.data, a->l_perm_address.len); 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); @@ -7853,20 +7795,20 @@ nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, NM_CMP_DIRECT(_address_pretty_sort_get_prio_6(&a2->address), _address_pretty_sort_get_prio_6(&a1->address)); - ipv6_privacy1 = NM_FLAGS_ANY(a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); - ipv6_privacy2 = NM_FLAGS_ANY(a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); + ipv6_privacy1 = NM_FLAGS_ANY(a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); + ipv6_privacy2 = NM_FLAGS_ANY(a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_SECONDARY); if (ipv6_privacy1 || ipv6_privacy2) { gboolean public1 = TRUE; gboolean public2 = TRUE; if (ipv6_privacy1) { - if (a1->n_ifa_flags & IFA_F_TEMPORARY) + if (a1->n_ifa_flags & IFA_F_SECONDARY) public1 = prefer_temp; else public1 = !prefer_temp; } if (ipv6_privacy2) { - if (a2->n_ifa_flags & IFA_F_TEMPORARY) + if (a2->n_ifa_flags & IFA_F_SECONDARY) public2 = prefer_temp; else public2 = !prefer_temp; @@ -7905,7 +7847,8 @@ nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState NM_HASH_COMBINE_BOOLS(guint8, obj->external, obj->use_ip4_broadcast_address, - obj->ip4acd_not_ready)); + obj->a_acd_not_ready, + obj->a_assume_config_once)); nm_hash_update_strarr(h, obj->label); } @@ -7927,7 +7870,8 @@ nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, const NMPlatformIP4Ad NM_CMP_FIELD(a, b, n_ifa_flags); NM_CMP_FIELD_STR(a, b, label); NM_CMP_FIELD_UNSAFE(a, b, external); - NM_CMP_FIELD_UNSAFE(a, b, ip4acd_not_ready); + NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready); + NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once); return 0; } @@ -7944,7 +7888,7 @@ nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState obj->plen, obj->address, obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, obj->external)); + NM_HASH_COMBINE_BOOLS(guint8, obj->external, obj->a_assume_config_once)); } int @@ -7965,6 +7909,7 @@ nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, const NMPlatformIP6Ad NM_CMP_FIELD(a, b, preferred); NM_CMP_FIELD(a, b, n_ifa_flags); NM_CMP_FIELD_UNSAFE(a, b, external); + NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once); return 0; } @@ -8065,7 +8010,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->initrwnd, obj->mtu, obj->r_rtm_flags, - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, obj->lock_window, @@ -8073,7 +8018,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, - obj->is_external)); + obj->is_external, + obj->r_assume_config_once)); break; } } @@ -8163,8 +8109,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_FIELD(a, b, initcwnd); NM_CMP_FIELD(a, b, initrwnd); NM_CMP_FIELD(a, b, mtu); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) { NM_CMP_FIELD_UNSAFE(a, b, is_external); + NM_CMP_FIELD_UNSAFE(a, b, r_assume_config_once); + } break; } return 0; @@ -8249,7 +8197,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, obj->rt_source, obj->mss, obj->r_rtm_flags, - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, obj->lock_window, @@ -8257,7 +8205,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, - obj->is_external), + obj->is_external, + obj->r_assume_config_once), obj->window, obj->cwnd, obj->initcwnd, @@ -8340,8 +8289,10 @@ 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) + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) { NM_CMP_FIELD_UNSAFE(a, b, is_external); + NM_CMP_FIELD_UNSAFE(a, b, r_assume_config_once); + } break; } return 0; @@ -8627,6 +8578,57 @@ nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) /*****************************************************************************/ +NMPlatformIP4Route * +nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + guint32 route_metric, + NMPlatformIP4Route * dst) +{ + in_addr_t network_4; + + /* When you add an IPv4 address (without "noprefixroute" flag), then kernel will + * automatically add a device route for the IPv4 subnet. This function generates + * such a route for the given address. */ + + nm_assert(addr); + nm_assert(addr->plen <= 32); + if (addr->plen == 0) + return NULL; + + if (addr->plen == 0) + return NULL; + + network_4 = nm_utils_ip4_address_clear_host_address(addr->peer_address, addr->plen); + + if (nm_utils_ip4_address_is_zeronet(network_4)) { + /* Kernel doesn't add device-routes for destinations that + * start with 0.x.y.z. Skip them. */ + return NULL; + } + + if (addr->plen == 32 && addr->address == addr->peer_address) { + /* Kernel doesn't add device-routes for /32 addresses unless + * they have a peer. */ + return NULL; + } + + *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), + }; + + nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst); + + return dst; +} + const char * nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type) { @@ -8918,6 +8920,10 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* construct-only */ priv->log_with_ptr = g_value_get_boolean(value); break; + case PROP_CACHE_TC: + /* construct-only */ + priv->cache_tc = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -9003,6 +9009,15 @@ nm_platform_class_init(NMPlatformClass *platform_class) TRUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property( + object_class, + PROP_CACHE_TC, + g_param_spec_boolean(NM_PLATFORM_CACHE_TC, + "", + "", + FALSE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + #define SIGNAL(signal, signal_id, method) \ G_STMT_START \ { \ diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 9d40cbbe..7101b48c 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -25,6 +25,7 @@ #define NM_PLATFORM_NETNS_SUPPORT "netns-support" #define NM_PLATFORM_USE_UDEV "use-udev" #define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr" +#define NM_PLATFORM_CACHE_TC "cache-tc" /*****************************************************************************/ @@ -42,10 +43,10 @@ typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_d /* workaround for older libnl version, that does not define these flags. */ #ifndef IFA_F_MANAGETEMPADDR - #define IFA_F_MANAGETEMPADDR 0x100 +#define IFA_F_MANAGETEMPADDR 0x100 #endif #ifndef IFA_F_NOPREFIXROUTE - #define IFA_F_NOPREFIXROUTE 0x200 +#define IFA_F_NOPREFIXROUTE 0x200 #endif #define NM_RT_SCOPE_LINK 253 /* RT_SCOPE_LINK */ @@ -231,6 +232,9 @@ struct _NMPlatformLink { /* IFLA_ADDRESS */ NMPLinkAddress l_address; + /* IFLA_PERM_ADDRESS */ + NMPLinkAddress l_perm_address; + /* IFLA_BROADCAST */ NMPLinkAddress l_broadcast; @@ -314,18 +318,18 @@ typedef enum { * IFA_FLAGS attribute. */ \ guint32 n_ifa_flags; \ \ - guint8 plen; \ - \ /* FIXME(l3cfg): the external marker won't be necessary anymore, because we only * merge addresses we care about, and ignore (don't remove) external addresses. */ \ bool external : 1; \ \ bool use_ip4_broadcast_address : 1; \ \ - /* 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 - * state is not yet ready for the address to be configured. */ \ - bool ip4acd_not_ready : 1; \ + /* Whether the address is should be configured once during assume. This is a meta flag + * that is not honored by NMPlatform (netlink code). Instead, it can be used by the upper + * layers which use NMPlatformIPAddress to track addresses that should be configured. */ \ + bool a_assume_config_once : 1; \ + \ + guint8 plen; \ ; /** @@ -348,6 +352,11 @@ typedef struct { struct _NMPlatformIP4Address { __NMPlatformIPAddress_COMMON; + /* 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 + * state is not yet ready for the address to be configured. */ + bool a_acd_not_ready : 1; + /* The local address IFA_LOCAL. */ in_addr_t address; @@ -470,6 +479,11 @@ typedef union { * and is not reflected on netlink. */ \ bool is_external : 1; \ \ + /* Whether the route is should be configured once during assume. This is a meta flag + * that is not honored by NMPlatform (netlink code). Instead, it can be used by the upper + * layers which use NMPlatformIPRoute to track routes that should be configured. */ \ + bool r_assume_config_once : 1; \ + \ /* rtnh_flags * * Routes with rtm_flags RTM_F_CLONED are hidden by platform and @@ -518,8 +532,7 @@ typedef union { * it means RTN_UNSPEC otherwise the type value is preserved. * */ \ guint8 type_coerced; \ - \ - /*end*/ + ; typedef struct { __NMPlatformIPRoute_COMMON; @@ -613,6 +626,10 @@ typedef union { #undef __NMPlatformIPRoute_COMMON +#define NM_PLATFORM_IP4_ROUTE_INIT(...) (&((const NMPlatformIP4Route){__VA_ARGS__})) + +#define NM_PLATFORM_IP6_ROUTE_INIT(...) (&((const NMPlatformIP6Route){__VA_ARGS__})) + typedef struct { /* struct fib_rule_uid_range */ guint32 start; @@ -1008,13 +1025,11 @@ typedef void (*NMPlatformAsyncCallback)(GError *error, gpointer user_data); /*****************************************************************************/ typedef enum { - NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL, NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED, + NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_PERM_ADDRESS, /* this also includes FRA_SPORT_RANGE and FRA_DPORT_RANGE which * were added at the same time. */ @@ -1105,13 +1120,12 @@ typedef struct { unsigned flags_mask, unsigned flags_set); - int (*link_set_user_ipv6ll_enabled)(NMPlatform *self, int ifindex, gboolean enabled); - gboolean (*link_set_token)(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); + int (*link_set_inet6_addr_gen_mode)(NMPlatform *self, int ifindex, guint8 enabled); + gboolean (*link_set_token)(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid); - gboolean (*link_get_permanent_address)(NMPlatform *self, - int ifindex, - guint8 * buf, - size_t * length); + gboolean (*link_get_permanent_address_ethtool)(NMPlatform * self, + int ifindex, + NMPLinkAddress *out_address); int (*link_set_address)(NMPlatform *self, int ifindex, gconstpointer address, size_t length); int (*link_set_mtu)(NMPlatform *self, int ifindex, guint32 mtu); gboolean (*link_set_name)(NMPlatform *self, int ifindex, const char *name); @@ -1253,8 +1267,10 @@ typedef struct { const NMPlatformRoutingRule *routing_rule); int (*qdisc_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc); + int (*qdisc_delete)(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); int (*tfilter_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); + int (*tfilter_delete)(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); } NMPlatformClass; /* NMPlatform signals @@ -1391,6 +1407,14 @@ _nm_platform_uint8_inv(guint8 scope) return (guint8) ~scope; } +static inline int +_nm_platform_link_get_inet6_addr_gen_mode(const NMPlatformLink *pllink) +{ + if (!pllink) + return -ENODEV; + return _nm_platform_uint8_inv(pllink->inet6_addr_gen_mode_inv); +} + /** * nm_platform_route_type_coerce: * @table: the route type, in its original value. @@ -1426,6 +1450,7 @@ nm_platform_route_type_uncoerce(guint8 type_coerced) gboolean nm_platform_get_use_udev(NMPlatform *self); gboolean nm_platform_get_log_with_ptr(NMPlatform *self); +gboolean nm_platform_get_cache_tc(NMPlatform *self); NMPNetns *nm_platform_netns_get(NMPlatform *self); gboolean nm_platform_netns_push(NMPlatform *self, NMPNetns **netns); @@ -1808,7 +1833,7 @@ gboolean nm_platform_link_is_up(NMPlatform *self, int ifindex); gboolean nm_platform_link_is_connected(NMPlatform *self, int ifindex); gboolean nm_platform_link_uses_arp(NMPlatform *self, int ifindex); guint32 nm_platform_link_get_mtu(NMPlatform *self, int ifindex); -gboolean nm_platform_link_get_user_ipv6ll_enabled(NMPlatform *self, int ifindex); +int nm_platform_link_get_inet6_addr_gen_mode(NMPlatform *self, int ifindex); gconstpointer nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length); @@ -1858,11 +1883,16 @@ const char *nm_platform_link_get_path(NMPlatform *self, int ifindex); struct udev_device *nm_platform_link_get_udev_device(NMPlatform *self, int ifindex); -int nm_platform_link_set_user_ipv6ll_enabled(NMPlatform *self, int ifindex, gboolean enabled); -gboolean nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); - +int nm_platform_link_set_inet6_addr_gen_mode(NMPlatform *self, int ifindex, guint8 mode); gboolean -nm_platform_link_get_permanent_address(NMPlatform *self, int ifindex, guint8 *buf, size_t *length); +nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid); + +gboolean nm_platform_link_get_permanent_address_ethtool(NMPlatform * self, + int ifindex, + NMPLinkAddress *out_address); +gboolean nm_platform_link_get_permanent_address(NMPlatform * self, + const NMPlatformLink *plink, + NMPLinkAddress * out_address); int nm_platform_link_set_address(NMPlatform *self, int ifindex, const void *address, size_t length); int nm_platform_link_set_mtu(NMPlatform *self, int ifindex, guint32 mtu); gboolean nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name); @@ -2113,7 +2143,7 @@ nm_platform_ip6_address_sync(NMPlatform *self, gboolean nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex); -static inline gconstpointer +static inline gpointer nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddress *addr) { nm_assert_addr_family(addr_family); @@ -2193,11 +2223,14 @@ int nm_platform_routing_rule_add(NMPlatform * self, NMPNlmFlags flags, const NMPlatformRoutingRule *routing_rule); -int nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc); -gboolean nm_platform_qdisc_sync(NMPlatform *self, int ifindex, GPtrArray *known_qdiscs); - +int nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc); +int nm_platform_qdisc_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); int nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); -gboolean nm_platform_tfilter_sync(NMPlatform *self, int ifindex, GPtrArray *known_tfilters); +int nm_platform_tfilter_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); +gboolean nm_platform_tc_sync(NMPlatform *self, + int ifindex, + GPtrArray * known_qdiscs, + GPtrArray * known_tfilters); const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len); @@ -2389,6 +2422,14 @@ struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self); /*****************************************************************************/ +NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + guint32 route_metric, + NMPlatformIP4Route *dst); + +/*****************************************************************************/ + gboolean nm_platform_ip_address_match(int addr_family, const NMPlatformIPAddress *addr, NMPlatformMatchFlags match_flag); diff --git a/src/libnm-platform/nmp-netns.c b/src/libnm-platform/nmp-netns.c index 2b28a4cd..d06c3e11 100644 --- a/src/libnm-platform/nmp-netns.c +++ b/src/libnm-platform/nmp-netns.c @@ -43,22 +43,20 @@ __ns_types_to_str(int ns_types, int ns_types_already_set, char *buf, gsize len) const char *b = buf; char bb[200]; - nm_utils_strbuf_append_c(&buf, &len, '['); + nm_strbuf_append_c(&buf, &len, '['); if (ns_types & ~ns_types_already_set) { - nm_utils_strbuf_append_str( - &buf, - &len, - _clone_ns_to_str(ns_types & ~ns_types_already_set, bb, sizeof(bb))); + nm_strbuf_append_str(&buf, + &len, + _clone_ns_to_str(ns_types & ~ns_types_already_set, bb, sizeof(bb))); } if (ns_types & ns_types_already_set) { if (ns_types & ~ns_types_already_set) - nm_utils_strbuf_append_c(&buf, &len, '/'); - nm_utils_strbuf_append_str( - &buf, - &len, - _clone_ns_to_str(ns_types & ns_types_already_set, bb, sizeof(bb))); + nm_strbuf_append_c(&buf, &len, '/'); + nm_strbuf_append_str(&buf, + &len, + _clone_ns_to_str(ns_types & ns_types_already_set, bb, sizeof(bb))); } - nm_utils_strbuf_append_c(&buf, &len, ']'); + nm_strbuf_append_c(&buf, &len, ']'); return b; } #define _ns_types_to_str(ns_types, ns_types_already_set, buf) \ diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index a7a46ef0..559fd8d6 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -949,30 +949,30 @@ _vt_cmd_obj_to_string_link(const NMPObject * obj, case NMP_OBJECT_TO_STRING_ID: return klass->cmd_plobj_to_string_id(&obj->object, buf, buf_size); case NMP_OBJECT_TO_STRING_ALL: - nm_utils_strbuf_append(&b, - &buf_size, - "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", - klass->obj_type_name, - obj, - obj->parent._ref_count, - nmp_object_is_alive(obj) ? '+' : '-', - nmp_object_is_visible(obj) ? '+' : '-', - obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device); + nm_strbuf_append(&b, + &buf_size, + "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", + klass->obj_type_name, + obj, + obj->parent._ref_count, + nmp_object_is_alive(obj) ? '+' : '-', + nmp_object_is_visible(obj) ? '+' : '-', + obj->_link.netlink.is_in_netlink ? '+' : '-', + obj->_link.udev.device); NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); + nm_strbuf_seek_end(&b, &buf_size); if (obj->_link.netlink.lnk) { - nm_utils_strbuf_append_str(&b, &buf_size, "; "); + nm_strbuf_append_str(&b, &buf_size, "; "); nmp_object_to_string(obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_ALL, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); + nm_strbuf_seek_end(&b, &buf_size); } - nm_utils_strbuf_append_c(&b, &buf_size, ']'); + nm_strbuf_append_c(&b, &buf_size, ']'); return buf; case NMP_OBJECT_TO_STRING_PUBLIC: NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); if (obj->_link.netlink.lnk) { - nm_utils_strbuf_seek_end(&b, &buf_size); - nm_utils_strbuf_append_str(&b, &buf_size, "; "); + nm_strbuf_seek_end(&b, &buf_size); + nm_strbuf_append_str(&b, &buf_size, "; "); nmp_object_to_string(obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, b, buf_size); } return buf; @@ -1065,29 +1065,28 @@ _vt_cmd_obj_to_string_lnk_wireguard(const NMPObject * obj, case NMP_OBJECT_TO_STRING_ALL: b = buf; - nm_utils_strbuf_append( - &b, - &buf_size, - "[%s,%p,%u,%calive,%cvisible; %s" - "%s", - klass->obj_type_name, - obj, - obj->parent._ref_count, - nmp_object_is_alive(obj) ? '+' : '-', - nmp_object_is_visible(obj) ? '+' : '-', - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof(buf2)), - obj->_lnk_wireguard.peers_len > 0 ? " peers {" : ""); + nm_strbuf_append(&b, + &buf_size, + "[%s,%p,%u,%calive,%cvisible; %s" + "%s", + klass->obj_type_name, + obj, + obj->parent._ref_count, + nmp_object_is_alive(obj) ? '+' : '-', + nmp_object_is_visible(obj) ? '+' : '-', + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof(buf2)), + obj->_lnk_wireguard.peers_len > 0 ? " peers {" : ""); for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) { const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i]; - nm_utils_strbuf_append_str(&b, &buf_size, " { "); + nm_strbuf_append_str(&b, &buf_size, " { "); nm_platform_wireguard_peer_to_string(peer, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); - nm_utils_strbuf_append_str(&b, &buf_size, " }"); + nm_strbuf_seek_end(&b, &buf_size); + nm_strbuf_append_str(&b, &buf_size, " }"); } if (obj->_lnk_wireguard.peers_len) - nm_utils_strbuf_append_str(&b, &buf_size, " }"); + nm_strbuf_append_str(&b, &buf_size, " }"); return buf; case NMP_OBJECT_TO_STRING_PUBLIC: @@ -1199,9 +1198,11 @@ _vt_cmd_obj_hash_update_lnk_wireguard(const NMPObject *obj, NMHashState *h) } int -nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2) +nmp_object_cmp_full(const NMPObject *obj1, const NMPObject *obj2, NMPObjectCmpFlags flags) { - const NMPClass *klass1, *klass2; + const NMPClass *klass1; + const NMPClass *klass2; + NMPObject obj_stackcopy; NM_CMP_SELF(obj1, obj2); @@ -1216,6 +1217,22 @@ nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2) return klass1->obj_type < klass2->obj_type ? -1 : 1; } + if (NM_FLAGS_HAS(flags, NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX)) { + if (!NM_IN_SET(klass1, + nmp_class_from_type(NMP_OBJECT_TYPE_IP4_ADDRESS), + nmp_class_from_type(NMP_OBJECT_TYPE_IP6_ADDRESS), + nmp_class_from_type(NMP_OBJECT_TYPE_IP4_ROUTE), + nmp_class_from_type(NMP_OBJECT_TYPE_IP6_ROUTE))) { + /* This flag is currently only implemented for certain types. + * That is, because we just create a stack copy, and that naive + * approach only knows for types where we know that it works. */ + } else if (obj1->obj_with_ifindex.ifindex != obj2->obj_with_ifindex.ifindex) { + nmp_object_stackinit(&obj_stackcopy, klass1->obj_type, &obj2->obj_with_ifindex); + obj_stackcopy.obj_with_ifindex.ifindex = obj1->obj_with_ifindex.ifindex; + obj2 = &obj_stackcopy; + } + } + if (klass1->cmd_obj_cmp) return klass1->cmd_obj_cmp(obj1, obj2); return klass1->cmd_plobj_cmp(&obj1->object, &obj2->object); @@ -2079,6 +2096,9 @@ nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type) nm_assert(lookup); switch (obj_type) { + default: + nm_assert_not_reached(); + /* fall-through */ case NMP_OBJECT_TYPE_LINK: case NMP_OBJECT_TYPE_IP4_ADDRESS: case NMP_OBJECT_TYPE_IP6_ADDRESS: @@ -2090,9 +2110,6 @@ nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type) _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L(lookup); - default: - nm_assert_not_reached(); - return NULL; } } @@ -2107,7 +2124,7 @@ nmp_lookup_init_link_by_ifname(NMPLookup *lookup, const char *ifname) o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_LINK); if (g_strlcpy(o->link.name, ifname, sizeof(o->link.name)) >= sizeof(o->link.name)) - g_return_val_if_reached(NULL); + nm_assert_not_reached(); lookup->cache_id_type = NMP_CACHE_ID_TYPE_LINK_BY_IFNAME; return _L(lookup); } diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index 021829db..bf140d78 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -120,10 +120,10 @@ typedef enum { /*< skip >*/ * the index NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX with * matching v4/v6 and ifindex -- or maybe not at all if it isn't visible. * */ -typedef enum { /*< skip >*/ - NMP_CACHE_ID_TYPE_NONE, +typedef enum { + NMP_CACHE_ID_TYPE_NONE, - /* all the objects of a certain type. + /* all the objects of a certain type. * * This index is special. It is the only one that contains *all* object. * Other indexes may consider some object as non "partitionable", hence @@ -136,20 +136,20 @@ typedef enum { /*< skip >*/ * expose all links, even invisible ones. For addresses/routes, this * distinction doesn't exist, as all addresses/routes that are alive * are visible as well. */ - NMP_CACHE_ID_TYPE_OBJECT_TYPE, + NMP_CACHE_ID_TYPE_OBJECT_TYPE, - /* index for the link objects by ifname. */ - NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, + /* index for the link objects by ifname. */ + NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, - /* indices for the visible default-routes, ignoring ifindex. + /* indices for the visible default-routes, ignoring ifindex. * This index only contains two partitions: all visible default-routes, * separate for IPv4 and IPv6. */ - NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, + NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - /* all the objects that have an ifindex (by object-type) for an ifindex. */ - NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, + /* all the objects that have an ifindex (by object-type) for an ifindex. */ + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, - /* Consider all the destination fields of a route, that is, the ID without the ifindex + /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). * The reason for this is that `ip route change` can replace an existing route * and modify its ifindex/gateway. Effectively, that means it deletes an existing @@ -157,15 +157,15 @@ typedef enum { /*< skip >*/ * sends one RTM_NEWADDR notification without notifying about the deletion. We detect * that by having this index to contain overlapping routes which require special * cache-resync. */ - NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, + NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, - /* a filter for objects that track an explicit address family. + /* a filter for objects that track an explicit address family. * * Note that currently on NMPObjectRoutingRule is indexed by this filter. */ - NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY, + NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY, - __NMP_CACHE_ID_TYPE_MAX, - NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1, + __NMP_CACHE_ID_TYPE_MAX, + NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1, } NMPCacheIdType; typedef struct { @@ -625,6 +625,20 @@ nmp_object_unref(const NMPObject *obj) _changed; \ }) +#define nm_clear_nmp_object_up_cast(ptr) \ + ({ \ + typeof(ptr) _ptr = (ptr); \ + typeof(*_ptr) _pptr; \ + gboolean _changed = FALSE; \ + \ + if (_ptr && (_pptr = *_ptr)) { \ + *_ptr = NULL; \ + nmp_object_unref(NMP_OBJECT_UP_CAST(_pptr)); \ + _changed = TRUE; \ + } \ + _changed; \ + }) + static inline gboolean nmp_object_ref_set(const NMPObject **pp, const NMPObject *obj) { @@ -643,6 +657,25 @@ nmp_object_ref_set(const NMPObject **pp, const NMPObject *obj) return _changed; } +static inline gboolean +nmp_object_ref_set_up_cast(gpointer pp, gconstpointer obj) +{ + gboolean _changed = FALSE; + const NMPObject *p; + gconstpointer * pp2 = pp; + + nm_assert(!pp2 || !*pp2 || NMP_OBJECT_IS_VALID(NMP_OBJECT_UP_CAST(*pp2))); + nm_assert(!obj || NMP_OBJECT_IS_VALID(NMP_OBJECT_UP_CAST(obj))); + + if (pp2 && ((p = *pp2) != obj)) { + nmp_object_ref(NMP_OBJECT_UP_CAST(obj)); + *pp2 = obj; + nmp_object_unref(NMP_OBJECT_UP_CAST(p)); + _changed = TRUE; + } + return _changed; +} + NMPObject *nmp_object_new(NMPObjectType obj_type, gconstpointer plobj); NMPObject *nmp_object_new_link(int ifindex); @@ -671,7 +704,22 @@ const char *nmp_object_to_string(const NMPObject * obj, char * buf, gsize buf_size); void nmp_object_hash_update(const NMPObject *obj, NMHashState *h); -int nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2); + +typedef enum { + NMP_OBJECT_CMP_FLAGS_NONE = 0, + + /* Warning: this flag is currently only implemented for certain object types + * (address and routes). */ + NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX = (1llu << 0), +} NMPObjectCmpFlags; + +int nmp_object_cmp_full(const NMPObject *obj1, const NMPObject *obj2, NMPObjectCmpFlags flags); + +static inline int +nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2) +{ + return nmp_object_cmp_full(obj1, obj2, NMP_OBJECT_CMP_FLAGS_NONE); +} static inline gboolean nmp_object_equal(const NMPObject *obj1, const NMPObject *obj2) @@ -1049,6 +1097,21 @@ nm_platform_lookup_object_by_addr_family(NMPlatform * platform, /*****************************************************************************/ +static inline gboolean +nmp_object_get_assume_config_once(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_assume_config_once; + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + return NMP_OBJECT_CAST_IP_ROUTE(obj)->r_assume_config_once; + default: + return nm_assert_unreachable_val(FALSE); + } +} + static inline const char * nmp_object_link_get_ifname(const NMPObject *obj) { @@ -1058,7 +1121,7 @@ nmp_object_link_get_ifname(const NMPObject *obj) } static inline gboolean -nmp_object_ip_route_is_best_defaut_route(const NMPObject *obj) +nmp_object_ip_route_is_best_default_route(const NMPObject *obj) { const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE(obj); diff --git a/src/libnm-platform/wifi/nm-wifi-utils-wext.c b/src/libnm-platform/wifi/nm-wifi-utils-wext.c index 13b47c2c..6fb37c49 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-wext.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-wext.c @@ -14,7 +14,7 @@ /* Hacks necessary to #include wireless.h; yay for WEXT */ #ifndef __user - #define __user +#define __user #endif #include <sys/types.h> #include <linux/types.h> diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 3c952b6f..0b5f8d71 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -15,7 +15,7 @@ #include "nm-wifi-utils-private.h" #include "nm-wifi-utils-nl80211.h" #if HAVE_WEXT - #include "nm-wifi-utils-wext.h" +#include "nm-wifi-utils-wext.h" #endif #include "libnm-platform/nm-platform-utils.h" |