summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-15 15:36:19 +0200
committerThomas Haller <thaller@redhat.com>2020-09-15 15:36:19 +0200
commit6ce482c526e0550c9bafdee8fcb5e6fa3c4e39e5 (patch)
tree58bfaa556620eec8f951e00bbfa1f12cc2515ed8
parente8eaaa78d1dc777bcaf11e20cc93d3509d9aa0b7 (diff)
downloadNetworkManager-6ce482c526e0550c9bafdee8fcb5e6fa3c4e39e5.tar.gz
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.
-rw-r--r--src/ndisc/nm-fake-ndisc.c11
-rw-r--r--src/ndisc/nm-lndp-ndisc.c55
-rw-r--r--src/ndisc/nm-ndisc.c47
-rw-r--r--src/ndisc/nm-ndisc.h2
4 files changed, 94 insertions, 21 deletions
diff --git a/src/ndisc/nm-fake-ndisc.c b/src/ndisc/nm-fake-ndisc.c
index 5e5adfb844..14ef18d58b 100644
--- a/src/ndisc/nm-fake-ndisc.c
+++ b/src/ndisc/nm-fake-ndisc.c
@@ -337,6 +337,14 @@ start (NMNDisc *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
nm_fake_ndisc_emit_new_ras (NMFakeNDisc *self)
{
@@ -388,7 +396,8 @@ nm_fake_ndisc_class_init (NMFakeNDiscClass *klass)
object_class->dispose = dispose;
- ndisc_class->start = start;
+ ndisc_class->start = start;
+ ndisc_class->stop = stop;
ndisc_class->send_rs = send_rs;
signals[RS_SENT] =
diff --git a/src/ndisc/nm-lndp-ndisc.c b/src/ndisc/nm-lndp-ndisc.c
index 0d78a5356b..654d9693ae 100644
--- a/src/ndisc/nm-lndp-ndisc.c
+++ b/src/ndisc/nm-lndp-ndisc.c
@@ -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
@@ -659,24 +689,8 @@ static void
dispose (GObject *object)
{
NMNDisc *ndisc = NM_NDISC (object);
- 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:
- g_assert_not_reached ();
- }
- ndp_close (priv->ndp);
- priv->ndp = NULL;
- }
+ _cleanup (ndisc);
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);
object_class->dispose = dispose;
- ndisc_class->start = start;
- ndisc_class->send_rs = send_rs;
- ndisc_class->send_ra = send_ra;
+ ndisc_class->start = start;
+ ndisc_class->stop = stop;
+ ndisc_class->send_rs = send_rs;
+ ndisc_class->send_ra = send_ra;
}
diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c
index 9b2002905c..e01bd42e3d 100644
--- a/src/ndisc/nm-ndisc.c
+++ b/src/ndisc/nm-ndisc.c
@@ -960,6 +960,53 @@ nm_ndisc_start (NMNDisc *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
nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal)
{
diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h
index 4130fd9f77..5190478cd2 100644
--- a/src/ndisc/nm-ndisc.h
+++ b/src/ndisc/nm-ndisc.h
@@ -163,6 +163,7 @@ typedef struct {
GObjectClass parent;
void (*start) (NMNDisc *ndisc);
+ void (*stop) (NMNDisc *ndisc);
gboolean (*send_rs) (NMNDisc *ndisc, GError **error);
gboolean (*send_ra) (NMNDisc *ndisc, GError **error);
} NMNDiscClass;
@@ -177,6 +178,7 @@ NMNDiscNodeType nm_ndisc_get_node_type (NMNDisc *self);
gboolean nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid);
void nm_ndisc_start (NMNDisc *ndisc);
+void nm_ndisc_stop (NMNDisc *ndisc);
NMNDiscConfigMap nm_ndisc_dad_failed (NMNDisc *ndisc,
const struct in6_addr *address,
gboolean emit_changed_signal);