diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2017-11-15 20:36:35 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2017-12-11 10:52:22 +0100 |
commit | ff9f27eb1231a8a6cb6e0ca5f172da61da136e96 (patch) | |
tree | 630245de968ad740b00c4a15f2125bda1b2f0f87 /src | |
parent | 82befe3c409cd0459768642895d41ad50ca295cc (diff) | |
download | NetworkManager-ff9f27eb1231a8a6cb6e0ca5f172da61da136e96.tar.gz |
platform: add support for queueing disciplines
Diffstat (limited to 'src')
-rw-r--r-- | src/nm-types.h | 3 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 173 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 121 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 26 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 47 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 16 |
6 files changed, 363 insertions, 23 deletions
diff --git a/src/nm-types.h b/src/nm-types.h index cad3c0315a..75c691942e 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_TYPES_H__ @@ -176,6 +176,7 @@ typedef enum { NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_INFINIBAND, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 43f230a023..31b5580499 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -250,27 +250,30 @@ enum { DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS, _DELAYED_ACTION_IDX_REFRESH_ALL_NUM, }; typedef enum { DELAYED_ACTION_TYPE_NONE = 0, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5), - DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6), - DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7), - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 8), + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << /* 0 */ DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << /* 1 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 6), + DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 10), + DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 11), + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 12), __DELAYED_ACTION_TYPE_MAX, DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, } DelayedActionType; @@ -970,6 +973,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) case RTM_DELADDR: s = "RTM_DELADDR"; break; case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; case RTM_DELROUTE: s = "RTM_DELROUTE"; break; + case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; + case RTM_DELQDISC: s = "RTM_DELQDISC"; break; case NLMSG_NOOP: s = "NLMSG_NOOP"; break; case NLMSG_ERROR: s = "NLMSG_ERROR"; break; case NLMSG_DONE: s = "NLMSG_DONE"; break; @@ -1016,6 +1021,7 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) case RTM_NEWLINK: case RTM_NEWADDR: case RTM_NEWROUTE: + case RTM_NEWQDISC: _F (NLM_F_REPLACE, "replace"); _F (NLM_F_EXCL, "excl"); _F (NLM_F_CREATE, "create"); @@ -1024,6 +1030,7 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) case RTM_GETLINK: case RTM_GETADDR: case RTM_GETROUTE: + case RTM_DELQDISC: _F (NLM_F_DUMP, "dump"); _F (NLM_F_ROOT, "root"); _F (NLM_F_MATCH, "match"); @@ -2327,6 +2334,40 @@ errout: return obj_result; } +static NMPObject * +_new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) +{ + NMPObject *obj = NULL; + const struct tcmsg *tcm; + struct nlattr *tb[TCA_MAX + 1]; + int err; + static const struct nla_policy policy[TCA_MAX + 1] = { + [TCA_KIND] = { .type = NLA_STRING }, + }; + + if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) + return NULL; + tcm = nlmsg_data (nlh); + + err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); + if (err < 0) + return NULL; + + if (!tb[TCA_KIND]) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); + + obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); + obj->qdisc.ifindex = tcm->tcm_ifindex; + obj->qdisc.addr_family = tcm->tcm_family; + obj->qdisc.handle = tcm->tcm_handle; + obj->qdisc.parent = tcm->tcm_parent; + obj->qdisc.info = tcm->tcm_info; + + return obj; +} + /** * nmp_object_new_from_nl: * @platform: (allow-none): for creating certain objects, the constructor wants to check @@ -2363,6 +2404,10 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m case RTM_DELROUTE: case RTM_GETROUTE: return _new_from_nl_route (msghdr, id_only); + case RTM_NEWQDISC: + case RTM_DELQDISC: + case RTM_GETQDISC: + return _new_from_nl_qdisc (msghdr, id_only); default: return NULL; } @@ -2816,6 +2861,35 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static struct nl_msg * +_nl_msg_new_qdisc (int nlmsg_type, + int nlmsg_flags, + const NMPlatformQdisc *qdisc) +{ + struct nl_msg *msg; + struct tcmsg tcm = { + .tcm_family = qdisc->addr_family, + .tcm_ifindex = qdisc->ifindex, + .tcm_handle = qdisc->handle, + .tcm_parent = qdisc->parent, + .tcm_info = qdisc->info, + }; + + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; + + if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -3217,6 +3291,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObj NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3227,6 +3302,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedA NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NMP_OBJECT_TYPE_QDISC), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3237,6 +3313,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActio NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3247,6 +3324,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), @@ -3684,7 +3762,7 @@ cache_on_change (NMPlatform *platform, { int ifindex = 0; - /* if we remove a link (from netlink), we must refresh the addresses and routes */ + /* if we remove a link (from netlink), we must refresh the addresses, routes and qdiscs */ if ( cache_op == NMP_CACHE_OPS_REMOVED && obj_old /* <-- nonsensical, make coverity happy */) ifindex = obj_old->link.ifindex; @@ -3699,7 +3777,8 @@ cache_on_change (NMPlatform *platform, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NULL); } } @@ -4022,9 +4101,6 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct rtgenmsg gmsg = { - .rtgen_family = klass->addr_family, - }; int nle; gint *out_refresh_all_in_progess; @@ -4051,7 +4127,17 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (!nlmsg) continue; - nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + if (klass->obj_type == NMP_OBJECT_TYPE_QDISC) { + struct tcmsg tcmsg = { + .tcm_family = AF_UNSPEC, + }; + nle = nlmsg_append (nlmsg, &tcmsg, sizeof (tcmsg), NLMSG_ALIGNTO); + } else { + struct rtgenmsg gmsg = { + .rtgen_family = klass->addr_family, + }; + nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + } if (nle < 0) continue; @@ -4173,6 +4259,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWADDR: case RTM_NEWLINK: case RTM_NEWROUTE: + case RTM_NEWQDISC: is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); break; @@ -4196,6 +4283,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWLINK: case RTM_NEWADDR: case RTM_GETLINK: + case RTM_NEWQDISC: cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); @@ -4289,13 +4377,13 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_DELLINK: case RTM_DELADDR: case RTM_DELROUTE: + case RTM_DELQDISC: cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } break; - default: break; } @@ -6153,6 +6241,9 @@ object_delete (NMPlatform *platform, case NMP_OBJECT_TYPE_IP6_ROUTE: nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); break; + case NMP_OBJECT_TYPE_QDISC: + nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj)); + break; default: break; } @@ -6243,6 +6334,45 @@ ip_route_get (NMPlatform *platform, /*****************************************************************************/ +static NMPlatformError +qdisc_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + int nle; + char s_buf[256]; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = _nl_msg_new_qdisc (RTM_NEWQDISC, flags, qdisc); + + event_handler_read_netlink (platform, FALSE); + + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + if (nle < 0) { + _LOGE ("do-add-qdisc: failed sending netlink request \"%s\" (%d)", + nl_geterror (nle), -nle); + return NM_PLATFORM_ERROR_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-qdisc: %s", + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + return NM_PLATFORM_ERROR_SUCCESS; + + return NM_PLATFORM_ERROR_UNSPECIFIED; +} + +/*****************************************************************************/ + #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) @@ -6524,7 +6654,8 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NULL); break; default: @@ -6784,6 +6915,7 @@ constructed (GObject *_object) RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, + RTNLGRP_TC, 0); g_assert (!nle); _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); @@ -6808,7 +6940,8 @@ constructed (GObject *_object) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NULL); delayed_action_handle_all (platform, FALSE); @@ -6974,6 +7107,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip_route_add = ip_route_add; platform_class->ip_route_get = ip_route_get; + platform_class->qdisc_add = qdisc_add; + platform_class->check_kernel_support = check_kernel_support; platform_class->process_events = process_events; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 37610e8eae..09a52574e1 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3997,7 +3997,8 @@ nm_platform_object_delete (NMPlatform *self, _CHECK_SELF (self, klass, FALSE); if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC)) g_return_val_if_reached (FALSE); _LOGD ("%s: delete %s", @@ -4332,6 +4333,72 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, /*****************************************************************************/ +NMPlatformError +nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + _LOGD ("adding or updating a qdisc: %s", nm_platform_qdisc_to_string (qdisc, NULL, 0)); + return klass->qdisc_add (self, flags, qdisc); +} + +gboolean +nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs) +{ + 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); + + g_hash_table_insert (known_qdiscs_idx, (gpointer) q, (gpointer) q); + } + } + + 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 *q = g_ptr_array_index (plat_qdiscs, i); + + if (!g_hash_table_lookup (known_qdiscs_idx, q)) + success &= nm_platform_object_delete (self, q); + } + } + + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (known_qdiscs, i); + + success &= (nm_platform_qdisc_add (self, NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_QDISC (q)) == NM_PLATFORM_ERROR_SUCCESS); + } + } + + return success; +} + +/*****************************************************************************/ + const char * nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -5164,6 +5231,51 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi return buf; } +const char * +nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len) +{ + char str_dev[TO_STRING_DEV_BUF_SIZE]; + + if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len)) + return buf; + + g_snprintf (buf, len, "%s%s family %d 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); + + return buf; +} + +void +nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h) +{ + nm_hash_update_str (h, obj->kind); + nm_hash_update_vals (h, + obj->ifindex, + obj->addr_family, + obj->handle, + obj->parent, + obj->info); +} + +int +nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, parent); + NM_CMP_FIELD_STR_INTERNED (a, b, kind); + NM_CMP_FIELD (a, b, addr_family); + NM_CMP_FIELD (a, b, handle); + NM_CMP_FIELD (a, b, info); + + return 0; +} + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h) { @@ -5977,6 +6089,12 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0)); } +static void +log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdisc *qdisc, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + _LOGD ("signal: qdisc %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_qdisc_to_string (qdisc, NULL, 0)); +} + /*****************************************************************************/ void @@ -6250,4 +6368,5 @@ nm_platform_class_init (NMPlatformClass *platform_class) SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route); + SIGNAL (NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 354cb79b76..bae2f35203 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -236,6 +236,7 @@ typedef enum { /*< skip >*/ NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, + NM_PLATFORM_SIGNAL_ID_QDISC, _NM_PLATFORM_SIGNAL_ID_LAST, } NMPlatformSignalIdType; @@ -529,6 +530,14 @@ typedef union { #undef __NMPlatformIPRoute_COMMON +typedef struct { + __NMPlatformObject_COMMON; + const char *kind; + int addr_family; + guint32 handle; + guint32 parent; + guint32 info; +} NMPlatformQdisc; #undef __NMPlatformObject_COMMON @@ -832,6 +841,10 @@ typedef struct { int oif_ifindex, NMPObject **out_route); + NMPlatformError (*qdisc_add) (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); + NMPlatformKernelSupportFlags (*check_kernel_support) (NMPlatform * self, NMPlatformKernelSupportFlags request_flags); } NMPlatformClass; @@ -852,6 +865,7 @@ typedef struct { #define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed" #define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" #define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" +#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed" const char *nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type); @@ -1247,6 +1261,13 @@ NMPlatformError nm_platform_ip_route_get (NMPlatform *self, int oif_ifindex, NMPObject **out_route); +NMPlatformError nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); +gboolean nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs); + const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); @@ -1261,6 +1282,7 @@ const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *addre const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len); const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); +const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len); const char *nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -1296,6 +1318,8 @@ nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6 return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); } +int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b); + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h); void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h); void nm_platform_ip6_address_hash_update (const NMPlatformIP6Address *obj, NMHashState *h); @@ -1311,6 +1335,8 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState * void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); +void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h); + NMPlatformKernelSupportFlags nm_platform_check_kernel_support (NMPlatform *self, NMPlatformKernelSupportFlags request_flags); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 15beb4e070..b1e5de3410 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -190,7 +190,8 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC) || !nmp_object_is_visible (obj_a)) { if (h) nm_hash_update_val (h, obj_a); @@ -737,6 +738,7 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->peer_address != obj->address ? "," : "", obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_utils_ip4_address_clear_host_address (obj->peer_address, obj->plen), buf2) : ""); _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); +_vt_cmd_plobj_to_string_id (qdisc, NMPlatformQdisc, "%d: %d", obj->ifindex, obj->parent); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h) @@ -1029,6 +1031,10 @@ _vt_cmd_plobj_id_cmp (ip6_address, NMPlatformIP6Address, /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ NM_CMP_FIELD_IN6ADDR (obj1, obj2, address); ) +_vt_cmd_plobj_id_cmp (qdisc, NMPlatformQdisc, + NM_CMP_FIELD (obj1, obj2, ifindex); + NM_CMP_FIELD (obj1, obj2, parent); +) static int _vt_cmd_plobj_id_cmp_ip4_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2) @@ -1107,6 +1113,11 @@ _vt_cmd_plobj_id_hash_update (ip4_route, NMPlatformIP4Route, { _vt_cmd_plobj_id_hash_update (ip6_route, NMPlatformIP6Route, { nm_platform_ip6_route_hash_update (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h); }) +_vt_cmd_plobj_id_hash_update (qdisc, NMPlatformQdisc, { + nm_hash_update_vals (h, + obj->ifindex, + obj->parent); +}) static inline void _vt_cmd_plobj_hash_update_ip4_route (const NMPlatformObject *obj, NMHashState *h) @@ -1168,6 +1179,12 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) && !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED); } +static gboolean +_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj) +{ + return obj->object.ifindex > 0; +} + gboolean nmp_object_is_visible (const NMPObject *obj) { @@ -1197,6 +1214,12 @@ _vt_cmd_obj_is_visible_link (const NMPObject *obj) /*****************************************************************************/ +static const guint8 _supported_cache_ids_object[] = { + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, + 0, +}; + static const guint8 _supported_cache_ids_link[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, @@ -1496,6 +1519,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP6_ADDRESS: case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: + case NMP_OBJECT_TYPE_QDISC: o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); @@ -1533,7 +1557,8 @@ nmp_lookup_init_object (NMPLookup *lookup, nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC)); if (ifindex <= 0) { return nmp_lookup_init_obj_type (lookup, @@ -2561,6 +2586,24 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full, }, + [NMP_OBJECT_TYPE_QDISC - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_QDISC, + .sizeof_data = sizeof (NMPObjectQdisc), + .sizeof_public = sizeof (NMPlatformQdisc), + .obj_type_name = "qdisc", + .rtm_gettype = RTM_GETQDISC, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_QDISC, + .signal_type = NM_PLATFORM_SIGNAL_QDISC_CHANGED, + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_qdisc, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_qdisc, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_qdisc, + .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_qdisc, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_qdisc_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_qdisc_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_qdisc_cmp, + }, [NMP_OBJECT_TYPE_LNK_GRE - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_GRE, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f2149e1ee2..3adbadef5e 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -225,6 +225,10 @@ typedef struct { NMPlatformIP6Route _public; } NMPObjectIP6Route; +typedef struct { + NMPlatformQdisc _public; +} NMPObjectQdisc; + struct _NMPObject { union { NMDedupMultiObj parent; @@ -276,6 +280,9 @@ struct _NMPObject { NMPlatformIP6Route ip6_route; NMPObjectIP4Route _ip4_route; NMPObjectIP6Route _ip6_route; + + NMPlatformQdisc qdisc; + NMPObjectQdisc _qdisc; }; }; @@ -408,6 +415,15 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ }) +#define NMP_OBJECT_CAST_QDISC(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_QDISC); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \ + }) + + const NMPClass *nmp_class_from_type (NMPObjectType obj_type); static inline const NMPObject * |