summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2018-12-20 17:03:16 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2018-12-20 18:51:15 +0100
commit72dfb22cb755773a2829f0cc4ab5a2168334e824 (patch)
tree9adf5b90f9954edaea80bcc2d928b9780de10911
parent50e9b0e1a62603611e9e838e22043c7304c7bb6e (diff)
downloadNetworkManager-72dfb22cb755773a2829f0cc4ab5a2168334e824.tar.gz
lldp: add support for management-address TLV
-rw-r--r--clients/cli/devices.c40
-rw-r--r--libnm-core/nm-dbus-interface.h1
-rw-r--r--libnm/libnm.ver1
-rw-r--r--libnm/nm-device.c21
-rw-r--r--libnm/nm-device.h2
-rw-r--r--src/devices/nm-lldp-listener.c138
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;
}