mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-02 14:40:13 +01:00
For NMPlatform instances we had an error reporting mechanism
which stores the last error reason in a private field. Later we
would check it via nm_platform_get_error().
Remove this. It was not used much, and it is not a great way
to report errors.
One problem is that at the point where the error happens, you don't
know whether anybody cares about an error code. So, you add code to set
the error reason because somebody *might* need it (but in realitiy, almost
no caller cares).
Also, we tested this functionality which is hardly used in non-testing code.
While this was a burden to maintain in the tests, it was likely still buggy
because there were no real use-cases, beside the tests.
Then, sometimes platform functions call each other which might overwrite the
error reason. So, every function must be cautious to preserve/set
the error reason according to it's own meaning. This can involve storing
the error code, calling another function, and restoring it afterwards.
This is harder to get right compared to a "return-error-code" pattern, where
every function manages its error code independently.
It is better to return the error reason whenever due. For that we already
have our common glib patterns
(1) gboolean fcn (...);
(2) gboolean fcn (..., GError **error);
In few cases, we need more details then a #gboolean, but don't want
to bother constructing a #GError. Then we should do instead:
(3) NMPlatformError fcn (...);
902 lines
26 KiB
C
902 lines
26 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/* nm-platform.c - Handle runtime kernel networking configuration
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2013 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <arpa/inet.h>
|
|
#include <netlink/route/addr.h>
|
|
|
|
#include "gsystem-local-alloc.h"
|
|
#include "nm-platform.h"
|
|
#include "nm-linux-platform.h"
|
|
#include "nm-fake-platform.h"
|
|
|
|
#define error(...) fprintf (stderr, __VA_ARGS__)
|
|
|
|
typedef gboolean boolean_t;
|
|
typedef int decimal_t;
|
|
typedef const char *string_t;
|
|
|
|
#define print_boolean(value) printf ("%s\n", value ? "yes" : "no")
|
|
#define print_decimal(value) printf ("%d\n", value)
|
|
#define print_string(value) printf ("%s\n", value)
|
|
|
|
static gboolean
|
|
do_sysctl_set (char **argv)
|
|
{
|
|
return nm_platform_sysctl_set (NM_PLATFORM_GET, argv[0], argv[1]);
|
|
}
|
|
|
|
static gboolean
|
|
do_sysctl_get (char **argv)
|
|
{
|
|
gs_free char *value = nm_platform_sysctl_get (NM_PLATFORM_GET, argv[0]);
|
|
|
|
printf ("%s\n", value);
|
|
|
|
return !!value;
|
|
}
|
|
|
|
static int
|
|
parse_ifindex (const char *str)
|
|
{
|
|
char *endptr;
|
|
int ifindex = 0;
|
|
|
|
ifindex = strtol (str, &endptr, 10);
|
|
|
|
if (*endptr) {
|
|
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, str);
|
|
}
|
|
|
|
return ifindex;
|
|
}
|
|
|
|
static gboolean
|
|
do_link_get_all (char **argv)
|
|
{
|
|
GArray *links;
|
|
NMPlatformLink *device;
|
|
int i;
|
|
|
|
links = nm_platform_link_get_all (NM_PLATFORM_GET);
|
|
for (i = 0; i < links->len; i++) {
|
|
device = &g_array_index (links, NMPlatformLink, i);
|
|
|
|
printf ("%d: %s type %d\n", device->ifindex, device->name, device->type);
|
|
}
|
|
g_array_unref (links);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_dummy_add (char **argv)
|
|
{
|
|
return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
do_bridge_add (char **argv)
|
|
{
|
|
return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
do_bond_add (char **argv)
|
|
{
|
|
return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
do_team_add (char **argv)
|
|
{
|
|
return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
do_vlan_add (char **argv)
|
|
{
|
|
const char *name = *argv++;
|
|
int parent = parse_ifindex (*argv++);
|
|
int vlanid = strtol (*argv++, NULL, 10);
|
|
guint32 vlan_flags = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL) == NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
static gboolean
|
|
do_link_exists (char **argv)
|
|
{
|
|
gboolean value = nm_platform_link_exists (NM_PLATFORM_GET, argv[0]);
|
|
|
|
print_boolean (value);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define LINK_CMD(cmdname) \
|
|
static gboolean \
|
|
do_link_##cmdname (char **argv) \
|
|
{ \
|
|
int ifindex = parse_ifindex (argv[0]); \
|
|
return ifindex ? nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex) : FALSE; \
|
|
}
|
|
|
|
#define LINK_CMD_GET_FULL(cmdname, type, cond) \
|
|
static gboolean \
|
|
do_link_##cmdname (char **argv) \
|
|
{ \
|
|
int ifindex = parse_ifindex (argv[0]); \
|
|
if (ifindex) { \
|
|
type##_t value = nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex); \
|
|
if (cond) { \
|
|
print_##type (value); \
|
|
return TRUE; \
|
|
} \
|
|
} \
|
|
return FALSE; \
|
|
}
|
|
#define LINK_CMD_GET(cmdname, type) LINK_CMD_GET_FULL (cmdname, type, TRUE);
|
|
|
|
LINK_CMD (delete)
|
|
|
|
/* do_link_delete_by_ifname:
|
|
*
|
|
* We don't need this as we allow ifname instead of ifindex anyway.
|
|
*/
|
|
|
|
static gboolean
|
|
do_link_get_ifindex (char **argv)
|
|
{
|
|
int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, argv[0]);
|
|
|
|
if (ifindex)
|
|
printf ("%d\n", ifindex);
|
|
|
|
return !!ifindex;
|
|
}
|
|
|
|
LINK_CMD_GET_FULL (get_name, string, value)
|
|
LINK_CMD_GET_FULL (get_type, decimal, value > 0)
|
|
LINK_CMD_GET (is_software, boolean)
|
|
LINK_CMD_GET (supports_slaves, boolean)
|
|
|
|
static gboolean
|
|
do_link_set_up (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (argv[0]);
|
|
|
|
return ifindex ? nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL) : FALSE;
|
|
}
|
|
|
|
LINK_CMD (set_down)
|
|
LINK_CMD (set_arp)
|
|
LINK_CMD (set_noarp)
|
|
LINK_CMD_GET (is_up, boolean)
|
|
LINK_CMD_GET (is_connected, boolean)
|
|
LINK_CMD_GET (uses_arp, boolean)
|
|
|
|
static gboolean
|
|
do_link_set_address (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
char *hex = *argv++;
|
|
int hexlen = strlen (hex);
|
|
char address[hexlen/2];
|
|
char *endptr;
|
|
int i;
|
|
|
|
g_assert (!(hexlen % 2));
|
|
|
|
for (i = 0; i < sizeof (address); i++) {
|
|
char digit[3];
|
|
|
|
digit[0] = hex[2*i];
|
|
digit[1] = hex[2*i+1];
|
|
digit[2] = '\0';
|
|
|
|
address[i] = strtoul (digit, &endptr, 16);
|
|
g_assert (!*endptr);
|
|
}
|
|
|
|
return nm_platform_link_set_address (NM_PLATFORM_GET, ifindex, address, sizeof (address));
|
|
}
|
|
|
|
static gboolean
|
|
do_link_get_address (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
const char *address;
|
|
size_t length;
|
|
int i;
|
|
|
|
address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &length);
|
|
|
|
if (!address || length <= 0)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < length; i++)
|
|
printf ("%02x", address[i]);
|
|
printf ("\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_link_set_mtu (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
int mtu = strtoul (*argv++, NULL, 10);
|
|
|
|
return nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, mtu);
|
|
}
|
|
|
|
LINK_CMD_GET (get_mtu, decimal);
|
|
LINK_CMD_GET (supports_carrier_detect, boolean)
|
|
LINK_CMD_GET (supports_vlans, boolean)
|
|
|
|
static gboolean
|
|
do_link_enslave (char **argv)
|
|
{
|
|
int master = parse_ifindex (*argv++);
|
|
int slave = parse_ifindex (*argv++);
|
|
|
|
return nm_platform_link_enslave (NM_PLATFORM_GET, master, slave);
|
|
}
|
|
|
|
static gboolean
|
|
do_link_release (char **argv)
|
|
{
|
|
int master = parse_ifindex (*argv++);
|
|
int slave = parse_ifindex (*argv++);
|
|
|
|
return nm_platform_link_release (NM_PLATFORM_GET, master, slave);
|
|
}
|
|
|
|
LINK_CMD_GET (get_master, decimal)
|
|
|
|
static gboolean
|
|
do_master_set_option (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
const char *option = *argv++;
|
|
const char *value = *argv++;
|
|
|
|
return nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, option, value);
|
|
}
|
|
|
|
static gboolean
|
|
do_master_get_option (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
const char *option = *argv++;
|
|
gs_free char *value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, option);
|
|
|
|
printf ("%s\n", value);
|
|
|
|
return !!value;
|
|
}
|
|
|
|
static gboolean
|
|
do_slave_set_option (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
const char *option = *argv++;
|
|
const char *value = *argv++;
|
|
|
|
return nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, option, value);
|
|
}
|
|
|
|
static gboolean
|
|
do_slave_get_option (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
const char *option = *argv++;
|
|
gs_free char *value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, option);
|
|
|
|
printf ("%s\n", value);
|
|
|
|
return !!value;
|
|
}
|
|
|
|
static gboolean
|
|
do_vlan_get_info (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
int parent;
|
|
int vlanid;
|
|
|
|
if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent, &vlanid))
|
|
return FALSE;
|
|
|
|
printf ("%d %d\n", parent, vlanid);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_vlan_set_ingress_map (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
int from = strtol (*argv++, NULL, 10);
|
|
int to = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to);
|
|
}
|
|
|
|
static gboolean
|
|
do_vlan_set_egress_map (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
int from = strtol (*argv++, NULL, 10);
|
|
int to = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to);
|
|
}
|
|
|
|
static gboolean
|
|
do_veth_get_properties (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
NMPlatformVethProperties props;
|
|
|
|
if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, ifindex, &props))
|
|
return FALSE;
|
|
|
|
printf ("peer: %d\n", props.peer);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_tun_get_properties (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
NMPlatformTunProperties props;
|
|
|
|
if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, ifindex, &props))
|
|
return FALSE;
|
|
|
|
printf ("mode: %s\n", props.mode);
|
|
if (props.owner == -1)
|
|
printf ("owner: none\n");
|
|
else
|
|
printf ("owner: %lu\n", (gulong) props.owner);
|
|
if (props.group == -1)
|
|
printf ("group: none\n");
|
|
else
|
|
printf ("group: %lu\n", (gulong) props.group);
|
|
printf ("no-pi: ");
|
|
print_boolean (props.no_pi);
|
|
printf ("vnet-hdr: ");
|
|
print_boolean (props.vnet_hdr);
|
|
printf ("multi-queue: ");
|
|
print_boolean (props.multi_queue);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_macvlan_get_properties (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
NMPlatformMacvlanProperties props;
|
|
|
|
if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
|
|
return FALSE;
|
|
|
|
printf ("parent: %d\n", props.parent_ifindex);
|
|
printf ("mode: %s\n", props.mode);
|
|
printf ("no-promisc: ");
|
|
print_boolean (props.no_promisc);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_vxlan_get_properties (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
NMPlatformVxlanProperties props;
|
|
char addrstr[INET6_ADDRSTRLEN];
|
|
|
|
if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
|
|
return FALSE;
|
|
|
|
printf ("parent-ifindex: %u\n", props.parent_ifindex);
|
|
printf ("id: %u\n", props.id);
|
|
if (props.group)
|
|
inet_ntop (AF_INET, &props.group, addrstr, sizeof (addrstr));
|
|
else if (props.group6.s6_addr[0])
|
|
inet_ntop (AF_INET6, &props.group6, addrstr, sizeof (addrstr));
|
|
else
|
|
strcpy (addrstr, "-");
|
|
printf ("group: %s\n", addrstr);
|
|
if (props.local)
|
|
inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
|
|
else if (props.local6.s6_addr[0])
|
|
inet_ntop (AF_INET6, &props.local6, addrstr, sizeof (addrstr));
|
|
else
|
|
strcpy (addrstr, "-");
|
|
printf ("local: %s\n", addrstr);
|
|
printf ("tos: %u\n", props.tos);
|
|
printf ("ttl: %u\n", props.ttl);
|
|
printf ("learning: ");
|
|
print_boolean (props.learning);
|
|
printf ("ageing: %u\n", props.ageing);
|
|
printf ("limit: %u\n", props.limit);
|
|
printf ("dst-port: %u\n", props.dst_port);
|
|
printf ("src-port-min: %u\n", props.src_port_min);
|
|
printf ("src-port-max: %u\n", props.src_port_max);
|
|
printf ("proxy: ");
|
|
print_boolean (props.proxy);
|
|
printf ("rsc: ");
|
|
print_boolean (props.rsc);
|
|
printf ("l2miss: ");
|
|
print_boolean (props.l2miss);
|
|
printf ("l3miss: ");
|
|
print_boolean (props.l3miss);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_gre_get_properties (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
NMPlatformGreProperties props;
|
|
char addrstr[INET_ADDRSTRLEN];
|
|
|
|
if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, ifindex, &props))
|
|
return FALSE;
|
|
|
|
printf ("parent-ifindex: %u\n", props.parent_ifindex);
|
|
printf ("input-flags: %u\n", props.input_flags);
|
|
printf ("output-flags: %u\n", props.input_flags);
|
|
printf ("input-key: %u\n", props.input_key);
|
|
printf ("output-key: %u\n", props.output_key);
|
|
if (props.local)
|
|
inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
|
|
else
|
|
strcpy (addrstr, "-");
|
|
printf ("local: %s\n", addrstr);
|
|
if (props.remote)
|
|
inet_ntop (AF_INET, &props.remote, addrstr, sizeof (addrstr));
|
|
else
|
|
strcpy (addrstr, "-");
|
|
printf ("remote: %s\n", addrstr);
|
|
printf ("ttl: %u\n", props.ttl);
|
|
printf ("tos: %u\n", props.tos);
|
|
printf ("path-mtu-discovery: ");
|
|
print_boolean (props.path_mtu_discovery);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip4_address_get_all (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (argv[0]);
|
|
GArray *addresses;
|
|
NMPlatformIP4Address *address;
|
|
char addrstr[INET_ADDRSTRLEN];
|
|
int i;
|
|
|
|
if (ifindex) {
|
|
addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
|
|
for (i = 0; i < addresses->len; i++) {
|
|
address = &g_array_index (addresses, NMPlatformIP4Address, i);
|
|
inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
|
|
printf ("%s/%d\n", addrstr, address->plen);
|
|
}
|
|
g_array_unref (addresses);
|
|
}
|
|
|
|
return !!ifindex;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_address_get_all (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (argv[0]);
|
|
GArray *addresses;
|
|
NMPlatformIP6Address *address;
|
|
char addrstr[INET6_ADDRSTRLEN];
|
|
int i;
|
|
|
|
if (ifindex) {
|
|
addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
|
|
for (i = 0; i < addresses->len; i++) {
|
|
address = &g_array_index (addresses, NMPlatformIP6Address, i);
|
|
inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
|
|
printf ("%s/%d\n", addrstr, address->plen);
|
|
}
|
|
g_array_unref (addresses);
|
|
}
|
|
|
|
return !!ifindex;
|
|
}
|
|
|
|
static gboolean
|
|
parse_ip_address (int family, char *str, gpointer address, int *plen)
|
|
{
|
|
char *endptr;
|
|
|
|
if (plen)
|
|
*plen = 0;
|
|
|
|
if (plen) {
|
|
char *ptr = strchr (str, '/');
|
|
if (ptr) {
|
|
*ptr++ = '\0';
|
|
*plen = strtol (ptr, &endptr, 10);
|
|
if (*endptr)
|
|
ptr = NULL;
|
|
}
|
|
if (!ptr) {
|
|
error ("Bad format of IP address, expected address/plen.\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (inet_pton (family, str, address))
|
|
return TRUE;
|
|
|
|
error ("Bad format of IP address, expected address%s.\n", plen ? "/plen" : "");
|
|
return FALSE;
|
|
}
|
|
|
|
typedef in_addr_t ip4_t;
|
|
typedef struct in6_addr ip6_t;
|
|
|
|
#define parse_ip4_address(s, a, p) parse_ip_address (AF_INET, s, a, p)
|
|
#define parse_ip6_address(s, a, p) parse_ip_address (AF_INET6, s, a, p)
|
|
|
|
static gboolean
|
|
do_ip4_address_add (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
ip4_t address;
|
|
int plen;
|
|
|
|
if (ifindex && parse_ip4_address (*argv++, &address, &plen)) {
|
|
guint32 lifetime = strtol (*argv++, NULL, 10);
|
|
guint32 preferred = strtol (*argv++, NULL, 10);
|
|
|
|
gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, 0, plen, lifetime, preferred, NULL);
|
|
return value;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_address_add (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
ip6_t address;
|
|
int plen;
|
|
|
|
if (ifindex && parse_ip6_address (*argv++, &address, &plen)) {
|
|
guint32 lifetime = strtol (*argv++, NULL, 10);
|
|
guint32 preferred = strtol (*argv++, NULL, 10);
|
|
guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0;
|
|
|
|
gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, in6addr_any, plen, lifetime, preferred, flags);
|
|
return value;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
#define ADDR_CMD_FULL(v, cmdname, print, ...) \
|
|
static gboolean \
|
|
do_##v##_address_##cmdname (char **argv) \
|
|
{ \
|
|
int ifindex = parse_ifindex (*argv++); \
|
|
v##_t address; \
|
|
int plen; \
|
|
if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \
|
|
gboolean value = nm_platform_##v##_address_##cmdname (NM_PLATFORM_GET, ifindex, address, plen, ##__VA_ARGS__); \
|
|
if (print) { \
|
|
print_boolean (value); \
|
|
return TRUE; \
|
|
} else \
|
|
return value; \
|
|
} else \
|
|
return FALSE; \
|
|
}
|
|
#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0) ADDR_CMD_FULL (ip6, cmdname, FALSE)
|
|
#define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE)
|
|
|
|
ADDR_CMD (delete)
|
|
ADDR_CMD_PRINT (exists)
|
|
|
|
static gboolean
|
|
do_ip4_route_get_all (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (argv[0]);
|
|
GArray *routes;
|
|
NMPlatformIP4Route *route;
|
|
char networkstr[INET_ADDRSTRLEN], gatewaystr[INET_ADDRSTRLEN];
|
|
int i;
|
|
|
|
if (ifindex) {
|
|
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
|
|
for (i = 0; i < routes->len; i++) {
|
|
route = &g_array_index (routes, NMPlatformIP4Route, i);
|
|
inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
|
|
inet_ntop (AF_INET, &route->gateway, gatewaystr, sizeof (gatewaystr));
|
|
printf ("%s/%d via %s metric %d\n",
|
|
networkstr, route->plen, gatewaystr, route->metric);
|
|
}
|
|
g_array_unref (routes);
|
|
}
|
|
|
|
return !!ifindex;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_route_get_all (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (argv[0]);
|
|
GArray *routes;
|
|
NMPlatformIP6Route *route;
|
|
char networkstr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN];
|
|
int i;
|
|
|
|
if (ifindex) {
|
|
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
|
|
for (i = 0; i < routes->len; i++) {
|
|
route = &g_array_index (routes, NMPlatformIP6Route, i);
|
|
inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));
|
|
inet_ntop (AF_INET6, &route->gateway, gatewaystr, sizeof (gatewaystr));
|
|
printf ("%s/%d via %s metric %d\n",
|
|
networkstr, route->plen, gatewaystr, route->metric);
|
|
}
|
|
g_array_unref (routes);
|
|
}
|
|
|
|
return !!ifindex;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip4_route_add (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
in_addr_t network, gateway;
|
|
int plen, metric, mss;
|
|
|
|
parse_ip4_address (*argv++, &network, &plen);
|
|
parse_ip4_address (*argv++, &gateway, NULL);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
mss = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
|
|
network, plen, gateway, 0,
|
|
metric, mss);
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_route_add (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
struct in6_addr network, gateway;
|
|
int plen, metric, mss;
|
|
|
|
parse_ip6_address (*argv++, &network, &plen);
|
|
parse_ip6_address (*argv++, &gateway, NULL);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
mss = strtol (*argv++, NULL, 10);
|
|
return nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
|
|
network, plen, gateway,
|
|
metric, mss);
|
|
}
|
|
|
|
static gboolean
|
|
do_ip4_route_delete (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
in_addr_t network;
|
|
int plen, metric;
|
|
|
|
parse_ip4_address (*argv++, &network, &plen);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_route_delete (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
struct in6_addr network;
|
|
int plen, metric;
|
|
|
|
parse_ip6_address (*argv++, &network, &plen);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
|
|
return nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
|
|
}
|
|
|
|
static gboolean
|
|
do_ip4_route_exists (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
in_addr_t network;
|
|
int plen, metric;
|
|
|
|
parse_ip4_address (*argv++, &network, &plen);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
|
|
print_boolean (nm_platform_ip4_route_exists (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_ip6_route_exists (char **argv)
|
|
{
|
|
int ifindex = parse_ifindex (*argv++);
|
|
struct in6_addr network;
|
|
int plen, metric;
|
|
|
|
parse_ip6_address (*argv++, &network, &plen);
|
|
metric = strtol (*argv++, NULL, 10);
|
|
|
|
print_boolean (nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
|
return TRUE;
|
|
}
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
const char *help;
|
|
int (*handler) (char **argv);
|
|
int argc;
|
|
const char *arghelp;
|
|
} command_t;
|
|
|
|
static const command_t commands[] = {
|
|
{ "sysctl-set", "get /proc/sys or /sys value", do_sysctl_set, 2, "<path> <value>" },
|
|
{ "sysctl-get", "get /proc/sys or /sys value", do_sysctl_get, 1, "<value>" },
|
|
{ "link-get-all", "print all links", do_link_get_all, 0, "" },
|
|
{ "dummy-add", "add dummy interface", do_dummy_add, 1, "<ifname>" },
|
|
{ "bridge-add", "add bridge interface", do_bridge_add, 1, "<ifname>" },
|
|
{ "bond-add", "add bond interface", do_bond_add, 1, "<ifname>" },
|
|
{ "team-add", "add team interface", do_team_add, 1, "<ifname>" },
|
|
{ "vlan-add", "add vlan interface", do_vlan_add, 4, "<ifname> <parent> <vlanid> <vlanflags>" },
|
|
{ "link-exists", "check ifname for existance", do_link_exists, 1, "<ifname>" },
|
|
{ "link-delete", "delete interface", do_link_delete, 1, "<ifname/ifindex>" },
|
|
{ "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "<ifname>" },
|
|
{ "link-get-name", "get interface name", do_link_get_name, 1, "<ifindex>" },
|
|
{ "link-get-type", "get interface type", do_link_get_type, 1, "<ifname/ifindex>" },
|
|
{ "link-is-software", "check if interface is a software one", do_link_is_software, 1, "<ifname/ifindex>" },
|
|
{ "link-supports-slaves", "check if interface supports slaves", do_link_supports_slaves, 1, "<ifname/ifindex>" },
|
|
{ "link-set-up", "set interface up", do_link_set_up, 1, "<ifname/ifindex>" },
|
|
{ "link-set-down", "set interface down", do_link_set_down, 1, "<ifname/ifindex>" },
|
|
{ "link-set-arp", "activate interface arp", do_link_set_arp, 1, "<ifname/ifindex>" },
|
|
{ "link-set-noarp", "deactivate interface arp", do_link_set_noarp, 1, "<ifname/ifindex>" },
|
|
{ "link-is-up", "check if interface is up", do_link_is_up, 1, "<ifname/ifindex>" },
|
|
{ "link-is-connected", "check interface carrier", do_link_is_connected, 1, "<ifname/ifindex>" },
|
|
{ "link-uses-arp", "check whether interface uses arp", do_link_uses_arp, 1, "<ifname/ifindex>" },
|
|
{ "link-get-address", "print link address", do_link_get_address, 1, "<ifname/ifindex>" },
|
|
{ "link-set-address", "set link address", do_link_set_address, 2, "<ifname/ifindex> <hex>" },
|
|
{ "link-get-mtu", "print link mtu", do_link_get_mtu, 1, "<ifname/ifindex>" },
|
|
{ "link-set-mtu", "set link mtu", do_link_set_mtu, 2, "<ifname/ifindex> <mtu>" },
|
|
{ "link-supports-carrier-detect", "check whether interface supports carrier detect",
|
|
do_link_supports_carrier_detect, 1, "<ifname/ifindex>" },
|
|
{ "link-supports-vlans", "check whether interface supports VLANs",
|
|
do_link_supports_vlans, 1, "<ifname/ifindex>" },
|
|
{ "link-enslave", "enslave slave interface with master", do_link_enslave, 2, "<master> <slave>" },
|
|
{ "link-release", "release save interface from master", do_link_release, 2, "<master> <slave>" },
|
|
{ "link-get-master", "print master interface of a slave", do_link_get_master, 1, "<ifname/ifindex>" },
|
|
{ "link-master-set-option", "set master option", do_master_set_option, 3,
|
|
"<ifname/ifindex> <option> <value>" },
|
|
{ "link-master-get-option", "get master option", do_master_get_option, 2,
|
|
"<ifname/ifindex> <option>" },
|
|
{ "link-slave-set-option", "set slave option", do_slave_set_option, 3,
|
|
"<ifname/ifindex> <option>" },
|
|
{ "link-slave-get-option", "get slave option", do_slave_get_option, 2,
|
|
"<ifname/ifindex> <option>" },
|
|
{ "vlan-get-info", "get vlan info", do_vlan_get_info, 1, "<ifname/ifindex>" },
|
|
{ "vlan-set-ingress-map", "set vlan ingress map", do_vlan_set_ingress_map, 3,
|
|
"<ifname/ifindex> <from> <to>" },
|
|
{ "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3,
|
|
"<ifname/ifindex> <from> <to>" },
|
|
{ "veth-get-properties", "get veth properties", do_veth_get_properties, 1,
|
|
"<ifname/ifindex>" },
|
|
{ "tun-get-properties", "get tun/tap properties", do_tun_get_properties, 1,
|
|
"<ifname/ifindex>" },
|
|
{ "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1,
|
|
"<ifname/ifindex>" },
|
|
{ "vxlan-get-properties", "get vxlan properties", do_vxlan_get_properties, 1,
|
|
"<ifname/ifindex>" },
|
|
{ "gre-get-properties", "get gre properties", do_gre_get_properties, 1,
|
|
"<ifname/ifindex>" },
|
|
{ "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "<ifname/ifindex>" },
|
|
{ "ip6-address-get-all", "print all IPv6 addresses", do_ip6_address_get_all, 1, "<ifname/ifindex>" },
|
|
{ "ip4-address-add", "add IPv4 address", do_ip4_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> <>" },
|
|
{ "ip6-address-add", "add IPv6 address", do_ip6_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> [<flags>] <>" },
|
|
{ "ip4-address-delete", "delete IPv4 address", do_ip4_address_delete, 2,
|
|
"<ifname/ifindex> <address>/<plen>" },
|
|
{ "ip6-address-delete", "delete IPv6 address", do_ip6_address_delete, 2,
|
|
"<ifname/ifindex> <address>/<plen>" },
|
|
{ "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_exists, 2,
|
|
"<ifname/ifindex> <address>/<plen>" },
|
|
{ "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_exists, 2,
|
|
"<ifname/ifindex> <address>/<plen>" },
|
|
{ "ip4-route-get-all", "print all IPv4 routes", do_ip4_route_get_all, 1, "<ifname/ifindex>" },
|
|
{ "ip6-route-get-all", "print all IPv6 routes", do_ip6_route_get_all, 1, "<ifname/ifindex>" },
|
|
{ "ip4-route-add", "add IPv4 route", do_ip4_route_add, 5,
|
|
"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
|
|
{ "ip6-route-add", "add IPv6 route", do_ip6_route_add, 5,
|
|
"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
|
|
{ "ip4-route-delete", "delete IPv4 route", do_ip4_route_delete, 3,
|
|
"<ifname/ifindex> <network>/<plen> <metric>" },
|
|
{ "ip6-route-delete", "delete IPv6 route", do_ip6_route_delete, 3,
|
|
"<ifname/ifindex> <network>/<plen> <metric>" },
|
|
{ "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_exists, 3,
|
|
"<ifname/ifindex> <network>/<plen> <metric>" },
|
|
{ "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_exists, 3,
|
|
"<ifname/ifindex> <network>/<plen> <metric>" },
|
|
{ NULL, NULL, NULL, 0, NULL },
|
|
};
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
const char *arg0 = *argv++;
|
|
const command_t *command = NULL;
|
|
gboolean status = TRUE;
|
|
|
|
#if !GLIB_CHECK_VERSION (2, 35, 0)
|
|
g_type_init ();
|
|
#endif
|
|
|
|
if (*argv && !g_strcmp0 (argv[1], "--fake")) {
|
|
nm_fake_platform_setup ();
|
|
} else
|
|
nm_linux_platform_setup ();
|
|
|
|
if (*argv)
|
|
for (command = commands; command->name; command++)
|
|
if (g_str_has_prefix (command->name, *argv))
|
|
break;
|
|
|
|
if (command && command->name) {
|
|
argv++;
|
|
if (g_strv_length (argv) == command->argc)
|
|
status = command->handler (argv);
|
|
else {
|
|
error ("Wrong number of arguments to '%s' (expected %d).\n\nUsage: %s %s %s\n-- %s\n",
|
|
command->name, command->argc,
|
|
arg0, command->name, command->arghelp, command->help);
|
|
return EXIT_FAILURE;
|
|
}
|
|
} else {
|
|
error ("Usage: %s COMMAND\n\n", arg0);
|
|
error ("COMMAND\n");
|
|
for (command = commands; command->name; command++)
|
|
error (" %s %s\n -- %s\n", command->name, command->arghelp, command->help);
|
|
error ("\n");
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|