rdisc: backport rate-limiting failures to send router solicitations

https://bugzilla.gnome.org/show_bug.cgi?id=759596
This commit is contained in:
Thomas Haller 2016-04-17 13:04:22 +02:00
commit 645bf63e0b
6 changed files with 62 additions and 12 deletions

View file

@ -59,6 +59,8 @@
#define CLOCK_BOOTTIME 7
#endif
G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int));
int _nm_utils_testing = 0;

View file

@ -232,4 +232,25 @@ gboolean nm_utils_get_testing_initialized (void);
NMUtilsTestFlags nm_utils_get_testing (void);
void _nm_utils_set_testing (NMUtilsTestFlags flags);
/*****************************************************************************/
/**
* NMUtilsError:
* @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
* @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
* pending aynchronous operations, the operation is cancelled with this
* error reason. Depending on the usage, this might indicate a bug because
* usually the target object should stay alive as long as there are pending
* operations.
*/
typedef enum {
NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/
NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/
} NMUtilsError;
#define NM_UTILS_ERROR (nm_utils_error_quark ())
GQuark nm_utils_error_quark (void);
/*****************************************************************************/
#endif /* __NETWORKMANAGER_UTILS_H__ */

View file

@ -236,7 +236,7 @@ nm_fake_rdisc_done (NMFakeRDisc *self)
/******************************************************************/
static gboolean
send_rs (NMRDisc *rdisc)
send_rs (NMRDisc *rdisc, GError **error)
{
g_signal_emit (rdisc, signals[RS_SENT], 0);
return TRUE;

View file

@ -52,20 +52,28 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC)
/******************************************************************/
static gboolean
send_rs (NMRDisc *rdisc)
send_rs (NMRDisc *rdisc, GError **error)
{
NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
struct ndp_msg *msg;
int error;
int errsv;
error = ndp_msg_new (&msg, NDP_MSG_RS);
g_assert (!error);
errsv = ndp_msg_new (&msg, NDP_MSG_RS);
if (errsv) {
errsv = errsv > 0 ? errsv : -errsv;
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"cannot create router solicitation");
return FALSE;
}
ndp_msg_ifindex_set (msg, rdisc->ifindex);
error = ndp_msg_send (priv->ndp, msg);
errsv = ndp_msg_send (priv->ndp, msg);
ndp_msg_destroy (msg);
if (error) {
error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error);
if (errsv) {
errsv = errsv > 0 ? errsv : -errsv;
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"%s (%d)",
g_strerror (errsv), errsv);
return FALSE;
}

View file

@ -38,6 +38,7 @@ typedef struct {
gint64 last_rs;
guint ra_timeout_id; /* first RA timeout */
guint timeout_id; /* prefix/dns/etc lifetime timeout */
char *last_send_rs_error;
} NMRDiscPrivate;
#define NM_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RDISC, NMRDiscPrivate))
@ -280,11 +281,25 @@ send_rs (NMRDisc *rdisc)
{
NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc);
NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
GError *error = NULL;
debug ("(%s): sending router solicitation", rdisc->ifname);
if (klass->send_rs (rdisc))
if (klass->send_rs (rdisc, &error)) {
debug ("(%s): router solicitation sent", rdisc->ifname);
priv->solicitations_left--;
g_clear_pointer (&priv->last_send_rs_error, g_free);
} else {
gboolean different_message;
different_message = g_strcmp0 (priv->last_send_rs_error, error->message) != 0;
nm_log (different_message ? LOGL_WARN : LOGL_DEBUG, LOGD_IP6,
"(%s): failure sending router solicitation: %s",
rdisc->ifname, error->message);
if (different_message) {
g_clear_pointer (&priv->last_send_rs_error, g_free);
priv->last_send_rs_error = g_strdup (error->message);
}
g_clear_error (&error);
}
priv->last_rs = nm_utils_get_monotonic_timestamp_s ();
if (priv->solicitations_left > 0) {
@ -581,8 +596,11 @@ timeout_cb (gpointer user_data)
void
nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed)
{
NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc);
clear_ra_timeout (rdisc);
clear_rs_timeout (rdisc);
g_clear_pointer (&priv->last_send_rs_error, g_free);
check_timestamps (rdisc, now, changed);
}
@ -621,6 +639,7 @@ dispose (GObject *object)
clear_ra_timeout (rdisc);
clear_rs_timeout (rdisc);
g_clear_pointer (&priv->last_send_rs_error, g_free);
if (priv->timeout_id) {
g_source_remove (priv->timeout_id);

View file

@ -133,7 +133,7 @@ typedef struct {
GObjectClass parent;
void (*start) (NMRDisc *rdisc);
gboolean (*send_rs) (NMRDisc *rdisc);
gboolean (*send_rs) (NMRDisc *rdisc, GError **error);
void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed);
void (*ra_process) (NMRDisc *rdisc);
void (*ra_timeout) (NMRDisc *rdisc);