lldp: support IEEE 802.3 TLVs
Add support for IEEE 802.3 organizationally specific TLVs: - MAC/PHY configuration/status (IEEE 802.1AB-2009 clause F.2) - power via medium dependent interface (clause F.3) - maximum frame size (clause F.4)
This commit is contained in:
@@ -843,6 +843,10 @@ typedef enum /*< flags >*/ {
|
||||
#define NM_LLDP_ATTR_IEEE_802_1_VLANS "ieee-802-1-vlans"
|
||||
#define NM_LLDP_ATTR_IEEE_802_1_PPVIDS "ieee-802-1-ppvids"
|
||||
|
||||
#define NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF "ieee-802-3-mac-phy-conf"
|
||||
#define NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI "ieee-802-3-power-via-mdi"
|
||||
#define NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE "ieee-802-3-max-frame-size"
|
||||
|
||||
/* These are deprecated in favor of NM_LLDP_ATTR_IEEE_802_1_VLANS,
|
||||
* which can report multiple VLANs */
|
||||
#define NM_LLDP_ATTR_IEEE_802_1_VID "ieee-802-1-vid"
|
||||
|
@@ -42,6 +42,7 @@ typedef enum {
|
||||
LLDP_ATTR_TYPE_NONE,
|
||||
LLDP_ATTR_TYPE_UINT32,
|
||||
LLDP_ATTR_TYPE_STRING,
|
||||
LLDP_ATTR_TYPE_VARDICT,
|
||||
LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS,
|
||||
} LldpAttrType;
|
||||
|
||||
@@ -60,6 +61,9 @@ typedef enum {
|
||||
LLDP_ATTR_ID_IEEE_802_1_VID,
|
||||
LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME,
|
||||
LLDP_ATTR_ID_IEEE_802_1_VLANS,
|
||||
LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF,
|
||||
LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI,
|
||||
LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE,
|
||||
_LLDP_ATTR_ID_COUNT,
|
||||
} LldpAttrId;
|
||||
|
||||
@@ -68,6 +72,7 @@ typedef struct {
|
||||
union {
|
||||
guint32 v_uint32;
|
||||
char *v_string;
|
||||
GVariant *v_variant;
|
||||
CList v_variant_list;
|
||||
};
|
||||
} LldpAttrData;
|
||||
@@ -178,6 +183,9 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId,
|
||||
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_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLANS, NM_LLDP_ATTR_IEEE_802_1_VLANS),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF, NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE,NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE),
|
||||
NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT),
|
||||
);
|
||||
|
||||
@@ -195,6 +203,9 @@ _NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType
|
||||
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 (LLDP_ATTR_ID_IEEE_802_1_VLANS, LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS),
|
||||
NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF, LLDP_ATTR_TYPE_VARDICT),
|
||||
NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, LLDP_ATTR_TYPE_VARDICT),
|
||||
NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE, LLDP_ATTR_TYPE_UINT32),
|
||||
NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT),
|
||||
);
|
||||
|
||||
@@ -244,6 +255,26 @@ _lldp_attr_set_uint32 (LldpAttrData *pdata, LldpAttrId attr_id, guint32 v_uint32
|
||||
pdata->v_uint32 = v_uint32;
|
||||
}
|
||||
|
||||
static void
|
||||
_lldp_attr_set_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *variant)
|
||||
{
|
||||
|
||||
nm_assert (pdata);
|
||||
nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_VARDICT);
|
||||
|
||||
pdata = &pdata[attr_id];
|
||||
|
||||
/* we ignore duplicate fields silently */
|
||||
if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) {
|
||||
if (g_variant_is_floating (variant))
|
||||
g_variant_unref (variant);
|
||||
return;
|
||||
}
|
||||
|
||||
pdata->attr_type = LLDP_ATTR_TYPE_VARDICT;
|
||||
pdata->v_variant = g_variant_ref_sink (variant);
|
||||
}
|
||||
|
||||
static void
|
||||
_lldp_attr_add_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *variant)
|
||||
{
|
||||
@@ -319,6 +350,9 @@ lldp_neighbor_free (LldpNeighbor *neighbor)
|
||||
case LLDP_ATTR_TYPE_STRING:
|
||||
g_free (neighbor->attrs[attr_id].v_string);
|
||||
break;
|
||||
case LLDP_ATTR_TYPE_VARDICT:
|
||||
g_variant_unref (neighbor->attrs[attr_id].v_variant);
|
||||
break;
|
||||
case LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS:
|
||||
nm_c_list_elem_free_all (&neighbor->attrs[attr_id].v_variant_list,
|
||||
(GDestroyNotify) g_variant_unref);
|
||||
@@ -577,14 +611,10 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!( memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0
|
||||
&& NM_IN_SET (subtype,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME)))
|
||||
if ( memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) != 0
|
||||
&& memcmp (oui, SD_LLDP_OUI_802_3, sizeof (oui)) != 0)
|
||||
continue;
|
||||
|
||||
|
||||
/* skip over leading TLV, OUI and subtype */
|
||||
#ifdef WITH_MORE_ASSERTS
|
||||
{
|
||||
@@ -603,8 +633,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error)
|
||||
data8 += 6;
|
||||
len -= 6;
|
||||
|
||||
/*if (memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0)*/
|
||||
{
|
||||
if (memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0) {
|
||||
GVariantDict dict;
|
||||
|
||||
switch (subtype) {
|
||||
@@ -663,7 +692,44 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
continue;
|
||||
}
|
||||
} else if (memcmp (oui, SD_LLDP_OUI_802_3, sizeof (oui)) == 0) {
|
||||
GVariantDict dict;
|
||||
|
||||
switch (subtype) {
|
||||
case SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS:
|
||||
if (len != 5)
|
||||
continue;
|
||||
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "autoneg", "u", (guint32) data8[0]);
|
||||
g_variant_dict_insert (&dict, "pmd-autoneg-cap", "u", (guint32) unaligned_read_be16 (&data8[1]));
|
||||
g_variant_dict_insert (&dict, "operational-mau-type", "u", (guint32) unaligned_read_be16 (&data8[3]));
|
||||
|
||||
_lldp_attr_set_vardict (neigh->attrs,
|
||||
LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF,
|
||||
g_variant_dict_end (&dict));
|
||||
break;
|
||||
case SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI:
|
||||
if (len != 3)
|
||||
continue;
|
||||
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
g_variant_dict_insert (&dict, "mdi-power-support", "u", (guint32) data8[0]);
|
||||
g_variant_dict_insert (&dict, "pse-power-pair", "u", (guint32) data8[1]);
|
||||
g_variant_dict_insert (&dict, "power-class", "u", (guint32) data8[2]);
|
||||
|
||||
_lldp_attr_set_vardict (neigh->attrs,
|
||||
LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI,
|
||||
g_variant_dict_end (&dict));
|
||||
break;
|
||||
case SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE:
|
||||
if (len != 2)
|
||||
continue;
|
||||
_lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE,
|
||||
unaligned_read_be16 (data8));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (sd_lldp_neighbor_tlv_next (neighbor_sd) > 0);
|
||||
@@ -728,6 +794,11 @@ 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_VARDICT:
|
||||
g_variant_builder_add (&builder, "{sv}",
|
||||
_lldp_attr_id_to_name (attr_id),
|
||||
data->v_variant);
|
||||
break;
|
||||
case LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS: {
|
||||
NMCListElem *elem;
|
||||
GVariantBuilder builder2;
|
||||
|
@@ -244,7 +244,7 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener)
|
||||
SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:30:F9:AD:A0",
|
||||
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/1");
|
||||
g_assert (neighbor);
|
||||
g_assert_cmpint (g_variant_n_children (neighbor), ==, 4 + 13);
|
||||
g_assert_cmpint (g_variant_n_children (neighbor), ==, 4 + 16);
|
||||
|
||||
attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_DESTINATION, G_VARIANT_TYPE_STRING);
|
||||
nmtst_assert_variant_string (attr, NM_LLDP_DEST_NEAREST_BRIDGE);
|
||||
@@ -287,10 +287,34 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener)
|
||||
nm_clear_g_variant (&child);
|
||||
nm_clear_g_variant (&attr);
|
||||
|
||||
/* unsupported: IEEE 802.3 - Power Via MDI */
|
||||
/* unsupported: IEEE 802.3 - MAC/PHY Configuration/Status */
|
||||
/* IEEE 802.3 - Power Via MDI */
|
||||
attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI, G_VARIANT_TYPE_VARDICT);
|
||||
g_assert (attr);
|
||||
g_variant_lookup (attr, "mdi-power-support", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 7);
|
||||
g_variant_lookup (attr, "pse-power-pair", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 1);
|
||||
g_variant_lookup (attr, "power-class", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 0);
|
||||
nm_clear_g_variant (&attr);
|
||||
|
||||
/* IEEE 802.3 - MAC/PHY Configuration/Status */
|
||||
attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF, G_VARIANT_TYPE_VARDICT);
|
||||
g_assert (attr);
|
||||
g_variant_lookup (attr, "autoneg", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 3);
|
||||
g_variant_lookup (attr, "pmd-autoneg-cap", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 0x6c00);
|
||||
g_variant_lookup (attr, "operational-mau-type", "u", &v_uint);
|
||||
g_assert_cmpint (v_uint, ==, 16);
|
||||
nm_clear_g_variant (&attr);
|
||||
|
||||
/* unsupported: IEEE 802.3 - Link Aggregation */
|
||||
/* unsupported: IEEE 802.3 - Maximum Frame Size*/
|
||||
|
||||
/* Maximum Frame Size */
|
||||
attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE, G_VARIANT_TYPE_UINT32);
|
||||
nmtst_assert_variant_uint32 (attr, 1522);
|
||||
nm_clear_g_variant (&attr);
|
||||
|
||||
/* IEEE 802.1 - Port VLAN ID */
|
||||
attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, G_VARIANT_TYPE_UINT32);
|
||||
|
@@ -762,6 +762,7 @@ class Device(ExportedObj):
|
||||
'flags': dbus.UInt32(0x31),
|
||||
}, signature = 'sv'),
|
||||
]),
|
||||
|
||||
}),
|
||||
dbus.Dictionary({
|
||||
'chassis-id-type': dbus.UInt32(6),
|
||||
@@ -787,7 +788,17 @@ class Device(ExportedObj):
|
||||
'interface-number': dbus.UInt32(1),
|
||||
'interface-number-subtype': dbus.UInt32(2),
|
||||
}, signature = 'sv'),
|
||||
])
|
||||
]),
|
||||
'ieee-802-3-mac-phy-conf': dbus.Dictionary({
|
||||
'autoneg': dbus.UInt32(3),
|
||||
'pmd-autoneg-cap': dbus.UInt32(0xfe),
|
||||
'operational-mau-type': dbus.UInt32(5),
|
||||
}, signature = 'sv'),
|
||||
'ieee-802-3-power-via-mdi': dbus.Dictionary({
|
||||
'mdi-power-support': dbus.UInt32(7),
|
||||
'pse-power-pair': dbus.UInt32(6),
|
||||
'power-class': dbus.UInt32(1),
|
||||
}, signature = 'sv'),
|
||||
})
|
||||
], 'a{sv}')
|
||||
}
|
||||
|
Reference in New Issue
Block a user