summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-10-22 15:36:28 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-10-22 17:43:48 +0200
commitf6b7064f065b6e1bf85cfd38efd859bb2474e273 (patch)
tree44e5cebe787ead394aca1066c39f972d86f978b6
parent254ed2d82578506533d07fcb89a84998d5c0b673 (diff)
downloadNetworkManager-bg/lldp-tests.tar.gz
lldp: add test casebg/lldp-tests
Add a basic test of the functionality of LLDP listener.
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am1
-rw-r--r--src/devices/Makefile.am1
-rw-r--r--src/devices/tests/Makefile.am40
-rw-r--r--src/devices/tests/test-lldp.c235
5 files changed, 279 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index e7d3ed9279..688b0915db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1051,6 +1051,8 @@ src/platform/Makefile
src/platform/tests/Makefile
src/rdisc/Makefile
src/rdisc/tests/Makefile
+src/devices/Makefile
+src/devices/tests/Makefile
src/devices/adsl/Makefile
src/devices/bluetooth/Makefile
src/devices/team/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 096cd5761e..0c96c4510d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,6 +26,7 @@ SUBDIRS += \
dhcp-manager/tests \
dnsmasq-manager/tests \
platform \
+ devices \
rdisc \
supplicant-manager/tests \
tests
diff --git a/src/devices/Makefile.am b/src/devices/Makefile.am
new file mode 100644
index 0000000000..3c6155b9c6
--- /dev/null
+++ b/src/devices/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = tests
diff --git a/src/devices/tests/Makefile.am b/src/devices/tests/Makefile.am
new file mode 100644
index 0000000000..162cc381ea
--- /dev/null
+++ b/src/devices/tests/Makefile.am
@@ -0,0 +1,40 @@
+AM_CPPFLAGS = \
+ -I${top_srcdir} \
+ -I${top_srcdir}/include \
+ -I${top_builddir}/include \
+ -I${top_srcdir}/src \
+ -I${top_builddir}/src \
+ -I${top_srcdir}/libnm-core \
+ -I${top_builddir}/libnm-core \
+ -I${srcdir}/.. \
+ -DG_LOG_DOMAIN=\""NetworkManager"\" \
+ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
+ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+ $(GLIB_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ $(LIBNL_CFLAGS)
+
+if REQUIRE_ROOT_TESTS
+AM_CPPFLAGS += -DREQUIRE_ROOT_TESTS=1
+endif
+
+DEVICES_SOURCES = \
+ ../nm-lldp-listener.c \
+TEST_SOURCES = $(DEVICE_SOURCES)
+AM_CFLAGS = $(CODE_COVERAGE_CFLAGS)
+AM_LDFLAGS = $(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(CODE_COVERAGE_LDFLAGS)
+DEVICES_LDADD = \
+ $(top_builddir)/src/libNetworkManager.la
+
+@GNOME_CODE_COVERAGE_RULES@
+
+noinst_PROGRAMS = \
+ test-lldp
+
+
+test_lldp_SOURCES = test-lldp.c $(TEST_SOURCES)
+test_lldp_LDADD = $(DEVICES_LDADD)
+
+@VALGRIND_RULES@
+TESTS = \
+ test-lldp
diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
new file mode 100644
index 0000000000..3303cbb1c5
--- /dev/null
+++ b/src/devices/tests/test-lldp.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <linux/if_tun.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "nm-lldp-listener.h"
+#include "nm-default.h"
+
+#include "nm-test-utils.h"
+
+static int
+create_tap (char *name, int *out_ifindex, guint8 *out_mac)
+{
+ struct ifreq ifr = { };
+ int fd, tmp = -1;
+
+ fd = open ("/dev/net/tun", O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy (ifr.ifr_name, name, IFNAMSIZ);
+ if (ioctl (fd, TUNSETIFF, &ifr) < 0)
+ goto out_err;
+
+ *out_ifindex = if_nametoindex (name);
+
+ /* Bring the interface up */
+ tmp = socket (AF_INET, SOCK_DGRAM, 0);
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl (tmp, SIOCSIFFLAGS, &ifr) < 0)
+ goto out_err;
+
+ /* Get its MAC address */
+ if (ioctl (tmp, SIOCGIFHWADDR, &ifr) < 0)
+ goto out_err;
+
+ memcpy (out_mac, ifr.ifr_addr.sa_data, ETH_ALEN);
+ close (tmp);
+
+ return fd;
+
+out_err:
+ if (fd >= 0)
+ close (fd);
+ if (tmp >= 0)
+ close (tmp);
+ return -1;
+}
+
+typedef struct {
+ int num_called;
+} TestInfo;
+
+static gboolean
+loop_quit (gpointer user_data)
+{
+ g_main_loop_quit ((GMainLoop *) user_data);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec,
+ gpointer user_data)
+{
+ TestInfo *info = user_data;
+
+ info->num_called++;
+}
+
+static GVariant *
+get_lldp_neighbor_attribute (GVariant *neighbors,
+ const char *chassis, const char *port,
+ const char *name)
+{
+ GVariantIter iter, attrs_iter;
+ GVariant *variant, *attr_variant;
+ const char *attr_name;
+ GVariant *chassis_v, *port_v, *attr_v;
+
+ g_return_val_if_fail (g_variant_is_of_type (neighbors,
+ G_VARIANT_TYPE ("aa{sv}")),
+ NULL);
+ g_variant_iter_init (&iter, neighbors);
+
+ while (g_variant_iter_next (&iter, "@a{sv}", &variant)) {
+ g_variant_iter_init (&attrs_iter, variant);
+ chassis_v = NULL;
+ port_v = NULL;
+ attr_v = NULL;
+
+ while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_variant)) {
+ if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_CHASSIS_ID))
+ chassis_v = attr_variant;
+ else if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_PORT_ID))
+ port_v = attr_variant;
+ else if (!g_strcmp0 (attr_name, name))
+ attr_v = attr_variant;
+ }
+
+ if ( g_variant_is_of_type (chassis_v, G_VARIANT_TYPE_STRING)
+ && g_variant_is_of_type (port_v, G_VARIANT_TYPE_STRING)
+ && !g_strcmp0 (chassis, g_variant_get_string (chassis_v, NULL))
+ && !g_strcmp0 (port, g_variant_get_string (port_v, NULL))) {
+
+ g_variant_ref (attr_v);
+ g_variant_unref (variant);
+
+ return attr_v;
+ }
+ g_variant_unref (variant);
+ }
+
+ /* neighbor not found */
+ return NULL;
+}
+
+static void
+test_receive_frame (void)
+{
+ NMLldpListener *listener;
+ int fd, ifindex = -1;
+ guint8 mac[ETH_ALEN];
+ GMainLoop *loop;
+ TestInfo info = { };
+ GVariant *neighbors, *attr;
+ 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 */
+ };
+
+ fd = create_tap ("nm-test-tap", &ifindex, mac);
+ g_assert_cmpint (fd, >=, 0);
+ g_assert_cmpint (ifindex, >=, 0);
+
+ listener = nm_lldp_listener_new ();
+ g_assert (listener != NULL);
+ g_assert (nm_lldp_listener_start (listener, ifindex, "nm-test-tap", mac, ETH_ALEN, NULL));
+
+ g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS,
+ (GCallback) lldp_neighbors_changed, &info);
+ loop = g_main_loop_new (NULL, FALSE);
+ g_timeout_add_seconds (1, loop_quit, loop);
+
+ g_assert (write (fd, frame, sizeof (frame)) == sizeof (frame));
+ g_assert (write (fd, frame, sizeof (frame)) == sizeof (frame));
+
+ g_main_loop_run (loop);
+
+ g_assert_cmpint (info.num_called, ==, 1);
+ neighbors = nm_lldp_listener_get_neighbors (listener);
+ g_assert (neighbors != NULL);
+
+ /* Check port description */
+ attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+ NM_LLDP_ATTR_PORT_DESCRIPTION);
+ g_assert (attr != NULL);
+ g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+ g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "Port");
+
+ /* Check system name */
+ attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+ NM_LLDP_ATTR_SYSTEM_NAME);
+ g_assert (attr != NULL);
+ g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+ g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "SYS");
+
+ /* Check destination */
+ attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+ NM_LLDP_ATTR_DESTINATION);
+ g_assert (attr != NULL);
+ g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+ g_assert_cmpstr (g_variant_get_string (attr, NULL), ==,
+ NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE);
+
+ g_clear_pointer (&loop, g_main_loop_unref);
+}
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+ nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
+
+ if (geteuid () != 0 || getegid () != 0) {
+#ifdef REQUIRE_ROOT_TESTS
+ g_print ("Fail test: requires root privileges (%s)\n", argv[0]);
+ return EXIT_FAILURE;
+#else
+ g_print ("Skipping test: requires root privileges (%s)\n", argv[0]);
+ return g_test_run ();
+#endif
+ }
+
+ g_test_add_func ("/lldp/receive_frame", test_receive_frame);
+
+ return g_test_run ();
+}