summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-04-14 09:39:54 +0200
committerThomas Haller <thaller@redhat.com>2021-04-16 15:18:27 +0200
commit655dd139025614c071aa64be27272faacce5f8f3 (patch)
treea2d475ec29a99ecb5315d2421197d306ec622c9c
parentb0d45c88c31c09914ed84f629d176d9f7dd0ef48 (diff)
downloadNetworkManager-655dd139025614c071aa64be27272faacce5f8f3.tar.gz
device/lldp: simplify NMLldpListener API
NMLldpListener API was a (refcounted) GObject with start/stop methods. That means, a listener instance itself had state, namely whether it was running and which ifindex was used. And this was not only internal state, but the user had to care about this. That is all entirely unnecessary. Beside requiring more code and having more overhead (of a GObject), it is also harder to use. NMDevice not only need to care whether priv->listener is set, it also needs to care whether it is running. Simplify this. The NMLldpListener is no longer ref-counted. As such, the notify callback is set in the constructor, and the user will stop receiving notifications by destroying the instance. Furthermore, the instance can only use one ifindex, that is determined at construct time too. The state that NMLldpListener now represents is simpler. This simplifies the usage from NMDevice, which now only call lldp_setup() to enable and disable the listener. There is also no need to restart the LLDP listener. The only exception is, if the ifindex changes. In that case, we throw away the old instance and create a new one. Otherwise, the LLDP listener is itself responsible to keep running. There is no excuse for it to fail, and if it does, it needs to autorecover as good as it can.
-rw-r--r--src/core/devices/nm-device.c112
-rw-r--r--src/core/devices/nm-lldp-listener.c371
-rw-r--r--src/core/devices/nm-lldp-listener.h31
-rw-r--r--src/core/devices/tests/test-lldp.c64
4 files changed, 229 insertions, 349 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 7ca03936fb..5b2903d809 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -2625,12 +2625,15 @@ set_interface_flags_full(NMDevice * self,
}
static gboolean
-set_interface_flags(NMDevice *self, NMDeviceInterfaceFlags interface_flags, gboolean set)
+set_interface_flags(NMDevice * self,
+ NMDeviceInterfaceFlags interface_flags,
+ gboolean set,
+ gboolean notify)
{
return set_interface_flags_full(self,
interface_flags,
set ? interface_flags : NM_DEVICE_INTERFACE_FLAG_NONE,
- TRUE);
+ notify);
}
void
@@ -5051,11 +5054,7 @@ nm_device_set_carrier(NMDevice *self, gboolean carrier)
if (NM_FLAGS_ALL(priv->capabilities,
NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) {
- notify_flags = set_interface_flags_full(self,
- NM_DEVICE_INTERFACE_FLAG_CARRIER,
- carrier ? NM_DEVICE_INTERFACE_FLAG_CARRIER
- : NM_DEVICE_INTERFACE_FLAG_NONE,
- FALSE);
+ notify_flags = set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_CARRIER, carrier, FALSE);
}
priv->carrier = carrier;
@@ -7944,14 +7943,6 @@ master_ready_cb(NMActiveConnection *active, GParamSpec *pspec, NMDevice *self)
nm_device_activate_schedule_stage1_device_prepare(self, FALSE);
}
-static void
-lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data)
-{
- NMDevice *self = NM_DEVICE(user_data);
-
- _notify(self, PROP_LLDP_NEIGHBORS);
-}
-
static NMPlatformVF *
sriov_vf_config_to_platform(NMDevice *self, NMSriovVF *vf, GError **error)
{
@@ -8239,43 +8230,56 @@ act_stage2_config(NMDevice *self, NMDeviceStateReason *out_failure_reason)
}
static void
-lldp_init(NMDevice *self, gboolean restart)
+_lldp_neighbors_changed_cb(NMLldpListener *lldp_listener, gpointer user_data)
+{
+ _notify(user_data, PROP_LLDP_NEIGHBORS);
+}
+
+static void
+lldp_setup(NMDevice *self, NMTernary enabled)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ int ifindex;
+ gboolean notify_lldp_neighbors = FALSE;
+ gboolean notify_interface_flags = FALSE;
- if (priv->ifindex > 0 && _prop_get_connection_lldp(self)) {
- gs_free_error GError *error = NULL;
+ ifindex = nm_device_get_ifindex(self);
- if (priv->lldp_listener) {
- if (restart && nm_lldp_listener_is_running(priv->lldp_listener)) {
- nm_lldp_listener_stop(priv->lldp_listener);
- set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, FALSE);
- }
- } else {
- priv->lldp_listener = nm_lldp_listener_new();
- g_signal_connect(priv->lldp_listener,
- "notify::" NM_LLDP_LISTENER_NEIGHBORS,
- G_CALLBACK(lldp_neighbors_changed),
- self);
- }
+ if (ifindex <= 0)
+ enabled = FALSE;
+ else if (enabled == NM_TERNARY_DEFAULT)
+ enabled = _prop_get_connection_lldp(self);
- if (!nm_lldp_listener_is_running(priv->lldp_listener)) {
- if (nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) {
- _LOGD(LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener);
- set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, TRUE);
- } else {
- _LOGD(LOGD_DEVICE,
- "LLDP listener %p could not be started: %s",
- priv->lldp_listener,
- error->message);
- }
- }
- } else {
- if (priv->lldp_listener) {
- nm_lldp_listener_stop(priv->lldp_listener);
- set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, FALSE);
+ if (priv->lldp_listener) {
+ if (!enabled || nm_lldp_listener_get_ifindex(priv->lldp_listener) != ifindex) {
+ nm_clear_pointer(&priv->lldp_listener, nm_lldp_listener_destroy);
+ notify_lldp_neighbors = TRUE;
}
}
+
+ if (enabled && !priv->lldp_listener) {
+ gs_free_error GError *error = NULL;
+
+ priv->lldp_listener =
+ nm_lldp_listener_new(ifindex, _lldp_neighbors_changed_cb, self, &error);
+ if (!priv->lldp_listener) {
+ /* This really shouldn't happen. It's likely a bug. Investigate when this happens! */
+ _LOGW(LOGD_DEVICE,
+ "LLDP listener for ifindex %d could not be started: %s",
+ ifindex,
+ error->message);
+ } else
+ notify_lldp_neighbors = TRUE;
+ }
+
+ notify_interface_flags = set_interface_flags(self,
+ NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED,
+ !!priv->lldp_listener,
+ FALSE);
+
+ nm_gobject_notify_together(self,
+ notify_lldp_neighbors ? PROP_LLDP_NEIGHBORS : PROP_0,
+ notify_interface_flags ? PROP_INTERFACE_FLAGS : PROP_0);
}
/* set-mode can be:
@@ -8488,7 +8492,7 @@ activate_stage2_device_config(NMDevice *self)
nm_device_queue_recheck_assume(info->slave);
}
- lldp_init(self, TRUE);
+ lldp_setup(self, NM_TERNARY_DEFAULT);
nm_device_activate_schedule_stage3_ip_config_start(self);
}
@@ -12720,7 +12724,7 @@ check_and_reapply_connection(NMDevice * self,
klass->reapply_connection(self, con_old, con_new);
if (priv->state >= NM_DEVICE_STATE_CONFIG)
- lldp_init(self, FALSE);
+ lldp_setup(self, NM_TERNARY_DEFAULT);
if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) {
s_ip4_old = nm_connection_get_setting_ip4_config(con_old);
@@ -15960,10 +15964,7 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
FALSE,
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
- if (priv->lldp_listener) {
- nm_lldp_listener_stop(priv->lldp_listener);
- set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, FALSE);
- }
+ lldp_setup(self, NM_TERNARY_FALSE);
nm_device_update_metered(self);
@@ -18396,14 +18397,7 @@ dispose(GObject *object)
nm_clear_g_source(&priv->device_link_changed_id);
nm_clear_g_source(&priv->device_ip_link_changed_id);
- if (priv->lldp_listener) {
- g_signal_handlers_disconnect_by_func(priv->lldp_listener,
- G_CALLBACK(lldp_neighbors_changed),
- self);
- nm_lldp_listener_stop(priv->lldp_listener);
- set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, FALSE);
- g_clear_object(&priv->lldp_listener);
- }
+ lldp_setup(self, FALSE);
nm_clear_g_source(&priv->concheck_x[0].p_cur_id);
nm_clear_g_source(&priv->concheck_x[1].p_cur_id);
diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c
index 5cf99484f1..76b7bd80e0 100644
--- a/src/core/devices/nm-lldp-listener.c
+++ b/src/core/devices/nm-lldp-listener.c
@@ -31,34 +31,21 @@
/*****************************************************************************/
-NM_GOBJECT_PROPERTIES_DEFINE(NMLldpListener, PROP_NEIGHBORS, );
-
-typedef struct {
+struct _NMLldpListener {
sd_lldp * lldp_handle;
GHashTable *lldp_neighbors;
GVariant * variant;
+ NMLldpListenerNotify notify_callback;
+ gpointer notify_user_data;
+
/* the timestamp in nsec until which we delay updates. */
gint64 ratelimit_next_nsec;
guint ratelimit_id;
int ifindex;
-} NMLldpListenerPrivate;
-
-struct _NMLldpListener {
- GObject parent;
- NMLldpListenerPrivate _priv;
-};
-
-struct _NMLldpListenerClass {
- GObjectClass parent;
};
-G_DEFINE_TYPE(NMLldpListener, nm_lldp_listener, G_TYPE_OBJECT)
-
-#define NM_LLDP_LISTENER_GET_PRIVATE(self) \
- _NM_GET_PRIVATE(self, NMLldpListener, NM_IS_LLDP_LISTENER)
-
/*****************************************************************************/
typedef struct {
@@ -74,27 +61,28 @@ typedef struct {
#define _NMLOG_PREFIX_NAME "lldp"
#define _NMLOG_DOMAIN LOGD_DEVICE
-#define _NMLOG(level, ...) \
- G_STMT_START \
- { \
- const NMLogLevel _level = (level); \
- \
- if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \
- char _sbuf[64]; \
- int _ifindex = (self) ? NM_LLDP_LISTENER_GET_PRIVATE(self)->ifindex : 0; \
- \
- _nm_log(_level, \
- _NMLOG_DOMAIN, \
- 0, \
- _ifindex > 0 ? nm_platform_link_get_name(NM_PLATFORM_GET, _ifindex) : NULL, \
- NULL, \
- "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- _NMLOG_PREFIX_NAME, \
- ((_ifindex > 0) ? nm_sprintf_buf(_sbuf, "[%p,%d]", (self), _ifindex) \
- : ((self) ? nm_sprintf_buf(_sbuf, "[%p]", (self)) : "")) \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } \
+#define _NMLOG(level, ...) \
+ G_STMT_START \
+ { \
+ const NMLogLevel _level = (level); \
+ \
+ if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \
+ char _sbuf[100]; \
+ \
+ _nm_log(_level, \
+ _NMLOG_DOMAIN, \
+ 0, \
+ (self) ? nm_platform_link_get_name(NM_PLATFORM_GET, (self)->ifindex) : NULL, \
+ NULL, \
+ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ _NMLOG_PREFIX_NAME, \
+ ((self) ? nm_sprintf_buf(_sbuf, \
+ "[" NM_HASH_OBFUSCATE_PTR_FMT ",%d]", \
+ NM_HASH_OBFUSCATE_PTR(self), \
+ (self)->ifindex) \
+ : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+ } \
+ } \
G_STMT_END
#define LOG_NEIGH_FMT "CHASSIS=%u/%s PORT=%u/%s"
@@ -812,80 +800,71 @@ nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len)
/*****************************************************************************/
static void
-data_changed_notify(NMLldpListener *self, NMLldpListenerPrivate *priv)
+data_changed_notify(NMLldpListener *self)
{
- nm_clear_g_variant(&priv->variant);
- _notify(self, PROP_NEIGHBORS);
+ nm_clear_g_variant(&self->variant);
+
+ self->notify_callback(self, self->notify_user_data);
}
static gboolean
data_changed_timeout(gpointer user_data)
{
- NMLldpListener * self = user_data;
- NMLldpListenerPrivate *priv;
+ NMLldpListener *self = user_data;
- g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), G_SOURCE_REMOVE);
-
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
-
- priv->ratelimit_id = 0;
- priv->ratelimit_next_nsec = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NSEC;
- data_changed_notify(self, priv);
+ self->ratelimit_id = 0;
+ self->ratelimit_next_nsec = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NSEC;
+ data_changed_notify(self);
return G_SOURCE_REMOVE;
}
static void
data_changed_schedule(NMLldpListener *self)
{
- NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
- gint64 now_nsec;
+ gint64 now_nsec;
- if (priv->ratelimit_id != 0)
+ if (self->ratelimit_id != 0)
return;
now_nsec = nm_utils_get_monotonic_timestamp_nsec();
- if (now_nsec < priv->ratelimit_next_nsec) {
- priv->ratelimit_id =
+ if (now_nsec < self->ratelimit_next_nsec) {
+ self->ratelimit_id =
g_timeout_add_full(G_PRIORITY_LOW,
- NM_UTILS_NSEC_TO_MSEC_CEIL(priv->ratelimit_next_nsec - now_nsec),
+ NM_UTILS_NSEC_TO_MSEC_CEIL(self->ratelimit_next_nsec - now_nsec),
data_changed_timeout,
self,
NULL);
return;
}
- priv->ratelimit_id = g_idle_add_full(G_PRIORITY_LOW, data_changed_timeout, self, NULL);
+ self->ratelimit_id = g_idle_add_full(G_PRIORITY_LOW, data_changed_timeout, self, NULL);
}
static void
process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean remove)
{
- NMLldpListenerPrivate * priv;
nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL;
LldpNeighbor * neigh_old;
- g_return_if_fail(NM_IS_LLDP_LISTENER(self));
-
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
+ nm_assert(self);
+ nm_assert(self->lldp_handle);
+ nm_assert(self->lldp_neighbors);
- g_return_if_fail(priv->lldp_handle);
g_return_if_fail(neighbor_sd);
- nm_assert(priv->lldp_neighbors);
-
neigh = lldp_neighbor_new(neighbor_sd);
if (!neigh) {
_LOGT("process: failed to parse neighbor");
return;
}
- neigh_old = g_hash_table_lookup(priv->lldp_neighbors, neigh);
+ neigh_old = g_hash_table_lookup(self->lldp_neighbors, neigh);
if (remove) {
if (neigh_old) {
_LOGT("process: %s neigh: " LOG_NEIGH_FMT, "remove", LOG_NEIGH_ARG(neigh));
- g_hash_table_remove(priv->lldp_neighbors, neigh_old);
+ g_hash_table_remove(self->lldp_neighbors, neigh_old);
goto handle_changed;
}
return;
@@ -896,7 +875,7 @@ process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gbool
_LOGD("process: %s neigh: " LOG_NEIGH_FMT, neigh_old ? "update" : "new", LOG_NEIGH_ARG(neigh));
- g_hash_table_add(priv->lldp_neighbors, g_steal_pointer(&neigh));
+ g_hash_table_add(self->lldp_neighbors, g_steal_pointer(&neigh));
handle_changed:
data_changed_schedule(self);
@@ -911,25 +890,57 @@ lldp_event_handler(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, vo
!NM_IN_SET(event, SD_LLDP_EVENT_ADDED, SD_LLDP_EVENT_UPDATED, SD_LLDP_EVENT_REFRESHED));
}
-gboolean
-nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error)
+/*****************************************************************************/
+
+int
+nm_lldp_listener_get_ifindex(NMLldpListener *self)
{
- NMLldpListenerPrivate *priv;
- int ret;
+ g_return_val_if_fail(self, 0);
- g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE);
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(!error || !*error, FALSE);
+ return self->ifindex;
+}
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
+/*****************************************************************************/
- if (priv->lldp_handle) {
- g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "already running");
- return FALSE;
+GVariant *
+nm_lldp_listener_get_neighbors(NMLldpListener *self)
+{
+ g_return_val_if_fail(self, FALSE);
+
+ if (G_UNLIKELY(!self->variant)) {
+ gs_free LldpNeighbor **neighbors = NULL;
+ GVariantBuilder array_builder;
+ guint i, n;
+
+ g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}"));
+ neighbors = (LldpNeighbor **)
+ nm_utils_hash_keys_to_array(self->lldp_neighbors, lldp_neighbor_id_cmp_p, NULL, &n);
+ for (i = 0; i < n; i++)
+ g_variant_builder_add_value(&array_builder, lldp_neighbor_to_variant(neighbors[i]));
+ self->variant = g_variant_ref_sink(g_variant_builder_end(&array_builder));
}
- ret = sd_lldp_new(&priv->lldp_handle);
- if (ret < 0) {
+ return self->variant;
+}
+
+/*****************************************************************************/
+
+NMLldpListener *
+nm_lldp_listener_new(int ifindex,
+ NMLldpListenerNotify notify_callback,
+ gpointer notify_user_data,
+ GError ** error)
+{
+ NMLldpListener *self = NULL;
+ sd_lldp * lldp_handle;
+ int r;
+
+ g_return_val_if_fail(ifindex > 0, FALSE);
+ g_return_val_if_fail(!error || !*error, FALSE);
+ g_return_val_if_fail(notify_callback, FALSE);
+
+ r = sd_lldp_new(&lldp_handle);
+ if (r < 0) {
g_set_error_literal(error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_FAILED,
@@ -937,189 +948,77 @@ nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error)
return FALSE;
}
- ret = sd_lldp_set_ifindex(priv->lldp_handle, ifindex);
- if (ret < 0) {
+ r = sd_lldp_set_ifindex(lldp_handle, ifindex);
+ if (r < 0) {
g_set_error_literal(error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_FAILED,
"failed setting ifindex");
- goto err;
+ goto fail_handle;
}
- ret = sd_lldp_set_callback(priv->lldp_handle, lldp_event_handler, self);
- if (ret < 0) {
- g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed");
- goto err;
- }
+ r = sd_lldp_set_neighbors_max(lldp_handle, MAX_NEIGHBORS);
+ nm_assert(r == 0);
- ret = sd_lldp_set_neighbors_max(priv->lldp_handle, MAX_NEIGHBORS);
- nm_assert(ret == 0);
+ self = g_slice_new(NMLldpListener);
+ *self = (NMLldpListener){
+ .ifindex = ifindex,
+ .notify_callback = notify_callback,
+ .notify_user_data = notify_user_data,
+ };
- priv->ifindex = ifindex;
+ r = sd_lldp_set_callback(lldp_handle, lldp_event_handler, self);
+ if (r < 0) {
+ g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed");
+ goto fail_handle;
+ }
- ret = sd_lldp_attach_event(priv->lldp_handle, NULL, 0);
- if (ret < 0) {
+ r = sd_lldp_attach_event(lldp_handle, NULL, 0);
+ if (r < 0) {
g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "attach event failed");
- goto err_free;
+ goto fail_attached;
}
- ret = sd_lldp_start(priv->lldp_handle);
- if (ret < 0) {
+ r = sd_lldp_start(lldp_handle);
+ if (r < 0) {
g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "start failed");
- goto err;
+ goto fail_attached;
}
- priv->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash,
+ self->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash,
lldp_neighbor_id_equal,
(GDestroyNotify) lldp_neighbor_free,
NULL);
-
- _LOGD("start");
-
- return TRUE;
-
-err:
- sd_lldp_detach_event(priv->lldp_handle);
-err_free:
- sd_lldp_unref(priv->lldp_handle);
- priv->lldp_handle = NULL;
- priv->ifindex = 0;
- return FALSE;
+ self->lldp_handle = lldp_handle;
+
+ _LOGD("start lldp listener");
+ return self;
+
+fail_attached:
+ sd_lldp_detach_event(lldp_handle);
+fail_handle:
+ if (self)
+ nm_g_slice_free(self);
+ sd_lldp_unref(lldp_handle);
+ return NULL;
}
void
-nm_lldp_listener_stop(NMLldpListener *self)
-{
- NMLldpListenerPrivate *priv;
- guint size;
- gboolean changed = FALSE;
-
- g_return_if_fail(NM_IS_LLDP_LISTENER(self));
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
-
- if (priv->lldp_handle) {
- _LOGD("stop");
- sd_lldp_stop(priv->lldp_handle);
- sd_lldp_detach_event(priv->lldp_handle);
- sd_lldp_unref(priv->lldp_handle);
- priv->lldp_handle = NULL;
-
- size = g_hash_table_size(priv->lldp_neighbors);
- g_hash_table_remove_all(priv->lldp_neighbors);
- nm_clear_pointer(&priv->lldp_neighbors, g_hash_table_unref);
- if (size > 0 || priv->ratelimit_id != 0)
- changed = TRUE;
- }
-
- nm_clear_g_source(&priv->ratelimit_id);
- priv->ratelimit_next_nsec = 0;
- priv->ifindex = 0;
-
- if (changed)
- data_changed_notify(self, priv);
-}
-
-gboolean
-nm_lldp_listener_is_running(NMLldpListener *self)
-{
- NMLldpListenerPrivate *priv;
-
- g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE);
-
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
- return !!priv->lldp_handle;
-}
-
-GVariant *
-nm_lldp_listener_get_neighbors(NMLldpListener *self)
-{
- NMLldpListenerPrivate *priv;
-
- g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE);
-
- priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
-
- if (G_UNLIKELY(!priv->variant)) {
- gs_free LldpNeighbor **neighbors = NULL;
- GVariantBuilder array_builder;
- guint i, n;
-
- g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}"));
- neighbors = (LldpNeighbor **)
- nm_utils_hash_keys_to_array(priv->lldp_neighbors, lldp_neighbor_id_cmp_p, NULL, &n);
- for (i = 0; i < n; i++)
- g_variant_builder_add_value(&array_builder, lldp_neighbor_to_variant(neighbors[i]));
- priv->variant = g_variant_ref_sink(g_variant_builder_end(&array_builder));
- }
- return priv->variant;
-}
-
-static void
-get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+nm_lldp_listener_destroy(NMLldpListener *self)
{
- NMLldpListener *self = NM_LLDP_LISTENER(object);
+ g_return_if_fail(self);
- switch (prop_id) {
- case PROP_NEIGHBORS:
- g_value_set_variant(value, nm_lldp_listener_get_neighbors(self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
+ sd_lldp_stop(self->lldp_handle);
+ sd_lldp_detach_event(self->lldp_handle);
+ sd_lldp_unref(self->lldp_handle);
-static void
-nm_lldp_listener_init(NMLldpListener *self)
-{
- _LOGT("lldp listener created");
-}
+ nm_clear_g_source(&self->ratelimit_id);
-NMLldpListener *
-nm_lldp_listener_new(void)
-{
- return g_object_new(NM_TYPE_LLDP_LISTENER, NULL);
-}
+ g_hash_table_destroy(self->lldp_neighbors);
-static void
-dispose(GObject *object)
-{
- nm_lldp_listener_stop(NM_LLDP_LISTENER(object));
-
- G_OBJECT_CLASS(nm_lldp_listener_parent_class)->dispose(object);
-}
-
-static void
-finalize(GObject *object)
-{
- NMLldpListener * self = NM_LLDP_LISTENER(object);
- NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE(self);
-
- nm_lldp_listener_stop(self);
-
- nm_clear_g_variant(&priv->variant);
+ nm_g_variant_unref(self->variant);
_LOGT("lldp listener destroyed");
- G_OBJECT_CLASS(nm_lldp_listener_parent_class)->finalize(object);
-}
-
-static void
-nm_lldp_listener_class_init(NMLldpListenerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- object_class->dispose = dispose;
- object_class->finalize = finalize;
- object_class->get_property = get_property;
-
- obj_properties[PROP_NEIGHBORS] =
- g_param_spec_variant(NM_LLDP_LISTENER_NEIGHBORS,
- "",
- "",
- G_VARIANT_TYPE("aa{sv}"),
- NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+ nm_g_slice_free(self);
}
diff --git a/src/core/devices/nm-lldp-listener.h b/src/core/devices/nm-lldp-listener.h
index 9d3e243685..762eb3d21a 100644
--- a/src/core/devices/nm-lldp-listener.h
+++ b/src/core/devices/nm-lldp-listener.h
@@ -6,28 +6,21 @@
#ifndef __NM_LLDP_LISTENER__
#define __NM_LLDP_LISTENER__
-#define NM_TYPE_LLDP_LISTENER (nm_lldp_listener_get_type())
-#define NM_LLDP_LISTENER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LLDP_LISTENER, NMLldpListener))
-#define NM_LLDP_LISTENER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass))
-#define NM_IS_LLDP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_LLDP_LISTENER))
-#define NM_IS_LLDP_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_LLDP_LISTENER))
-#define NM_LLDP_LISTENER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass))
-
-#define NM_LLDP_LISTENER_NEIGHBORS "neighbors"
-
-typedef struct _NMLldpListenerClass NMLldpListenerClass;
-
-GType nm_lldp_listener_get_type(void);
-NMLldpListener *nm_lldp_listener_new(void);
-gboolean nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error);
-void nm_lldp_listener_stop(NMLldpListener *self);
-gboolean nm_lldp_listener_is_running(NMLldpListener *self);
+/*****************************************************************************/
+typedef void (*NMLldpListenerNotify)(NMLldpListener *self, gpointer user_data);
+
+NMLldpListener *nm_lldp_listener_new(int ifindex,
+ NMLldpListenerNotify notify_callback,
+ gpointer notify_user_data,
+ GError ** error);
+void nm_lldp_listener_destroy(NMLldpListener *self);
+
+int nm_lldp_listener_get_ifindex(NMLldpListener *self);
GVariant *nm_lldp_listener_get_neighbors(NMLldpListener *self);
+/*****************************************************************************/
+
GVariant *nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len);
#endif /* __NM_LLDP_LISTENER__ */
diff --git a/src/core/devices/tests/test-lldp.c b/src/core/devices/tests/test-lldp.c
index ef0b154903..fd0deae4d0 100644
--- a/src/core/devices/tests/test-lldp.c
+++ b/src/core/devices/tests/test-lldp.c
@@ -83,6 +83,7 @@ typedef struct {
const uint8_t *frame;
const char * as_variant;
} TestRecvFrame;
+
#define TEST_RECV_FRAME_DEFINE(name, _as_variant, ...) \
static const guint8 _##name##_v[] = {__VA_ARGS__}; \
static const TestRecvFrame name = { \
@@ -92,11 +93,17 @@ typedef struct {
}
typedef struct {
+ int num_called;
+ GMainLoop *loop_to_quit;
+} TestRecvCallbackInfo;
+
+typedef struct {
guint expected_num_called;
gsize frames_len;
const TestRecvFrame *frames[10];
- void (*check)(GMainLoop *loop, NMLldpListener *listener);
+ void (*check)(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info);
} TestRecvData;
+
#define TEST_RECV_DATA_DEFINE(name, _expected_num_called, _check, ...) \
static const TestRecvData name = { \
.expected_num_called = _expected_num_called, \
@@ -213,7 +220,7 @@ _test_recv_data0_check_do(GMainLoop *loop, NMLldpListener *listener, const TestR
}
static void
-_test_recv_data0_check(GMainLoop *loop, NMLldpListener *listener)
+_test_recv_data0_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info)
{
_test_recv_data0_check_do(loop, listener, &_test_recv_data0_frame0);
}
@@ -528,7 +535,7 @@ TEST_RECV_FRAME_DEFINE(
);
static void
-_test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener)
+_test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info)
{
GVariant * neighbors, *attr, *child;
gs_unref_variant GVariant *neighbor = NULL;
@@ -756,21 +763,17 @@ TEST_RECV_FRAME_DEFINE(
);
static void
-_test_recv_data2_ttl1_check(GMainLoop *loop, NMLldpListener *listener)
+_test_recv_data2_ttl1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info)
{
- gulong notify_id;
GVariant *neighbors;
_test_recv_data0_check_do(loop, listener, &_test_recv_data2_frame0_ttl1);
/* wait for signal. */
- notify_id = g_signal_connect(listener,
- "notify::" NM_LLDP_LISTENER_NEIGHBORS,
- nmtst_main_loop_quit_on_notify,
- loop);
+ info->loop_to_quit = loop;
if (!nmtst_main_loop_run(loop, 5000))
g_assert_not_reached();
- nm_clear_g_signal_handler(listener, &notify_id);
+ info->loop_to_quit = NULL;
neighbors = nm_lldp_listener_get_neighbors(listener);
nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}"));
@@ -852,46 +855,37 @@ again:
memcpy(fixture->mac, link->l_address.data, ETH_ALEN);
}
-typedef struct {
- int num_called;
-} TestRecvCallbackInfo;
-
static void
-lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data)
+lldp_neighbors_changed(NMLldpListener *lldp_listener, gpointer user_data)
{
TestRecvCallbackInfo *info = user_data;
info->num_called++;
+ if (info->loop_to_quit)
+ g_main_loop_quit(info->loop_to_quit);
}
static void
test_recv(TestRecvFixture *fixture, gconstpointer user_data)
{
- const TestRecvData *data = user_data;
- gs_unref_object NMLldpListener *listener = NULL;
- GMainLoop * loop;
- TestRecvCallbackInfo info = {};
- gsize i_frames;
- gulong notify_id;
- GError * error = NULL;
- guint sd_id;
+ const TestRecvData * data = user_data;
+ NMLldpListener * listener;
+ GMainLoop * loop;
+ TestRecvCallbackInfo info = {};
+ gsize i_frames;
+ GError * error = NULL;
+ guint sd_id;
if (fixture->ifindex == 0) {
g_test_skip("Tun device not available");
return;
}
- listener = nm_lldp_listener_new();
- g_assert(listener != NULL);
- g_assert(nm_lldp_listener_start(listener, fixture->ifindex, &error));
- g_assert_no_error(error);
+ listener = nm_lldp_listener_new(fixture->ifindex, lldp_neighbors_changed, &info, &error);
+ nmtst_assert_success(listener, error);
- notify_id = g_signal_connect(listener,
- "notify::" NM_LLDP_LISTENER_NEIGHBORS,
- (GCallback) lldp_neighbors_changed,
- &info);
- loop = g_main_loop_new(NULL, FALSE);
- sd_id = nm_sd_event_attach_default();
+ loop = g_main_loop_new(NULL, FALSE);
+ sd_id = nm_sd_event_attach_default();
for (i_frames = 0; i_frames < data->frames_len; i_frames++) {
const TestRecvFrame *f = data->frames[i_frames];
@@ -904,9 +898,9 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data)
g_assert_cmpint(info.num_called, ==, data->expected_num_called);
- nm_clear_g_signal_handler(listener, &notify_id);
+ data->check(loop, listener, &info);
- data->check(loop, listener);
+ nm_clear_pointer(&listener, nm_lldp_listener_destroy);
nm_clear_g_source(&sd_id);
nm_clear_pointer(&loop, g_main_loop_unref);