Commit 8200078e authored by Beniamino Galvani's avatar Beniamino Galvani

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)
parent 452851cc
......@@ -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}')
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment