diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2018-12-20 17:03:16 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2018-12-20 18:51:15 +0100 |
commit | 72dfb22cb755773a2829f0cc4ab5a2168334e824 (patch) | |
tree | 9adf5b90f9954edaea80bcc2d928b9780de10911 | |
parent | 50e9b0e1a62603611e9e838e22043c7304c7bb6e (diff) | |
download | NetworkManager-72dfb22cb755773a2829f0cc4ab5a2168334e824.tar.gz |
lldp: add support for management-address TLV
-rw-r--r-- | clients/cli/devices.c | 40 | ||||
-rw-r--r-- | libnm-core/nm-dbus-interface.h | 1 | ||||
-rw-r--r-- | libnm/libnm.ver | 1 | ||||
-rw-r--r-- | libnm/nm-device.c | 21 | ||||
-rw-r--r-- | libnm/nm-device.h | 2 | ||||
-rw-r--r-- | src/devices/nm-lldp-listener.c | 138 |
6 files changed, 182 insertions, 21 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index f1a97d3ea8..f582889d10 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -674,18 +674,19 @@ const NmcMetaGenericInfo *const nmc_fields_dev_lldp_list[] = { NMC_META_GENERIC ("SYSTEM-NAME"), /* 5 */ NMC_META_GENERIC ("SYSTEM-DESCRIPTION"), /* 6 */ NMC_META_GENERIC ("SYSTEM-CAPABILITIES"), /* 7 */ - NMC_META_GENERIC ("IEEE-802-1-PVID"), /* 8 */ - NMC_META_GENERIC ("IEEE-802-1-PPVID"), /* 9 */ - NMC_META_GENERIC ("IEEE-802-1-PPVID-FLAGS"), /* 10 */ - NMC_META_GENERIC ("IEEE-802-1-VID"), /* 11 */ - NMC_META_GENERIC ("IEEE-802-1-VLAN-NAME"), /* 12 */ - NMC_META_GENERIC ("DESTINATION"), /* 13 */ - NMC_META_GENERIC ("CHASSIS-ID-TYPE"), /* 14 */ - NMC_META_GENERIC ("PORT-ID-TYPE"), /* 15 */ + NMC_META_GENERIC ("MANAGEMENT-ADDRESSES"), /* 8 */ + NMC_META_GENERIC ("IEEE-802-1-PVID"), /* 9 */ + NMC_META_GENERIC ("IEEE-802-1-PPVID"), /* 10 */ + NMC_META_GENERIC ("IEEE-802-1-PPVID-FLAGS"), /* 11 */ + NMC_META_GENERIC ("IEEE-802-1-VID"), /* 12 */ + NMC_META_GENERIC ("IEEE-802-1-VLAN-NAME"), /* 13 */ + NMC_META_GENERIC ("DESTINATION"), /* 14 */ + NMC_META_GENERIC ("CHASSIS-ID-TYPE"), /* 15 */ + NMC_META_GENERIC ("PORT-ID-TYPE"), /* 16 */ NULL, }; #define NMC_FIELDS_DEV_LLDP_LIST_COMMON "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \ - "SYSTEM-CAPABILITIES" + "MANAGEMENT-ADDRESSES,SYSTEM-CAPABILITIES" static guint progress_id = 0; /* ID of event source for displaying progress */ @@ -4007,6 +4008,7 @@ show_device_lldp_list (NMDevice *device, NmCli *nmc, const char *fields_str, int for (i = 0; i < neighbors->len; i++) { NMLldpNeighbor *neighbor = neighbors->pdata[i]; + GVariant *variant; guint value; arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); @@ -4032,29 +4034,33 @@ show_device_lldp_list (NMDevice *device, NmCli *nmc, const char *fields_str, int if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, &value)) set_val_str (arr, 7, g_strdup_printf ("%u (%s)", value, nmc_parse_lldp_capabilities (value))); + /* FIXME */ + variant = nm_lldp_neighbor_get_attr_value (neighbor, NM_LLDP_ATTR_MANAGEMENT_ADDRESSES); + set_val_str (arr, 8, variant ? g_variant_print (variant, FALSE) : g_strdup ("")); + if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, &value)) - set_val_str (arr, 8, g_strdup_printf ("%u", value)); + set_val_str (arr, 9, g_strdup_printf ("%u", value)); if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID, &value)) - set_val_str (arr, 9, g_strdup_printf ("%u", value)); + set_val_str (arr, 10, g_strdup_printf ("%u", value)); if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, &value)) - set_val_str (arr, 10, g_strdup_printf ("%u", value)); + set_val_str (arr, 11, g_strdup_printf ("%u", value)); if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VID, &value)) - set_val_str (arr, 11, g_strdup_printf ("%u", value)); + set_val_str (arr, 12, g_strdup_printf ("%u", value)); if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, &str)) - set_val_strc (arr, 12, str); + set_val_strc (arr, 13, str); if (nm_lldp_neighbor_get_attr_string_value (neighbor, NM_LLDP_ATTR_DESTINATION, &str)) - set_val_strc (arr, 13, str); + set_val_strc (arr, 14, str); if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_CHASSIS_ID_TYPE, &value)) - set_val_strc (arr, 14, g_strdup_printf ("%u", value)); + set_val_strc (arr, 15, g_strdup_printf ("%u", value)); if (nm_lldp_neighbor_get_attr_uint_value (neighbor, NM_LLDP_ATTR_PORT_ID_TYPE, &value)) - set_val_strc (arr, 15, g_strdup_printf ("%u", value)); + set_val_strc (arr, 16, g_strdup_printf ("%u", value)); g_ptr_array_add (out.output_data, arr); } diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index aac4d7eadd..f9ee2cc706 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -826,6 +826,7 @@ typedef enum /*< flags >*/ { #define NM_LLDP_ATTR_SYSTEM_NAME "system-name" #define NM_LLDP_ATTR_SYSTEM_DESCRIPTION "system-description" #define NM_LLDP_ATTR_SYSTEM_CAPABILITIES "system-capabilities" +#define NM_LLDP_ATTR_MANAGEMENT_ADDRESSES "management-addresses" #define NM_LLDP_ATTR_IEEE_802_1_PVID "ieee-802-1-pvid" #define NM_LLDP_ATTR_IEEE_802_1_PPVID "ieee-802-1-ppvid" #define NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS "ieee-802-1-ppvid-flags" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index f1f6954e53..8ffa72b62e 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1452,4 +1452,5 @@ global: nm_device_get_connectivity; nm_team_link_watcher_get_vlanid; nm_team_link_watcher_new_arp_ping2; + nm_lldp_neighbor_get_attr_value; } libnm_1_14_0; diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 4bcd7c6ca4..69cdfdaa54 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -2811,6 +2811,27 @@ nm_lldp_neighbor_get_attr_uint_value (NMLldpNeighbor *neighbor, char *name, } /** + * nm_lldp_neighbor_get_attr_value: + * @neighbor: the #NMLldpNeighbor + * @name: the attribute name + * + * Gets the value (as a GVariant) of attribute with name @name on @neighbor + * + * Returns: the value or %NULL if the attribute with @name was + * not found. + * + * Since: 1.16 + **/ +GVariant * +nm_lldp_neighbor_get_attr_value (NMLldpNeighbor *neighbor, char *name) +{ + g_return_val_if_fail (neighbor, FALSE); + g_return_val_if_fail (name && name[0], FALSE); + + return g_hash_table_lookup (neighbor->attrs, name); +} + +/** * nm_lldp_neighbor_get_attr_type: * @neighbor: the #NMLldpNeighbor * @name: the attribute name diff --git a/libnm/nm-device.h b/libnm/nm-device.h index fcda93abcc..377d0decc7 100644 --- a/libnm/nm-device.h +++ b/libnm/nm-device.h @@ -234,6 +234,8 @@ gboolean nm_lldp_neighbor_get_attr_uint_value (NMLldpNeighbor *neighbor, char *n guint *out_value); NM_AVAILABLE_IN_1_2 const GVariantType *nm_lldp_neighbor_get_attr_type (NMLldpNeighbor *neighbor, char *name); +NM_AVAILABLE_IN_1_16 +GVariant *nm_lldp_neighbor_get_attr_value (NMLldpNeighbor *neighbor, char *name); G_END_DECLS diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index 483a14b106..a3037e3898 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -26,6 +26,7 @@ #include <errno.h> #include "platform/nm-platform.h" +#include "nm-utils/nm-c-list.h" #include "nm-utils.h" #include "systemd/nm-sd.h" @@ -41,6 +42,7 @@ typedef enum { LLDP_ATTR_TYPE_NONE, LLDP_ATTR_TYPE_UINT32, LLDP_ATTR_TYPE_STRING, + LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS, } LldpAttrType; typedef enum { @@ -50,6 +52,7 @@ typedef enum { LLDP_ATTR_ID_SYSTEM_NAME, LLDP_ATTR_ID_SYSTEM_DESCRIPTION, LLDP_ATTR_ID_SYSTEM_CAPABILITIES, + LLDP_ATTR_ID_MANAGEMENT_ADDRESSES, LLDP_ATTR_ID_IEEE_802_1_PVID, LLDP_ATTR_ID_IEEE_802_1_PPVID, LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, @@ -63,6 +66,7 @@ typedef struct { union { guint32 v_uint32; char *v_string; + CList v_variant_list; }; } LldpAttrData; @@ -171,6 +175,15 @@ _access_uint16 (const void *data) return ntohs (v); } +static guint32 +_access_uint32 (const void *data) +{ + guint32 v; + + memcpy (&v, data, sizeof (v)); + return ntohl (v); +} + /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, @@ -179,6 +192,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, 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_MANAGEMENT_ADDRESSES, NM_LLDP_ATTR_MANAGEMENT_ADDRESSES), 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), @@ -193,6 +207,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType 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_MANAGEMENT_ADDRESSES, LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS), 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), @@ -268,6 +283,21 @@ _lldp_attr_set_uint32 (LldpAttrData *pdata, LldpAttrId attr_id, guint32 v_uint32 pdata->v_uint32 = v_uint32; } +static void +_lldp_attr_add_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *variant) +{ + nm_assert (pdata); + nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS); + + pdata = &pdata[attr_id]; + + if (pdata->attr_type == LLDP_ATTR_TYPE_NONE) + c_list_init (&pdata->v_variant_list); + + pdata->attr_type = LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS; + c_list_link_tail (&pdata->v_variant_list, &nm_c_list_elem_new_stale (variant)->lst); +} + /*****************************************************************************/ static guint @@ -313,13 +343,23 @@ static void lldp_neighbor_free (LldpNeighbor *neighbor) { LldpAttrId attr_id; + LldpAttrType attr_type; + NMCListElem *elem, *safe; if (neighbor) { g_free (neighbor->chassis_id); g_free (neighbor->port_id); for (attr_id = 0; attr_id < _LLDP_ATTR_ID_COUNT; attr_id++) { - if (neighbor->attrs[attr_id].attr_type == LLDP_ATTR_TYPE_STRING) + attr_type = neighbor->attrs[attr_id].attr_type; + + if (attr_type == LLDP_ATTR_TYPE_STRING) g_free (neighbor->attrs[attr_id].v_string); + else if (attr_type == LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS) { + c_list_for_each_entry_safe (elem, safe, &neighbor->attrs[attr_id].v_variant_list, lst) { + g_variant_unref (elem->data); + nm_c_list_elem_free (elem); + } + } } g_clear_pointer (&neighbor->variant, g_variant_unref); g_slice_free (LldpNeighbor, neighbor); @@ -368,6 +408,66 @@ lldp_neighbor_equal (LldpNeighbor *a, LldpNeighbor *b) return TRUE; } +static GVariant * +parse_mgmt_address_tlv (uint8_t *data, gsize len) +{ + GVariantDict dict; + GVariant *variant; + gsize addr_len, oid_len; + + g_variant_dict_init (&dict, NULL); + + /* 802.1AB-2005 - Figure 8-11 + * + * - TLV type / length (2 bytes) + * - address string length (1 byte) + * - address subtype (1 byte) + * - address (1 to 31 bytes) + * - interface number subtype (1 byte) + * - interface number (4 bytes) + * - OID string length (1 byte) + * - OID (0 to 128 bytes) + */ + + if (len < 11) + goto err; + + data += 2; + addr_len = *data; + + if (addr_len <= 2 || addr_len > 32) + goto err; + if (len < 3 + addr_len + 6) + goto err; + + data++; + g_variant_dict_insert (&dict, "address-subtype", "u", *data); + + variant = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, data + 1, addr_len - 1, 1); + g_variant_dict_insert_value (&dict, "address", variant); + + data += addr_len; + g_variant_dict_insert (&dict, "interface-number-subtype", "u", *data); + data++; + g_variant_dict_insert (&dict, "interface-number", "u", _access_uint32 (data)); + + data += 4; + oid_len = *data; + + if (len < 3 + addr_len + 6 + oid_len) + goto err; + + data++; + variant = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, data, oid_len, 1); + g_variant_dict_insert_value (&dict, "object-id", variant); + + return g_variant_dict_end (&dict); + +err: + g_variant_dict_clear (&dict); + return NULL; +} + static LldpNeighbor * lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) { @@ -469,7 +569,25 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) } do { guint8 oui[3]; - guint8 subtype; + guint8 type, subtype; + GVariant *variant; + + if (sd_lldp_neighbor_tlv_get_type (neighbor_sd, &type) < 0) + continue; + + if (sd_lldp_neighbor_tlv_get_raw (neighbor_sd, (void *) &data8, &len) < 0) + continue; + + switch (type) { + case SD_LLDP_TYPE_MGMT_ADDRESS: + variant = parse_mgmt_address_tlv (data8, len); + if (variant) { + _lldp_attr_add_vardict (neigh->attrs, + LLDP_ATTR_ID_MANAGEMENT_ADDRESSES, + g_variant_ref_sink (variant)); + } + break; + } r = sd_lldp_neighbor_tlv_get_oui (neighbor_sd, oui, &subtype); if (r < 0) { @@ -487,8 +605,6 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME))) continue; - if (sd_lldp_neighbor_tlv_get_raw (neighbor_sd, (void *) &data8, &len) < 0) - continue; /* skip over leading TLV, OUI and subtype */ #ifdef WITH_MORE_ASSERTS @@ -609,6 +725,20 @@ lldp_neighbor_to_variant (LldpNeighbor *neigh) _lldp_attr_id_to_name (attr_id), g_variant_new_string (data->v_string)); break; + case LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS: { + NMCListElem *elem; + GVariantBuilder builder2; + + g_variant_builder_init (&builder2, G_VARIANT_TYPE ("aa{sv}")); + + c_list_for_each_entry (elem, &data->v_variant_list, lst) + g_variant_builder_add_value (&builder2, elem->data); + + g_variant_builder_add (&builder, "{sv}", + _lldp_attr_id_to_name (attr_id), + g_variant_builder_end (&builder2)); + break; + } default: break; } |