diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2019-04-30 16:09:06 +0200 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2019-04-30 16:09:06 +0200 |
commit | 19bf820de3b869338f49ed08868feb032e27cfae (patch) | |
tree | e697477cbd16e3ab8724ca3044148e43de4d9d23 | |
parent | 7574b722a6bb803679f2d7a603a24f175a0225fa (diff) | |
parent | 900292147d8fd584479a7af0881984c2d77a60bf (diff) | |
download | NetworkManager-19bf820de3b869338f49ed08868feb032e27cfae.tar.gz |
merge: branch 'lr/tc-attrs'
https://github.com/NetworkManager/NetworkManager/pull/338
-rw-r--r-- | libnm-core/nm-utils.c | 24 | ||||
-rw-r--r-- | src/devices/nm-device.c | 52 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 105 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 84 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 24 |
5 files changed, 274 insertions, 15 deletions
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 9a1430f6c7..442ab9af64 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2308,12 +2308,25 @@ static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = { NULL, }; +static const NMVariantAttributeSpec * const tc_qdisc_fq_codel_spec[] = { + TC_ATTR_SPEC_PTR ("limit", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("flows", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("target", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("interval", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("quantum", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("ce_threshold", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("memory", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("ecn", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), + NULL, +}; + typedef struct { const char *kind; const NMVariantAttributeSpec * const *attrs; } NMQdiscAttributeSpec; static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = { + &(const NMQdiscAttributeSpec) { "fq_codel", tc_qdisc_fq_codel_spec }, NULL, }; @@ -2528,6 +2541,15 @@ static const NMVariantAttributeSpec * const tc_action_simple_attribute_spec[] = NULL, }; +static const NMVariantAttributeSpec * const tc_action_mirred_attribute_spec[] = { + TC_ATTR_SPEC_PTR ("egress", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("ingress", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("mirror", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("redirect", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ), + TC_ATTR_SPEC_PTR ("dev", G_VARIANT_TYPE_STRING, TRUE, FALSE, 'a' ), + NULL, +}; + static const NMVariantAttributeSpec * const tc_action_attribute_spec[] = { TC_ATTR_SPEC_PTR ("kind", G_VARIANT_TYPE_STRING, TRUE, FALSE, 'a' ), TC_ATTR_SPEC_PTR ("", G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a' ), @@ -2622,6 +2644,8 @@ nm_utils_tc_action_from_str (const char *str, GError **error) kind = g_variant_get_string (variant, NULL); if (strcmp (kind, "simple") == 0) attrs = tc_action_simple_attribute_spec; + else if (strcmp (kind, "mirred") == 0) + attrs = tc_action_mirred_attribute_spec; else attrs = NULL; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index bd4fbcc37f..1a9a8a3745 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6526,6 +6526,29 @@ tc_commit (NMDevice *self) qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc); qdisc->info = 0; +#define GET_ATTR(name, dst, variant_type, type, dflt) G_STMT_START { \ + GVariant *_variant = nm_tc_qdisc_get_attribute (s_qdisc, ""name""); \ + \ + if ( _variant \ + && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ + (dst) = g_variant_get_ ## type (_variant); \ + else \ + (dst) = (dflt); \ +} G_STMT_END + + if (strcmp (qdisc->kind, "fq_codel") == 0) { + GET_ATTR("limit", qdisc->fq_codel.limit, UINT32, uint32, 0); + GET_ATTR("flows", qdisc->fq_codel.flows, UINT32, uint32, 0); + GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0); + GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0); + GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0); + GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, -1); + GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, -1); + GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE); + } + +#undef GET_ADDR + g_ptr_array_add (qdiscs, q); } @@ -6547,16 +6570,35 @@ tc_commit (NMDevice *self) action = nm_tc_tfilter_get_action (s_tfilter); if (action) { + GVariant *var; + tfilter->action.kind = nm_tc_action_get_kind (action); if (strcmp (tfilter->action.kind, "simple") == 0) { - GVariant *sdata; - - sdata = nm_tc_action_get_attribute (action, "sdata"); - if (sdata && g_variant_is_of_type (sdata, G_VARIANT_TYPE_BYTESTRING)) { + var = nm_tc_action_get_attribute (action, "sdata"); + if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) { g_strlcpy (tfilter->action.simple.sdata, - g_variant_get_bytestring (sdata), + g_variant_get_bytestring (var), sizeof (tfilter->action.simple.sdata)); } + } else if (strcmp (tfilter->action.kind, "mirred") == 0) { + if (nm_tc_action_get_attribute (action, "egress")) + tfilter->action.mirred.egress = TRUE; + + if (nm_tc_action_get_attribute (action, "ingress")) + tfilter->action.mirred.ingress = TRUE; + + if (nm_tc_action_get_attribute (action, "mirror")) + tfilter->action.mirred.mirror = TRUE; + + if (nm_tc_action_get_attribute (action, "redirect")) + tfilter->action.mirred.redirect = TRUE; + + var = nm_tc_action_get_attribute (action, "dev"); + if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_STRING)) { + int ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self), + g_variant_get_string (var, NULL)); + tfilter->action.mirred.ifindex = ifindex; + } } } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index d4b0115252..6064d89eb6 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -34,6 +34,7 @@ #include <linux/if_tun.h> #include <linux/if_tunnel.h> #include <linux/ip6_tunnel.h> +#include <linux/tc_act/tc_mirred.h> #include <netinet/icmp6.h> #include <netinet/in.h> #include <poll.h> @@ -84,6 +85,13 @@ enum { /*****************************************************************************/ +/* Compat with older kernels. */ + +#define TCA_FQ_CODEL_CE_THRESHOLD 7 +#define TCA_FQ_CODEL_MEMORY_LIMIT 9 + +/*****************************************************************************/ + #define VLAN_FLAG_MVRP 0x8 /*****************************************************************************/ @@ -3481,6 +3489,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, + [TCA_OPTIONS] = { .type = NLA_NESTED }, }; struct nlattr *tb[G_N_ELEMENTS (policy)]; const struct tcmsg *tcm; @@ -3506,6 +3515,45 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) obj->qdisc.parent = tcm->tcm_parent; obj->qdisc.info = tcm->tcm_info; + if (tb[TCA_OPTIONS]) { + struct nlattr *options_attr; + int remaining; + + nla_for_each_nested (options_attr, tb[TCA_OPTIONS], remaining) { + if (nla_len (options_attr) < sizeof (uint32_t)) + continue; + + if (nm_streq0 (obj->qdisc.kind, "fq_codel")) { + switch (nla_type (options_attr)) { + case TCA_FQ_CODEL_LIMIT: + obj->qdisc.fq_codel.limit = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_FLOWS: + obj->qdisc.fq_codel.flows = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_TARGET: + obj->qdisc.fq_codel.target = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_INTERVAL: + obj->qdisc.fq_codel.interval = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_QUANTUM: + obj->qdisc.fq_codel.quantum = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_CE_THRESHOLD: + obj->qdisc.fq_codel.ce_threshold = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_MEMORY_LIMIT: + obj->qdisc.fq_codel.memory = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_ECN: + obj->qdisc.fq_codel.ecn = nla_get_u32 (options_attr); + break; + } + } + } + } + return obj; } @@ -4161,6 +4209,7 @@ _nl_msg_new_qdisc (int nlmsg_type, const NMPlatformQdisc *qdisc) { nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nlattr *tc_options; const struct tcmsg tcm = { .tcm_family = qdisc->addr_family, .tcm_ifindex = qdisc->ifindex, @@ -4176,6 +4225,30 @@ _nl_msg_new_qdisc (int nlmsg_type, NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); + if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) + goto nla_put_failure; + + if (strcmp (qdisc->kind, "fq_codel") == 0) { + if (qdisc->fq_codel.limit) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit); + if (qdisc->fq_codel.flows) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_FLOWS, qdisc->fq_codel.flows); + if (qdisc->fq_codel.target) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_TARGET, qdisc->fq_codel.target); + if (qdisc->fq_codel.interval) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval); + if (qdisc->fq_codel.quantum) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum); + if (qdisc->fq_codel.ce_threshold != -1) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold); + if (qdisc->fq_codel.memory != -1) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory); + if (qdisc->fq_codel.ecn) + NLA_PUT_S32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn); + } + + nla_nest_end (msg, tc_options); + return g_steal_pointer (&msg); nla_put_failure: @@ -4204,6 +4277,36 @@ nla_put_failure: } static gboolean +_add_action_mirred (struct nl_msg *msg, + const NMPlatformActionMirred *mirred) +{ + struct nlattr *act_options; + struct tc_mirred sel = { 0, }; + + if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS))) + goto nla_put_failure; + + if (mirred->egress && mirred->redirect) + sel.eaction = TCA_EGRESS_REDIR; + else if (mirred->egress && mirred->mirror) + sel.eaction = TCA_EGRESS_MIRROR; + else if (mirred->ingress && mirred->redirect) + sel.eaction = TCA_INGRESS_REDIR; + else if (mirred->ingress && mirred->mirror) + sel.eaction = TCA_INGRESS_MIRROR; + sel.ifindex = mirred->ifindex; + + NLA_PUT (msg, TCA_MIRRED_PARMS, sizeof (sel), &sel); + + nla_nest_end (msg, act_options); + + return TRUE; + +nla_put_failure: + return FALSE; +} + +static gboolean _add_action (struct nl_msg *msg, const NMPlatformAction *action) { @@ -4218,6 +4321,8 @@ _add_action (struct nl_msg *msg, if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) _add_action_simple (msg, &action->simple); + else if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_MIRRED)) + _add_action_mirred (msg, &action->mirred); nla_nest_end (msg, prio); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 1fc0ccb750..6f23ddb589 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -34,6 +34,7 @@ #include <linux/if_tun.h> #include <linux/if_tunnel.h> #include <linux/rtnetlink.h> +#include <linux/tc_act/tc_mirred.h> #include <libudev.h> #include "nm-utils.h" @@ -6430,13 +6431,32 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len) 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); + 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); + + if (nm_streq0 (qdisc->kind, "fq_codel")) { + if (qdisc->fq_codel.limit) + nm_utils_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); + if (qdisc->fq_codel.target) + nm_utils_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); + if (qdisc->fq_codel.quantum) + nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum); + if (qdisc->fq_codel.ce_threshold != -1) + nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold); + if (qdisc->fq_codel.memory != -1) + nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory); + if (qdisc->fq_codel.ecn) + nm_utils_strbuf_append (&buf, &len, " ecn"); + } return buf; } @@ -6451,6 +6471,17 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h) obj->handle, obj->parent, obj->info); + if (nm_streq0 (obj->kind, "fq_codel")) { + nm_hash_update_vals (h, + obj->fq_codel.limit, + obj->fq_codel.flows, + obj->fq_codel.target, + obj->fq_codel.interval, + obj->fq_codel.quantum, + obj->fq_codel.ce_threshold, + obj->fq_codel.memory, + obj->fq_codel.ecn == TRUE); + } } int @@ -6464,6 +6495,17 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b) NM_CMP_FIELD (a, b, handle); NM_CMP_FIELD (a, b, info); + if (nm_streq0 (a->kind, "fq_codel")) { + NM_CMP_FIELD (a, b, fq_codel.limit); + NM_CMP_FIELD (a, b, fq_codel.flows); + NM_CMP_FIELD (a, b, fq_codel.target); + NM_CMP_FIELD (a, b, fq_codel.interval); + NM_CMP_FIELD (a, b, fq_codel.quantum); + NM_CMP_FIELD (a, b, fq_codel.ce_threshold); + NM_CMP_FIELD (a, b, fq_codel.memory); + NM_CMP_FIELD (a, b, fq_codel.ecn == TRUE); + } + return 0; } @@ -6492,11 +6534,18 @@ nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsiz NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL | 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); } } else act_buf[0] = '\0'; - g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x%s", + g_snprintf (buf, len, "%s%s family %u handle %x parent %x info %x%s", tfilter->kind, _to_string_dev (NULL, tfilter->ifindex, str_dev, sizeof (str_dev)), tfilter->addr_family, @@ -6520,8 +6569,16 @@ nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h) obj->info); if (obj->action.kind) { nm_hash_update_str (h, obj->action.kind); - if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { nm_hash_update_strarr (h, obj->action.simple.sdata); + } else if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { + nm_hash_update_vals (h, + obj->action.mirred.ingress, + obj->action.mirred.egress, + obj->action.mirred.mirror, + obj->action.mirred.redirect, + obj->action.mirred.ifindex); + } } } @@ -6538,8 +6595,15 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b) NM_CMP_FIELD_STR_INTERNED (a, b, action.kind); if (a->action.kind) { - if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { NM_CMP_FIELD_STR (a, b, action.simple.sdata); + } else if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { + NM_CMP_FIELD (a, b, action.mirred.ingress); + NM_CMP_FIELD (a, b, action.mirred.egress); + NM_CMP_FIELD (a, b, action.mirred.mirror); + NM_CMP_FIELD (a, b, action.mirred.redirect); + NM_CMP_FIELD (a, b, action.mirred.ifindex); + } } return 0; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 97be88324e..16747f093b 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -597,12 +597,26 @@ typedef struct { } NMPlatformRoutingRule; typedef struct { + guint32 limit; + guint32 flows; + guint32 target; + guint32 interval; + guint32 quantum; + guint32 ce_threshold; + guint32 memory; + bool ecn:1; +} NMPlatformQdiscFqCodel; + +typedef struct { __NMPlatformObjWithIfindex_COMMON; const char *kind; int addr_family; guint32 handle; guint32 parent; guint32 info; + union { + NMPlatformQdiscFqCodel fq_codel; + }; } NMPlatformQdisc; typedef struct { @@ -610,13 +624,23 @@ typedef struct { } NMPlatformActionSimple; typedef struct { + gboolean egress; + gboolean ingress; + gboolean mirror; + gboolean redirect; + int ifindex; +} NMPlatformActionMirred; + +typedef struct { const char *kind; union { NMPlatformActionSimple simple; + NMPlatformActionMirred mirred; }; } NMPlatformAction; #define NM_PLATFORM_ACTION_KIND_SIMPLE "simple" +#define NM_PLATFORM_ACTION_KIND_MIRRED "mirred" typedef struct { __NMPlatformObjWithIfindex_COMMON; |