summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2014-06-10 16:50:57 +0200
committerJiří Klimeš <jklimes@redhat.com>2014-06-11 09:58:39 +0200
commit700f5ec0ef584b17b44cc0e1968712d97ba95263 (patch)
tree0205ad09269f0452174f6da15e1e1de4657b26e9
parente8fb3864d1d29f137b4eef42dee8c1214f474a0f (diff)
downloadNetworkManager-700f5ec0ef584b17b44cc0e1968712d97ba95263.tar.gz
cli: allow missing next hop for routes (bgo #727615)
https://bugzilla.gnome.org/show_bug.cgi?id=727615
-rw-r--r--cli/src/common.c220
-rw-r--r--cli/src/common.h4
-rw-r--r--cli/src/settings.c44
3 files changed, 163 insertions, 105 deletions
diff --git a/cli/src/common.c b/cli/src/common.c
index 939a00ea5e..9635011cd7 100644
--- a/cli/src/common.c
+++ b/cli/src/common.c
@@ -487,131 +487,181 @@ finish:
return addr;
}
+typedef struct {
+ long int prefix;
+ long int metric;
+ union _IpDest {
+ guint32 ip4_dst;
+ struct in6_addr ip6_dst;
+ } dst;
+ union _IpNextHop {
+ guint32 ip4_nh;
+ struct in6_addr ip6_nh;
+ } nh;
+} ParsedRoute;
+
/*
- * Parse IPv4 routes from strings to NMIP4Route stucture.
- * ip_str is the IPv4 route in the form of address/prefix
- * next_hop_str is the next_hop address
- * metric_str is the route metric
+ * _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
+ * @out: (out): route struct to fill
+ * @error: location to store GError
+ *
+ * Parse route from strings and fill @out parameter.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
*/
-NMIP4Route *
-nmc_parse_and_build_ip4_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error)
+static gboolean
+_parse_and_build_route (int family,
+ const char *first,
+ const char *second,
+ const char *third,
+ ParsedRoute *out,
+ GError **error)
{
- NMIP4Route *route = NULL;
- guint32 ip4_addr, next_hop_addr;
- char *tmp;
- char *plen;
- long int prefix, metric;
-
- g_return_val_if_fail (ip_str != NULL, NULL);
- g_return_val_if_fail (next_hop_str != NULL, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ int max_prefix;
+ char *tmp, *plen;
+ gboolean success = FALSE;
+
+ 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 (out, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ max_prefix = (family == AF_INET) ? 32 : 128;
+ /* initialize default values */
+ out->prefix = max_prefix;
+ out->metric = 0;
+ if (family == AF_INET)
+ out->nh.ip4_nh = 0;
+ else
+ out->nh.ip6_nh = in6addr_any;
- tmp = g_strdup (ip_str);
+ tmp = g_strdup (first);
plen = strchr (tmp, '/'); /* prefix delimiter */
if (plen)
*plen++ = '\0';
- if (inet_pton (AF_INET, tmp, &ip4_addr) < 1) {
+ if (inet_pton (family, tmp, family == AF_INET ? (void *) &out->dst.ip4_dst : (void *) &out->dst.ip6_dst) < 1) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid IPv4 route '%s'"), tmp);
+ _("invalid route destination address '%s'"), tmp);
goto finish;
}
- prefix = 32;
if (plen) {
- if (!nmc_string_to_int (plen, TRUE, 0, 32, &prefix)) {
+ if (!nmc_string_to_int (plen, TRUE, 0, max_prefix, &out->prefix)) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid prefix '%s'; <0-32> allowed"), plen);
+ _("invalid prefix '%s'; <0-%d> allowed"),
+ plen, max_prefix);
goto finish;
}
}
- if (inet_pton (AF_INET, next_hop_str, &next_hop_addr) < 1) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid next hop address '%s'"), next_hop_str);
- goto finish;
+ if (second) {
+ if (inet_pton (family, second, family == AF_INET ? (void *) &out->nh.ip4_nh : (void *) &out->nh.ip6_nh) < 1) {
+ if (third) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("invalid next hop address '%s'"), second);
+ goto finish;
+ } else {
+ /* 'second' can be a metric */
+ if (!nmc_string_to_int (second, TRUE, 0, G_MAXUINT32, &out->metric)) {
+ g_set_error (error, 1, 0, _("the second component of route ('%s') is neither "
+ "a next hop address nor a metric"), second);
+ goto finish;
+ }
+ }
+ }
}
- metric = 0;
- if (metric_str) {
- if (!nmc_string_to_int (metric_str, TRUE, 0, G_MAXUINT32, &metric)) {
- g_set_error (error, 1, 0, _("invalid metric '%s'"), metric_str);
+ if (third) {
+ if (!nmc_string_to_int (third, TRUE, 0, G_MAXUINT32, &out->metric)) {
+ g_set_error (error, 1, 0, _("invalid metric '%s'"), third);
goto finish;
}
}
- route = nm_ip4_route_new ();
- nm_ip4_route_set_dest (route, ip4_addr);
- nm_ip4_route_set_prefix (route, (guint32) prefix);
- nm_ip4_route_set_next_hop (route, next_hop_addr);
- nm_ip4_route_set_metric (route, (guint32) metric);
+ success = TRUE;
finish:
g_free (tmp);
- return route;
+ return success;
}
/*
- * Parse IPv6 route from strings to NMIP6Route stucture.
- * ip_str is the IPv6 route in the form address/prefix
- * next_hop_str is the next hop
- * metric_str is the route metric
+ * nmc_parse_and_build_ip4_route:
+ * @first: the IPv4 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
+ * @error: location to store GError
+ *
+ * Parse IPv4 route from strings to NMIP4Route stucture.
+ *
+ * Returns: route as a NMIP4Route object, or %NULL on failure
*/
-NMIP6Route *
-nmc_parse_and_build_ip6_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error)
+NMIP4Route *
+nmc_parse_and_build_ip4_route (const char *first,
+ const char *second,
+ const char *third,
+ GError **error)
{
- NMIP6Route *route = NULL;
- struct in6_addr ip_addr, next_hop_addr;
- char *tmp;
- char *plen;
- long int prefix, metric;
+ ParsedRoute tmp_route;
+ NMIP4Route *route = NULL;
- g_return_val_if_fail (ip_str != NULL, NULL);
+ g_return_val_if_fail (first != NULL, NULL);
+ g_return_val_if_fail (second || !third, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- tmp = g_strdup (ip_str);
- plen = strchr (tmp, '/'); /* prefix delimiter */
- if (plen)
- *plen++ = '\0';
-
- if (inet_pton (AF_INET6, tmp, &ip_addr) < 1) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid IPv6 route '%s'"), tmp);
- goto finish;
+ if (_parse_and_build_route (AF_INET, first, second, third, &tmp_route, error)) {
+ route = nm_ip4_route_new ();
+ nm_ip4_route_set_dest (route, tmp_route.dst.ip4_dst);
+ nm_ip4_route_set_prefix (route, (guint32) tmp_route.prefix);
+ nm_ip4_route_set_next_hop (route, tmp_route.nh.ip4_nh);
+ nm_ip4_route_set_metric (route, (guint32) tmp_route.metric);
}
+ return route;
+}
- prefix = 128;
- if (plen) {
- if (!nmc_string_to_int (plen, TRUE, 0, 128, &prefix)) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid prefix '%s'; <0-128> allowed"), plen);
- goto finish;
- }
- }
+/*
+ * nmc_parse_and_build_ip6_route:
+ * @first: the IPv6 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
+ * @error: location to store GError
+ *
+ * Parse IPv6 route from strings to NMIP6Route stucture.
+ *
+ * Returns: route as a NMIP6Route object, or %NULL on failure
+ */
+NMIP6Route *
+nmc_parse_and_build_ip6_route (const char *first,
+ const char *second,
+ const char *third,
+ GError **error)
+{
+ ParsedRoute tmp_route;
+ NMIP6Route *route = NULL;
- if (inet_pton (AF_INET6, next_hop_str, &next_hop_addr) < 1) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid next hop address '%s'"), next_hop_str);
- goto finish;
- }
+ g_return_val_if_fail (first != NULL, NULL);
+ g_return_val_if_fail (second || !third, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- metric = 0;
- if (metric_str) {
- if (!nmc_string_to_int (metric_str, TRUE, 0, G_MAXUINT32, &metric)) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("invalid metric '%s'"), metric_str);
- goto finish;
- }
+ if (_parse_and_build_route (AF_INET6, first, second, third, &tmp_route, error)) {
+ route = nm_ip6_route_new ();
+ nm_ip6_route_set_dest (route, &tmp_route.dst.ip6_dst);
+ nm_ip6_route_set_prefix (route, (guint32) tmp_route.prefix);
+ nm_ip6_route_set_next_hop (route, &tmp_route.nh.ip6_nh);
+ nm_ip6_route_set_metric (route, (guint32) tmp_route.metric);
}
-
- route = nm_ip6_route_new ();
- nm_ip6_route_set_dest (route, &ip_addr);
- nm_ip6_route_set_prefix (route, (guint32) prefix);
- nm_ip6_route_set_next_hop (route, &next_hop_addr);
- nm_ip6_route_set_metric (route, (guint32) metric);
-
-finish:
- g_free (tmp);
return route;
}
diff --git a/cli/src/common.h b/cli/src/common.h
index 31f4ab3f34..228375b97e 100644
--- a/cli/src/common.h
+++ b/cli/src/common.h
@@ -40,8 +40,8 @@ gboolean print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group
NMIP4Address *nmc_parse_and_build_ip4_address (const char *ip_str, const char *gw_str, GError **error);
NMIP6Address *nmc_parse_and_build_ip6_address (const char *ip_str, const char *gw_str, GError **error);
-NMIP4Route *nmc_parse_and_build_ip4_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error);
-NMIP6Route *nmc_parse_and_build_ip6_route (const char *ip_str, const char *next_hop_str, const char *metric_str, GError **error);
+NMIP4Route *nmc_parse_and_build_ip4_route (const char *first, const char *second, const char *third, GError **error);
+NMIP6Route *nmc_parse_and_build_ip6_route (const char *first, const char *second, const char *third, GError **error);
const char * nmc_device_state_to_string (NMDeviceState state);
const char * nmc_device_reason_to_string (NMDeviceStateReason reason);
diff --git a/cli/src/settings.c b/cli/src/settings.c
index b0c1ecad99..d4f34eaf39 100644
--- a/cli/src/settings.c
+++ b/cli/src/settings.c
@@ -3218,17 +3218,19 @@ _parse_ipv4_route (const char *route, GError **error)
{
char *value = g_strdup (route);
char **routev;
- NMIP4Route *ip4route;
+ guint len;
+ NMIP4Route *ip4route = NULL;
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
- if (g_strv_length (routev) < 2 || g_strv_length (routev) > 3) {
- g_set_error (error, 1, 0, _("'%s' is not valid (use ip/[prefix] next-hop [metric])"),
+ 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);
- g_free (value);
- g_strfreev (routev);
- return NULL;
+ goto finish;
}
- ip4route = nmc_parse_and_build_ip4_route (routev[0], routev[1], routev[2], error);
+ ip4route = nmc_parse_and_build_ip4_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
+
+finish:
g_free (value);
g_strfreev (routev);
return ip4route;
@@ -3284,10 +3286,12 @@ static const char *
nmc_property_ipv4_describe_routes (NMSetting *setting, const char *prop)
{
return _("Enter a list of IPv4 routes formatted as:\n"
- " ip/[prefix] next-hop [metric],...\n"
+ " ip[/prefix] [next-hop] [metric],...\n\n"
"Missing prefix is regarded as a prefix of 32.\n"
+ "Missing next-hop is regarded as 0.0.0.0.\n"
"Missing metric is regarded as a metric of 0.\n\n"
- "Example: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n");
+ "Examples: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n"
+ " 10.1.2.0/24\n");
}
static char *
@@ -3529,17 +3533,19 @@ _parse_ipv6_route (const char *route, GError **error)
{
char *value = g_strdup (route);
char **routev;
- NMIP6Route *ip6route;
+ guint len;
+ NMIP6Route *ip6route = NULL;
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
- if (g_strv_length (routev) < 2 || g_strv_length (routev) > 3) {
- g_set_error (error, 1, 0, _("'%s' is not valid (use <dest IP>/prefix <next-hop IP> [metric])"),
+ 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);
- g_free (value);
- g_strfreev (routev);
- return NULL;
+ goto finish;
}
- ip6route = nmc_parse_and_build_ip6_route (routev[0], routev[1], routev[2], error);
+ ip6route = nmc_parse_and_build_ip6_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
+
+finish:
g_free (value);
g_strfreev (routev);
return ip6route;
@@ -3595,10 +3601,12 @@ static const char *
nmc_property_ipv6_describe_routes (NMSetting *setting, const char *prop)
{
return _("Enter a list of IPv6 routes formatted as:\n"
- " ip/[prefix] next-hop [metric],...\n"
+ " ip[/prefix] [next-hop] [metric],...\n\n"
"Missing prefix is regarded as a prefix of 128.\n"
+ "Missing next-hop is regarded as \"::\".\n"
"Missing metric is regarded as a metric of 0.\n\n"
- "Example: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n");
+ "Examples: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n"
+ " abbe::/64 55\n");
}
static gboolean