dhcp: add DHCP lease release capability

This commit is contained in:
Dan Williams 2011-01-05 16:23:00 -06:00
parent 6ae91e2f67
commit 9917da2c71
7 changed files with 123 additions and 62 deletions

View file

@ -136,10 +136,10 @@ watch_cleanup (NMDHCPClient *self)
}
}
static void
stop_process (GPid pid, const char *iface)
void
nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs)
{
int i = 15; /* 3 seconds */
int i = (timeout_secs ? timeout_secs : 3) * 5; /* default 3 seconds */
g_return_if_fail (pid > 0);
@ -183,7 +183,7 @@ stop_process (GPid pid, const char *iface)
}
static void
real_stop (NMDHCPClient *self)
real_stop (NMDHCPClient *self, gboolean release)
{
NMDHCPClientPrivate *priv;
@ -196,7 +196,7 @@ real_stop (NMDHCPClient *self)
/* Clean up the watch handler since we're explicitly killing the daemon */
watch_cleanup (self);
stop_process (priv->pid, priv->iface);
nm_dhcp_client_stop_pid (priv->pid, priv->iface, 0);
priv->info_only = FALSE;
}
@ -376,7 +376,7 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name)
exe = proc_contents;
if (!strcmp (exe, binary_name))
stop_process ((GPid) tmp, NULL);
nm_dhcp_client_stop_pid ((GPid) tmp, NULL, 0);
}
}
@ -387,7 +387,7 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name)
}
void
nm_dhcp_client_stop (NMDHCPClient *self)
nm_dhcp_client_stop (NMDHCPClient *self, gboolean release)
{
NMDHCPClientPrivate *priv;
@ -398,7 +398,7 @@ nm_dhcp_client_stop (NMDHCPClient *self)
/* Kill the DHCP client */
if (!priv->dead) {
NM_DHCP_CLIENT_GET_CLASS (self)->stop (self);
NM_DHCP_CLIENT_GET_CLASS (self)->stop (self, release);
priv->dead = TRUE;
nm_log_info (LOGD_DHCP, "(%s): canceled DHCP transaction, DHCP client pid %d",

View file

@ -76,18 +76,19 @@ typedef struct {
/* Methods */
GPid (*ip4_start) (NMDHCPClient *self,
NMSettingIP4Config *s_ip4,
guint8 *anycast_addr,
const char *hostname);
GPid (*ip4_start) (NMDHCPClient *self,
NMSettingIP4Config *s_ip4,
guint8 *anycast_addr,
const char *hostname);
GPid (*ip6_start) (NMDHCPClient *self,
NMSettingIP6Config *s_ip6,
guint8 *anycast_addr,
const char *hostname,
gboolean info_only);
GPid (*ip6_start) (NMDHCPClient *self,
NMSettingIP6Config *s_ip6,
guint8 *anycast_addr,
const char *hostname,
gboolean info_only);
void (*stop) (NMDHCPClient *self);
void (*stop) (NMDHCPClient *self,
gboolean release);
/* Signals */
void (*state_changed) (NMDHCPClient *self, NMDHCPState state);
@ -116,7 +117,7 @@ gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self,
const char *hostname,
gboolean info_only);
void nm_dhcp_client_stop (NMDHCPClient *self);
void nm_dhcp_client_stop (NMDHCPClient *self, gboolean release);
void nm_dhcp_client_new_options (NMDHCPClient *self,
GHashTable *options,
@ -133,5 +134,7 @@ NMIP6Config *nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test)
/* Backend helpers */
void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name);
void nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs);
#endif /* NM_DHCP_CLIENT_H */

View file

@ -411,15 +411,15 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED)
static GPid
dhclient_start (NMDHCPClient *client,
const char *ip_opt,
const char *mode_opt)
const char *mode_opt,
gboolean release)
{
NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
GPtrArray *argv = NULL;
GPid pid = -1;
GError *error = NULL;
const char *iface, *uuid;
char *binary_name, *cmd_str;
char *binary_name, *cmd_str, *pid_file = NULL;
gboolean ipv6;
guint log_domain;
@ -436,28 +436,33 @@ dhclient_start (NMDHCPClient *client,
nm_log_warn (log_domain, "(%s): ISC dhcp3 does not support IPv6", iface);
return -1;
}
#else
g_return_val_if_fail (ip_opt != NULL, -1);
#endif
priv->pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid",
ipv6 ? "6" : "",
iface);
if (!priv->pid_file) {
nm_log_warn (log_domain, "(%s): not enough memory for dhcpcd options.", iface);
return -1;
}
if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
nm_log_warn (log_domain, "%s does not exist.", priv->path);
return -1;
}
pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid",
ipv6 ? "6" : "",
iface);
if (!pid_file) {
nm_log_warn (log_domain, "(%s): not enough memory for dhcpcd options.", iface);
return -1;
}
/* Kill any existing dhclient from the pidfile */
binary_name = g_path_get_basename (priv->path);
nm_dhcp_client_stop_existing (priv->pid_file, binary_name);
nm_dhcp_client_stop_existing (pid_file, binary_name);
g_free (binary_name);
if (release) {
/* release doesn't use the pidfile after killing an old client */
g_free (pid_file);
pid_file = NULL;
}
g_free (priv->lease_file);
priv->lease_file = get_leasefile_for_iface (iface, uuid, ipv6);
if (!priv->lease_file) {
nm_log_warn (log_domain, "(%s): not enough memory for dhclient options.", iface);
@ -469,17 +474,26 @@ dhclient_start (NMDHCPClient *client,
g_ptr_array_add (argv, (gpointer) "-d");
if (release)
g_ptr_array_add (argv, (gpointer) "-r");
#if !defined(DHCLIENT_V3)
g_ptr_array_add (argv, (gpointer) ip_opt);
if (mode_opt)
g_ptr_array_add (argv, (gpointer) mode_opt);
if (ipv6) {
g_ptr_array_add (argv, (gpointer) "-6");
if (mode_opt)
g_ptr_array_add (argv, (gpointer) mode_opt);
} else {
g_ptr_array_add (argv, (gpointer) "-4");
}
#endif
g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */
g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH );
g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */
g_ptr_array_add (argv, (gpointer) priv->pid_file);
if (pid_file) {
g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */
g_ptr_array_add (argv, (gpointer) pid_file);
}
g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */
g_ptr_array_add (argv, (gpointer) priv->lease_file);
@ -501,8 +515,10 @@ dhclient_start (NMDHCPClient *client,
nm_log_warn (log_domain, "dhclient failed to start: '%s'", error->message);
g_error_free (error);
pid = -1;
} else
} else {
nm_log_info (log_domain, "dhclient started with pid %d", pid);
priv->pid_file = pid_file;
}
g_ptr_array_free (argv, TRUE);
return pid;
@ -525,7 +541,7 @@ real_ip4_start (NMDHCPClient *client,
return -1;
}
return dhclient_start (client, "-4", NULL);
return dhclient_start (client, NULL, FALSE);
}
static GPid
@ -535,21 +551,34 @@ real_ip6_start (NMDHCPClient *client,
const char *hostname,
gboolean info_only)
{
return dhclient_start (client, "-6", info_only ? "-S" : "-N");
return dhclient_start (client, info_only ? "-S" : "-N", FALSE);
}
static void
real_stop (NMDHCPClient *client)
real_stop (NMDHCPClient *client, gboolean release)
{
NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
/* Chain up to parent */
NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client);
NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release);
if (priv->conf_file)
remove (priv->conf_file);
if (priv->pid_file)
if (priv->pid_file) {
remove (priv->pid_file);
g_free (priv->pid_file);
priv->pid_file = NULL;
}
if (release) {
GPid rpid;
rpid = dhclient_start (client, NULL, TRUE);
if (rpid > 0) {
/* Wait a few seconds for the release to happen */
nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client), 5);
}
}
}
/***************************************************/

View file

@ -170,15 +170,17 @@ real_ip6_start (NMDHCPClient *client,
}
static void
real_stop (NMDHCPClient *client)
real_stop (NMDHCPClient *client, gboolean release)
{
NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
/* Chain up to parent */
NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client);
NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release);
if (priv->pid_file)
remove (priv->pid_file);
/* FIXME: implement release... */
}
/***************************************************/

View file

@ -429,7 +429,7 @@ client_start (NMDHCPManager *self,
/* Kill any old client instance */
client = get_client_for_iface (self, iface, ipv6);
if (client) {
nm_dhcp_client_stop (client);
nm_dhcp_client_stop (client, FALSE);
remove_client (self, client);
}

View file

@ -184,8 +184,8 @@ static NMActStageReturn dhcp6_start (NMDevice *self,
NMDeviceStateReason *reason);
static void addrconf6_cleanup (NMDevice *self);
static void dhcp6_cleanup (NMDevice *self, gboolean stop);
static void dhcp4_cleanup (NMDevice *self, gboolean stop);
static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release);
static void dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release);
static void
@ -1467,7 +1467,7 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data)
if (!nm_device_get_act_request (device))
return;
nm_dhcp_client_stop (client);
nm_dhcp_client_stop (client, FALSE);
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
if (nm_dhcp_client_get_ipv6 (client))
@ -1480,17 +1480,16 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data)
static NMActStageReturn
dhcp4_start (NMDevice *self,
NMConnection *connection,
NMSettingIP4Config *s_ip4,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingConnection *s_con;
NMSettingIP4Config *s_ip4;
guint8 *anycast = NULL;
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
/* Begin a DHCP transaction on the interface */
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (priv->dhcp_anycast_address)
anycast = priv->dhcp_anycast_address->data;
@ -1500,6 +1499,7 @@ dhcp4_start (NMDevice *self,
g_object_unref (priv->dhcp4_config);
priv->dhcp4_config = nm_dhcp4_config_new ();
/* Begin DHCP on the interface */
g_warn_if_fail (priv->dhcp4_client == NULL);
priv->dhcp4_client = nm_dhcp_manager_start_ip4 (priv->dhcp_manager,
nm_device_get_ip_iface (self),
@ -1525,6 +1525,31 @@ dhcp4_start (NMDevice *self,
return NM_ACT_STAGE_RETURN_POSTPONE;
}
gboolean
nm_device_dhcp4_renew (NMDevice *self, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret;
NMDeviceStateReason reason;
NMActRequest *req;
NMConnection *connection;
g_return_val_if_fail (priv->dhcp4_client != NULL, FALSE);
/* Terminate old DHCP instance and release the old lease */
dhcp4_cleanup (self, TRUE, TRUE);
req = nm_device_get_act_request (self);
g_assert (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
/* Start DHCP again on the interface */
ret = dhcp4_start (self, connection, &reason);
return (ret != NM_ACT_STAGE_RETURN_FAILURE);
}
static NMActStageReturn
real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
{
@ -1554,7 +1579,7 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
method = nm_setting_ip4_config_get_method (s_ip4);
if (!s_ip4 || !method || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
ret = dhcp4_start (self, connection, s_ip4, reason);
ret = dhcp4_start (self, connection, reason);
} else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
GError *error = NULL;
const char *iface = nm_device_get_iface (self);
@ -2675,7 +2700,7 @@ delayed_transitions_clear (NMDevice *self)
}
static void
dhcp4_cleanup (NMDevice *self, gboolean stop)
dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@ -2698,7 +2723,7 @@ dhcp4_cleanup (NMDevice *self, gboolean stop)
}
if (stop)
nm_dhcp_client_stop (priv->dhcp4_client);
nm_dhcp_client_stop (priv->dhcp4_client, release);
g_object_unref (priv->dhcp4_client);
priv->dhcp4_client = NULL;
@ -2706,7 +2731,7 @@ dhcp4_cleanup (NMDevice *self, gboolean stop)
}
static void
dhcp6_cleanup (NMDevice *self, gboolean stop)
dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@ -2730,7 +2755,7 @@ dhcp6_cleanup (NMDevice *self, gboolean stop)
}
if (stop)
nm_dhcp_client_stop (priv->dhcp6_client);
nm_dhcp_client_stop (priv->dhcp6_client, release);
g_object_unref (priv->dhcp6_client);
priv->dhcp6_client = NULL;
@ -2779,8 +2804,8 @@ nm_device_deactivate_quickly (NMDevice *self)
/* Clear any delayed transitions */
delayed_transitions_clear (self);
dhcp4_cleanup (self, TRUE);
dhcp6_cleanup (self, TRUE);
dhcp4_cleanup (self, TRUE, FALSE);
dhcp6_cleanup (self, TRUE, FALSE);
addrconf6_cleanup (self);
dnsmasq_cleanup (self);
aipd_cleanup (self);
@ -3357,8 +3382,8 @@ dispose (GObject *object)
delayed_transitions_clear (self);
/* Clean up and stop DHCP */
dhcp4_cleanup (self, take_down);
dhcp6_cleanup (self, take_down);
dhcp4_cleanup (self, take_down, FALSE);
dhcp6_cleanup (self, take_down, FALSE);
addrconf6_cleanup (self);
dnsmasq_cleanup (self);

View file

@ -185,6 +185,8 @@ void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr);
void nm_device_clear_autoconnect_inhibit (NMDevice *device);
gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release);
G_END_DECLS
#endif /* NM_DEVICE_H */