Beniamino Galvani 2021-09-20 13:35:37 +02:00
commit e7fb9a682b
13 changed files with 212 additions and 167 deletions

View file

@ -4180,7 +4180,6 @@ check_programs += \
src/core/platform/tests/test-platform-general \
src/core/platform/tests/test-route-fake \
src/core/platform/tests/test-route-linux \
src/core/platform/tests/test-tc-fake \
src/core/platform/tests/test-tc-linux \
$(NULL)
@ -4236,11 +4235,6 @@ src_core_platform_tests_test_route_linux_CPPFLAGS = $(src_core_tests_cppflags_li
src_core_platform_tests_test_route_linux_LDFLAGS = $(src_core_platform_tests_ldflags)
src_core_platform_tests_test_route_linux_LDADD = $(src_core_platform_tests_libadd)
src_core_platform_tests_test_tc_fake_SOURCES = src/core/platform/tests/test-tc.c
src_core_platform_tests_test_tc_fake_CPPFLAGS = $(src_core_tests_cppflags_fake)
src_core_platform_tests_test_tc_fake_LDFLAGS = $(src_core_platform_tests_ldflags)
src_core_platform_tests_test_tc_fake_LDADD = $(src_core_platform_tests_libadd)
src_core_platform_tests_test_tc_linux_SOURCES = src/core/platform/tests/test-tc.c
src_core_platform_tests_test_tc_linux_CPPFLAGS = $(src_core_tests_cppflags_linux)
src_core_platform_tests_test_tc_linux_LDFLAGS = $(src_core_platform_tests_ldflags)

View file

@ -1709,5 +1709,11 @@ nm_platform_get()
void
nm_linux_platform_setup(void)
{
nm_platform_setup(nm_linux_platform_new(FALSE, FALSE));
nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, FALSE));
}
void
nm_linux_platform_setup_with_tc_cache(void)
{
nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, TRUE));
}

View file

@ -277,6 +277,7 @@ NMPlatform *nm_platform_get(void);
#define NM_PLATFORM_GET (nm_platform_get())
void nm_linux_platform_setup(void);
void nm_linux_platform_setup_with_tc_cache(void);
/*****************************************************************************/

View file

@ -505,6 +505,7 @@ typedef struct _NMDevicePrivate {
NMDeviceStageState stage1_sriov_state : 3;
bool ip_config_started : 1;
bool tc_committed : 1;
char *current_stable_id;
@ -8486,10 +8487,7 @@ tc_commit(NMDevice *self)
qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex);
tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex);
if (!nm_platform_qdisc_sync(platform, ip_ifindex, qdiscs))
return FALSE;
if (!nm_platform_tfilter_sync(platform, ip_ifindex, tfilters))
if (!nm_platform_tc_sync(platform, ip_ifindex, qdiscs, tfilters))
return FALSE;
return TRUE;
@ -8519,13 +8517,14 @@ activate_stage2_device_config(NMDevice *self)
_ethtool_state_set(self);
if (!nm_device_sys_iface_state_is_external_or_assume(self)) {
if (!tc_commit(self)) {
_LOGW(LOGD_IP6, "failed applying traffic control rules");
if (!priv->tc_committed && !tc_commit(self)) {
_LOGW(LOGD_DEVICE, "failed applying traffic control rules");
nm_device_state_changed(self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_CONFIG_FAILED);
return;
}
priv->tc_committed = TRUE;
}
_routing_rules_sync(self, NM_TERNARY_TRUE);
@ -16054,12 +16053,13 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
set_ipv6_token(self, &iid, "::");
if (nm_device_get_applied_setting(self, NM_TYPE_SETTING_TC_CONFIG)) {
nm_platform_tfilter_sync(platform, ifindex, NULL);
nm_platform_qdisc_sync(platform, ifindex, NULL);
nm_platform_tc_sync(platform, ifindex, NULL, NULL);
}
}
}
priv->tc_committed = FALSE;
_routing_rules_sync(self,
cleanup_type == CLEANUP_TYPE_KEEP ? NM_TERNARY_DEFAULT : NM_TERNARY_FALSE);

View file

@ -14,7 +14,6 @@ test_units = [
['test-platform-general', 'test-platform-general.c', test_c_flags, default_test_timeout],
['test-route-fake', 'test-route.c', test_fake_c_flags, default_test_timeout],
['test-route-linux', 'test-route.c', test_linux_c_flags, default_test_timeout],
['test-tc-fake', 'test-tc.c', test_fake_c_flags, default_test_timeout],
['test-tc-linux', 'test-tc.c', test_linux_c_flags, default_test_timeout],
]

View file

@ -37,7 +37,9 @@ gboolean
nmtstp_is_root_test(void)
{
g_assert(_nmtstp_setup_platform_func);
return _nmtstp_setup_platform_func == nm_linux_platform_setup;
return NM_IN_SET(_nmtstp_setup_platform_func,
nm_linux_platform_setup,
nm_linux_platform_setup_with_tc_cache);
}
gboolean

View file

@ -2751,7 +2751,7 @@ _test_netns_create_platform(void)
netns = nmp_netns_new();
g_assert(NMP_IS_NETNS(netns));
platform = nm_linux_platform_new(TRUE, TRUE);
platform = nm_linux_platform_new(TRUE, TRUE, TRUE);
g_assert(NM_IS_LINUX_PLATFORM(platform));
nmp_netns_pop(netns);
@ -2840,7 +2840,7 @@ test_netns_general(gpointer fixture, gconstpointer test_data)
if (_check_sysctl_skip())
return;
platform_1 = nm_linux_platform_new(TRUE, TRUE);
platform_1 = nm_linux_platform_new(TRUE, TRUE, TRUE);
platform_2 = _test_netns_create_platform();
/* add some dummy devices. The "other-*" devices are there to bump the ifindex */
@ -2968,7 +2968,7 @@ test_netns_set_netns(gpointer fixture, gconstpointer test_data)
if (_test_netns_check_skip())
return;
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE);
platforms[1] = platform_1 = _test_netns_create_platform();
platforms[2] = platform_2 = _test_netns_create_platform();
@ -3067,7 +3067,7 @@ test_netns_push(gpointer fixture, gconstpointer test_data)
if (_check_sysctl_skip())
return;
pl[0].platform = platform_0 = nm_linux_platform_new(TRUE, TRUE);
pl[0].platform = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE);
pl[1].platform = platform_1 = _test_netns_create_platform();
pl[2].platform = platform_2 = _test_netns_create_platform();
@ -3214,7 +3214,7 @@ test_netns_bind_to_path(gpointer fixture, gconstpointer test_data)
if (_test_netns_check_skip())
return;
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE);
platforms[1] = platform_1 = _test_netns_create_platform();
platforms[2] = platform_2 = _test_netns_create_platform();
@ -3379,7 +3379,7 @@ test_sysctl_netns_switch(void)
if (_test_netns_check_skip())
return;
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE);
platforms[1] = platform_1 = _test_netns_create_platform();
platforms[2] = platform_2 = _test_netns_create_platform();
PL = platforms[nmtst_get_rand_uint32() % 3];

View file

@ -31,7 +31,7 @@ test_init_linux_platform(void)
{
gs_unref_object NMPlatform *platform = NULL;
platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE);
}
/*****************************************************************************/
@ -42,7 +42,7 @@ test_link_get_all(void)
gs_unref_object NMPlatform *platform = NULL;
gs_unref_ptrarray GPtrArray *links = NULL;
platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE);
links = nm_platform_link_get_all(platform, TRUE);
}

View file

@ -57,7 +57,7 @@ test_qdisc1(void)
g_ptr_array_add(known, qdisc_new(ifindex, "fq_codel", TC_H_ROOT));
g_ptr_array_add(known, qdisc_new(ifindex, "ingress", TC_H_INGRESS));
g_assert(nm_platform_qdisc_sync(NM_PLATFORM_GET, ifindex, known));
g_assert(nm_platform_tc_sync(NM_PLATFORM_GET, ifindex, known, NULL));
plat = qdiscs_lookup(ifindex);
g_assert(plat);
g_assert_cmpint(plat->len, ==, 2);
@ -97,7 +97,7 @@ test_qdisc_fq_codel(void)
obj->qdisc.fq_codel.quantum = 1000;
g_ptr_array_add(known, obj);
g_assert(nm_platform_qdisc_sync(NM_PLATFORM_GET, ifindex, known));
g_assert(nm_platform_tc_sync(NM_PLATFORM_GET, ifindex, known, NULL));
plat = qdiscs_lookup(ifindex);
g_assert(plat);
g_assert_cmpint(plat->len, ==, 1);
@ -136,7 +136,7 @@ test_qdisc_sfq(void)
obj->qdisc.sfq.flows = 256;
g_ptr_array_add(known, obj);
g_assert(nm_platform_qdisc_sync(NM_PLATFORM_GET, ifindex, known));
g_assert(nm_platform_tc_sync(NM_PLATFORM_GET, ifindex, known, NULL));
plat = qdiscs_lookup(ifindex);
g_assert(plat);
g_assert_cmpint(plat->len, ==, 1);
@ -179,7 +179,7 @@ test_qdisc_tbf(void)
obj->qdisc.handle = TC_H_MAKE(0x8005 << 16, 0);
g_ptr_array_add(known, obj);
g_assert(nm_platform_qdisc_sync(NM_PLATFORM_GET, ifindex, known));
g_assert(nm_platform_tc_sync(NM_PLATFORM_GET, ifindex, known, NULL));
plat = qdiscs_lookup(ifindex);
g_assert(plat);
g_assert_cmpint(plat->len, ==, 2);
@ -202,7 +202,7 @@ test_qdisc_tbf(void)
/*****************************************************************************/
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup_with_tc_cache;
void
_nmtstp_init_tests(int *argc, char ***argv)
@ -213,10 +213,8 @@ _nmtstp_init_tests(int *argc, char ***argv)
void
_nmtstp_setup_tests(void)
{
if (nmtstp_is_root_test()) {
nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, TRUE);
}
nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, TRUE);
nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, TRUE);
}

View file

@ -3880,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;
@ -3980,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},
@ -3989,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;
@ -4059,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;
}
@ -8850,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)
@ -8893,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
@ -9388,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"
@ -9399,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);
@ -9445,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",
@ -9532,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;
@ -9546,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);
}
@ -9687,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;
}

View file

@ -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__ */

View file

@ -176,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;
@ -212,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
@ -5295,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;
_CHECK_SELF(self, klass, -NME_BUG);
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);
}
}
}
return success;
_LOG3D("deleting a qdisc: parent 0x%08x", parent);
return klass->qdisc_delete(self, ifindex, parent, log_error);
}
/*****************************************************************************/
@ -5398,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);
nm_platform_qdisc_delete(self, ifindex, TC_H_ROOT, FALSE);
nm_platform_qdisc_delete(self, ifindex, TC_H_INGRESS, FALSE);
if (known_tfilters) {
for (i = 0; i < known_tfilters->len; i++) {
const NMPObject *q = g_ptr_array_index(known_tfilters, i);
/* 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);
g_hash_table_insert(known_tfilters_idx, (gpointer) q, (gpointer) q);
}
}
if (known_qdiscs) {
for (i = 0; i < known_qdiscs->len; i++) {
const NMPObject *q = g_ptr_array_index(known_qdiscs, i);
plat_tfilters =
nm_platform_lookup_clone(self,
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_TFILTER, ifindex),
NULL,
NULL);
if (plat_tfilters) {
for (i = 0; i < plat_tfilters->len; i++) {
const NMPObject *q = g_ptr_array_index(plat_tfilters, 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);
}
}
@ -8937,6 +8869,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;
@ -9022,6 +8958,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 \
{ \

View file

@ -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"
/*****************************************************************************/
@ -1266,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
@ -1447,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);
@ -2219,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);