Beispiel #1
0
static int lldp_get_destination_type(tlv_packet *m) {
    int dest;

    assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
    assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);

    return 0;
}
Beispiel #2
0
static void test_receive_basic_packet(sd_event *e) {
    sd_lldp *lldp;
    sd_lldp_packet **packets;
    uint8_t type, *data;
    uint16_t length, ttl;
    int dest_type;
    char *str;
    uint8_t frame[] = {
        /* Ethernet header */
        0x01, 0x80, 0xc2, 0x00, 0x00, 0x03,     /* Destination MAC*/
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06,     /* Source MAC */
        0x88, 0xcc,                             /* Ethertype */
        /* LLDP mandatory TLVs */
        0x02, 0x07, 0x04, 0x00, 0x01, 0x02,     /* Chassis: MAC, 00:01:02:03:04:05 */
        0x03, 0x04, 0x05,
        0x04, 0x04, 0x05, 0x31, 0x2f, 0x33,     /* Port: interface name, "1/3" */
        0x06, 0x02, 0x00, 0x78,                 /* TTL: 120 seconds*/
        /* LLDP optional TLVs */
        0x08, 0x04, 0x50, 0x6f, 0x72, 0x74,     /* Port Description: "Port" */
        0x0a, 0x03, 0x53, 0x59, 0x53,           /* System Name: "SYS" */
        0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00,     /* System Description: "foo" (NULL-terminated) */
        0x00, 0x00                              /* End Of LLDPDU */
    };

    lldp_handler_calls = 0;
    assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);

    assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
    sd_event_run(e, 0);
    assert_se(lldp_handler_calls == 1);
    assert_se(sd_lldp_get_packets(lldp, &packets) == 1);

    assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
    assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
    assert_se(length == ETH_ALEN);
    assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));

    assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
    assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
    assert_se(length == 3);
    assert_se(strneq((char *) data, "1/3", 3));

    assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
    assert_se(length == 4);
    assert_se(strneq(str, "Port", 4));

    assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
    assert_se(length == 3);
    assert_se(strneq(str, "SYS", 3));

    assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
    assert_se(length == 4);         /* This is the real length in the TLV packet */
    assert_se(strneq(str, "foo", 3));

    assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
    assert_se(ttl == 120);

    assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
    assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);

    sd_lldp_packet_unref(packets[0]);
    free(packets);

    assert_se(stop_lldp(lldp) == 0);
}
static void
process_lldp_neighbors (NMLldpListener *self)
{
	NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
	sd_lldp_packet **packets = NULL;
	GHashTable *hash;
	int num, i;

	num = sd_lldp_get_packets (priv->lldp_handle, &packets);
	if (num < 0) {
		nm_log_dbg (LOGD_DEVICE, "LLDP: error %d retrieving neighbor packets for %s",
		            num, priv->iface);
		return;
	}

	hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal,
	                              lldp_neighbor_free, NULL);

	for (i = 0; packets && i < num; i++) {
		uint8_t chassis_id_type, port_id_type, *chassis_id, *port_id, data8;
		uint16_t chassis_id_len, port_id_len, len, data16;
		LLDPNeighbor *neigh;
		GValue *value;
		char *str;
		int r;

		if (i >= MAX_NEIGHBORS)
			goto next_packet;

		r = sd_lldp_packet_read_chassis_id (packets[i], &chassis_id_type,
		                                    &chassis_id, &chassis_id_len);
		if (r < 0)
			goto next_packet;

		r = sd_lldp_packet_read_port_id (packets[i], &port_id_type,
		                                 &port_id, &port_id_len);
		if (r < 0)
			goto next_packet;

		neigh = g_malloc0 (sizeof (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;
		sd_lldp_packet_get_destination_type (packets[i], &neigh->dest);

		if (chassis_id_len < 1) {
			lldp_neighbor_free (neigh);
			goto next_packet;
		}

		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 = strndup ((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:
			nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported chassis ID type %d", chassis_id_type);
			lldp_neighbor_free (neigh);
			goto next_packet;
		}

		if (port_id_len < 1) {
			lldp_neighbor_free (neigh);
			goto next_packet;
		}

		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:
			nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported port ID type %d", port_id_type);
			lldp_neighbor_free (neigh);
			goto next_packet;
		}

		if (sd_lldp_packet_read_port_description (packets[i], &str, &len) == 0) {
			value = gvalue_new_nstr (str, len);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_PORT_DESCRIPTION, value);
		}

		if (sd_lldp_packet_read_system_name (packets[i], &str, &len) == 0) {
			value = gvalue_new_nstr (str, len);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_NAME, value);
		}

		if (sd_lldp_packet_read_system_description (packets[i], &str, &len) == 0) {
			value = gvalue_new_nstr (str, len);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, value);
		}

		if (sd_lldp_packet_read_system_capability (packets[i], &data16) == 0) {
			value = gvalue_new_uint (data16);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, value);
		}

		if (sd_lldp_packet_read_port_vlan_id (packets[i], &data16) == 0) {
			value = gvalue_new_uint (data16);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID, value);
		}

		if (sd_lldp_packet_read_port_protocol_vlan_id (packets[i], &data8, &data16) == 0) {
			value = gvalue_new_uint (data16);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID, value);

			value = gvalue_new_uint (data8);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, value);
		}

		if (sd_lldp_packet_read_vlan_name (packets[i], &data16, &str, &len) == 0) {
			value = gvalue_new_uint (data16);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID, value);

			value = gvalue_new_nstr (str, len);
			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, value);
		}

		nm_log_dbg (LOGD_DEVICE, "LLDP: new neigh: CHASSIS='%s' PORT='%s'",
		            neigh->chassis_id, neigh->port_id);

		g_hash_table_add (hash, neigh);
next_packet:
		sd_lldp_packet_unref (packets[i]);
	}

	g_free (packets);

	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);
	}

	/* 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;
}