libnm: implement team's _link_watcher_from_variant() reusing meta data

- re-use the existing meta-data. That is, don't duplicate the
dbus-names, the types, or the default value. Instead, parse the
settings according to these flags.

- notice and return if there are any suspicious/wrong keys in the
variant. For strict parsing, we should not silently ignore them.

- previously, the code used g_variant_lookup() to search for the
expected keys. As the number of keys that we look up is fixed, this
still had O(n). But if we want to detect and reject invalid keys,
we cannot use g_variant_lookup() but need to iterate the entire variant
once.
This commit is contained in:
Thomas Haller
2019-05-22 18:08:49 +02:00
parent 396818c35d
commit cfcc4ff7e3

View File

@@ -120,6 +120,25 @@ typedef enum {
LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS,
} LinkWatcherAttribute;
#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL LINK_WATCHER_ATTRIBUTE_NAME, \
LINK_WATCHER_ATTRIBUTE_DELAY_UP, \
LINK_WATCHER_ATTRIBUTE_DELAY_DOWN
#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING LINK_WATCHER_ATTRIBUTE_NAME, \
LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \
LINK_WATCHER_ATTRIBUTE_INTERVAL, \
LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \
LINK_WATCHER_ATTRIBUTE_TARGET_HOST
#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING LINK_WATCHER_ATTRIBUTE_NAME, \
LINK_WATCHER_ATTRIBUTE_INIT_WAIT, \
LINK_WATCHER_ATTRIBUTE_INTERVAL, \
LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \
LINK_WATCHER_ATTRIBUTE_VLANID, \
LINK_WATCHER_ATTRIBUTE_TARGET_HOST, \
LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, \
LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, \
LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, \
LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS
typedef struct {
const char *js_key;
const char *dbus_name;
@@ -1064,8 +1083,7 @@ _link_watcher_from_json (const json_t *root_js_obj,
\
for (_i = 0; _i < (int) G_N_ELEMENTS ((_parse_results)); _i++) { \
if ( (_parse_results)[_i].has \
&& !NM_IN_SET ((LinkWatcherAttribute) _i, LINK_WATCHER_ATTRIBUTE_NAME, \
__VA_ARGS__)) \
&& !NM_IN_SET ((LinkWatcherAttribute) _i, __VA_ARGS__)) \
break; \
} \
\
@@ -1075,19 +1093,13 @@ _link_watcher_from_json (const json_t *root_js_obj,
v_name = _LINK_WATCHER_ATTR_GET_STRING (args, LINK_WATCHER_ATTRIBUTE_NAME);
if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
LINK_WATCHER_ATTRIBUTE_DELAY_UP,
LINK_WATCHER_ATTRIBUTE_DELAY_DOWN))
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args, _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL))
*out_unrecognized_content = TRUE;
result = nm_team_link_watcher_new_ethtool (_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_UP),
_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN),
NULL);
} else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_NSNA_PING)) {
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
LINK_WATCHER_ATTRIBUTE_INIT_WAIT,
LINK_WATCHER_ATTRIBUTE_INTERVAL,
LINK_WATCHER_ATTRIBUTE_MISSED_MAX,
LINK_WATCHER_ATTRIBUTE_TARGET_HOST))
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args, _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING))
*out_unrecognized_content = TRUE;
result = nm_team_link_watcher_new_nsna_ping (_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT),
_LINK_WATCHER_ATTR_GET_INT (args, LINK_WATCHER_ATTRIBUTE_INTERVAL),
@@ -1097,16 +1109,7 @@ _link_watcher_from_json (const json_t *root_js_obj,
} else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
NMTeamLinkWatcherArpPingFlags v_flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args,
LINK_WATCHER_ATTRIBUTE_INIT_WAIT,
LINK_WATCHER_ATTRIBUTE_INTERVAL,
LINK_WATCHER_ATTRIBUTE_MISSED_MAX,
LINK_WATCHER_ATTRIBUTE_VLANID,
LINK_WATCHER_ATTRIBUTE_TARGET_HOST,
LINK_WATCHER_ATTRIBUTE_SOURCE_HOST,
LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE,
LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE,
LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS))
if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES (args, _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING))
*out_unrecognized_content = TRUE;
if (_LINK_WATCHER_ATTR_GET_BOOL (args, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE))
@@ -1182,75 +1185,134 @@ _link_watcher_to_variant (const NMTeamLinkWatcher *link_watcher)
return g_variant_builder_end (&builder);
}
static NMTeamLinkWatcher *
_link_watcher_from_variant (GVariant *watcher_var)
#define _LINK_WATCHER_ATTR_VARGET(variants, link_watcher_attribute, _value_type, c_type, _cmd) \
({ \
GVariant *const*_variants = (variants); \
GVariant *_cc; \
\
nm_assert (link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \
\
(_cc = _variants[(link_watcher_attribute)]) \
? (_cmd) \
: link_watcher_attr_datas[(link_watcher_attribute)].default_val.c_type; \
})
#define _LINK_WATCHER_ATTR_VARGET_BOOL(variants, link_watcher_attribute) (_LINK_WATCHER_ATTR_VARGET (variants, link_watcher_attribute, NM_VALUE_TYPE_BOOL, v_bool, g_variant_get_boolean (_cc) ))
#define _LINK_WATCHER_ATTR_VARGET_INT(variants, link_watcher_attribute) (_LINK_WATCHER_ATTR_VARGET (variants, link_watcher_attribute, NM_VALUE_TYPE_INT, v_int, g_variant_get_int32 (_cc) ))
#define _LINK_WATCHER_ATTR_VARGET_STRING(variants, link_watcher_attribute) (_LINK_WATCHER_ATTR_VARGET (variants, link_watcher_attribute, NM_VALUE_TYPE_STRING, v_string, g_variant_get_string (_cc, NULL) ))
static void
_variants_list_link_watcher_unref_auto (GVariant *(*p_variants)[])
{
NMTeamLinkWatcher *watcher;
const char *name;
int val1;
int val2;
int val3 = 0;
int val4 = -1;
const char *target_host = NULL;
const char *source_host = NULL;
gboolean bval;
NMTeamLinkWatcherArpPingFlags flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
gs_free_error GError *error = NULL;
int i;
nm_assert (g_variant_is_of_type (watcher_var, G_VARIANT_TYPE ("a{sv}")));
for (i = 0; i < (int) G_N_ELEMENTS (link_watcher_attr_datas); i++)
nm_g_variant_unref ((*p_variants)[i]);
}
if (!g_variant_lookup (watcher_var, "name", "&s", &name))
return NULL;
static NMTeamLinkWatcher *
_link_watcher_from_variant (GVariant *watcher_var,
gboolean *out_unrecognized_content)
{
nm_auto (_variants_list_link_watcher_unref_auto) GVariant *variants[G_N_ELEMENTS (link_watcher_attr_datas)] = { NULL, };
const char *v_key;
GVariant *v_val;
const char *v_name;
NMTeamLinkWatcher *result = NULL;
GVariantIter iter;
if (!NM_IN_STRSET (name,
NM_TEAM_LINK_WATCHER_ETHTOOL,
NM_TEAM_LINK_WATCHER_ARP_PING,
NM_TEAM_LINK_WATCHER_NSNA_PING)) {
return NULL;
}
g_return_val_if_fail (g_variant_is_of_type (watcher_var, G_VARIANT_TYPE ("a{sv}")), NULL);
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
if (!g_variant_lookup (watcher_var, "delay-up", "i", &val1))
val1 = 0;
if (!g_variant_lookup (watcher_var, "delay-down", "i", &val2))
val2 = 0;
watcher = nm_team_link_watcher_new_ethtool (val1, val2, &error);
} else {
if (!g_variant_lookup (watcher_var, "target-host", "&s", &target_host))
return NULL;
if (!g_variant_lookup (watcher_var, "init-wait", "i", &val1))
val1 = 0;
if (!g_variant_lookup (watcher_var, "interval", "i", &val2))
val2 = 0;
if (!g_variant_lookup (watcher_var, "missed-max", "i", &val3))
val3 = 3;
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
if (!g_variant_lookup (watcher_var, "vlanid", "i", &val4))
val4 = -1;
if (!g_variant_lookup (watcher_var, "source-host", "&s", &source_host))
return NULL;
if (!g_variant_lookup (watcher_var, "validate-active", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
if (!g_variant_lookup (watcher_var, "validate-inactive", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
if (!g_variant_lookup (watcher_var, "send-always", "b", &bval))
bval = FALSE;
if (bval)
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
watcher = nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4,
target_host, source_host,
flags, &error);
} else {
watcher = nm_team_link_watcher_new_nsna_ping (val1, val2, val3,
target_host, &error);
g_variant_iter_init (&iter, watcher_var);
while (g_variant_iter_next (&iter, "{&sv}", &v_key, &v_val)) {
_nm_unused gs_unref_variant GVariant *v_val_free = v_val;
const LinkWatcherAttrData *attr_data = NULL;
const GVariantType *variant_type;
int i;
for (i = 0; i < (int) G_N_ELEMENTS (link_watcher_attr_datas); i++) {
if (nm_streq (link_watcher_attr_datas[i].dbus_name, v_key)) {
attr_data = &link_watcher_attr_datas[i];
break;
}
}
if (!attr_data) {
*out_unrecognized_content = TRUE;
continue;
}
if (attr_data->value_type == NM_VALUE_TYPE_INT)
variant_type = G_VARIANT_TYPE_INT32;
else
variant_type = nm_value_type_get_variant_type (attr_data->value_type);
if (!g_variant_is_of_type (v_val, variant_type)) {
*out_unrecognized_content = TRUE;
continue;
}
if (variants[attr_data->link_watcher_attr]) {
*out_unrecognized_content = TRUE;
g_variant_unref (variants[attr_data->link_watcher_attr]);
}
variants[attr_data->link_watcher_attr] = g_steal_pointer (&v_val_free);
}
return watcher;
#define _VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES(_variants, ...) \
({ \
int _i; \
\
for (_i = 0; _i < (int) G_N_ELEMENTS ((_variants)); _i++) { \
if ( (_variants)[_i] \
&& !NM_IN_SET ((LinkWatcherAttribute) _i, __VA_ARGS__)) \
break; \
} \
\
(_i == (int) G_N_ELEMENTS ((_variants))); \
})
v_name = _LINK_WATCHER_ATTR_VARGET_STRING (variants, LINK_WATCHER_ATTRIBUTE_NAME);
if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
if (_VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES (variants, _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL))
*out_unrecognized_content = TRUE;
result = nm_team_link_watcher_new_ethtool (_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_DELAY_UP),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN),
NULL);
} else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_NSNA_PING)) {
if (_VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES (variants, _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING))
*out_unrecognized_content = TRUE;
result = nm_team_link_watcher_new_nsna_ping (_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_INIT_WAIT),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_INTERVAL),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_MISSED_MAX),
_LINK_WATCHER_ATTR_VARGET_STRING (variants, LINK_WATCHER_ATTRIBUTE_TARGET_HOST),
NULL);
} else if (nm_streq0 (v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
NMTeamLinkWatcherArpPingFlags v_flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
if (_VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES (variants, _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING))
*out_unrecognized_content = TRUE;
if (_LINK_WATCHER_ATTR_VARGET_BOOL (variants, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE))
v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
if (_LINK_WATCHER_ATTR_VARGET_BOOL (variants, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE))
v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
if (_LINK_WATCHER_ATTR_VARGET_BOOL (variants, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS))
v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
result = nm_team_link_watcher_new_arp_ping2 (_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_INIT_WAIT),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_INTERVAL),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_MISSED_MAX),
_LINK_WATCHER_ATTR_VARGET_INT (variants, LINK_WATCHER_ATTRIBUTE_VLANID),
_LINK_WATCHER_ATTR_VARGET_STRING (variants, LINK_WATCHER_ATTRIBUTE_TARGET_HOST),
_LINK_WATCHER_ATTR_VARGET_STRING (variants, LINK_WATCHER_ATTRIBUTE_SOURCE_HOST),
v_flags,
NULL);
}
if (!result)
*out_unrecognized_content = TRUE;
return result;
}
/*****************************************************************************/
@@ -1298,6 +1360,7 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value)
GPtrArray *link_watchers;
GVariantIter iter;
GVariant *watcher_var;
gboolean unrecognized_content = FALSE;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
@@ -1308,7 +1371,7 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value)
_nm_unused gs_unref_variant GVariant *watcher_var_free = watcher_var;
NMTeamLinkWatcher *watcher;
watcher = _link_watcher_from_variant (watcher_var);
watcher = _link_watcher_from_variant (watcher_var, &unrecognized_content);
if (watcher)
g_ptr_array_add (link_watchers, watcher);
}
@@ -1974,7 +2037,7 @@ nm_team_setting_reset (NMTeamSetting *self,
}
static void
_variants_list_unref_auto (GVariant *(*p_variants)[])
_variants_list_team_unref_auto (GVariant *(*p_variants)[])
{
int i;
@@ -1990,7 +2053,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self,
guint /* NMSettingParseFlags */ parse_flags,
GError **error)
{
nm_auto (_variants_list_unref_auto) GVariant *variants[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, };
nm_auto (_variants_list_team_unref_auto) GVariant *variants[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, };
gs_unref_ptrarray GPtrArray *v_link_watchers = NULL;
const TeamAttrData *attr_data;
GVariantIter iter;