]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
test: add tests for new tcp controller matching algorithm
authorMartin Belanger <martin.belanger@dell.com>
Fri, 18 Aug 2023 01:36:01 +0000 (21:36 -0400)
committerDaniel Wagner <wagi@monom.org>
Wed, 30 Aug 2023 15:21:59 +0000 (17:21 +0200)
Signed-off-by: Martin Belanger <martin.belanger@dell.com>
test/meson.build
test/mock-ifaddrs.c [new file with mode: 0644]
test/tree.c

index a8cfe9f950b59acdda343533e4e7d6bf47b52f08..0c4587945805c6706aed2c29d5aa15b40cd6f6fa 100644 (file)
@@ -67,14 +67,20 @@ uuid = executable(
 test('uuid', uuid)
 
 if conf.get('HAVE_NETDB')
+    mock_ifaddrs = library(
+        'mock-ifaddrs',
+        ['mock-ifaddrs.c', ],
+    )
+
     tree = executable(
         'tree',
         ['tree.c'],
         dependencies: libnvme_dep,
-        include_directories: [incdir, internal_incdir]
+        include_directories: [incdir, internal_incdir],
+        link_with: mock_ifaddrs,
     )
 
-    test('tree', tree)
+    test('tree', tree, env: ['LD_PRELOAD=' + mock_ifaddrs.full_path()])
 
     test_util = executable(
         'test-util',
diff --git a/test/mock-ifaddrs.c b/test/mock-ifaddrs.c
new file mode 100644 (file)
index 0000000..87a2e50
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/**
+ * This file is part of libnvme.
+ * Copyright (c) 2023 Martin Belanger, Dell Technologies Inc.
+ */
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+struct ifaddrs_storage {
+       struct ifaddrs ifa;
+       union {
+               /* Reserve space for the biggest of the sockaddr types */
+               struct sockaddr_in  s4;
+               struct sockaddr_in6 s6;
+       } addr, netmask, broadaddr;
+       char name[IF_NAMESIZE + 1];
+};
+
+static void init_entry(struct ifaddrs_storage *storage,
+                      const char *ifname,
+                      int family,
+                      uint32_t addr1,
+                      uint32_t addr2,
+                      uint32_t addr3,
+                      uint32_t addr4,
+                      bool last)
+{
+       struct ifaddrs *p;
+
+       p = &storage->ifa;
+       p->ifa_next = last ? NULL : &storage[1].ifa;
+       p->ifa_name = storage->name;
+       strcpy(p->ifa_name, ifname);
+       p->ifa_flags = 0;
+
+       if (family == AF_INET) {
+               struct sockaddr_in *ipv4;
+
+               ipv4 = &storage->addr.s4;
+               ipv4->sin_family = family;
+               ipv4->sin_port = 0;
+               ipv4->sin_addr.s_addr = htonl(addr1);
+               p->ifa_addr = (struct sockaddr *)ipv4;
+
+               ipv4 = &storage->netmask.s4;
+               ipv4->sin_family = family;
+               ipv4->sin_port = 0;
+               ipv4->sin_addr.s_addr = 0xffffff00;
+               p->ifa_netmask = (struct sockaddr *)ipv4;
+
+               ipv4 = &storage->broadaddr.s4;
+               ipv4->sin_family = family;
+               ipv4->sin_port = 0;
+               ipv4->sin_addr.s_addr = 0;
+               p->ifa_broadaddr = (struct sockaddr *)ipv4;;
+       } else {
+               struct sockaddr_in6 *ipv6;
+
+               ipv6 = &storage->addr.s6;
+               ipv6->sin6_family = family;
+               ipv6->sin6_port = 0;
+               ipv6->sin6_flowinfo = 0;
+               ipv6->sin6_addr.s6_addr32[0] = htonl(addr1);
+               ipv6->sin6_addr.s6_addr32[1] = htonl(addr2);
+               ipv6->sin6_addr.s6_addr32[2] = htonl(addr3);
+               ipv6->sin6_addr.s6_addr32[3] = htonl(addr4);
+               ipv6->sin6_scope_id = 0;
+               p->ifa_addr = (struct sockaddr *)ipv6;
+
+               ipv6 = &storage->netmask.s6;
+               ipv6->sin6_family = family;
+               ipv6->sin6_port = 0;
+               ipv6->sin6_flowinfo = 0;
+               ipv6->sin6_addr.s6_addr32[0] = 0xffffffff;
+               ipv6->sin6_addr.s6_addr32[1] = 0xffffffff;
+               ipv6->sin6_addr.s6_addr32[2] = 0xffffffff;
+               ipv6->sin6_addr.s6_addr32[3] = 0;
+               ipv6->sin6_scope_id = 0;
+               p->ifa_netmask = (struct sockaddr *)ipv6;
+
+               ipv6 = &storage->broadaddr.s6;
+               ipv6->sin6_family = family;
+               ipv6->sin6_port = 0;
+               ipv6->sin6_flowinfo = 0;
+               ipv6->sin6_addr.s6_addr32[0] = 0;
+               ipv6->sin6_addr.s6_addr32[1] = 0;
+               ipv6->sin6_addr.s6_addr32[2] = 0;
+               ipv6->sin6_addr.s6_addr32[3] = 0;
+               ipv6->sin6_scope_id = 0;
+               p->ifa_broadaddr = (struct sockaddr *)ipv6;
+       }
+
+       p->ifa_data = NULL;
+}
+
+int getifaddrs(struct ifaddrs **ifap) {
+       struct ifaddrs_storage *storage;
+
+       /* Allocate memory for 4 interfaces */
+       storage = (struct ifaddrs_storage *)calloc(4, sizeof(struct ifaddrs_storage));
+       *ifap = &storage[0].ifa;
+
+       init_entry(&storage[0], "eth0", AF_INET, 0xc0a80114, 0, 0, 0, false); /* 192.168.1.20 */
+       init_entry(&storage[1], "eth0", AF_INET6, 0xfe800000, 0, 0, 0xdeadbeef, false); /* fe80::dead:beef */
+
+       /* Loopback interface */
+       init_entry(&storage[2], "lo", AF_INET, 0x7f000001, 0, 0, 0, false); /* 127.0.0.1 */
+       init_entry(&storage[3], "lo", AF_INET6, 0, 0, 0, 1, true); /* ::1 */
+
+       return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa) {
+       free(ifa);
+}
+
index 0483d3ef544e9b2d66d286ffb65e6fb68ed3f471..873b155a8c22b58a3518d5c003a6162617979866 100644 (file)
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <arpa/inet.h>
 
 #include <ccan/array_size/array_size.h>
 
@@ -212,53 +213,6 @@ static void test_lookup_1(void)
        nvme_free_tree(r);
 }
 
-static void test_lookup_2(void)
-{
-       nvme_root_t r;
-       nvme_subsystem_t s;
-       nvme_host_t h;
-       nvme_ctrl_t c1, c2, c3, c4;
-
-       printf("test_lookup_2:\n");
-
-       r = nvme_create_root(stdout, LOG_DEBUG);
-       assert(r);
-       h = nvme_default_host(r);
-       assert(h);
-
-       s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN);
-       assert(s);
-
-       assert(nvme_lookup_ctrl(s, "tcp", "192.168.2.1", "192.168.2.20",
-                               "eth0", "4420", NULL));
-
-       c1 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
-                             NULL, NULL, NULL);
-       assert(c1);
-       printf("%10s %10s    ", "", "");
-       show_ctrl(c1);
-
-       c2 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
-                             "eth0", NULL, NULL);
-       assert(c1 == c2);
-       printf("%10s %10s    ", "eth0", "-");
-       show_ctrl(c2);
-
-       c3 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
-                             NULL, "4420", NULL);
-       assert(c1 == c3);
-       printf("%10s %10s    ", "-", "4420");
-       show_ctrl(c3);
-
-       c4 = nvme_lookup_ctrl(s, "tcp", "192.168.1.1", "192.168.1.20",
-                             "eth0", "4420", NULL);
-       assert(c1 == c4);
-       printf("%10s %10s    ", "eth0", "4420");
-       show_ctrl(c4);
-
-       nvme_free_tree(r);
-}
-
 bool test_src_addr()
 {
        bool pass = true;
@@ -405,14 +359,636 @@ bool test_src_addr()
        return pass;
 }
 
+struct ctrl_args {
+       const char *transport;
+       const char *traddr;
+       const char *trsvcid;
+       const char *host_traddr;
+       const char *host_iface;
+       const char *address;
+};
+
+void set_ctrl_args(struct ctrl_args *args,
+                  const char *transport,
+                  const char *traddr,
+                  const char *trsvcid,
+                  const char *host_traddr,
+                  const char *host_iface,
+                  const char *address)
+{
+       args->transport   = transport;
+       args->traddr      = traddr;
+       args->trsvcid     = trsvcid;
+       args->host_traddr = host_traddr;
+       args->host_iface  = host_iface;
+       args->address     = address;
+}
+
+static bool ctrl_match(const char *tag,
+                      int reference_id,
+                      int candidate_id,
+                      struct ctrl_args *reference,
+                      struct ctrl_args *candidate,
+                      bool should_match)
+{
+       nvme_root_t r;
+       nvme_host_t h;
+       nvme_ctrl_t reference_ctrl; /* Existing controller (from sysfs) */
+       nvme_ctrl_t candidate_ctrl;
+       nvme_subsystem_t s;
+
+       r = nvme_create_root(stdout, LOG_DEBUG);
+       assert(r);
+
+       nvme_init_logging(r, LOG_INFO, false, false);
+
+       h = nvme_default_host(r);
+       assert(h);
+
+       s = nvme_lookup_subsystem(h, DEFAULT_SUBSYSNAME, DEFAULT_SUBSYSNQN);
+       assert(s);
+
+       reference_ctrl = nvme_lookup_ctrl(s, reference->transport, reference->traddr,
+                                         reference->host_traddr, reference->host_iface,
+                                         reference->trsvcid, NULL);
+       assert(reference_ctrl);
+       reference_ctrl->name = "nvme1";  /* fake the device name */
+       if (reference->address) {
+               reference_ctrl->address = (char *)reference->address;
+       }
+
+       candidate_ctrl = nvme_lookup_ctrl(s, candidate->transport, candidate->traddr,
+                                         candidate->host_traddr, candidate->host_iface,
+                                         candidate->trsvcid, NULL);
+
+       if (should_match) {
+               if (candidate_ctrl != reference_ctrl) {
+                       printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s) failed to match (%s, %s, %s, %s, %s, %s)\n",
+                              tag, reference_id, candidate_id,
+                              candidate->transport, candidate->traddr, candidate->trsvcid,
+                              candidate->host_traddr, candidate->host_iface,
+                              reference->transport, reference->traddr, reference->trsvcid,
+                              reference->host_traddr, reference->host_iface, reference->address);
+                       return false;
+               }
+       } else {
+               if (candidate_ctrl == reference_ctrl) {
+                       printf("%s-%d-%d: Candidate (%s, %s, %s, %s, %s) should not match (%s, %s, %s, %s, %s, %s)\n",
+                              tag, reference_id, candidate_id,
+                              candidate->transport, candidate->traddr, candidate->trsvcid,
+                              candidate->host_traddr, candidate->host_iface,
+                              reference->transport, reference->traddr, reference->trsvcid,
+                              reference->host_traddr, reference->host_iface, reference->address);
+                       return false;
+               }
+       }
+
+       /* Set the faked data back to NULL before freeing the tree */
+       reference_ctrl->name = NULL;
+       reference_ctrl->address = NULL;
+
+       nvme_free_tree(r);
+
+       return true;
+}
+
+/**
+ * test_ctrl_match_fc - Test that we can look up FC controllers
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_fc(void)
+{
+       bool pass = true;
+       struct ctrl_args reference = {0};
+       struct ctrl_args candidate = {0};
+
+       printf("test_ctrl_match_fc:\n");
+
+       /*******************************************************************/
+       /* Reference ID 1 */
+       set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL);
+       pass &= ctrl_match("FC", 1, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 1, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 1, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 1, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 1, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:21", NULL, NULL);
+       pass &= ctrl_match("FC", 1, 5, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL);
+       pass &= ctrl_match("FC", 1, 6, &reference, &candidate, false);
+
+
+       /*******************************************************************/
+       /* Reference ID 2 */
+       set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL);
+       pass &= ctrl_match("FC", 2, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 2, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 2, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 2, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 2, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL);
+       pass &= ctrl_match("FC", 2, 5, &reference, &candidate, false);
+
+
+       /*******************************************************************/
+       /* Reference ID 3 */
+       set_ctrl_args(&reference, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", "21:00:00:e0:8b:05:05:20", NULL, NULL);
+       pass &= ctrl_match("FC", 3, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 3, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 3, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "fc", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("FC", 3, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("FC", 3, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "fc", "21:00:00:e0:8b:05:05:01", "8009", NULL, "", NULL);
+       pass &= ctrl_match("FC", 3, 5, &reference, &candidate, false);
+
+       return pass;
+}
+
+/**
+ * test_ctrl_match_rdma - Test that we can look up RDMA controllers
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_rdma(void)
+{
+       bool pass = true;
+       struct ctrl_args reference = {0};
+       struct ctrl_args candidate = {0};
+
+       printf("test_ctrl_match_rdma:\n");
+
+       /*******************************************************************/
+       /* Reference ID 1 */
+       set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("RDMA", 1, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 1, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 1, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 1, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 1, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("RDMA", 1, 5, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL);
+       pass &= ctrl_match("RDMA", 1, 6, &reference, &candidate, false);
+
+
+       /*******************************************************************/
+       /* Reference ID 2 */
+       set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("RDMA", 2, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 2, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 2, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 2, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 2, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL);
+       pass &= ctrl_match("RDMA", 2, 5, &reference, &candidate, false);
+
+
+       /*******************************************************************/
+       /* Reference ID 3 */
+       set_ctrl_args(&reference, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("RDMA", 3, 0, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 3, 1, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 3, 2, &reference, &candidate, true);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.2", "4420", NULL, "eth0", NULL);
+       pass &= ctrl_match("RDMA", 3, 3, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("RDMA", 3, 4, &reference, &candidate, false);
+
+       set_ctrl_args(&candidate, "rdma", "192.168.2.1", "8009", NULL, "", NULL);
+       pass &= ctrl_match("RDMA", 3, 5, &reference, &candidate, false);
+
+       return pass;
+}
+
+/**
+ * test_ctrl_match_tcp - Test that we can look up TCP controllers
+ *
+ * @note: The mocked getifaddrs() returns 4 interface entries as follows.
+ *        Therefore the tests must use IP addresses that match there.
+ *
+ *        eth0
+ *         \_ 192.168.1.20
+ *         \_ fe80::dead:beef
+ *
+ *        lo
+ *         \_ 127.0.0.1
+ *         \_ ::1
+ *
+ * @return true when all tests have passed. false otherwise.
+ */
+static bool test_ctrl_match_tcp()
+{
+       bool pass = true;
+       struct ctrl_args reference = {0};
+       struct ctrl_args candidate = {0};
+
+       printf("\n"
+              "test_ctrl_match_tcp:\n");
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 1 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 1, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 1, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 1, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 1, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 1, 4, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 1, 5, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 1, 6, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 1, 7, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 1, 8, &reference, &candidate, true);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 2 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 2, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 2, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 2, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 2, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 2, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 2, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 2, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 2, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 2, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 3 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 3, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 3, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 3, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 3, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 3, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 3, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 3, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 3, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 3, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 4 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 4, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 4, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 4, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 4, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 4, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 4, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 4, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 4, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 4, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 5 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 5, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 5, 1, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 5, 2, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 5, 3, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 5, 4, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 5, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 5, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 5, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 5, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 6 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, "traddr=123.123.123.123,trsvcid=8009,src_addr=192.168.1.20");
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 6, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 6, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 6, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 6, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 6, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 6, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 6, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 6, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 6, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv4: Reference ID 7 */
+       set_ctrl_args(&reference, "tcp", "123.123.123.123", "8009", NULL, NULL, "traddr=123.123.123.123,trsvcid=8009,src_addr=127.0.0.1");
+
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv4", 7, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", NULL, NULL);
+       pass &= ctrl_match("IPv4", 7, 1, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv4", 7, 2, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 7, 3, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", NULL, NULL);
+       pass &= ctrl_match("IPv4", 7, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "eth0", NULL);
+       pass &= ctrl_match("IPv4", 7, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv4", 7, 6, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.20", "lo", NULL);
+       pass &= ctrl_match("IPv4", 7, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "123.123.123.123", "8009", "192.168.1.21", "lo", NULL);
+       pass &= ctrl_match("IPv4", 7, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 1 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 1, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 1, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 1, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 1, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 1, 4, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 1, 5, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 1, 6, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 1, 7, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 1, 8, &reference, &candidate, true);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 2 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 2, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 2, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 2, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 2, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 2, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 2, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 2, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 2, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 2, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 3 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 3, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 3, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 3, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 3, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 3, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 3, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 3, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 3, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 3, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 4 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 4, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 4, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 4, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 4, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 4, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 4, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 4, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 4, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 4, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 5 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 5, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 5, 1, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 5, 2, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 5, 3, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 5, 4, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 5, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 5, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 5, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 5, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 6 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, "traddr=aaaa::bbbb,trsvcid=8009,src_addr=fe80::dead:beef");
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 6, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 6, 1, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 6, 2, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 6, 3, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 6, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 6, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 6, 6, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 6, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 6, 8, &reference, &candidate, false);
+
+       /*******************************************************************/
+       /* IPv6: Reference ID 7 */
+       set_ctrl_args(&reference, "tcp", "aaaa::bbbb", "8009", NULL, NULL, "traddr=aaaa::bbbb,trsvcid=8009,src_addr=::1");
+
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, NULL, NULL);
+       pass &= ctrl_match("IPv6", 7, 0, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", NULL, NULL);
+       pass &= ctrl_match("IPv6", 7, 1, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "eth0", NULL);
+       pass &= ctrl_match("IPv6", 7, 2, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 7, 3, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", NULL, NULL);
+       pass &= ctrl_match("IPv6", 7, 4, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "eth0", NULL);
+       pass &= ctrl_match("IPv6", 7, 5, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", NULL, "lo", NULL);
+       pass &= ctrl_match("IPv6", 7, 6, &reference, &candidate, true);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:beef", "lo", NULL);
+       pass &= ctrl_match("IPv6", 7, 7, &reference, &candidate, false);
+       set_ctrl_args(&candidate, "tcp", "aaaa::bbbb", "8009", "fe80::dead:cafe", "lo", NULL);
+       pass &= ctrl_match("IPv6", 7, 8, &reference, &candidate, false);
+
+       return pass;
+}
+
+
 int main(int argc, char *argv[])
 {
-       int exit_val = EXIT_SUCCESS;
+       bool pass = true;
 
        test_lookup_1();
-       test_lookup_2();
 
-       if (!test_src_addr()) exit_val = EXIT_FAILURE;
+       pass &= test_src_addr();
+       pass &= test_ctrl_match_fc();
+       pass &= test_ctrl_match_rdma();
+       pass &= test_ctrl_match_tcp();
+
+       fflush(stdout);
 
-       exit(exit_val);
+       exit(pass ? EXIT_SUCCESS : EXIT_FAILURE);
 }