Linux Audio

Check our new training course

Loading...
/* main.c - Application main entry point */

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL);

#include <zephyr/ztest.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/sys/printk.h>
#include <zephyr/net/net_core.h>
#include <zephyr/net/net_ip.h>
#include <zephyr/net/ethernet.h>
#include <zephyr/linker/sections.h>

#include "nbr.h"

#define NET_LOG_ENABLED 1
#include "net_private.h"

static int remove_count, add_count, clear_called;

static void net_neighbor_data_remove(struct net_nbr *nbr)
{
	printk("Neighbor %p removed\n", nbr);

	remove_count++;
}

static void net_neighbor_table_clear(struct net_nbr_table *table)
{
	printk("Neighbor table %p cleared\n", table);

	clear_called = true;
}

NET_NBR_POOL_INIT(net_test_neighbor_pool, CONFIG_NET_IPV6_MAX_NEIGHBORS,
		  0, net_neighbor_data_remove, 0);

NET_NBR_TABLE_INIT(NET_NBR_LOCAL, test_neighbor, net_test_neighbor_pool,
		   net_neighbor_table_clear);


static struct net_eth_addr hwaddr1 = { { 0x42, 0x11, 0x69, 0xde, 0xfa, 0x01 } };
static struct net_eth_addr hwaddr2 = { { 0x5f, 0x1c, 0x04, 0xae, 0x99, 0x02 } };
static struct net_eth_addr hwaddr3 = { { 0xee, 0xe1, 0x55, 0xfe, 0x44, 0x03 } };
static struct net_eth_addr hwaddr4 = { { 0x61, 0xf2, 0xfe, 0x4e, 0x8e, 0x04 } };
static struct net_eth_addr hwaddr5 = { { 0x8a, 0x52, 0x01, 0x21, 0x11, 0x05 } };

ZTEST(neighbor_test_suite, test_neighbor)
{
	struct net_eth_addr *addrs[] = {
		&hwaddr1,
		&hwaddr2,
		&hwaddr3,
		&hwaddr4,
		&hwaddr5,
		NULL
	};
	struct net_nbr *nbrs[sizeof(addrs) - 1] = { 0 };
	struct net_eth_addr *eth_addr;

	struct net_nbr *nbr;
	struct net_linkaddr lladdr;
	struct net_linkaddr_storage *lladdr_ptr;
	struct net_if *iface1 = INT_TO_POINTER(1);
	struct net_if *iface2 = INT_TO_POINTER(2);
	int ret, i;

	zassert_true(CONFIG_NET_IPV6_MAX_NEIGHBORS == (ARRAY_SIZE(addrs) - 2),
		     "There should be exactly %d valid entries in addrs array\n",
		     CONFIG_NET_IPV6_MAX_NEIGHBORS + 1);

	/* First adding a neighbor and trying to add multiple hw addresses
	 * to it. Only the first one should succeed.
	 */
	nbr = net_nbr_get(&net_test_neighbor.table);
	zassert_not_null(nbr, "Cannot get neighbor from table %p\n",
			 &net_test_neighbor.table);

	zassert_false(nbr->ref != 1, "Invalid ref count %d\n", nbr->ref);

	lladdr.len = sizeof(struct net_eth_addr);

	for (i = 0; i < 2; i++) {
		eth_addr = addrs[i];

		lladdr.addr = eth_addr->addr;

		ret = net_nbr_link(nbr, iface1, &lladdr);

		/* One neighbor can have only one lladdr */
		zassert_false(i == 0 && ret < 0, "Cannot add %s to nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);

		if (!ret) {
			printk("Adding %s\n",
			       net_sprint_ll_addr(eth_addr->addr,
						  sizeof(struct net_eth_addr)));
		}
	}

	lladdr.addr = addrs[0]->addr;
	nbr = net_nbr_lookup(&net_test_neighbor.table, iface1, &lladdr);
	zassert_true(nbr->idx == 0, "Wrong index %d should be %d\n", nbr->idx, 0);

	for (i = 0; i < 2; i++) {
		eth_addr = addrs[i];

		lladdr.addr = eth_addr->addr;

		ret = net_nbr_unlink(nbr, &lladdr);
		zassert_false(i == 0 && ret < 0, "Cannot add %s to nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);
		if (!ret) {
			printk("Deleting %s\n",
			       net_sprint_ll_addr(eth_addr->addr,
						  sizeof(struct net_eth_addr)));
		}
	}

	net_nbr_unref(nbr);
	zassert_false(nbr->ref != 0, "nbr still referenced, ref %d\n",
		      nbr->ref);

	/* Then adding multiple neighbors.
	 */
	lladdr.len = sizeof(struct net_eth_addr);

	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
		nbr = net_nbr_get(&net_test_neighbor.table);
		if (!nbr) {
			if (i >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
				/* Ok, last entry will not fit cache */
				break;
			}
			zassert_true(1, "[%d] Cannot get neighbor from table %p\n",
				     i, &net_test_neighbor.table);
		}

		zassert_true(nbr->ref == 1, "[%d] Invalid ref count %d\n", i, nbr->ref);
		nbrs[i] = nbr;

		eth_addr = addrs[i];

		lladdr.addr = eth_addr->addr;

		ret = net_nbr_link(nbr, iface1, &lladdr);
		zassert_false(ret < 0, "Cannot add %s to nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);
		printk("Adding %s\n", net_sprint_ll_addr(eth_addr->addr,
							 sizeof(struct net_eth_addr)));
	}

	for (i = 0; i < ARRAY_SIZE(addrs) - 2; i++) {
		lladdr.addr = addrs[i]->addr;
		nbr = net_nbr_lookup(&net_test_neighbor.table, iface1, &lladdr);
		zassert_false(nbr->idx != i, "Wrong index %d should be %d\n", nbr->idx, i);
	}

	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
		eth_addr = addrs[i];
		nbr = nbrs[i];
		lladdr.addr = eth_addr->addr;

		if (!nbr || i >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
			break;
		}

		ret = net_nbr_unlink(nbr, &lladdr);
		zassert_false(ret < 0, "Cannot del %s from nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);
		printk("Deleting %s\n", net_sprint_ll_addr(eth_addr->addr,
							   sizeof(struct net_eth_addr)));

		net_nbr_unref(nbr);
		zassert_false(nbr->ref != 0, "nbr still referenced, ref %d\n",
			      nbr->ref);
	}

	/* Then adding multiple neighbors but some of them in different
	 * interface.
	 */
	lladdr.len = sizeof(struct net_eth_addr);
	remove_count = add_count = 0;

	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
		nbr = net_nbr_get(&net_test_neighbor.table);
		if (!nbr) {
			if (i >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
				/* Ok, last entry will not fit cache */
				break;
			}
			zassert_true(1, "[%d] Cannot get neighbor from table %p\n",
				     i, &net_test_neighbor.table);
		}

		zassert_false(nbr->ref != 1, "[%d] Invalid ref count %d\n", i, nbr->ref);
		nbrs[i] = nbr;

		eth_addr = addrs[i];

		lladdr.addr = eth_addr->addr;

		if (i % 2) {
			ret = net_nbr_link(nbr, iface1, &lladdr);
		} else {
			ret = net_nbr_link(nbr, iface2, &lladdr);
		}
		zassert_false(ret < 0, "Cannot add %s to nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);
		printk("Adding %s iface %p\n",
		       net_sprint_ll_addr(eth_addr->addr,
					  sizeof(struct net_eth_addr)),
		       nbr->iface);
		add_count++;
	}

	for (i = 0; i < ARRAY_SIZE(addrs) - 2; i++) {
		lladdr.addr = addrs[i]->addr;
		if (i % 2) {
			nbr = net_nbr_lookup(&net_test_neighbor.table, iface1,
					     &lladdr);
		} else {
			nbr = net_nbr_lookup(&net_test_neighbor.table, iface2,
					     &lladdr);
		}
		zassert_false(nbr->idx != i, "Wrong index %d should be %d\n", nbr->idx, i);

		lladdr_ptr = net_nbr_get_lladdr(i);
		if (memcmp(lladdr_ptr->addr, addrs[i]->addr,
			   sizeof(struct net_eth_addr))) {
			zassert_true(1, "Wrong lladdr %s in index %d\n",
				     net_sprint_ll_addr(lladdr_ptr->addr,
							lladdr_ptr->len),
				     i);
		}
	}

	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
		struct net_if *iface;

		eth_addr = addrs[i];
		nbr = nbrs[i];
		lladdr.addr = eth_addr->addr;

		if (!nbr || i >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
			break;
		}

		iface = nbr->iface;

		ret = net_nbr_unlink(nbr, &lladdr);
		zassert_false(ret < 0, "Cannot del %s from nbr cache (%d)\n",
			      net_sprint_ll_addr(lladdr.addr, lladdr.len),
			      ret);

		printk("Deleting %s iface %p\n", net_sprint_ll_addr(eth_addr->addr,
								    sizeof(struct net_eth_addr)), iface);

		net_nbr_unref(nbr);
		zassert_false(nbr->ref != 0, "nbr still referenced, ref %d\n", nbr->ref);
	}

	zassert_false(add_count != remove_count, "Remove count %d does not match add count %d\n",
		      remove_count, add_count);

	net_nbr_clear_table(&net_test_neighbor.table);

	zassert_true(clear_called, "Table clear check failed");

	/* The table should be empty now */
	lladdr.addr = addrs[0]->addr;
	nbr = net_nbr_lookup(&net_test_neighbor.table, iface1, &lladdr);

	zassert_is_null(nbr, "Some entries still found in nbr cache");

	return;
}

void *setup(void)
{
	if (IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE)) {
		k_thread_priority_set(k_current_get(),
				K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1));
	} else {
		k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(9));
	}
	return NULL;
}

/*test case main entry*/
ZTEST_SUITE(neighbor_test_suite, NULL, setup, NULL, NULL, NULL);