dhcp: simplify DHCP states

The existing DHC_* states are pretty specific to dhclient, and aren't
useful for more generalized DHCP.  NetworkManager wasn't using many
of the states anyway, and doesn't need to differentiate between
states like REBOOT/REBIND/RENEW anyway.  So simplify the DHCP states
into the ones we really care about.
This commit is contained in:
Dan Williams 2014-05-15 12:49:11 -05:00
parent 30cdd1248c
commit 9e75e2ad0d
3 changed files with 76 additions and 144 deletions

View file

@ -2699,7 +2699,7 @@ dhcp4_fail (NMDevice *device, gboolean timeout)
static void
dhcp4_state_changed (NMDHCPClient *client,
NMDHCPState state,
NMDhcpState state,
gpointer user_data)
{
NMDevice *device = NM_DEVICE (user_data);
@ -2712,10 +2712,7 @@ dhcp4_state_changed (NMDHCPClient *client,
nm_device_get_iface (device), state);
switch (state) {
case DHC_BOUND4: /* lease obtained */
case DHC_RENEW4: /* lease renewed */
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
case DHC_REBIND4: /* new, different lease */
case NM_DHCP_STATE_BOUND:
config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
if (!config) {
nm_log_warn (LOGD_DHCP4, "(%s): failed to get IPv4 config in response to DHCP event.",
@ -2740,12 +2737,11 @@ dhcp4_state_changed (NMDHCPClient *client,
g_object_unref (config);
break;
case DHC_TIMEOUT: /* timed out contacting DHCP server */
case NM_DHCP_STATE_TIMEOUT:
dhcp4_fail (device, TRUE);
break;
case DHC_END: /* dhclient exited normally */
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
case DHC_ABEND: /* dhclient exited abnormally */
case NM_DHCP_STATE_DONE:
case NM_DHCP_STATE_FAIL:
/* dhclient quit and can't get/renew a lease; so kill the connection */
dhcp4_fail (device, FALSE);
break;
@ -3150,7 +3146,7 @@ dhcp6_fail (NMDevice *device, gboolean timeout)
static void
dhcp6_state_changed (NMDHCPClient *client,
NMDHCPState state,
NMDhcpState state,
gpointer user_data)
{
NMDevice *device = NM_DEVICE (user_data);
@ -3162,10 +3158,7 @@ dhcp6_state_changed (NMDHCPClient *client,
nm_device_get_iface (device), state);
switch (state) {
case DHC_BOUND6:
case DHC_RENEW6: /* lease renewed */
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
case DHC_REBIND6: /* new, different lease */
case NM_DHCP_STATE_BOUND:
g_clear_object (&priv->dhcp6_ip6_config);
priv->dhcp6_ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
@ -3188,10 +3181,10 @@ dhcp6_state_changed (NMDHCPClient *client,
} else if (priv->ip6_state == IP_DONE)
dhcp6_lease_change (device);
break;
case DHC_TIMEOUT: /* timed out contacting DHCP server */
case NM_DHCP_STATE_TIMEOUT:
dhcp6_fail (device, TRUE);
break;
case DHC_END: /* dhclient exited normally */
case NM_DHCP_STATE_DONE:
/* In IPv6 info-only mode, the client doesn't handle leases so it
* may exit right after getting a response from the server. That's
* normal. In that case we just ignore the exit.
@ -3199,8 +3192,7 @@ dhcp6_state_changed (NMDHCPClient *client,
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF)
break;
/* Otherwise, fall through */
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
case DHC_ABEND: /* dhclient exited abnormally */
case NM_DHCP_STATE_FAIL:
/* dhclient quit and can't get/renew a lease; so kill the connection */
dhcp6_fail (device, FALSE);
break;

View file

@ -44,7 +44,7 @@ typedef struct {
guint32 timeout;
GByteArray * duid;
guchar state;
NMDhcpState state;
pid_t pid;
guint timeout_id;
guint watch_id;
@ -201,7 +201,7 @@ signal_remove (gpointer user_data)
static void
dhcp_client_set_state (NMDHCPClient *self,
NMDHCPState state,
NMDhcpState state,
gboolean emit_state,
gboolean remove_now)
{
@ -212,7 +212,7 @@ dhcp_client_set_state (NMDHCPClient *self,
if (emit_state)
g_signal_emit (G_OBJECT (self), signals[SIGNAL_STATE_CHANGED], 0, priv->state);
if (state == DHC_END || state == DHC_ABEND) {
if (state == NM_DHCP_STATE_DONE || state == NM_DHCP_STATE_FAIL) {
/* Start the remove signal timer */
if (remove_now) {
g_signal_emit (G_OBJECT (self), signals[SIGNAL_REMOVE], 0);
@ -228,7 +228,7 @@ daemon_watch_cb (GPid pid, gint status, gpointer user_data)
{
NMDHCPClient *self = NM_DHCP_CLIENT (user_data);
NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
NMDHCPState new_state;
NMDhcpState new_state;
if (priv->ipv6) {
nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 client pid %d exited with status %d",
@ -241,10 +241,10 @@ daemon_watch_cb (GPid pid, gint status, gpointer user_data)
}
if (!WIFEXITED (status)) {
new_state = DHC_ABEND;
new_state = NM_DHCP_STATE_FAIL;
nm_log_warn (LOGD_DHCP, "DHCP client died abnormally");
} else
new_state = DHC_END;
new_state = NM_DHCP_STATE_DONE;
watch_cleanup (self);
timeout_cleanup (self);
@ -519,7 +519,7 @@ nm_dhcp_client_stop (NMDHCPClient *self, gboolean release)
/* And clean stuff up */
dhcp_client_set_state (self, DHC_END, FALSE, TRUE);
dhcp_client_set_state (self, NM_DHCP_STATE_DONE, FALSE, TRUE);
g_hash_table_remove_all (priv->options);
@ -529,71 +529,44 @@ nm_dhcp_client_stop (NMDHCPClient *self, gboolean release)
/********************************************/
static gboolean
state_is_bound (guint32 state)
{
if ( (state == DHC_BOUND4)
|| (state == DHC_BOUND6)
|| (state == DHC_RENEW4)
|| (state == DHC_RENEW6)
|| (state == DHC_REBOOT)
|| (state == DHC_REBIND4)
|| (state == DHC_REBIND6)
|| (state == DHC_IPV4LL))
return TRUE;
return FALSE;
}
static const char *state_table[] = {
[DHC_NBI] = "nbi",
[DHC_PREINIT] = "preinit",
[DHC_PREINIT6] = "preinit6",
[DHC_BOUND4] = "bound",
[DHC_BOUND6] = "bound6",
[DHC_IPV4LL] = "ipv4ll",
[DHC_RENEW4] = "renew",
[DHC_RENEW6] = "renew6",
[DHC_REBOOT] = "reboot",
[DHC_REBIND4] = "rebind",
[DHC_REBIND6] = "rebind6",
[DHC_DEPREF6] = "depref6",
[DHC_STOP] = "stop",
[DHC_STOP6] = "stop6",
[DHC_MEDIUM] = "medium",
[DHC_TIMEOUT] = "timeout",
[DHC_FAIL] = "fail",
[DHC_EXPIRE] = "expire",
[DHC_EXPIRE6] = "expire6",
[DHC_RELEASE] = "release",
[DHC_RELEASE6] = "release6",
[DHC_START] = "start",
[DHC_ABEND] = "abend",
[DHC_END] = "end",
static const char *state_table[NM_DHCP_STATE_MAX + 1] = {
[NM_DHCP_STATE_UNKNOWN] = "unknown",
[NM_DHCP_STATE_BOUND] = "bound",
[NM_DHCP_STATE_TIMEOUT] = "timeout",
[NM_DHCP_STATE_DONE] = "done",
[NM_DHCP_STATE_FAIL] = "fail",
};
static const char *
state_to_string (NMDHCPState state)
state_to_string (NMDhcpState state)
{
if (state >= 0 && state < G_N_ELEMENTS (state_table))
return state_table[state];
return NULL;
}
static NMDHCPState
string_to_state (const char *name)
static NMDhcpState
reason_to_state (const char *iface, const char *reason)
{
int i;
if (g_ascii_strcasecmp (reason, "bound") == 0 ||
g_ascii_strcasecmp (reason, "bound6") == 0 ||
g_ascii_strcasecmp (reason, "renew") == 0 ||
g_ascii_strcasecmp (reason, "renew6") == 0 ||
g_ascii_strcasecmp (reason, "reboot") == 0 ||
g_ascii_strcasecmp (reason, "rebind") == 0 ||
g_ascii_strcasecmp (reason, "rebind6") == 0)
return NM_DHCP_STATE_BOUND;
else if (g_ascii_strcasecmp (reason, "timeout") == 0)
return NM_DHCP_STATE_TIMEOUT;
else if (g_ascii_strcasecmp (reason, "end") == 0)
return NM_DHCP_STATE_DONE;
else if (g_ascii_strcasecmp (reason, "fail") == 0 ||
g_ascii_strcasecmp (reason, "abend") == 0 ||
g_ascii_strcasecmp (reason, "nak") == 0)
return NM_DHCP_STATE_FAIL;
if (name) {
for (i = 0; i < G_N_ELEMENTS (state_table); i++) {
const char *n = state_table[i];
if (n && !strcasecmp (name, n))
return i;
}
}
return 255;
nm_log_dbg (LOGD_DHCP, "(%s): unmapped DHCP state '%s'", iface, reason);
return NM_DHCP_STATE_UNKNOWN;
}
static char *
@ -665,44 +638,31 @@ nm_dhcp_client_new_options (NMDHCPClient *self,
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
old_state = priv->state;
new_state = string_to_state (reason);
new_state = reason_to_state (priv->iface, reason);
/* Clear old and save new DHCP options */
g_hash_table_remove_all (priv->options);
g_hash_table_foreach (options, copy_option, priv->options);
if (old_state == new_state) {
/* dhclient will stay in the same state (or, really, provide the same
* reason) for operations like RENEW and REBIND. We need to ensure
* that triggers various DHCP lease change code, so we need to pass
* along same-state transitions for these states.
*/
if ( new_state != DHC_BOUND4
&& new_state != DHC_RENEW4
&& new_state != DHC_REBIND4
&& new_state != DHC_BOUND6
&& new_state != DHC_RENEW6
&& new_state != DHC_REBIND6)
return;
}
/* dhclient sends same-state transitions for RENEW/REBIND events, but
* the lease may have changed, so handle same-state transitions for
* these events. Ignore same-state transitions for other events since
* the lease won't have changed and the state was already handled.
*/
if ((old_state == new_state) && (new_state != NM_DHCP_STATE_BOUND))
return;
/* Handle changed device state */
if (state_is_bound (new_state)) {
if (new_state == NM_DHCP_STATE_BOUND) {
/* Cancel the timeout if the DHCP client is now bound */
timeout_cleanup (self);
}
if (priv->ipv6) {
nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 state changed %s -> %s",
priv->iface,
state_to_string (old_state),
state_to_string (new_state));
} else {
nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 state changed %s -> %s",
priv->iface,
state_to_string (old_state),
state_to_string (new_state));
}
nm_log_info (priv->ipv6 ? LOGD_DHCP6 : LOGD_DHCP4,
"(%s): DHCPv%c state changed %s -> %s",
priv->iface,
priv->ipv6 ? '6' : '4',
state_to_string (old_state),
state_to_string (new_state));
dhcp_client_set_state (self, new_state, TRUE, FALSE);
}
@ -724,12 +684,11 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self,
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
if (!state_is_bound (priv->state)) {
if (priv->ipv6) {
nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 client didn't bind to a lease.", priv->iface);
} else {
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 client didn't bind to a lease.", priv->iface);
}
if (priv->state != NM_DHCP_STATE_BOUND) {
nm_log_warn (priv->ipv6 ? LOGD_DHCP6 : LOGD_DHCP4,
"(%s): DHCPv%c client didn't bind to a lease.",
priv->iface,
priv->ipv6 ? '6' : '4');
}
g_hash_table_iter_init (&iter, priv->options);
@ -1319,7 +1278,7 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test)
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
if (test && !state_is_bound (priv->state)) {
if (test && (priv->state != NM_DHCP_STATE_BOUND)) {
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 client didn't bind to a lease.", priv->iface);
return NULL;
}
@ -1437,7 +1396,7 @@ nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test)
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
if (test && !state_is_bound (priv->state)) {
if (test && (priv->state != NM_DHCP_STATE_BOUND)) {
nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 client didn't bind to a lease.", priv->iface);
return NULL;
}
@ -1640,8 +1599,7 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMDHCPClientClass, state_changed),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[SIGNAL_TIMEOUT] =

View file

@ -47,32 +47,14 @@
#define NM_DHCP_CLIENT_SIGNAL_REMOVE "remove"
typedef enum {
DHC_NBI = 0, /* no broadcast interfaces found */
DHC_PREINIT, /* configuration started */
DHC_PREINIT6, /* configuration started */
DHC_BOUND4, /* IPv4 lease obtained */
DHC_BOUND6, /* IPv6 lease obtained */
DHC_IPV4LL, /* IPv4LL address obtained */
DHC_RENEW4, /* IPv4 lease renewed */
DHC_RENEW6, /* IPv6 lease renewed */
DHC_REBOOT, /* have valid lease, but now obtained a different one */
DHC_REBIND4, /* IPv4 new/different lease */
DHC_REBIND6, /* IPv6 new/different lease */
DHC_DEPREF6, /* IPv6 lease depreferred */
DHC_STOP, /* remove old lease */
DHC_STOP6, /* remove old lease */
DHC_MEDIUM, /* media selection begun */
DHC_TIMEOUT, /* timed out contacting DHCP server */
DHC_FAIL, /* all attempts to contact server timed out, sleeping */
DHC_EXPIRE, /* lease has expired, renewing */
DHC_EXPIRE6, /* lease has expired, renewing */
DHC_RELEASE, /* releasing lease */
DHC_RELEASE6, /* releasing lease */
DHC_START, /* sent when dhclient started OK */
DHC_ABEND, /* dhclient exited abnormally */
DHC_END, /* dhclient exited normally */
DHC_END_OPTIONS, /* last option in subscription sent */
} NMDHCPState;
NM_DHCP_STATE_UNKNOWN = 0,
NM_DHCP_STATE_BOUND, /* lease changed (state_is_bound) */
NM_DHCP_STATE_TIMEOUT, /* TIMEOUT */
NM_DHCP_STATE_DONE, /* END */
NM_DHCP_STATE_FAIL, /* failed or quit unexpectedly */
__NM_DHCP_STATE_MAX,
NM_DHCP_STATE_MAX = __NM_DHCP_STATE_MAX - 1,
} NMDhcpState;
typedef struct {
GObject parent;
@ -110,7 +92,7 @@ typedef struct {
GByteArray * (*get_duid) (NMDHCPClient *self);
/* Signals */
void (*state_changed) (NMDHCPClient *self, NMDHCPState state);
void (*state_changed) (NMDHCPClient *self, NMDhcpState state);
void (*timeout) (NMDHCPClient *self);
void (*remove) (NMDHCPClient *self);
} NMDHCPClientClass;