diff options
author | Thomas Haller <thaller@redhat.com> | 2016-03-17 15:14:53 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-03-17 15:14:53 +0100 |
commit | d4ca43613eeb0e20c5f9a4369150017ad206587e (patch) | |
tree | f0f667aeb7b436180912303558ef625b04d5dc21 | |
parent | 2778d257cce43623fa69588ebca39fd96ee0bf98 (diff) | |
parent | 3363d8fd4eaea9f8cad0489e53747f0843b1f555 (diff) | |
download | NetworkManager-d4ca43613eeb0e20c5f9a4369150017ad206587e.tar.gz |
lldp: merge branch 'th/lldp-bgo763499'
https://bugzilla.gnome.org/show_bug.cgi?id=763499
-rw-r--r-- | shared/nm-macros-internal.h | 14 | ||||
-rw-r--r-- | src/devices/nm-lldp-listener.c | 918 | ||||
-rw-r--r-- | src/devices/tests/test-lldp.c | 2 | ||||
-rw-r--r-- | src/nm-core-utils.h | 3 | ||||
-rw-r--r-- | src/nm-logging.c | 3 | ||||
-rw-r--r-- | src/nm-logging.h | 1 | ||||
-rw-r--r-- | src/systemd/nm-sd-adapt.h | 2 | ||||
-rw-r--r-- | src/systemd/src/libsystemd-network/sd-lldp.c | 17 |
8 files changed, 550 insertions, 410 deletions
diff --git a/shared/nm-macros-internal.h b/shared/nm-macros-internal.h index 1f638bab18..e87539218d 100644 --- a/shared/nm-macros-internal.h +++ b/shared/nm-macros-internal.h @@ -287,8 +287,10 @@ _NM_IN_STRSET_streq (const char *x, const char *s) #if NM_MORE_ASSERTS #define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END +#define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END #else #define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END +#define nm_assert_not_reached() G_STMT_START { ; } G_STMT_END #endif /*****************************************************************************/ @@ -313,6 +315,18 @@ _notify (obj_type *obj, _PropertyEnums prop) \ /*****************************************************************************/ +#define nm_unauto(pp) \ + ({ \ + G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer)); \ + gpointer *_pp = (gpointer *) (pp); \ + gpointer _p = *_pp; \ + \ + *_pp = NULL; \ + _p; \ + }) + +/*****************************************************************************/ + static inline gpointer nm_g_object_ref (gpointer obj) { diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index fe53a179c2..e678dc678d 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -34,28 +34,57 @@ #include "lldp.h" #define MAX_NEIGHBORS 4096 -#define MIN_UPDATE_INTERVAL 2 +#define MIN_UPDATE_INTERVAL_NS (2 * NM_UTILS_NS_PER_SECOND) #define LLDP_MAC_NEAREST_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e })) #define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 })) #define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 })) +typedef enum { + LLDP_ATTR_TYPE_NONE, + LLDP_ATTR_TYPE_UINT32, + LLDP_ATTR_TYPE_STRING, +} LldpAttrType; + +typedef enum { + /* the order of the enum values determines the order of the fields in + * the variant. */ + LLDP_ATTR_ID_PORT_DESCRIPTION, + LLDP_ATTR_ID_SYSTEM_NAME, + LLDP_ATTR_ID_SYSTEM_DESCRIPTION, + LLDP_ATTR_ID_SYSTEM_CAPABILITIES, + LLDP_ATTR_ID_IEEE_802_1_PVID, + LLDP_ATTR_ID_IEEE_802_1_PPVID, + LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, + LLDP_ATTR_ID_IEEE_802_1_VID, + LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, + _LLDP_PROP_ID_COUNT, +} LldpAttrId; + +typedef struct { + LldpAttrType attr_type; + union { + guint32 v_uint32; + char *v_string; + }; +} LldpAttrData; + typedef struct { char *iface; int ifindex; sd_lldp *lldp_handle; GHashTable *lldp_neighbors; - guint timer; - guint num_pending_events; + + /* the timestamp in nsec until which we delay updates. */ + gint64 ratelimit_next; + guint ratelimit_id; + GVariant *variant; } NMLldpListenerPrivate; -enum { - PROP_0, +NM_GOBJECT_PROPERTIES_DEFINE (NMLldpListener, PROP_NEIGHBORS, - - LAST_PROP -}; +); G_DEFINE_TYPE (NMLldpListener, nm_lldp_listener, G_TYPE_OBJECT) @@ -69,10 +98,12 @@ typedef struct { struct ether_addr destination_address; - GHashTable *tlvs; -} LLDPNeighbor; + bool valid:1; + + LldpAttrData attrs[_LLDP_PROP_ID_COUNT]; -static void process_lldp_neighbors (NMLldpListener *self); + GVariant *variant; +} LldpNeighbor; /*****************************************************************************/ @@ -98,6 +129,9 @@ static void process_lldp_neighbors (NMLldpListener *self); } \ } G_STMT_END \ +#define LOG_NEIGH_FMT "CHASSIS=%s%s%s PORT=%s%s%s" +#define LOG_NEIGH_ARG(neigh) NM_PRINT_FMT_QUOTE_STRING ((neigh)->chassis_id), NM_PRINT_FMT_QUOTE_STRING ((neigh)->port_id) + /*****************************************************************************/ static gboolean @@ -110,82 +144,124 @@ ether_addr_equal (const struct ether_addr *a1, const struct ether_addr *a2) return memcmp (a1, a2, ETH_ALEN) == 0; } -static void -gvalue_destroy (gpointer data) +static guint32 +_access_uint8 (const void *data) +{ + return *((const guint8 *) data); +} + +static guint32 +_access_uint16 (const void *data) { - GValue *value = (GValue *) data; + guint16 v; - g_value_unset (value); - g_slice_free (GValue, value); + memcpy (&v, data, sizeof (v)); + return ntohs (v); } -static GValue * -gvalue_new_str (const char *str) +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, + NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_PORT_DESCRIPTION, NM_LLDP_ATTR_PORT_DESCRIPTION), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_SYSTEM_NAME, NM_LLDP_ATTR_SYSTEM_NAME), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_SYSTEM_DESCRIPTION, NM_LLDP_ATTR_SYSTEM_DESCRIPTION), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_SYSTEM_CAPABILITIES, NM_LLDP_ATTR_SYSTEM_CAPABILITIES), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_PVID, NM_LLDP_ATTR_IEEE_802_1_PVID), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID, NM_LLDP_ATTR_IEEE_802_1_PPVID), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VID, NM_LLDP_ATTR_IEEE_802_1_VID), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME), + NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_PROP_ID_COUNT), +); + +_NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType, + NM_UTILS_LOOKUP_DEFAULT_WARN (LLDP_ATTR_TYPE_NONE), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_PORT_DESCRIPTION, LLDP_ATTR_TYPE_STRING), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_SYSTEM_NAME, LLDP_ATTR_TYPE_STRING), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_SYSTEM_DESCRIPTION, LLDP_ATTR_TYPE_STRING), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_SYSTEM_CAPABILITIES, LLDP_ATTR_TYPE_UINT32), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_PVID, LLDP_ATTR_TYPE_UINT32), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID, LLDP_ATTR_TYPE_UINT32), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, LLDP_ATTR_TYPE_UINT32), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_VID, LLDP_ATTR_TYPE_UINT32), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, LLDP_ATTR_TYPE_STRING), + NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_PROP_ID_COUNT), +); + +static void +_lldp_attr_set_str (LldpAttrData *pdata, LldpAttrId attr_id, const char *v_string) { - GValue *value; + nm_assert (pdata); + nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_STRING); + + pdata = &pdata[attr_id]; - value = g_slice_new0 (GValue); - g_value_init (value, G_TYPE_STRING); - g_value_set_string (value, str ?: ""); - return value; + /* we ignore duplicate fields silently. */ + if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) + return; + pdata->attr_type = LLDP_ATTR_TYPE_STRING; + pdata->v_string = g_strdup (v_string ?: ""); } -static GValue * -gvalue_new_str_ptr (const void *str, gsize len) +static void +_lldp_attr_set_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, const void *str, gsize len) { const char *s = str; const char *tmp; gsize len0 = len; gs_free char *str_free = NULL; - gs_free char *str_escaped = NULL; + + nm_assert (pdata); + nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_STRING); + + pdata = &pdata[attr_id]; + + /* we ignore duplicate fields silently. */ + if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) + return; + + pdata->attr_type = LLDP_ATTR_TYPE_STRING; /* truncate at first NUL, including removing trailing NULs*/ tmp = memchr (s, '\0', len); if (tmp) len = tmp - s; - if (!len) - return gvalue_new_str (""); + if (!len) { + pdata->v_string = g_strdup (""); + return; + } if (len0 <= len || s[len] != '\0') { /* hmpf, g_strescape needs a trailing NUL. Need to clone */ s = str_free = g_strndup (s, len); } - str_escaped = g_strescape (s, NULL); - return gvalue_new_str (str_escaped); + pdata->v_string = g_strescape (s, NULL); } -static GValue * -gvalue_new_uint (guint val) +static void +_lldp_attr_set_uint32 (LldpAttrData *pdata, LldpAttrId attr_id, guint32 v_uint32) { - GValue *value; + nm_assert (pdata); + nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_UINT32); - value = g_slice_new0 (GValue); - g_value_init (value, G_TYPE_UINT); - g_value_set_uint (value, val); - return value; -} + pdata = &pdata[attr_id]; -static GValue * -gvalue_new_uint_u8 (const void *data) -{ - return gvalue_new_uint (*((const guint8 *) data)); + /* we ignore duplicate fields silently. */ + if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) + return; + pdata->attr_type = LLDP_ATTR_TYPE_UINT32; + pdata->v_uint32 = v_uint32; } -static GValue * -gvalue_new_uint_u16 (const void *data) -{ - guint16 v; - - memcpy (&v, data, sizeof (v)); - return gvalue_new_uint (ntohs (v)); -} +/*****************************************************************************/ static guint lldp_neighbor_id_hash (gconstpointer ptr) { - const LLDPNeighbor *neigh = ptr; + const LldpNeighbor *neigh = ptr; guint hash; hash = 23423423u + ((guint) (neigh->chassis_id ? g_str_hash (neigh->chassis_id) : 12321u)); @@ -195,355 +271,443 @@ lldp_neighbor_id_hash (gconstpointer ptr) return hash; } +static int +lldp_neighbor_id_cmp (gconstpointer a, gconstpointer b) +{ + const LldpNeighbor *x = a, *y = b; + int c; + + if (x->chassis_id_type != y->chassis_id_type) + return x->chassis_id_type < y->chassis_id_type ? -1 : 1; + if (x->port_id_type != y->port_id_type) + return x->port_id_type < y->port_id_type ? -1 : 1; + c = g_strcmp0 (x->chassis_id, y->chassis_id); + if (c == 0) + c = g_strcmp0 (x->port_id, y->port_id); + return c < 0 ? -1 : (c > 0 ? 1 : 0); +} + static gboolean lldp_neighbor_id_equal (gconstpointer a, gconstpointer b) { - const LLDPNeighbor *x = a, *y = b; - - return x->chassis_id_type == y->chassis_id_type && - x->port_id_type == y->port_id_type && - !g_strcmp0 (x->chassis_id, y->chassis_id) && - !g_strcmp0 (x->port_id, y->port_id); + return lldp_neighbor_id_cmp (a, b) == 0; } static void -lldp_neighbor_free (LLDPNeighbor *neighbor) +lldp_neighbor_free (LldpNeighbor *neighbor) { + LldpAttrId attr_id; + if (neighbor) { g_free (neighbor->chassis_id); g_free (neighbor->port_id); - g_hash_table_unref (neighbor->tlvs); - g_slice_free (LLDPNeighbor, neighbor); + for (attr_id = 0; attr_id < _LLDP_PROP_ID_COUNT; attr_id++) { + if (neighbor->attrs[attr_id].attr_type == LLDP_ATTR_TYPE_STRING) + g_free (neighbor->attrs[attr_id].v_string); + } + g_clear_pointer (&neighbor->variant, g_variant_unref); + g_slice_free (LldpNeighbor, neighbor); } } static void -lldp_neighbor_freep (LLDPNeighbor **ptr) +lldp_neighbor_freep (LldpNeighbor **ptr) { lldp_neighbor_free (*ptr); } static gboolean -lldp_neighbor_equal (LLDPNeighbor *a, LLDPNeighbor *b) +lldp_neighbor_equal (LldpNeighbor *a, LldpNeighbor *b) { - GHashTableIter iter; - gpointer k, v; + LldpAttrId attr_id; - g_return_val_if_fail (a && a->tlvs, FALSE); - g_return_val_if_fail (b && b->tlvs, FALSE); + nm_assert (a); + nm_assert (b); if ( a->chassis_id_type != b->chassis_id_type || a->port_id_type != b->port_id_type || ether_addr_equal (&a->destination_address, &b->destination_address) - || g_strcmp0 (a->chassis_id, b->chassis_id) - || g_strcmp0 (a->port_id, b->port_id)) - return FALSE; - - if (g_hash_table_size (a->tlvs) != g_hash_table_size (b->tlvs)) + || !nm_streq0 (a->chassis_id, b->chassis_id) + || !nm_streq0 (a->port_id, b->port_id)) return FALSE; - g_hash_table_iter_init (&iter, a->tlvs); - while (g_hash_table_iter_next (&iter, &k, &v)) { - GValue *value_a, *value_b; - - value_a = v; - value_b = g_hash_table_lookup (b->tlvs, k); - - if (!value_b) + for (attr_id = 0; attr_id < _LLDP_PROP_ID_COUNT; attr_id++) { + if (a->attrs[attr_id].attr_type != b->attrs[attr_id].attr_type) return FALSE; - - g_return_val_if_fail (G_VALUE_TYPE (value_a) == G_VALUE_TYPE (value_b), FALSE); - - if (G_VALUE_HOLDS_STRING (value_a)) { - if (g_strcmp0 (g_value_get_string (value_a), g_value_get_string (value_b))) + switch (a->attrs[attr_id].attr_type) { + case LLDP_ATTR_TYPE_UINT32: + if (a->attrs[attr_id].v_uint32 != b->attrs[attr_id].v_uint32) return FALSE; - } else if (G_VALUE_HOLDS_UINT (value_a)) { - if (g_value_get_uint (value_a) != g_value_get_uint (value_b)) + break; + case LLDP_ATTR_TYPE_STRING: + if (!nm_streq (a->attrs[attr_id].v_string, b->attrs[attr_id].v_string)) return FALSE; - } else - g_return_val_if_reached (FALSE); + break; + default: + nm_assert (a->attrs[attr_id].attr_type == LLDP_ATTR_TYPE_NONE); + break; + } } return TRUE; } -static gboolean -lldp_hash_table_equal (GHashTable *a, GHashTable *b) +static LldpNeighbor * +lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) { - GHashTableIter iter; - gpointer val; - - g_return_val_if_fail (a, FALSE); - g_return_val_if_fail (b, FALSE); - - if (g_hash_table_size (a) != g_hash_table_size (b)) - return FALSE; - - g_hash_table_iter_init (&iter, a); - while (g_hash_table_iter_next (&iter, NULL, &val)) { - LLDPNeighbor *neigh_a, *neigh_b; - - neigh_a = val; - neigh_b = g_hash_table_lookup (b, val); - - if (!neigh_b) - return FALSE; - - if (!lldp_neighbor_equal (neigh_a, neigh_b)) - return FALSE; + nm_auto (lldp_neighbor_freep) LldpNeighbor *neigh = NULL; + uint8_t chassis_id_type, port_id_type; + uint16_t data16; + uint8_t *data8; + const void *chassis_id, *port_id; + gsize chassis_id_len, port_id_len, len; + const char *str; + int r; + + r = sd_lldp_neighbor_get_chassis_id (neighbor_sd, &chassis_id_type, + &chassis_id, &chassis_id_len); + if (r < 0) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failed reading chassis-id: %s", g_strerror (-r)); + return NULL; + } + if (chassis_id_len < 1) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "empty chassis-id"); + return NULL; } - return TRUE; -} + r = sd_lldp_neighbor_get_port_id (neighbor_sd, &port_id_type, + &port_id, &port_id_len); + if (r < 0) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failed reading port-id: %s", g_strerror (-r)); + return NULL; + } + if (port_id_len < 1) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "empty port-id"); + return NULL; + } -static gboolean -lldp_timeout (gpointer user_data) -{ - NMLldpListener *self = user_data; - NMLldpListenerPrivate *priv; + neigh = g_slice_new0 (LldpNeighbor); + neigh->chassis_id_type = chassis_id_type; + neigh->port_id_type = port_id_type; - g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), G_SOURCE_REMOVE); + r = sd_lldp_neighbor_get_destination_address (neighbor_sd, &neigh->destination_address); + if (r < 0) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failed getting destination address: %s", g_strerror (-r)); + goto out; + } - priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + switch (chassis_id_type) { + case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + neigh->chassis_id = g_strndup ((const char *) chassis_id, chassis_id_len); + break; + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + neigh->chassis_id = nm_utils_hwaddr_ntoa (chassis_id, chassis_id_len); + break; + default: + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "unsupported chassis-id type %d", chassis_id_type); + goto out; + } - priv->timer = 0; + switch (port_id_type) { + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + neigh->port_id = strndup ((char *) port_id, port_id_len); + break; + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + neigh->port_id = nm_utils_hwaddr_ntoa (port_id, port_id_len); + break; + default: + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "unsupported port-id type %d", port_id_type); + goto out; + } - if (priv->num_pending_events) - process_lldp_neighbors (self); + if (sd_lldp_neighbor_get_port_description (neighbor_sd, &str) == 0) + _lldp_attr_set_str (neigh->attrs, LLDP_ATTR_ID_PORT_DESCRIPTION, str); - return G_SOURCE_REMOVE; -} + if (sd_lldp_neighbor_get_system_name (neighbor_sd, &str) == 0) + _lldp_attr_set_str (neigh->attrs, LLDP_ATTR_ID_SYSTEM_NAME, str); -static void -process_lldp_neighbors (NMLldpListener *self) -{ - NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); - nm_auto_free sd_lldp_neighbor **neighbors = NULL; - GHashTable *hash; - int num, i, r; + if (sd_lldp_neighbor_get_system_description (neighbor_sd, &str) == 0) + _lldp_attr_set_str (neigh->attrs, LLDP_ATTR_ID_SYSTEM_DESCRIPTION, str); - g_return_if_fail (priv->lldp_handle); + if (sd_lldp_neighbor_get_system_capabilities (neighbor_sd, &data16) == 0) + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_SYSTEM_CAPABILITIES, data16); - num = sd_lldp_get_neighbors (priv->lldp_handle, &neighbors); - if (num < 0) { - _LOGD ("process: error %d retrieving neighbor packets for %s", - num, priv->iface); - return; + r = sd_lldp_neighbor_tlv_rewind (neighbor_sd); + if (r < 0) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failed reading tlv (rewind): %s", g_strerror (-r)); + goto out; } + do { + guint8 oui[3]; + guint8 subtype; - hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal, - (GDestroyNotify) lldp_neighbor_free, NULL); + r = sd_lldp_neighbor_tlv_get_oui (neighbor_sd, oui, &subtype); + if (r < 0) { + if (r == -ENXIO) + continue; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failed reading tlv: %s", g_strerror (-r)); + goto out; + } - for (i = 0; neighbors && i < num; i++) { - nm_auto (lldp_neighbor_freep) LLDPNeighbor *neigh = NULL; - uint8_t chassis_id_type, port_id_type; - uint16_t data16; - uint8_t *data8; - const void *chassis_id, *port_id; - gsize chassis_id_len, port_id_len, len; - GValue *value; - const char *str; + if (!( memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0 + && NM_IN_SET (subtype, + LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID, + LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID, + LLDP_OUI_802_1_SUBTYPE_VLAN_NAME))) + continue; - if (i >= MAX_NEIGHBORS) - break; + if (sd_lldp_neighbor_tlv_get_raw (neighbor_sd, (void *) &data8, &len) < 0) + continue; - r = sd_lldp_neighbor_get_chassis_id (neighbors[i], &chassis_id_type, - &chassis_id, &chassis_id_len); - if (r < 0) - goto next_neighbor; - if (chassis_id_len < 1) - goto next_neighbor; - - r = sd_lldp_neighbor_get_port_id (neighbors[i], &port_id_type, - &port_id, &port_id_len); - if (r < 0) - goto next_neighbor; - if (port_id_len < 1) - goto next_neighbor; - - neigh = g_slice_new0 (LLDPNeighbor); - neigh->tlvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); - neigh->chassis_id_type = chassis_id_type; - neigh->port_id_type = port_id_type; - - if (sd_lldp_neighbor_get_destination_address (neighbors[i], &neigh->destination_address) < 0) - goto next_neighbor; - - switch (chassis_id_type) { - case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: - case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - neigh->chassis_id = g_strndup ((const char *) chassis_id, chassis_id_len); - break; - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - neigh->chassis_id = nm_utils_hwaddr_ntoa (chassis_id, chassis_id_len); - break; - default: - _LOGD ("process: unsupported chassis ID type %d", chassis_id_type); - goto next_neighbor; + /* skip over leading TLV, OUI and subtype */ +#ifdef WITH_MORE_ASSERTS + { + guint8 check_hdr[] = { + 0xfe | (((len - 2) >> 8) & 0x01), ((len - 2) & 0xFF), + oui[0], oui[1], oui[2], + subtype + }; + + nm_assert (len > 2 + 3 +1); + nm_assert (memcmp (data8, check_hdr, sizeof check_hdr) == 0); } +#endif + if (len <= 6) + continue; + data8 += 6; + len -= 6; + + /*if (memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0)*/ + { + switch (subtype) { + case LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: + if (len != 2) + continue; + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_PVID, + _access_uint16 (data8)); + break; + case LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: + if (len != 3) + continue; + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, + _access_uint8 (&data8[0])); + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_PPVID, + _access_uint16 (&data8[1])); + break; + case LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: { + int l; + + if (len <= 3) + continue; - switch (port_id_type) { - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - neigh->port_id = strndup ((char *) port_id, port_id_len); - break; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: - neigh->port_id = nm_utils_hwaddr_ntoa (port_id, port_id_len); - break; - default: - _LOGD ("process: unsupported port ID type %d", port_id_type); - goto next_neighbor; - } + l = data8[2]; + if (len != 3 + l) + continue; - if (sd_lldp_neighbor_get_port_description (neighbors[i], &str) == 0) { - value = gvalue_new_str (str); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_PORT_DESCRIPTION, value); + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VID, + _access_uint16 (&data8[0])); + _lldp_attr_set_str_ptr (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, + &data8[3], len); + break; + } + default: + g_assert_not_reached (); + } } + } while (sd_lldp_neighbor_tlv_next (neighbor_sd) > 0); - if (sd_lldp_neighbor_get_system_name (neighbors[i], &str) == 0) { - value = gvalue_new_str (str); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_NAME, value); - } + neigh->valid = TRUE; - if (sd_lldp_neighbor_get_system_description (neighbors[i], &str) == 0) { - value = gvalue_new_str (str); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, value); - } +out: + return nm_unauto (&neigh); +} - if (sd_lldp_neighbor_get_system_capabilities (neighbors[i], &data16) == 0) { - value = gvalue_new_uint (data16); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, value); - } +static GVariant * +lldp_neighbor_to_variant (LldpNeighbor *neigh) +{ + GVariantBuilder builder; + const char *dest_str; + LldpAttrId attr_id; + + if (neigh->variant) + return neigh->variant; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&builder, "{sv}", + NM_LLDP_ATTR_CHASSIS_ID_TYPE, + g_variant_new_uint32 (neigh->chassis_id_type)); + g_variant_builder_add (&builder, "{sv}", + NM_LLDP_ATTR_CHASSIS_ID, + g_variant_new_string (neigh->chassis_id)); + g_variant_builder_add (&builder, "{sv}", + NM_LLDP_ATTR_PORT_ID_TYPE, + g_variant_new_uint32 (neigh->port_id_type)); + g_variant_builder_add (&builder, "{sv}", + NM_LLDP_ATTR_PORT_ID, + g_variant_new_string (neigh->port_id)); + + if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_BRIDGE)) + dest_str = NM_LLDP_DEST_NEAREST_BRIDGE; + else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) + dest_str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; + else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) + dest_str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; + else + dest_str = NULL; + if (dest_str) { + g_variant_builder_add (&builder, "{sv}", + NM_LLDP_ATTR_DESTINATION, + g_variant_new_string (dest_str)); + } - if (sd_lldp_neighbor_tlv_rewind (neighbors[i]) < 0) - goto next_neighbor; - do { - guint8 oui[3]; - guint8 subtype; + for (attr_id = 0; attr_id < _LLDP_PROP_ID_COUNT; attr_id++) { + const LldpAttrData *data = &neigh->attrs[attr_id]; - r = sd_lldp_neighbor_tlv_get_oui (neighbors[i], oui, &subtype); - if (r < 0) { - if (r == -ENXIO) - continue; - goto next_neighbor; - } + nm_assert (NM_IN_SET (data->attr_type, _lldp_attr_id_to_type (attr_id), LLDP_ATTR_TYPE_NONE)); + switch (data->attr_type) { + case LLDP_ATTR_TYPE_UINT32: + g_variant_builder_add (&builder, "{sv}", + _lldp_attr_id_to_name (attr_id), + g_variant_new_uint32 (data->v_uint32)); + break; + case LLDP_ATTR_TYPE_STRING: + g_variant_builder_add (&builder, "{sv}", + _lldp_attr_id_to_name (attr_id), + g_variant_new_string (data->v_string)); + break; + default: + break; + } + } - if (!( memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0 - && NM_IN_SET (subtype, - LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID, - LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID, - LLDP_OUI_802_1_SUBTYPE_VLAN_NAME))) - continue; + return (neigh->variant = g_variant_ref_sink (g_variant_builder_end (&builder))); +} - if (sd_lldp_neighbor_tlv_get_raw (neighbors[i], (void *) &data8, &len) < 0) - continue; +/*****************************************************************************/ - /* skip over leading TLV, OUI and subtype */ -#ifdef WITH_MORE_ASSERTS - { - guint8 check_hdr[] = { - 0xfe | (((len - 2) >> 8) & 0x01), ((len - 2) & 0xFF), - oui[0], oui[1], oui[2], - subtype - }; - - nm_assert (len > 2 + 3 +1); - nm_assert (memcmp (data8, check_hdr, sizeof check_hdr) == 0); - } -#endif - if (len <= 6) - goto next_neighbor; - data8 += 6; - len -= 6; - - /*if (memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0)*/ - { - switch (subtype) { - case LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: - if (len != 2) - goto next_neighbor; - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID, - gvalue_new_uint_u16 (data8)); - break; - case LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: - if (len != 3) - goto next_neighbor; - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, - gvalue_new_uint_u8 (&data8[0])); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID, - gvalue_new_uint_u16 (&data8[1])); - break; - case LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: { - int l; - - if (len <= 3) - goto next_neighbor; - - l = data8[2]; - if (len != 3 + l) - goto next_neighbor; - - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID, - gvalue_new_uint_u16 (&data8[0])); - g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, - gvalue_new_str_ptr (&data8[3], len)); - break; - } - default: - g_assert_not_reached (); - } - } - } while (sd_lldp_neighbor_tlv_next (neighbors[i]) > 0); +static void +data_changed_notify (NMLldpListener *self, NMLldpListenerPrivate *priv) +{ + nm_clear_g_variant (&priv->variant); + _notify (self, PROP_NEIGHBORS); +} - _LOGD ("process: new neigh: CHASSIS='%s' PORT='%s'", - neigh->chassis_id, neigh->port_id); +static gboolean +data_changed_timeout (gpointer user_data) +{ + NMLldpListener *self = user_data; + NMLldpListenerPrivate *priv; - g_hash_table_add (hash, neigh); - neigh = NULL; -next_neighbor: - ; - } + g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), G_SOURCE_REMOVE); - for (i = 0; neighbors && i < num; i++) - sd_lldp_neighbor_unref (neighbors[i]); + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); - if (lldp_hash_table_equal (priv->lldp_neighbors, hash)) { - g_hash_table_destroy (hash); - } else { - g_hash_table_destroy (priv->lldp_neighbors); - priv->lldp_neighbors = hash; - nm_clear_g_variant (&priv->variant); - g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS); - } + priv->ratelimit_id = 0; + priv->ratelimit_next = nm_utils_get_monotonic_timestamp_ns() + MIN_UPDATE_INTERVAL_NS; + data_changed_notify (self, priv); + return G_SOURCE_REMOVE; +} - /* Since the processing of the neighbor list is potentially - * expensive when there are many neighbors, coalesce multiple - * events arriving in short time. - */ - priv->timer = g_timeout_add_seconds (MIN_UPDATE_INTERVAL, lldp_timeout, self); - priv->num_pending_events = 0; +static void +data_changed_schedule (NMLldpListener *self) +{ + NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + gint64 now; + + now = nm_utils_get_monotonic_timestamp_ns (); + if (now >= priv->ratelimit_next) { + nm_clear_g_source (&priv->ratelimit_id); + priv->ratelimit_next = now + MIN_UPDATE_INTERVAL_NS; + data_changed_notify (self, priv); + } else if (!priv->ratelimit_id) + priv->ratelimit_id = g_timeout_add (NM_UTILS_NS_TO_MSEC_CEIL (priv->ratelimit_next - now), data_changed_timeout, self); } static void -lldp_event_handler (sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) +process_lldp_neighbor (NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean neighbor_valid) { - NMLldpListener *self = userdata; NMLldpListenerPrivate *priv; + nm_auto (lldp_neighbor_freep) LldpNeighbor *neigh = NULL; + LldpNeighbor *neigh_old; + gs_free_error GError *parse_error = NULL; + GError **p_parse_error; + gboolean changed = FALSE; g_return_if_fail (NM_IS_LLDP_LISTENER (self)); priv = NM_LLDP_LISTENER_GET_PRIVATE (self); - if (priv->timer > 0) { - priv->num_pending_events++; + g_return_if_fail (priv->lldp_handle); + g_return_if_fail (neighbor_sd); + + p_parse_error = _LOGT_ENABLED () ? &parse_error : NULL; + + neigh = lldp_neighbor_new (neighbor_sd, p_parse_error); + if (!neigh) { + _LOGT ("process: failed to parse neighbor: %s", parse_error->message); + return; + } + + if (!neigh->valid) + neighbor_valid = FALSE; + + neigh_old = g_hash_table_lookup (priv->lldp_neighbors, neigh); + if (neigh_old) { + if (!neighbor_valid) { + _LOGT ("process: %s neigh: "LOG_NEIGH_FMT"%s%s%s", + "remove", LOG_NEIGH_ARG (neigh), + NM_PRINT_FMT_QUOTED (parse_error, " (failed to parse: ", parse_error->message, ")", "")); + + g_hash_table_remove (priv->lldp_neighbors, neigh_old); + changed = TRUE; + goto done; + } else if (lldp_neighbor_equal (neigh_old, neigh)) + return; + } else if (!neighbor_valid) { + if (parse_error) + _LOGT ("process: failed to parse neighbor: %s", parse_error->message); + return; + } + + /* ensure that we have at most MAX_NEIGHBORS entires */ + if ( !neigh_old /* only matters in the "add" case. */ + && (g_hash_table_size (priv->lldp_neighbors) + 1 > MAX_NEIGHBORS)) { + _LOGT ("process: ignore neighbor due to overall limit of %d", MAX_NEIGHBORS); return; } - process_lldp_neighbors (self); + _LOGD ("process: %s neigh: "LOG_NEIGH_FMT, + neigh_old ? "update" : "new", + LOG_NEIGH_ARG (neigh)); + + changed = TRUE; + g_hash_table_add (priv->lldp_neighbors, nm_unauto (&neigh)); + +done: + if (changed) + data_changed_schedule (self); +} + +static void +lldp_event_handler (sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) +{ + process_lldp_neighbor (userdata, n, event != SD_LLDP_EVENT_REMOVED); } gboolean @@ -571,18 +735,20 @@ nm_lldp_listener_start (NMLldpListener *self, int ifindex, GError **error) return FALSE; } - ret = sd_lldp_attach_event (priv->lldp_handle, NULL, 0); + 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, - "attach event failed"); - goto err_free; + "set callback failed"); + goto err; } - ret = sd_lldp_set_callback (priv->lldp_handle, lldp_event_handler, self); + priv->ifindex = ifindex; + + ret = sd_lldp_attach_event (priv->lldp_handle, NULL, 0); if (ret < 0) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "set callback failed"); - goto err; + "attach event failed"); + goto err_free; } ret = sd_lldp_start (priv->lldp_handle); @@ -592,8 +758,8 @@ nm_lldp_listener_start (NMLldpListener *self, int ifindex, GError **error) goto err; } - priv->ifindex = ifindex; _LOGD ("start"); + return TRUE; err: @@ -601,6 +767,7 @@ err: err_free: sd_lldp_unref (priv->lldp_handle); priv->lldp_handle = NULL; + priv->ifindex = 0; return FALSE; } @@ -609,6 +776,7 @@ 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); @@ -622,14 +790,16 @@ nm_lldp_listener_stop (NMLldpListener *self) size = g_hash_table_size (priv->lldp_neighbors); g_hash_table_remove_all (priv->lldp_neighbors); - if (size) { - nm_clear_g_variant (&priv->variant); - g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS); - } + if (size || priv->ratelimit_id) + changed = TRUE; } - nm_clear_g_source (&priv->timer); + nm_clear_g_source (&priv->ratelimit_id); + priv->ratelimit_next = 0; priv->ifindex = 0; + + if (changed) + data_changed_notify (self, priv); } gboolean @@ -646,76 +816,23 @@ nm_lldp_listener_is_running (NMLldpListener *self) GVariant * nm_lldp_listener_get_neighbors (NMLldpListener *self) { - GVariantBuilder array_builder, neigh_builder; - GHashTableIter iter; NMLldpListenerPrivate *priv; - LLDPNeighbor *neigh; + GVariantBuilder array_builder; + GList *neighbors, *iter; g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE); priv = NM_LLDP_LISTENER_GET_PRIVATE (self); - if (priv->variant) - goto out; - - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - g_hash_table_iter_init (&iter, priv->lldp_neighbors); - - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &neigh)) { - GHashTableIter val_iter; - gpointer key, val; - const char *dest_str; - - g_variant_builder_init (&neigh_builder, G_VARIANT_TYPE ("a{sv}")); - - g_variant_builder_add (&neigh_builder, "{sv}", - NM_LLDP_ATTR_CHASSIS_ID_TYPE, - g_variant_new_uint32 (neigh->chassis_id_type)); - g_variant_builder_add (&neigh_builder, "{sv}", - NM_LLDP_ATTR_CHASSIS_ID, - g_variant_new_string (neigh->chassis_id)); - g_variant_builder_add (&neigh_builder, "{sv}", - NM_LLDP_ATTR_PORT_ID_TYPE, - g_variant_new_uint32 (neigh->port_id_type)); - g_variant_builder_add (&neigh_builder, "{sv}", - NM_LLDP_ATTR_PORT_ID, - g_variant_new_string (neigh->port_id)); - - if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_BRIDGE)) - dest_str = NM_LLDP_DEST_NEAREST_BRIDGE; - else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) - dest_str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; - else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) - dest_str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; - else - dest_str = NULL; - if (dest_str) { - g_variant_builder_add (&neigh_builder, "{sv}", - NM_LLDP_ATTR_DESTINATION, - g_variant_new_string (dest_str)); - } - - g_hash_table_iter_init (&val_iter, neigh->tlvs); - while (g_hash_table_iter_next (&val_iter, &key, &val)) { - GValue *item = val; - - if (G_VALUE_HOLDS_STRING (item)) { - g_variant_builder_add (&neigh_builder, "{sv}", - key, - g_variant_new_string (g_value_get_string (item))); - } else if (G_VALUE_HOLDS_UINT (item)) { - g_variant_builder_add (&neigh_builder, "{sv}", - key, - g_variant_new_uint32 (g_value_get_uint (item))); - } - } - - g_variant_builder_add (&array_builder, "a{sv}", &neigh_builder); + if (!priv->variant) { + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + neighbors = g_hash_table_get_keys (priv->lldp_neighbors); + neighbors = g_list_sort (neighbors, lldp_neighbor_id_cmp); + for (iter = neighbors; iter; iter = iter->next) + g_variant_builder_add_value (&array_builder, lldp_neighbor_to_variant (iter->data)); + g_list_free (neighbors); + priv->variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); } - - priv->variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); - -out: return priv->variant; } @@ -788,12 +905,13 @@ nm_lldp_listener_class_init (NMLldpListenerClass *klass) object_class->finalize = finalize; object_class->get_property = get_property; - g_object_class_install_property - (object_class, PROP_NEIGHBORS, - g_param_spec_variant (NM_LLDP_LISTENER_NEIGHBORS, "", "", - G_VARIANT_TYPE ("aa{sv}"), - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + 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); } diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index e66b370690..85c3b5106a 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -335,7 +335,7 @@ _test_recv_data2_ttl1_check (GMainLoop *loop, NMLldpListener *listener) /* wait for signal. */ notify_id = g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS, nmtst_main_loop_quit_on_notify, loop); - if (!nmtst_main_loop_run (loop, 20000)) + if (!nmtst_main_loop_run (loop, 5000)) g_assert_not_reached (); nm_clear_g_signal_handler (listener, ¬ify_id); diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 8e6392349b..2fb5273d74 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -317,6 +317,9 @@ int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnect void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); #define NM_UTILS_NS_PER_SECOND ((gint64) 1000000000) +#define NM_UTILS_NS_PER_MSEC ((gint64) 1000000) +#define NM_UTILS_NS_TO_MSEC_CEIL(nsec) (((nsec) + (NM_UTILS_NS_PER_MSEC - 1)) / NM_UTILS_NS_PER_MSEC) + gint64 nm_utils_get_monotonic_timestamp_ns (void); gint64 nm_utils_get_monotonic_timestamp_us (void); gint64 nm_utils_get_monotonic_timestamp_ms (void); diff --git a/src/nm-logging.c b/src/nm-logging.c index 704c77c969..935b34a8e3 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -111,7 +111,7 @@ static struct { char *logging_domains_to_string; const LogLevelDesc level_desc[_LOGL_N]; -#define _DOMAIN_DESC_LEN 36 +#define _DOMAIN_DESC_LEN 37 /* Would be nice to use C99 flexible array member here, * but that feature doesn't seem well supported. */ const LogDesc domain_desc[_DOMAIN_DESC_LEN]; @@ -164,6 +164,7 @@ static struct { { LOGD_DCB, "DCB" }, { LOGD_DISPATCH, "DISPATCH" }, { LOGD_AUDIT, "AUDIT" }, + { LOGD_SYSTEMD, "SYSTEMD" }, { 0, NULL } /* keep _DOMAIN_DESC_LEN in sync */ }, diff --git a/src/nm-logging.h b/src/nm-logging.h index 41b5c16007..27f89f5d5b 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -64,6 +64,7 @@ typedef enum { /*< skip >*/ LOGD_DCB = (1LL << 32), /* Data Center Bridging */ LOGD_DISPATCH = (1LL << 33), LOGD_AUDIT = (1LL << 34), + LOGD_SYSTEMD = (1LL << 35), __LOGD_MAX, LOGD_ALL = ((__LOGD_MAX - 1LL) << 1) - 1LL, diff --git a/src/systemd/nm-sd-adapt.h b/src/systemd/nm-sd-adapt.h index 4fa0f5c18d..010c8a80f6 100644 --- a/src/systemd/nm-sd-adapt.h +++ b/src/systemd/nm-sd-adapt.h @@ -53,7 +53,7 @@ _slog_level_to_nm (int slevel) const int _nm_e = (error); \ const NMLogLevel _nm_l = _slog_level_to_nm ((level)); \ \ - if (nm_logging_enabled (_nm_l, LOGD_DHCP)) { \ + if (nm_logging_enabled (_nm_l, LOGD_SYSTEMD)) { \ const char *_nm_location = strrchr ((""file), '/'); \ \ _nm_log_impl (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, ("%s"format), "libsystemd: ", ## __VA_ARGS__); \ diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 8ca7f36702..71d1581212 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -114,6 +114,8 @@ static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { return true; } +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); + static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; bool keep; @@ -138,7 +140,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ - lldp_neighbor_start_ttl(old); + lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; } @@ -164,7 +166,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { n->lldp = lldp; - lldp_neighbor_start_ttl(n); + lldp_start_timer(lldp, n); lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); return 1; @@ -370,8 +372,6 @@ static int neighbor_compare_func(const void *a, const void *b) { return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); } -static int lldp_start_timer(sd_lldp *lldp); - static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { sd_lldp *lldp = userdata; int r, q; @@ -380,19 +380,22 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { if (r < 0) return log_lldp_errno(r, "Failed to make space: %m"); - q = lldp_start_timer(lldp); + q = lldp_start_timer(lldp, NULL); if (q < 0) return log_lldp_errno(q, "Failed to restart timer: %m"); return 0; } -static int lldp_start_timer(sd_lldp *lldp) { +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { sd_lldp_neighbor *n; int r; assert(lldp); + if (neighbor) + lldp_neighbor_start_ttl(neighbor); + n = prioq_peek(lldp->neighbor_by_expiry); if (!n) { @@ -442,7 +445,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { if (!l) return -ENOMEM; - r = lldp_start_timer(lldp); + r = lldp_start_timer(lldp, NULL); if (r < 0) { free(l); return r; |