Commit 5d851c0f authored by Thomas Haller's avatar Thomas Haller

libnm,platform: merge branch 'th/various-cleanup-platform-libnm'

NetworkManager/NetworkManager!131
parents 143f518c f2ae994b
Pipeline #35691 passed with stages
in 23 minutes and 3 seconds
......@@ -1212,25 +1212,22 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
g_hash_table_remove (route->attributes, name);
}
#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \
&(NMVariantAttributeSpec) { name, type, v4, v6, FALSE, FALSE, str_type }
static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, FALSE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, .v4 = TRUE, .v6 = TRUE, .str_type = 'a', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, .v6 = TRUE, .str_type = 'p', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_ONLINK, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ),
NULL,
};
......
......@@ -365,17 +365,14 @@ nm_sriov_vf_get_attribute (const NMSriovVF *vf, const char *name)
return g_hash_table_lookup (vf->attributes, name);
}
#define SRIOV_ATTR_SPEC_PTR(name, type, str_type) \
&(NMVariantAttributeSpec) { name, type, FALSE, FALSE, FALSE, FALSE, str_type }
const NMVariantAttributeSpec * const _nm_sriov_vf_attribute_spec[] = {
SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MAC, G_VARIANT_TYPE_STRING, 'm'),
SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, G_VARIANT_TYPE_BOOLEAN, 0),
SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_TRUST, G_VARIANT_TYPE_BOOLEAN, 0),
SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, G_VARIANT_TYPE_UINT32, 0),
SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, G_VARIANT_TYPE_UINT32, 0),
const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MAC, G_VARIANT_TYPE_STRING, .str_type = 'm', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, G_VARIANT_TYPE_BOOLEAN, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_TRUST, G_VARIANT_TYPE_BOOLEAN, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, G_VARIANT_TYPE_UINT32, ),
/* D-Bus only, synthetic attributes */
SRIOV_ATTR_SPEC_PTR ("vlans", G_VARIANT_TYPE_STRING, 'd'),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("vlans", G_VARIANT_TYPE_STRING, .str_type = 'd', ),
NULL,
};
......
......@@ -38,6 +38,13 @@ struct _NMVariantAttributeSpec {
char str_type;
};
#define NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(_name, _type, ...) \
(&((const NMVariantAttributeSpec) { \
.name = _name, \
.type = _type, \
__VA_ARGS__ \
}))
gboolean _nm_utils_string_slist_validate (GSList *list,
const char **valid_values);
......
......@@ -2279,50 +2279,76 @@ _nm_utils_string_append_tc_parent (GString *string, const char *prefix, guint32
guint32
_nm_utils_parse_tc_handle (const char *str, GError **error)
{
gint64 maj, min;
char *sep;
gint64 maj;
gint64 min = 0;
const char *sep;
maj = g_ascii_strtoll (str, &sep, 0x10);
if (*sep == ':')
min = g_ascii_strtoll (&sep[1], &sep, 0x10);
else
min = 0;
nm_assert (str);
if (*sep != '\0' || maj <= 0 || maj > 0xffff || min < 0 || min > 0xffff) {
g_set_error (error, 1, 0, _("'%s' is not a valid handle."), str);
return TC_H_UNSPEC;
maj = g_ascii_strtoll (str, (char **) &sep, 0x10);
if (sep == str)
goto fail;
sep = nm_str_skip_leading_spaces (sep);
if (sep[0] == ':') {
const char *str2 = &sep[1];
min = g_ascii_strtoll (str2, (char **) &sep, 0x10);
sep = nm_str_skip_leading_spaces (sep);
if (sep[0] != '\0')
goto fail;
} else if (sep[0] != '\0')
goto fail;
if ( maj <= 0
|| maj > 0xffff
|| min < 0
|| min > 0xffff
|| !NM_STRCHAR_ALL (str, ch, ( g_ascii_isxdigit (ch)
|| ch == ':'
|| g_ascii_isspace (ch)))) {
goto fail;
}
return TC_H_MAKE (maj << 16, min);
return TC_H_MAKE (((guint32) maj) << 16, (guint32) min);
fail:
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not a valid handle."), str);
return TC_H_UNSPEC;
}
#define TC_ATTR_SPEC_PTR(name, type, no_value, consumes_rest, str_type) \
&(NMVariantAttributeSpec) { name, type, FALSE, FALSE, no_value, consumes_rest, str_type }
static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = {
TC_ATTR_SPEC_PTR ("root", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ),
TC_ATTR_SPEC_PTR ("parent", G_VARIANT_TYPE_STRING, FALSE, FALSE, 'a' ),
TC_ATTR_SPEC_PTR ("handle", G_VARIANT_TYPE_STRING, FALSE, FALSE, 'a' ),
TC_ATTR_SPEC_PTR ("kind", G_VARIANT_TYPE_STRING, TRUE, FALSE, 'a' ),
TC_ATTR_SPEC_PTR ("", G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a' ),
static const NMVariantAttributeSpec *const tc_object_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("root", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("parent", G_VARIANT_TYPE_STRING, .str_type = 'a', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("handle", G_VARIANT_TYPE_STRING, .str_type = 'a', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("kind", G_VARIANT_TYPE_STRING, .no_value = TRUE, .str_type = 'a', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("", G_VARIANT_TYPE_STRING, .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
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 ),
static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("limit", G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("flows", G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("target", G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("interval", G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("quantum", G_VARIANT_TYPE_UINT32, ),
/* 0x83126E97u is not a valid value (it means "disabled"). We should reject that
* value. Or alternatively, reject all values >= MAX_INT(32). */
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ce_threshold", G_VARIANT_TYPE_UINT32, ),
/* kernel clamps the value at 2^31. Possibly such values should be rejected from configuration
* as they cannot be configured. Leaving the attribute unspecified causes kernel to choose
* a default (currently 32MB). */
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("memory_limit", G_VARIANT_TYPE_UINT32, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ecn", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NULL,
};
typedef struct {
const char *kind;
const NMVariantAttributeSpec * const *attrs;
const NMVariantAttributeSpec *const *attrs;
} NMQdiscAttributeSpec;
static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
......@@ -2536,23 +2562,23 @@ nm_utils_tc_qdisc_from_str (const char *str, GError **error)
/*****************************************************************************/
static const NMVariantAttributeSpec * const tc_action_simple_attribute_spec[] = {
TC_ATTR_SPEC_PTR ("sdata", G_VARIANT_TYPE_BYTESTRING, FALSE, FALSE, 0 ),
static const NMVariantAttributeSpec *const tc_action_simple_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("sdata", G_VARIANT_TYPE_BYTESTRING, ),
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' ),
static const NMVariantAttributeSpec *const tc_action_mirred_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("egress", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ingress", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("mirror", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("redirect", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("dev", G_VARIANT_TYPE_STRING, .no_value = TRUE, .str_type = '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' ),
static const NMVariantAttributeSpec *const tc_action_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("kind", G_VARIANT_TYPE_STRING, .no_value = TRUE, .str_type = 'a', ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("", G_VARIANT_TYPE_STRING, .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
NULL,
};
......@@ -2621,7 +2647,7 @@ nm_utils_tc_action_from_str (const char *str, GError **error)
gs_unref_hashtable GHashTable *ht = NULL;
gs_unref_hashtable GHashTable *options = NULL;
GVariant *variant;
const NMVariantAttributeSpec * const *attrs;
const NMVariantAttributeSpec *const *attrs;
nm_assert (str);
nm_assert (!error || !*error);
......@@ -2749,9 +2775,9 @@ nm_utils_tc_tfilter_to_str (NMTCTfilter *tfilter, GError **error)
return g_string_free (string, FALSE);
}
static const NMVariantAttributeSpec * const tc_tfilter_attribute_spec[] = {
TC_ATTR_SPEC_PTR ("action", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ),
TC_ATTR_SPEC_PTR ("", G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a' ),
static const NMVariantAttributeSpec *const tc_tfilter_attribute_spec[] = {
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("action", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("", G_VARIANT_TYPE_STRING, .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
NULL,
};
......@@ -6441,7 +6467,7 @@ nm_utils_parse_variant_attributes (const char *string,
gs_unref_hashtable GHashTable *ht = NULL;
const char *ptr = string, *start = NULL, *sep;
GVariant *variant;
const NMVariantAttributeSpec * const *s;
const NMVariantAttributeSpec *const *s;
g_return_val_if_fail (string, NULL);
g_return_val_if_fail (attr_separator, NULL);
......
......@@ -3088,6 +3088,60 @@ test_routing_rule (gconstpointer test_data)
/*****************************************************************************/
static void
test_parse_tc_handle (void)
{
#define _parse_tc_handle(str, exp) \
G_STMT_START { \
gs_free_error GError *_error = NULL; \
GError **_perror = nmtst_get_rand_bool () ? &_error : NULL; \
guint32 _v; \
const guint32 _v_exp = (exp); \
\
_v = _nm_utils_parse_tc_handle (""str"", _perror); \
\
if (_v != _v_exp) \
g_error ("%s:%d: \"%s\" gave %08x but %08x expected.", __FILE__, __LINE__, ""str"", _v, _v_exp); \
\
if (_v == TC_H_UNSPEC) \
g_assert (!_perror || *_perror); \
else \
g_assert (!_perror || !*_perror); \
\
} G_STMT_END
#define _parse_tc_handle_inval(str) _parse_tc_handle (str, TC_H_UNSPEC)
#define _parse_tc_handle_valid(str, maj, min) _parse_tc_handle (str, TC_H_MAKE (((guint32) (maj)) << 16, ((guint16) (min))))
_parse_tc_handle_inval ("");
_parse_tc_handle_inval (" ");
_parse_tc_handle_inval (" \n");
_parse_tc_handle_valid ("1", 1, 0);
_parse_tc_handle_valid(" 1 ", 1, 0);
_parse_tc_handle_valid ("1:", 1, 0);
_parse_tc_handle_valid ("1: ", 1, 0);
_parse_tc_handle_valid ("1:0", 1, 0);
_parse_tc_handle_valid ("1 :0", 1, 0);
_parse_tc_handle_valid ("1 \t\n\f\r:0", 1, 0);
_parse_tc_handle_inval ("1 \t\n\f\r\v:0");
_parse_tc_handle_valid (" 1 : 0 ", 1, 0);
_parse_tc_handle_inval (" \t\v\n1: 0");
_parse_tc_handle_valid ("1:2", 1, 2);
_parse_tc_handle_valid ("01:02", 1, 2);
_parse_tc_handle_inval ("0x01:0x02");
_parse_tc_handle_valid (" 01: 02", 1, 2);
_parse_tc_handle_valid ("019: 020", 0x19, 0x20);
_parse_tc_handle_valid ("FFFF: 020", 0xFFFF, 0x20);
_parse_tc_handle_valid ("FfFF: ffff", 0xFFFF, 0xFFFF);
_parse_tc_handle_valid ("FFFF", 0xFFFF, 0);
_parse_tc_handle_inval ("0xFFFF");
_parse_tc_handle_inval ("10000");
_parse_tc_handle_valid ("\t\n\f\r FFFF", 0xFFFF, 0);
_parse_tc_handle_inval ("\t\n\f\r \vFFFF");
}
/*****************************************************************************/
NMTST_DEFINE ();
int
......@@ -3173,5 +3227,7 @@ main (int argc, char **argv)
g_test_add_data_func ("/libnm/settings/routing-rule/1", GINT_TO_POINTER (0), test_routing_rule);
g_test_add_func ("/libnm/parse-tc-handle", test_parse_tc_handle);
return g_test_run ();
}
......@@ -734,10 +734,7 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
gint64 v;
const char *s = NULL;
if (str) {
while (g_ascii_isspace (str[0]))
str++;
}
str = nm_str_skip_leading_spaces (str);
if (!str || !str[0]) {
errno = EINVAL;
return fallback;
......@@ -748,9 +745,9 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
if (errno != 0)
return fallback;
if (s[0] != '\0') {
while (g_ascii_isspace (s[0]))
s++;
s = nm_str_skip_leading_spaces (s);
if (s[0] != '\0') {
errno = EINVAL;
return fallback;
......
......@@ -6500,7 +6500,7 @@ tc_commit (NMDevice *self)
NMSettingTCConfig *s_tc = NULL;
int ip_ifindex;
guint nqdiscs, ntfilters;
int i;
guint i;
connection = nm_device_get_applied_connection (self);
if (connection)
......@@ -6520,7 +6520,12 @@ tc_commit (NMDevice *self)
NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC (q);
qdisc->ifindex = ip_ifindex;
/* Note: kind string is still owned by NMTCTfilter.
* This qdisc instance must not be kept alive beyond this function.
* nm_platform_qdisc_sync() promises to do that. */
qdisc->kind = nm_tc_qdisc_get_kind (s_qdisc);
qdisc->addr_family = AF_UNSPEC;
qdisc->handle = nm_tc_qdisc_get_handle (s_qdisc);
qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc);
......@@ -6537,14 +6542,14 @@ tc_commit (NMDevice *self)
} 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);
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, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED);
GET_ATTR ("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
GET_ATTR ("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
}
#undef GET_ADDR
......@@ -6562,7 +6567,12 @@ tc_commit (NMDevice *self)
NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER (q);
tfilter->ifindex = ip_ifindex;
/* Note: kind string is still owned by NMTCTfilter.
* This tfilter instance must not be kept alive beyond this function.
* nm_platform_tfilter_sync() promises to do that. */
tfilter->kind = nm_tc_tfilter_get_kind (s_tfilter);
tfilter->addr_family = AF_UNSPEC;
tfilter->handle = nm_tc_tfilter_get_handle (s_tfilter);
tfilter->parent = nm_tc_tfilter_get_parent (s_tfilter);
......@@ -6572,7 +6582,11 @@ tc_commit (NMDevice *self)
if (action) {
GVariant *var;
/* Note: kind string is still owned by NMTCAction.
* This tfilter instance must not be kept alive beyond this function.
* nm_platform_tfilter_sync() promises to do that. */
tfilter->action.kind = nm_tc_action_get_kind (action);
if (strcmp (tfilter->action.kind, "simple") == 0) {
var = nm_tc_action_get_attribute (action, "sdata");
if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) {
......@@ -6595,8 +6609,11 @@ tc_commit (NMDevice *self)
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),
int ifindex;
ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self),
g_variant_get_string (var, NULL));
if (ifindex > 0)
tfilter->action.mirred.ifindex = ifindex;
}
}
......
......@@ -3515,6 +3515,11 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
obj->qdisc.parent = tcm->tcm_parent;
obj->qdisc.info = tcm->tcm_info;
if (nm_streq0 (obj->qdisc.kind, "fq_codel")) {
obj->qdisc.fq_codel.memory_limit = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET;
obj->qdisc.fq_codel.ce_threshold = NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED;
}
if (tb[TCA_OPTIONS]) {
struct nlattr *options_attr;
int remaining;
......@@ -3544,10 +3549,10 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
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);
obj->qdisc.fq_codel.memory_limit = nla_get_u32 (options_attr);
break;
case TCA_FQ_CODEL_ECN:
obj->qdisc.fq_codel.ecn = nla_get_u32 (options_attr);
obj->qdisc.fq_codel.ecn = !!nla_get_u32 (options_attr);
break;
}
}
......@@ -3676,7 +3681,7 @@ _nl_msg_new_link_set_afspec (struct nl_msg *msg,
return TRUE;
nla_put_failure:
return FALSE;
g_return_val_if_reached (FALSE);
}
static gboolean
......@@ -3827,7 +3832,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg,
return TRUE;
nla_put_failure:
return FALSE;
g_return_val_if_reached (FALSE);
}
static struct nl_msg *
......@@ -4239,12 +4244,12 @@ _nl_msg_new_qdisc (int nlmsg_type,
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)
if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
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.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory_limit);
if (qdisc->fq_codel.ecn)
NLA_PUT_S32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
}
nla_nest_end (msg, tc_options);
......@@ -4255,11 +4260,47 @@ nla_put_failure:
g_return_val_if_reached (NULL);
}
static gboolean
_add_action_simple (struct nl_msg *msg,
const NMPlatformActionSimple *simple)
static struct nl_msg *
_nl_msg_new_tfilter (int nlmsg_type,
int nlmsg_flags,
const NMPlatformTfilter *tfilter)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
struct nlattr *tc_options;
struct nlattr *act_tab;
const struct tcmsg tcm = {
.tcm_family = tfilter->addr_family,
.tcm_ifindex = tfilter->ifindex,
.tcm_handle = tfilter->handle,
.tcm_parent = tfilter->parent,
.tcm_info = tfilter->info,
};
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
if (nlmsg_append_struct (msg, &tcm) < 0)
goto nla_put_failure;
NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind);
if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS)))
goto nla_put_failure;
if (!(act_tab = nla_nest_start (msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND
goto nla_put_failure;
if (tfilter->action.kind) {
const NMPlatformAction *action = &tfilter->action;
struct nlattr *prio;
struct nlattr *act_options;
if (!(prio = nla_nest_start (msg, 1 /* priority */)))
goto nla_put_failure;
NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind);
if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
const NMPlatformActionSimple *simple = &action->simple;
struct tc_defact sel = { 0, };
if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
......@@ -4270,17 +4311,8 @@ _add_action_simple (struct nl_msg *msg,
nla_nest_end (msg, act_options);
return TRUE;
nla_put_failure:
return FALSE;
}
static gboolean
_add_action_mirred (struct nl_msg *msg,
const NMPlatformActionMirred *mirred)
{
struct nlattr *act_options;
} else if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
const NMPlatformActionMirred *mirred = &action->mirred;
struct tc_mirred sel = { 0, };
if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
......@@ -4299,70 +4331,10 @@ _add_action_mirred (struct nl_msg *msg,
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)
{
struct nlattr *prio;
nm_assert (action || action->kind);
if (!(prio = nla_nest_start (msg, 1 /* priority */)))
goto nla_put_failure;
NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind);
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);
return TRUE;
nla_put_failure:
return FALSE;
}
static struct nl_msg *
_nl_msg_new_tfilter (int nlmsg_type,
int nlmsg_flags,
const NMPlatformTfilter *tfilter)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
struct nlattr *tc_options;
struct nlattr *act_tab;
const struct tcmsg tcm = {
.tcm_family = tfilter->addr_family,
.tcm_ifindex = tfilter->ifindex,
.tcm_handle = tfilter->handle,
.tcm_parent = tfilter->parent,
.tcm_info = tfilter->info,
};
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
if (nlmsg_append_struct (msg, &tcm) < 0)
goto nla_put_failure;
NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind);
if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS)))
goto nla_put_failure;
if (!(act_tab = nla_nest_start (msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND
goto nla_put_failure;
if (tfilter->action.kind)
_add_action (msg, &tfilter->action);
}
nla_nest_end (msg, tc_options);
......@@ -8273,6 +8245,9 @@ qdisc_add (NMPlatform *platform,
char s_buf[256];
nm_auto_nlmsg struct nl_msg *msg = NULL;
/* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind
* is undefined. */
msg = _nl_msg_new_qdisc (RTM_NEWQDISC, flags, qdisc);
event_handler_read_netlink (platform, FALSE);
......@@ -8314,6 +8289,9 @@ tfilter_add (NMPlatform *platform,
char s_buf[256];
nm_auto_nlmsg struct nl_msg *msg = NULL;
/* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind
* and tfilter.action.kind is undefined. */
msg = _nl_msg_new_tfilter (RTM_NEWTFILTER, flags, tfilter);
event_handler_read_netlink (platform, FALSE);
......
......@@ -5077,10 +5077,27 @@ nm_platform_qdisc_add (NMPlatform *self,
int ifindex = qdisc->ifindex;
_CHECK_SELF (self, klass, -NME_BUG);
/* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind
* is undefined. */
_LOG3D ("adding or updating a qdisc: %s", nm_platform_qdisc_to_string (qdisc, NULL, 0));
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,
......@@ -5143,10 +5160,27 @@ nm_platform_tfilter_add (NMPlatform *self,
int ifindex = tfilter->ifindex;
_CHECK_SELF (self, klass, -NME_BUG);
/* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind
* and tfilter.action.kind is undefined. */
_LOG3D ("adding or updating a tfilter: %s", nm_platform_tfilter_to_string (tfilter, NULL, 0));
return klass->tfilter_add (self, flags, tfilter);
}
/**
* nm_platform_qdisc_sync:
* @self: the #NMPlatform instance
* @ifindex: the ifindex where to configure the qdiscs.