Commit d0949141 authored by Beniamino Galvani's avatar Beniamino Galvani

cli: support route options

parent 40e1fd95
......@@ -395,26 +395,20 @@ finish:
/*
* nmc_parse_and_build_route:
* @family: AF_INET or AF_INET6
* @first: the route destination in the form of "address/prefix"
(/prefix is optional)
* @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be
either next hop address or metric. (It can be NULL when @third is NULL).
* @third: (allow-none): route metric
* @str: route string to be parsed
* @error: location to store GError
*
* Parse route from strings and return an #NMIPRoute
* Parse route from string and return an #NMIPRoute
*
* Returns: %TRUE on success, %FALSE on failure
* Returns: a new #NMIPRoute or %NULL on error
*/
NMIPRoute *
nmc_parse_and_build_route (int family,
const char *first,
const char *second,
const char *third,
const char *str,
GError **error)
{
int max_prefix = (family == AF_INET) ? 32 : 128;
char *dest = NULL, *plen = NULL;
char *plen = NULL;
const char *next_hop = NULL;
const char *canon_dest;
long int prefix = max_prefix;
......@@ -423,13 +417,27 @@ nmc_parse_and_build_route (int family,
gboolean success = FALSE;
GError *local = NULL;
gint64 metric = -1;
guint i, len;
gs_strfreev char **routev = NULL;
gs_free char *value = NULL;
gs_free char *dest = NULL;
gs_unref_hashtable GHashTable *attrs = NULL;
GHashTable *tmp_attrs;
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
g_return_val_if_fail (first != NULL, FALSE);
g_return_val_if_fail (second || !third, FALSE);
g_return_val_if_fail (str, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
dest = g_strdup (first);
value = g_strdup (str);
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
len = g_strv_length (routev);
if (len < 1) {
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric] [attr=val] [attr=val])"),
str);
goto finish;
}
dest = g_strdup (routev[0]);
plen = strchr (dest, '/'); /* prefix delimiter */
if (plen)
*plen++ = '\0';
......@@ -443,26 +451,50 @@ nmc_parse_and_build_route (int family,
}
}
if (second) {
if (third || nm_utils_ipaddr_valid (family, second))
next_hop = second;
else {
/* 'second' can be a metric */
if (!nmc_string_to_uint (second, TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
g_set_error (error, 1, 0, _("the second component of route ('%s') is neither "
"a next hop address nor a metric"), second);
for (i = 1; i < len; i++) {
if (nm_utils_ipaddr_valid (family, routev[i])) {
if (metric != -1 || attrs) {
g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
goto finish;
}
next_hop = routev[i];
} else if (nmc_string_to_uint (routev[i], TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
if (attrs) {
g_set_error (error, 1, 0, _("the metric ('%s') must be before attributes"), routev[i]);
goto finish;
}
metric = tmp_ulong;
}
}
} else if (strchr (routev[i], '=')) {
GHashTableIter iter;
char *iter_key;
GVariant *iter_value;
tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE,
nm_ip_route_get_variant_attribute_spec(),
error);
if (!tmp_attrs) {
g_prefix_error (error, "invalid option '%s': ", routev[i]);
goto finish;
}
if (!attrs)
attrs = g_hash_table_new (g_str_hash, g_str_equal);
if (third) {
if (!nmc_string_to_uint (third, TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
g_set_error (error, 1, 0, _("invalid metric '%s'"), third);
g_hash_table_iter_init (&iter, tmp_attrs);
while (g_hash_table_iter_next (&iter, (gpointer *) &iter_key, (gpointer *) &iter_value)) {
if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) {
g_prefix_error (error, "%s: ", iter_key);
g_hash_table_unref (tmp_attrs);
goto finish;
}
g_hash_table_insert (attrs, iter_key, iter_value);
g_hash_table_iter_steal (&iter);
}
g_hash_table_unref (tmp_attrs);
} else {
g_set_error (error, 1, 0, _("unrecognized option '%s'"), routev[i]);
goto finish;
}
metric = tmp_ulong;
}
route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &local);
......@@ -485,10 +517,19 @@ nmc_parse_and_build_route (int family,
goto finish;
}
if (attrs) {
GHashTableIter iter;
char *name;
GVariant *variant;
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant))
nm_ip_route_set_attribute (route, name, variant);
}
success = TRUE;
finish:
g_free (dest);
return route;
}
......
......@@ -31,7 +31,7 @@ gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, NmCli *nmc, const char *group_
gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, NmCli *nmc, const char *group_prefix, const char *one_field);
NMIPAddress *nmc_parse_and_build_address (int family, const char *ip_str, GError **error);
NMIPRoute *nmc_parse_and_build_route (int family, const char *first, const char *second, const char *third, GError **error);
NMIPRoute *nmc_parse_and_build_route (int family, const char *str, GError **error);
const char * nmc_device_state_to_string (NMDeviceState state);
const char * nmc_device_reason_to_string (NMDeviceStateReason reason);
......
......@@ -3470,29 +3470,6 @@ _parse_ip_address (int family, const char *address, GError **error)
return ipaddr;
}
static NMIPRoute *
_parse_ip_route (int family, const char *route, GError **error)
{
char *value = g_strdup (route);
char **routev;
guint len;
NMIPRoute *iproute = NULL;
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
len = g_strv_length (routev);
if (len < 1 || len > 3) {
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"),
route);
goto finish;
}
iproute = nmc_parse_and_build_route (family, routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
finish:
g_free (value);
g_strfreev (routev);
return iproute;
}
DEFINE_GETTER (nmc_property_ipv4_get_method, NM_SETTING_IP_CONFIG_METHOD)
DEFINE_GETTER (nmc_property_ipv4_get_dns, NM_SETTING_IP_CONFIG_DNS)
DEFINE_GETTER (nmc_property_ipv4_get_dns_search, NM_SETTING_IP_CONFIG_DNS_SEARCH)
......@@ -3536,8 +3513,21 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
num_routes = nm_setting_ip_config_get_num_routes (s_ip);
for (i = 0; i < num_routes; i++) {
gs_free char *attr_str = NULL;
gs_strfreev char **attr_names = NULL;
gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
int j;
route = nm_setting_ip_config_get_route (s_ip, i);
attr_names = nm_ip_route_get_attribute_names (route);
for (j = 0; attr_names && attr_names[j]; j++) {
g_hash_table_insert (hash, attr_names[j],
nm_ip_route_get_attribute (route, attr_names[j]));
}
attr_str = nm_utils_format_variant_attributes (hash, ' ', '=');
if (get_type == NMC_PROPERTY_GET_PARSABLE) {
if (printable->len > 0)
g_string_append (printable, ", ");
......@@ -3550,7 +3540,10 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
g_string_append_printf (printable, " %s", nm_ip_route_get_next_hop (route));
if (nm_ip_route_get_metric (route) != -1)
g_string_append_printf (printable, " %u", (guint32) nm_ip_route_get_metric (route));
if (attr_str)
g_string_append_printf (printable, " %s", attr_str);
} else {
if (printable->len > 0)
g_string_append (printable, "; ");
......@@ -3567,6 +3560,8 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
if (nm_ip_route_get_metric (route) != -1)
g_string_append_printf (printable, ", mt = %u", (guint32) nm_ip_route_get_metric (route));
if (attr_str)
g_string_append_printf (printable, " %s", attr_str);
g_string_append (printable, " }");
}
......@@ -3858,7 +3853,7 @@ nmc_property_ipv4_set_gateway (NMSetting *setting, const char *prop, const char
static NMIPRoute *
_parse_ipv4_route (const char *route, GError **error)
{
return _parse_ip_route (AF_INET, route, error);
return nmc_parse_and_build_route (AF_INET, route, error);
}
static gboolean
......@@ -4201,7 +4196,7 @@ nmc_property_ipv6_set_gateway (NMSetting *setting, const char *prop, const char
static NMIPRoute *
_parse_ipv6_route (const char *route, GError **error)
{
return _parse_ip_route (AF_INET6, route, error);
return nmc_parse_and_build_route (AF_INET6, route, error);
}
static gboolean
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment