device/ndisc: add nm_ndisc_stop() method

It is bad style to rely on the last unref of an object for stopping
the operation. With a ref-counted object you should never rely on
anybody else still having (or not having) a reference. Hence, you
should not rely on stopping the ND during the last unref.

Add an explicit nm_ndisc_stop() function.
This commit is contained in:
Thomas Haller 2020-09-15 15:36:19 +02:00
parent e8eaaa78d1
commit 6ce482c526
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 94 additions and 21 deletions

View file

@ -337,6 +337,14 @@ start (NMNDisc *ndisc)
priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, ndisc); priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, ndisc);
} }
static void
stop (NMNDisc *ndisc)
{
NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (ndisc);
nm_clear_g_source (&priv->receive_ra_id);
}
void void
nm_fake_ndisc_emit_new_ras (NMFakeNDisc *self) nm_fake_ndisc_emit_new_ras (NMFakeNDisc *self)
{ {
@ -388,7 +396,8 @@ nm_fake_ndisc_class_init (NMFakeNDiscClass *klass)
object_class->dispose = dispose; object_class->dispose = dispose;
ndisc_class->start = start; ndisc_class->start = start;
ndisc_class->stop = stop;
ndisc_class->send_rs = send_rs; ndisc_class->send_rs = send_rs;
signals[RS_SENT] = signals[RS_SENT] =

View file

@ -535,6 +535,36 @@ start (NMNDisc *ndisc)
} }
} }
static void
_cleanup (NMNDisc *ndisc)
{
NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc);
nm_clear_g_source_inst (&priv->event_source);
if (priv->ndp) {
switch (nm_ndisc_get_node_type (ndisc)) {
case NM_NDISC_NODE_TYPE_HOST:
ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, nm_ndisc_get_ifindex (ndisc), ndisc);
break;
case NM_NDISC_NODE_TYPE_ROUTER:
ndp_msgrcv_handler_unregister (priv->ndp, receive_rs, NDP_MSG_RS, nm_ndisc_get_ifindex (ndisc), ndisc);
break;
default:
nm_assert_not_reached ();
break;
}
ndp_close (priv->ndp);
priv->ndp = NULL;
}
}
static void
stop (NMNDisc *ndisc)
{
_cleanup (ndisc);
}
/*****************************************************************************/ /*****************************************************************************/
static int static int
@ -659,24 +689,8 @@ static void
dispose (GObject *object) dispose (GObject *object)
{ {
NMNDisc *ndisc = NM_NDISC (object); NMNDisc *ndisc = NM_NDISC (object);
NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc);
nm_clear_g_source_inst (&priv->event_source); _cleanup (ndisc);
if (priv->ndp) {
switch (nm_ndisc_get_node_type (ndisc)) {
case NM_NDISC_NODE_TYPE_HOST:
ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, nm_ndisc_get_ifindex (ndisc), ndisc);
break;
case NM_NDISC_NODE_TYPE_ROUTER:
ndp_msgrcv_handler_unregister (priv->ndp, receive_rs, NDP_MSG_RS, nm_ndisc_get_ifindex (ndisc), ndisc);
break;
default:
g_assert_not_reached ();
}
ndp_close (priv->ndp);
priv->ndp = NULL;
}
G_OBJECT_CLASS (nm_lndp_ndisc_parent_class)->dispose (object); G_OBJECT_CLASS (nm_lndp_ndisc_parent_class)->dispose (object);
} }
@ -688,7 +702,8 @@ nm_lndp_ndisc_class_init (NMLndpNDiscClass *klass)
NMNDiscClass *ndisc_class = NM_NDISC_CLASS (klass); NMNDiscClass *ndisc_class = NM_NDISC_CLASS (klass);
object_class->dispose = dispose; object_class->dispose = dispose;
ndisc_class->start = start; ndisc_class->start = start;
ndisc_class->send_rs = send_rs; ndisc_class->stop = stop;
ndisc_class->send_ra = send_ra; ndisc_class->send_rs = send_rs;
ndisc_class->send_ra = send_ra;
} }

View file

@ -960,6 +960,53 @@ nm_ndisc_start (NMNDisc *ndisc)
announce_router_initial (ndisc); announce_router_initial (ndisc);
} }
void
nm_ndisc_stop (NMNDisc *ndisc)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
NMNDiscDataInternal *rdata;
NMNDiscPrivate *priv;
g_return_if_fail (NM_IS_NDISC (ndisc));
priv = NM_NDISC_GET_PRIVATE (ndisc);
nm_assert (NM_NDISC_GET_CLASS (ndisc)->stop);
_LOGD ("stopping neighbor discovery for ifindex %d",
priv->ifindex);
if (!nm_ndisc_netns_push (ndisc, &netns))
return;
NM_NDISC_GET_CLASS (ndisc)->stop (ndisc);
rdata = &priv->rdata;
g_array_set_size (rdata->gateways, 0);
g_array_set_size (rdata->addresses, 0);
g_array_set_size (rdata->routes, 0);
g_array_set_size (rdata->dns_servers, 0);
g_array_set_size (rdata->dns_domains, 0);
priv->rdata.public.hop_limit = 64;
/* Start at very low number so that last_rs - router_solicitation_interval
* is much lower than nm_utils_get_monotonic_timestamp_sec() at startup.
*/
priv->last_rs = G_MININT32;
nm_clear_g_source_inst (&priv->ra_timeout_source);
nm_clear_g_source (&priv->send_rs_id);
nm_clear_g_source (&priv->send_ra_id);
nm_clear_g_free (&priv->last_error);
nm_clear_g_source (&priv->timeout_id);
priv->solicitations_left = 0;
priv->announcements_left = 0;
priv->last_rs = G_MININT32;
priv->last_ra = G_MININT32;
}
NMNDiscConfigMap NMNDiscConfigMap
nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal) nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal)
{ {

View file

@ -163,6 +163,7 @@ typedef struct {
GObjectClass parent; GObjectClass parent;
void (*start) (NMNDisc *ndisc); void (*start) (NMNDisc *ndisc);
void (*stop) (NMNDisc *ndisc);
gboolean (*send_rs) (NMNDisc *ndisc, GError **error); gboolean (*send_rs) (NMNDisc *ndisc, GError **error);
gboolean (*send_ra) (NMNDisc *ndisc, GError **error); gboolean (*send_ra) (NMNDisc *ndisc, GError **error);
} NMNDiscClass; } NMNDiscClass;
@ -177,6 +178,7 @@ NMNDiscNodeType nm_ndisc_get_node_type (NMNDisc *self);
gboolean nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid); gboolean nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid);
void nm_ndisc_start (NMNDisc *ndisc); void nm_ndisc_start (NMNDisc *ndisc);
void nm_ndisc_stop (NMNDisc *ndisc);
NMNDiscConfigMap nm_ndisc_dad_failed (NMNDisc *ndisc, NMNDiscConfigMap nm_ndisc_dad_failed (NMNDisc *ndisc,
const struct in6_addr *address, const struct in6_addr *address,
gboolean emit_changed_signal); gboolean emit_changed_signal);