net: tests: Add initial set of IPv6 tests

Change-Id: Ib68b38a809068ca14ee9307e9ea605f03611ebd3
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2016-09-22 15:57:42 +03:00
commit 338c2be888
6 changed files with 479 additions and 0 deletions

7
tests/net/ipv6/Makefile Normal file
View file

@ -0,0 +1,7 @@
BOARD ?= qemu_x86
MDEF_FILE = prj.mdef
KERNEL_TYPE ?= nano
ARCH ?= x86
CONF_FILE = prj_$(ARCH).conf
include $(ZEPHYR_BASE)/Makefile.inc

5
tests/net/ipv6/prj.mdef Normal file
View file

@ -0,0 +1,5 @@
% Application : Network test
% TASK NAME PRIO ENTRY STACK GROUPS
% ===================================================
TASK MAIN 7 mainloop 2048 [EXE]

View file

@ -0,0 +1,23 @@
CONFIG_NETWORKING=y
CONFIG_NET_YAIP=y
CONFIG_NET_IPV6=y
CONFIG_NET_UDP=y
CONFIG_NET_TCP=n
CONFIG_NET_IPV4=n
CONFIG_NET_L2_DUMMY=y
CONFIG_NET_LOG=y
CONFIG_SYS_LOG_SHOW_COLOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_IPV6_ND=y
CONFIG_NET_IPV6_DAD=y
CONFIG_NET_NBUF_TX_COUNT=3
CONFIG_NET_NBUF_RX_COUNT=4
CONFIG_NET_NBUF_DATA_COUNT=7
#CONFIG_NETWORK_IP_STACK_DEBUG_IPV6=y
#CONFIG_NETWORK_IP_STACK_DEBUG_CORE=y
#CONFIG_NETWORK_IP_STACK_DEBUG_IF=y
#CONFIG_NETWORK_IP_STACK_DEBUG_UTILS=y
#CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF=y
#CONFIG_NETWORK_IP_STACK_DEBUG_CONN=y
#CONFIG_NETWORK_IP_STACK_DEBUG_L2=y

View file

@ -0,0 +1,3 @@
obj-y = main.o
ccflags-y += -I${ZEPHYR_BASE}/tests/include
ccflags-y += -I${ZEPHYR_BASE}/net/yaip

435
tests/net/ipv6/src/main.c Normal file
View file

@ -0,0 +1,435 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2015 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <sections.h>
#include <tc_util.h>
#include <net/ethernet.h>
#include <net/buf.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <net/net_context.h>
#include "net_private.h"
#include "icmpv6.h"
#include "ipv6.h"
#if defined(CONFIG_NETWORK_IP_STACK_DEBUG_IPV6)
#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif
static struct in6_addr my_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x2 } } };
static struct in6_addr mcast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
/* ICMPv6 NS frame (74 bytes) */
static const unsigned char icmpv6_ns_invalid[] = {
/* IPv6 header starts here */
0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3A, 0xFF,
0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
/* ICMPv6 NS header starts here */
0x87, 0x00, 0x7B, 0x9C, 0x60, 0x00, 0x00, 0x00,
/* Target Address */
0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
/* Source link layer address */
0x01, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD8,
/* Target link layer address */
0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD7,
/* Source link layer address */
0x01, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD6,
/* MTU option */
0x05, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD5,
};
/* ICMPv6 NS frame (64 bytes) */
static const unsigned char icmpv6_ns_no_sllao[] = {
/* IPv6 header starts here */
0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3A, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
/* ICMPv6 NS header starts here */
0x87, 0x00, 0x7B, 0x9C, 0x60, 0x00, 0x00, 0x00,
/* Target Address */
0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
};
static bool test_failed;
static struct nano_sem wait_data;
#define WAIT_TIME (sys_clock_ticks_per_sec / 4)
#define WAIT_TIME_LONG (sys_clock_ticks_per_sec)
#define SENDING 93244
#define MY_PORT 1969
#define PEER_PORT 16233
struct net_test_ipv6 {
uint8_t mac_addr[sizeof(struct net_eth_addr)];
struct net_linkaddr ll_addr;
};
int net_test_dev_init(struct device *dev)
{
return 0;
}
static uint8_t *net_test_get_mac(struct device *dev)
{
struct net_test_ipv6 *context = dev->driver_data;
if (context->mac_addr[0] == 0x00) {
/* 10-00-00-00-00 to 10-00-00-00-FF Documentation RFC7042 */
context->mac_addr[0] = 0x10;
context->mac_addr[1] = 0x00;
context->mac_addr[2] = 0x00;
context->mac_addr[3] = 0x00;
context->mac_addr[4] = 0x00;
context->mac_addr[5] = sys_rand32_get();
}
return context->mac_addr;
}
static void net_test_iface_init(struct net_if *iface)
{
uint8_t *mac = net_test_get_mac(net_if_get_device(iface));
net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr));
}
static int tester_send(struct net_if *iface, struct net_buf *buf)
{
if (!buf->frags) {
TC_ERROR("No data to send!\n");
return -ENODATA;
}
/* TC_PRINT("Data to be sent, len %d\n", net_buf_frags_len(buf)); */
/* Feed this data back to us */
if (net_recv_data(iface, buf) < 0) {
TC_ERROR("Data receive failed.");
goto out;
}
return 0;
out:
net_nbuf_unref(buf);
test_failed = true;
return 0;
}
struct net_test_ipv6 net_test_data;
static struct net_if_api net_test_if_api = {
.init = net_test_iface_init,
.send = tester_send,
};
#define _ETH_L2_LAYER DUMMY_L2
#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
NET_DEVICE_INIT(net_test_ipv6, "net_test_ipv6",
net_test_dev_init, &net_test_data, NULL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE,
127);
static bool test_init(void)
{
struct net_if_addr *ifaddr;
struct net_if_mcast_addr *maddr;
struct net_if *iface = net_if_get_default();
if (!iface) {
TC_ERROR("Interface is NULL\n");
return false;
}
ifaddr = net_if_ipv6_addr_add(iface, &my_addr,
NET_ADDR_MANUAL, 0);
if (!ifaddr) {
TC_ERROR("Cannot add IPv6 address %s\n",
net_sprint_ipv6_addr(&my_addr));
return false;
}
net_ipv6_addr_create(&mcast_addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001);
maddr = net_if_ipv6_maddr_add(iface, &mcast_addr);
if (!maddr) {
TC_ERROR("Cannot add multicast IPv6 address %s\n",
net_sprint_ipv6_addr(&mcast_addr));
return false;
}
/* The semaphore is there to wait the data to be received. */
nano_sem_init(&wait_data);
return true;
}
static bool net_test_send_ns_mcast(void)
{
int ret;
struct in6_addr tgt;
net_ipv6_addr_create_solicited_node(&my_addr, &tgt);
ret = net_ipv6_send_ns(net_if_get_default(),
NULL,
&peer_addr,
&my_addr,
&tgt,
false);
if (ret < 0) {
TC_ERROR("Cannot send NS (%d)\n", ret);
return false;
}
return true;
}
static bool net_test_send_ns(void)
{
int ret;
ret = net_ipv6_send_ns(net_if_get_default(),
NULL,
&peer_addr,
&my_addr,
&my_addr,
false);
if (ret < 0) {
TC_ERROR("Cannot send NS (%d)\n", ret);
return false;
}
return true;
}
static bool net_test_nbr_lookup_fail(void)
{
struct net_nbr *nbr;
nbr = net_ipv6_nbr_lookup(net_if_get_default(),
&peer_addr);
if (nbr) {
TC_ERROR("Neighbor %s found in cache\n",
net_sprint_ipv6_addr(&peer_addr));
return false;
}
return true;
}
static bool net_test_nbr_lookup_ok(void)
{
struct net_nbr *nbr;
nbr = net_ipv6_nbr_lookup(net_if_get_default(),
&peer_addr);
if (!nbr) {
TC_ERROR("Neighbor %s not found in cache\n",
net_sprint_ipv6_addr(&peer_addr));
return false;
}
return true;
}
static bool net_test_send_ns_extra_options(void)
{
struct net_buf *buf, *frag;
struct net_if *iface;
uint16_t reserve;
buf = net_nbuf_get_reserve_tx(0);
NET_ASSERT_INFO(buf, "Out of TX buffers");
iface = net_if_get_default();
reserve = net_if_get_ll_reserve(iface, NULL);
frag = net_nbuf_get_reserve_data(reserve);
net_buf_frag_add(buf, frag);
net_nbuf_set_ll_reserve(buf, reserve);
net_nbuf_set_iface(buf, iface);
net_nbuf_set_family(buf, AF_INET6);
net_nbuf_set_ip_hdr_len(buf, sizeof(struct net_ipv6_hdr));
net_nbuf_ll_clear(buf);
memcpy(net_buf_add(frag, sizeof(icmpv6_ns_invalid)),
icmpv6_ns_invalid, sizeof(icmpv6_ns_invalid));
if (net_recv_data(iface, buf) < 0) {
TC_ERROR("Data receive for invalid NS failed.");
return false;
}
return true;
}
static bool net_test_send_ns_no_options(void)
{
struct net_buf *buf, *frag;
struct net_if *iface;
uint16_t reserve;
buf = net_nbuf_get_reserve_tx(0);
NET_ASSERT_INFO(buf, "Out of TX buffers");
iface = net_if_get_default();
reserve = net_if_get_ll_reserve(iface, NULL);
frag = net_nbuf_get_reserve_data(reserve);
net_buf_frag_add(buf, frag);
net_nbuf_set_ll_reserve(buf, reserve);
net_nbuf_set_iface(buf, iface);
net_nbuf_set_family(buf, AF_INET6);
net_nbuf_set_ip_hdr_len(buf, sizeof(struct net_ipv6_hdr));
net_nbuf_ll_clear(buf);
memcpy(net_buf_add(frag, sizeof(icmpv6_ns_no_sllao)),
icmpv6_ns_no_sllao, sizeof(icmpv6_ns_no_sllao));
if (net_recv_data(iface, buf) < 0) {
TC_ERROR("Data receive for invalid NS failed.");
return false;
}
return true;
}
static bool net_test_prefix_timeout(void)
{
struct net_if_ipv6_prefix *prefix;
struct in6_addr addr = { { { 0x20, 1, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1 } } };
int len = 64, lifetime = 1;
prefix = net_if_ipv6_prefix_add(net_if_get_default(),
&addr, len, lifetime);
net_if_ipv6_prefix_set_lf(prefix, false);
net_if_ipv6_prefix_set_timer(prefix, lifetime);
nano_sem_take(&wait_data, SECONDS(lifetime * 3/2));
prefix = net_if_ipv6_prefix_lookup(net_if_get_default(),
&addr, len);
if (prefix) {
TC_ERROR("Prefix %s/%d should have expired",
net_sprint_ipv6_addr(&addr), len);
return false;
}
return true;
}
static bool net_test_prefix_timeout_overflow(void)
{
struct net_if_ipv6_prefix *prefix;
struct in6_addr addr = { { { 0x20, 1, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1 } } };
int len = 64, lifetime = 0xfffffffe;
prefix = net_if_ipv6_prefix_add(net_if_get_default(),
&addr, len, lifetime);
net_if_ipv6_prefix_set_lf(prefix, false);
net_if_ipv6_prefix_set_timer(prefix, lifetime);
if (nano_sem_take(&wait_data, SECONDS(lifetime * 3/2))) {
TC_ERROR("Prefix %s/%d lock should still be there",
net_sprint_ipv6_addr(&addr), len);
return false;
}
if (!net_if_ipv6_prefix_rm(net_if_get_default(), &addr, len)) {
TC_ERROR("Prefix %s/%d should have been removed",
net_sprint_ipv6_addr(&addr), len);
return false;
}
return true;
}
static const struct {
const char *name;
bool (*func)(void);
} tests[] = {
{ "test init", test_init },
{ "IPv6 send NS mcast", net_test_send_ns_mcast },
{ "IPv6 neighbor lookup fail", net_test_nbr_lookup_fail },
{ "IPv6 send NS", net_test_send_ns },
{ "IPv6 neighbor lookup ok", net_test_nbr_lookup_ok },
{ "IPv6 send NS extra options", net_test_send_ns_extra_options },
{ "IPv6 send NS no options", net_test_send_ns_no_options },
{ "IPv6 prefix timeout", net_test_prefix_timeout },
{ "IPv6 prefix timeout overflow", net_test_prefix_timeout_overflow },
};
void main(void)
{
int count, pass;
for (count = 0, pass = 0; count < ARRAY_SIZE(tests); count++) {
TC_START(tests[count].name);
test_failed = false;
if (!tests[count].func() || test_failed) {
TC_END(FAIL, "failed\n");
} else {
TC_END(PASS, "passed\n");
pass++;
}
fiber_yield();
}
TC_END_REPORT(((pass != ARRAY_SIZE(tests)) ? TC_FAIL : TC_PASS));
}

View file

@ -0,0 +1,6 @@
[test]
tags = net-ipv6
build_only = true
arch_whitelist = x86
# Doesn't work for ia32_pci
filter = CONFIG_SOC : "ia32"