summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2019-04-30 16:09:06 +0200
committerLubomir Rintel <lkundrak@v3.sk>2019-04-30 16:09:06 +0200
commit19bf820de3b869338f49ed08868feb032e27cfae (patch)
treee697477cbd16e3ab8724ca3044148e43de4d9d23
parent7574b722a6bb803679f2d7a603a24f175a0225fa (diff)
parent900292147d8fd584479a7af0881984c2d77a60bf (diff)
downloadNetworkManager-19bf820de3b869338f49ed08868feb032e27cfae.tar.gz
merge: branch 'lr/tc-attrs'
https://github.com/NetworkManager/NetworkManager/pull/338
-rw-r--r--libnm-core/nm-utils.c24
-rw-r--r--src/devices/nm-device.c52
-rw-r--r--src/platform/nm-linux-platform.c105
-rw-r--r--src/platform/nm-platform.c84
-rw-r--r--src/platform/nm-platform.h24
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;