dispatcher: enhance dispatcher script environment (bgo #648382)

For VPN connections, the interface name would be that of the VPN's
IP interface, but the script environment would be the that of the
VPN's parent device.  Enhance the environment by adding any VPN
specific details as additional environment variables prefixed by
"VPN_".  Leave the existing environment setup intact for backwards
compatiblity.

Additionally, the dispatcher never got updated for IPv6 support,
so push IPv6 configuration and DHCPv6 configuration into the
environment too.

Even better, push everything the dispatcher needs to it instead
of making the dispatcher make D-Bus requests back to NM, which
sometimes fails if NM has already torn down the device or the
connection which the device was using.

And add some testcases to ensure that we don't break backwards compat,
the testcases here were grabbed from a 0.8.4 machine with a hacked up
dispatcher to dump everything it was given from NM.
This commit is contained in:
Dan Williams
2011-05-02 22:38:51 -05:00
parent a2fc80b0ea
commit f898dbf1a9
18 changed files with 1646 additions and 320 deletions

View File

@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
* Copyright (C) 2004 - 2011 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
*/
@@ -373,6 +373,72 @@ nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting)
nm_ip6_config_set_never_default (ip6_config, TRUE);
}
static void
dump_object_to_props (GObject *object, GHashTable *hash)
{
GParamSpec **pspecs;
guint len = 0, i;
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &len);
for (i = 0; i < len; i++) {
value_hash_add_object_property (hash,
pspecs[i]->name,
object,
pspecs[i]->name,
pspecs[i]->value_type);
}
g_free (pspecs);
}
static void
fill_device_props (NMDevice *device,
GHashTable *dev_hash,
GHashTable *ip4_hash,
GHashTable *ip6_hash,
GHashTable *dhcp4_hash,
GHashTable *dhcp6_hash)
{
NMIP4Config *ip4_config;
NMIP6Config *ip6_config;
NMDHCP4Config *dhcp4_config;
NMDHCP6Config *dhcp6_config;
/* If the action is for a VPN, send the VPN's IP interface instead of the device's */
value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_IP_INTERFACE, nm_device_get_ip_iface (device));
value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_INTERFACE, nm_device_get_iface (device));
value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_TYPE, nm_device_get_device_type (device));
value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_STATE, nm_device_get_state (device));
value_hash_add_object_path (dev_hash, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device));
ip4_config = nm_device_get_ip4_config (device);
if (ip4_config)
dump_object_to_props (G_OBJECT (ip4_config), ip4_hash);
ip6_config = nm_device_get_ip6_config (device);
if (ip6_config)
dump_object_to_props (G_OBJECT (ip6_config), ip6_hash);
dhcp4_config = nm_device_get_dhcp4_config (device);
if (dhcp4_config)
dump_object_to_props (G_OBJECT (dhcp4_config), dhcp4_hash);
dhcp6_config = nm_device_get_dhcp6_config (device);
if (dhcp6_config)
dump_object_to_props (G_OBJECT (dhcp6_config), dhcp6_hash);
}
static void
fill_vpn_props (NMIP4Config *ip4_config,
NMIP6Config *ip6_config,
GHashTable *ip4_hash,
GHashTable *ip6_hash)
{
if (ip4_config)
dump_object_to_props (G_OBJECT (ip4_config), ip4_hash);
if (ip6_config)
dump_object_to_props (G_OBJECT (ip6_config), ip6_hash);
}
static void
dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
@@ -384,7 +450,9 @@ void
nm_utils_call_dispatcher (const char *action,
NMConnection *connection,
NMDevice *device,
const char *vpn_iface)
const char *vpn_iface,
NMIP4Config *vpn_ip4_config,
NMIP6Config *vpn_ip6_config)
{
NMDBusManager *dbus_mgr;
DBusGProxy *proxy;
@@ -392,12 +460,21 @@ nm_utils_call_dispatcher (const char *action,
GHashTable *connection_hash;
GHashTable *connection_props;
GHashTable *device_props;
GHashTable *device_ip4_props;
GHashTable *device_ip6_props;
GHashTable *device_dhcp4_props;
GHashTable *device_dhcp6_props;
GHashTable *vpn_ip4_props;
GHashTable *vpn_ip6_props;
g_return_if_fail (action != NULL);
/* All actions except 'hostname' require a device */
if (strcmp (action, "hostname"))
if (strcmp (action, "hostname") != 0)
g_return_if_fail (NM_IS_DEVICE (device));
/* VPN actions require at least an IPv4 config (for now) */
if (strcmp (action, "vpn-up") == 0)
g_return_if_fail (vpn_ip4_config != NULL);
dbus_mgr = nm_dbus_manager_get ();
g_connection = nm_dbus_manager_get_connection (dbus_mgr);
@@ -426,25 +503,23 @@ nm_utils_call_dispatcher (const char *action,
}
device_props = value_hash_create ();
device_ip4_props = value_hash_create ();
device_ip6_props = value_hash_create ();
device_dhcp4_props = value_hash_create ();
device_dhcp6_props = value_hash_create ();
vpn_ip4_props = value_hash_create ();
vpn_ip6_props = value_hash_create ();
/* Hostname actions do not require a device */
if (strcmp (action, "hostname")) {
/* interface */
value_hash_add_str (device_props, NMD_DEVICE_PROPS_INTERFACE, nm_device_get_iface (device));
/* IP interface */
if (vpn_iface) {
value_hash_add_str (device_props, NMD_DEVICE_PROPS_IP_INTERFACE, vpn_iface);
} else if (nm_device_get_ip_iface (device)) {
value_hash_add_str (device_props, NMD_DEVICE_PROPS_IP_INTERFACE, nm_device_get_ip_iface (device));
}
/* type */
value_hash_add_uint (device_props, NMD_DEVICE_PROPS_TYPE, nm_device_get_device_type (device));
/* state */
value_hash_add_uint (device_props, NMD_DEVICE_PROPS_STATE, nm_device_get_state (device));
value_hash_add_object_path (device_props, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device));
/* hostname actions only send the hostname */
if (strcmp (action, "hostname") != 0) {
fill_device_props (device,
device_props,
device_ip4_props,
device_ip6_props,
device_dhcp4_props,
device_dhcp6_props);
if (vpn_iface)
fill_vpn_props (vpn_ip4_config, NULL, vpn_ip4_props, vpn_ip6_props);
}
/* Do a non-blocking call, but wait for the reply, because dbus-glib
@@ -455,17 +530,30 @@ nm_utils_call_dispatcher (const char *action,
*/
dbus_g_proxy_begin_call_with_timeout (proxy, "Action",
dispatcher_done_cb,
dbus_mgr,
dbus_mgr, /* automatically unref the dbus mgr when call is done */
g_object_unref,
5000,
G_TYPE_STRING, action,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash,
DBUS_TYPE_G_MAP_OF_VARIANT, connection_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_ip4_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_ip6_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp4_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp6_props,
G_TYPE_STRING, vpn_iface ? vpn_iface : "",
DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip4_props,
DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip6_props,
G_TYPE_INVALID);
g_hash_table_destroy (connection_hash);
g_hash_table_destroy (connection_props);
g_hash_table_destroy (device_props);
g_hash_table_destroy (device_ip4_props);
g_hash_table_destroy (device_ip6_props);
g_hash_table_destroy (device_dhcp4_props);
g_hash_table_destroy (device_dhcp6_props);
g_hash_table_destroy (vpn_ip4_props);
g_hash_table_destroy (vpn_ip6_props);
}
gboolean
@@ -670,6 +758,21 @@ value_hash_add_bool (GHashTable *hash,
value_hash_add (hash, key, value);
}
void
value_hash_add_object_property (GHashTable *hash,
const char *key,
GObject *object,
const char *prop,
GType val_type)
{
GValue *value;
value = g_slice_new0 (GValue);
g_value_init (value, val_type);
g_object_get_property (object, prop, value);
value_hash_add (hash, key, value);
}
gboolean
nm_utils_do_sysctl (const char *path, const char *value)
{