2008-10-10 Dan Williams <dcbw@redhat.com>

Rework default route handling to consolidate decisions in the policy,
	and to take active VPN connections into account when changing the default
	route (bgo #545912)

	* src/NetworkManager.c
		- (main): pass the vpn_manager to the policy so it knows about active
			VPN connections; clean up the named manager which wasn't done before

	* src/NetworkManagerPolicy.c
	  src/NetworkManagerPolicy.h
		- (nm_policy_new): get a clue about the vpn_manager
		- (update_default_route): remove, fold into update_routing_and_dns()
		- (update_routing_and_dns): handle active VPN connections too; an
			active VPN connection becomes the default route if it does not have
			server-specified or user-specified custom routes.  Otherwise, the
			best active device gets the default route
		- (vpn_connection_activated, vpn_connection_deactivated, nm_policy_new,
		   nm_policy_destroy): track VPN connection activation and deactivation
			and update the default route when appropriate

	* src/NetworkManagerSystem.c
	  src/NetworkManagerSystem.h
		- (nm_system_vpn_device_unset_from_ip4_config): remove, put functionality
			in the VPN connection itself
		- (nm_system_vpn_device_set_from_ip4_config,
		   nm_system_device_set_from_ip4_config): merge together to make
			nm_system_apply_ip4_config()
		- (add_vpn_gateway_route): add a route to the VPN's external gateway
			via the parent device
		- (nm_system_apply_ip4_config): simplify
		- (add_ip4_route_to_gateway): new function; add a direct route to the
			gateway if needed
		- (nm_system_device_replace_default_ip4_route): simplify, break gateway
			route stuff out into add_ip4_route_to_gateway() for clarity

	* src/nm-device.c
		- (nm_device_set_ip4_config): update for nm_system_apply_ip4_config()

	* src/vpn-manager/nm-vpn-connection.c
	  src/vpn-manager/nm-vpn-connection.h
		- (nm_vpn_connection_get_ip4_config, nm_vpn_connection_get_ip_iface,
		   nm_vpn_connection_get_parent_device): add
		- (nm_vpn_connection_ip4_config_get): make the requirement of a tunnel
			device explicit
		- (connection_state_changed): update the named manager now that
			nm_system_vpn_device_unset_from_ip4_config() is gone; do something
			useful on errors

	* src/vpn-manager/nm-vpn-manager.c
	  src/vpn-manager/nm-vpn-manager.h
		- Add a 'connection-activated' signal
		- (nm_vpn_manager_get_active_connections): new function; mainly for the
			policy to find out about active VPN connections



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4167 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2008-10-10 23:05:45 +00:00
parent 9b82c1e92f
commit ad7a46d867
11 changed files with 420 additions and 223 deletions

View File

@@ -43,6 +43,7 @@
#include "nm-setting-connection.h"
#include "NetworkManagerSystem.h"
#include "nm-named-manager.h"
#include "nm-vpn-manager.h"
typedef struct LookupThread LookupThread;
@@ -69,6 +70,10 @@ struct NMPolicy {
GSList *signal_ids;
GSList *dev_signal_ids;
NMVPNManager *vpn_manager;
gulong vpn_activated_id;
gulong vpn_deactivated_id;
NMDevice *default_device;
LookupThread *lookup;
@@ -461,35 +466,22 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
}
}
static void
update_default_route (NMPolicy *policy, NMDevice *new)
{
const char *ip_iface;
/* FIXME: Not sure if the following makes any sense. */
/* If iface and ip_iface are the same, it's a regular network device and we
treat it as such. However, if they differ, it's most likely something like
a serial device with ppp interface, so route all the traffic to it. */
ip_iface = nm_device_get_ip_iface (new);
if (strcmp (ip_iface, nm_device_get_iface (new))) {
nm_system_device_replace_default_ip4_route (ip_iface, 0, 0);
} else {
NMIP4Config *config;
const NMSettingIP4Address *def_addr;
config = nm_device_get_ip4_config (new);
def_addr = nm_ip4_config_get_address (config, 0);
nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config));
}
}
static void
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
{
NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
NMDevice *best = NULL;
NMActRequest *best_req = NULL;
NMNamedManager *named_mgr;
GSList *devices = NULL, *iter;
GSList *devices = NULL, *iter, *vpns;
NMIP4Config *ip4_config = NULL;
const char *ip_iface = NULL;
const char *parent_iface = NULL;
NMVPNConnection *vpn = NULL;
NMConnection *connection = NULL;
NMSettingConnection *s_con = NULL;
guint32 parent_mss = 0;
guint32 gateway = 0;
best = get_best_device (policy->manager, &best_req);
if (!best)
@@ -497,8 +489,69 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (!force_update && (best == policy->default_device))
goto out;
update_default_route (policy, best);
/* If a VPN connection is active, it is preferred */
vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
for (iter = vpns; iter; iter = g_slist_next (iter)) {
NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
if (!vpn && (nm_vpn_connection_get_vpn_state (candidate) == NM_VPN_CONNECTION_STATE_ACTIVATED))
vpn = g_object_ref (candidate);
g_object_unref (candidate);
}
g_slist_free (vpns);
/* VPNs are the default route only if they don't have custom routes */
if (vpn) {
NMIP4Config *vpn_config;
vpn_config = nm_vpn_connection_get_ip4_config (vpn);
if (nm_ip4_config_get_num_routes (vpn_config) == 0) {
NMIP4Config *parent_ip4;
NMDevice *parent;
connection = nm_vpn_connection_get_connection (vpn);
ip_iface = nm_vpn_connection_get_ip_iface (vpn);
ip4_config = vpn_config;
parent = nm_vpn_connection_get_parent_device (vpn);
parent_iface = nm_device_get_ip_iface (parent);
parent_ip4 = nm_device_get_ip4_config (parent);
if (parent_ip4)
parent_mss = nm_ip4_config_get_mss (parent_ip4);
dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
}
g_object_unref (vpn);
}
/* The best device gets the default route if a VPN connection didn't */
if (!ip_iface || !ip4_config) {
const NMSettingIP4Address *addr;
connection = nm_act_request_get_connection (best_req);
ip_iface = nm_device_get_ip_iface (best);
ip4_config = nm_device_get_ip4_config (best);
if (ip4_config) {
addr = nm_ip4_config_get_address (ip4_config, 0);
gateway = addr->gateway;
}
dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
}
if (!ip_iface || !ip4_config) {
nm_warning ("%s: couldn't determine IP interface (%p) or IPv4 config (%p)!",
__func__, ip_iface, ip4_config);
goto out;
}
/* Set the new default route */
nm_system_device_replace_default_ip4_route (ip_iface,
gateway,
nm_ip4_config_get_mss (ip4_config),
parent_iface,
parent_mss);
/* Update the default active connection. Only mark the new default
* active connection after setting default = FALSE on all other connections
* first. The order is important, we don't want two connections marked
@@ -515,10 +568,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
}
named_mgr = nm_named_manager_get ();
nm_named_manager_add_ip4_config (named_mgr,
nm_device_get_ip_iface (best),
nm_device_get_ip4_config (best),
NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE);
nm_named_manager_add_ip4_config (named_mgr, ip_iface, ip4_config, dns_type);
g_object_unref (named_mgr);
/* Now set new default active connection _after_ updating DNS info, so that
@@ -527,8 +577,13 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (best_req)
nm_act_request_set_default (best_req, TRUE);
nm_info ("Policy set (%s) as default device for routing and DNS.",
nm_device_get_iface (best));
if (connection)
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
if (s_con && s_con->id)
nm_info ("Policy set '%s' (%s) as default for routing and DNS.", s_con->id, ip_iface);
else
nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface);
out:
/* Update the system hostname */
@@ -617,6 +672,24 @@ auto_activate_device (gpointer user_data)
/*****************************************************************************/
static void
vpn_connection_activated (NMVPNManager *manager,
NMVPNConnection *vpn,
gpointer user_data)
{
update_routing_and_dns ((NMPolicy *) user_data, TRUE);
}
static void
vpn_connection_deactivated (NMVPNManager *manager,
NMVPNConnection *vpn,
NMVPNConnectionState state,
NMVPNConnectionStateReason reason,
gpointer user_data)
{
update_routing_and_dns ((NMPolicy *) user_data, TRUE);
}
static void
global_state_changed (NMManager *manager, NMState state, gpointer user_data)
{
@@ -868,7 +941,7 @@ connection_removed (NMManager *manager,
}
NMPolicy *
nm_policy_new (NMManager *manager)
nm_policy_new (NMManager *manager, NMVPNManager *vpn_manager)
{
NMPolicy *policy;
static gboolean initialized = FALSE;
@@ -881,6 +954,14 @@ nm_policy_new (NMManager *manager)
policy->manager = g_object_ref (manager);
policy->update_state_id = 0;
policy->vpn_manager = g_object_ref (vpn_manager);
id = g_signal_connect (policy->vpn_manager, "connection-activated",
G_CALLBACK (vpn_connection_activated), policy);
policy->vpn_activated_id = id;
id = g_signal_connect (policy->vpn_manager, "connection-deactivated",
G_CALLBACK (vpn_connection_deactivated), policy);
policy->vpn_deactivated_id = id;
id = g_signal_connect (manager, "state-changed",
G_CALLBACK (global_state_changed), policy);
policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
@@ -944,6 +1025,9 @@ nm_policy_destroy (NMPolicy *policy)
}
g_slist_free (policy->pending_activation_checks);
g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id);
g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
for (iter = policy->signal_ids; iter; iter = g_slist_next (iter))
g_signal_handler_disconnect (policy->manager, (gulong) iter->data);
g_slist_free (policy->signal_ids);