summaryrefslogtreecommitdiff
path: root/cesar/lib
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/lib')
-rw-r--r--cesar/lib/Config2
-rw-r--r--cesar/lib/Module5
-rw-r--r--cesar/lib/seq_check.h170
-rw-r--r--cesar/lib/src/seq_check.c154
-rw-r--r--cesar/lib/src/utils.c42
-rw-r--r--cesar/lib/test/fixed/src/test_fixed.c12
-rw-r--r--cesar/lib/test/heap/src/test_heap.c2
-rw-r--r--cesar/lib/test/mbox/src/mbox.c2
-rw-r--r--cesar/lib/test/seq_check/Config2
-rw-r--r--cesar/lib/test/seq_check/Makefile8
-rw-r--r--cesar/lib/test/seq_check/src/seq_check.c250
-rw-r--r--cesar/lib/test/utils/src/test_utils.c50
-rw-r--r--cesar/lib/utils.h12
13 files changed, 703 insertions, 8 deletions
diff --git a/cesar/lib/Config b/cesar/lib/Config
index bf0afe4a15..cb6dd037a9 100644
--- a/cesar/lib/Config
+++ b/cesar/lib/Config
@@ -27,3 +27,5 @@ CONFIG_GPIO_FATAL_BLINK_DELAY = 10000000
CONFIG_SLAB_ALLOC_SCRAMBLE = n
CONFIG_RND_MT19937 = n
CONFIG_RND_TT800 = y
+CONFIG_SEQ_CHECK = n
+CONFIG_SEQ_CHECK_VLAN_MAX = 64
diff --git a/cesar/lib/Module b/cesar/lib/Module
index 0c9d1aa51b..e57586f636 100644
--- a/cesar/lib/Module
+++ b/cesar/lib/Module
@@ -1,7 +1,7 @@
SOURCES := crc.c dbg.c heap.c test.c blk.c slab.c list.c \
aatree.c try.c fixed.c blk_table.c \
swap.c read_word.c bitstream.c circular_buffer.c mbox.c \
- mac_lookup_table.c init.c rnd.c
+ mac_lookup_table.c init.c rnd.c utils.c
ifeq ($(CONFIG_HEAP_SKEW),y)
SOURCES += skewheap.c
endif
@@ -26,3 +26,6 @@ endif
ifeq ($(CONFIG_RND_TT800),y)
SOURCES += tt800.c
endif
+ifeq ($(CONFIG_SEQ_CHECK),y)
+SOURCES += seq_check.c
+endif
diff --git a/cesar/lib/seq_check.h b/cesar/lib/seq_check.h
new file mode 100644
index 0000000000..5e0916ce29
--- /dev/null
+++ b/cesar/lib/seq_check.h
@@ -0,0 +1,170 @@
+#ifndef lib_seq_check_h
+#define lib_seq_check_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file lib/seq_check.h
+ * \brief Check sequence number in data packets
+ * \ingroup lib
+ *
+ * This lib is used to check sequence number in data packets generated by
+ * IPerf or Ixia. It supports VLAN if packets are tagged.
+ *
+ * De-sequence is stored in traces (no assert is done).
+ *
+ * You can configure:
+ * - position of the sequence number in the packet,
+ * - Ethernet type to inspect.
+ *
+ * This lib has some limitations:
+ * - you can not ignore some packets: for example during an IPerf traffic, if
+ * they are some pings, they will be inspected. If there is video traffic, it
+ * will be inspected too,
+ * - having different kind of throughput at the same time is not possible: an
+ * IPerf, an Ixia and video. You can only configure for one throughput,
+ * - you can not specify the first sequence number value,
+ * - you can not specify the size/length of the sequence number,
+ * - it can not support VLAN and non VLAN traffic at the same time (sequence
+ * position is the same for both).
+ *
+ * This lib should only be enabled when needed as it will probably impact
+ * performance (it needs to inspect packets).
+ */
+
+#include "config/seq/check.h"
+
+#if CONFIG_SEQ_CHECK
+
+/**
+ * Callback used when there is a de-sequencing in the packets.
+ * \param user an user pointer
+ * \param vlan the VLAN id which in the packet or 0 if there is none
+ * \param seq_expected the sequence number expected
+ * \param seq_actual the sequence actually in the packet
+ *
+ * This function is called by lib_seq_check_packet when there the sequence
+ * number is not the one expected.
+ */
+typedef void
+(*lib_seq_check_error_cb_t) (void *user, uint vlan, uint seq_expected,
+ uint seq_actual);
+
+/**
+ * Ethernet type IP.
+ */
+#define SEQ_CHECK_ET_IP 0x8000
+
+/**
+ * Sequence counters.
+ * This structure is used to store states of the sequence counter. There is
+ * one for each VLAN.
+ */
+typedef struct lib_seq_check_t
+{
+ /**
+ * Sequence counters, for each VLAN id.
+ * \note if no VLAN is present on frames, first index of the table is
+ * used. There should be no problem, as VLAN 0 is for management.
+ */
+ uint seq[CONFIG_SEQ_CHECK_VLAN_MAX];
+ /**
+ * Callback when sequence is wrong.
+ */
+ lib_seq_check_error_cb_t cb;
+ /**
+ * The user pointer used when calling the callback.
+ */
+ void *cb_user;
+} lib_seq_check_t;
+
+/**
+ * Configuration structure.
+ */
+typedef struct lib_seq_check_config_t
+{
+ /**
+ * Sequence number size.
+ * It only support 16 for the moment.
+ */
+ u8 seq_size;
+ /**
+ * Position of the sequence number in the packet.
+ * The position start at first bit of the Ethernet frame.
+ * This counter is expressed in byte.
+ */
+ uint seq_pos;
+ /**
+ * Ethernet type the packet has to have.
+ */
+ uint ethertype;
+} lib_seq_check_config_t;
+
+BEGIN_DECLS
+
+/**
+ * Configure lib sequencer check.
+ * \param config the new configuration structure to use.
+ *
+ * All fields are copied to the configuration. If you only want to setup one
+ * field, you need to use lib_seq_check_config_get before.
+ */
+void
+lib_seq_check_config_set (lib_seq_check_config_t *config);
+
+/**
+ * Get current configuration.
+ * \param config a configuration which will be set to the current one of the
+ * sequencer check of the lib.
+ */
+void
+lib_seq_check_config_get (lib_seq_check_config_t *config);
+
+/**
+ * Initialize lib sequencer check configuration.
+ * You need to do this only one time in the life of the station.
+ */
+void
+lib_seq_check_config_init (void);
+
+/**
+ * Initialize lib sequencer check.
+ * \param ctx the context to initialize
+ * \param cb the callback to use when there is an problem of sequence in the
+ * packet
+ * \param user an user pointer used when calling the callback
+ *
+ * This need to be done for each entry point to inspect.
+ */
+void
+lib_seq_check_init (lib_seq_check_t *ctx, lib_seq_check_error_cb_t cb,
+ void *user);
+
+/**
+ * Data packet to inspect.
+ * \param ctx the context of lib seq check
+ * \param buffer the packet buffer
+ * \param len the packet length (in byte)
+ * \return true if there is a de-sequencing in the packet and callback was
+ * called, false otherwise (this include packets which can not be inspected).
+ */
+bool
+lib_seq_check_packet (lib_seq_check_t *ctx, u8 *buffer, uint len);
+
+END_DECLS
+
+#else /* !CONFIG_SEQ_CHECK */
+
+# define lib_seq_check_config_get() ((void) 0)
+# define lib_seq_check_config_set() ((void) 0)
+# define lib_seq_check_config_init() ((void) 0)
+# define lib_seq_check_init(args...) ((void) 0)
+# define lib_seq_check_packet(args...) ((void) 0)
+
+#endif /* !CONFIG_SEQ_CHECK */
+
+#endif /* lib_seq_check_h */
diff --git a/cesar/lib/src/seq_check.c b/cesar/lib/src/seq_check.c
new file mode 100644
index 0000000000..5b7d0a1e01
--- /dev/null
+++ b/cesar/lib/src/seq_check.c
@@ -0,0 +1,154 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file lib/src/seq_check.c
+ * \brief Check sequence number in data packets
+ * \ingroup lib
+ *
+ *
+ */
+#include "common/std.h"
+#include "lib/bitstream.h"
+#include "lib/swap.h"
+#include "lib/stats.h"
+
+#include "config/seq/check/vlan/max.h"
+
+#include "lib/seq_check.h"
+
+/**
+ * Ethernet type VLAN ID.
+ */
+#define SEQ_CHECK_ET_VLAN 0x8100
+
+lib_seq_check_config_t lib_seq_check_config;
+
+void
+lib_seq_check_config_set (lib_seq_check_config_t *config)
+{
+ dbg_assert (config);
+ /* Set configuration. */
+ lib_seq_check_config = *config;
+}
+
+void
+lib_seq_check_config_get (lib_seq_check_config_t *config)
+{
+ dbg_assert (config);
+ /* Get configuration. */
+ *config = lib_seq_check_config;
+}
+
+void
+lib_seq_check_config_init (void)
+{
+ /* Set default configuration. */
+ lib_seq_check_config_t config =
+ {
+ .seq_size = 16,
+ .seq_pos = 44, /* For IPerf. */
+ .ethertype = SEQ_CHECK_ET_IP, /* No check for Ethernet type. */
+ };
+ lib_seq_check_config_set (&config);
+
+ /* Register our configuration item. */
+ lib_stats_set_stat_value_notype ("SEQ_CHECK_SEQ_POS",
+ &lib_seq_check_config.seq_pos,
+ LIB_STATS_ACCESS_READ_WRITE,
+ LIB_STATS_DEBUG);
+ lib_stats_set_stat_value_notype ("SEQ_CHECK_ETHERTYPE",
+ &lib_seq_check_config.ethertype,
+ LIB_STATS_ACCESS_READ_WRITE,
+ LIB_STATS_DEBUG);
+}
+
+void
+lib_seq_check_init (lib_seq_check_t *ctx, lib_seq_check_error_cb_t cb,
+ void *user)
+{
+ /* Check parameters. */
+ dbg_assert (ctx);
+ dbg_assert (cb);
+
+ uint i;
+ /* Initialize sequence number to 0. */
+ for (i = 0; i < CONFIG_SEQ_CHECK_VLAN_MAX; i++)
+ {
+ ctx->seq[i] = 0;
+ }
+ ctx->cb = cb;
+ ctx->cb_user = user;
+}
+
+bool
+lib_seq_check_packet (lib_seq_check_t *ctx, u8 *buffer, uint len)
+{
+ /* Check parameter. */
+ dbg_assert (ctx);
+
+ bool result = false;
+
+ /* Get Ethernet type (after SRC & DST MAC (6 bytes each)). */
+ uint ethertype = swap16 (bitstream_direct_read (buffer, 6 * 8 * 2, 2 *
+ 8));
+
+ /* Position of sequence counter index in the table. */
+ uint seq_index = 0;
+
+ /* VLAN in used? */
+ if (ethertype == SEQ_CHECK_ET_VLAN)
+ {
+ /* VLAN id on 12 bits. VLAN id is located after SRC & DST (6 bytes
+ * each) & VLAN/IEEE_802.1Q fields (TPID + PCP + CFI = 20 bits). But
+ * we can only get on 2 bytes. We need to get TCI field (PCP, CFI &
+ * VID). */
+ seq_index = swap16 (bitstream_direct_read (buffer, (6 * 2 + 2) * 8,
+ 16));
+ /* Remove PCP & CFI. */
+ seq_index &= (0xFFFF >> 4);
+ dbg_assert (seq_index < CONFIG_SEQ_CHECK_VLAN_MAX);
+
+ /* Get real Ethernet type, located after SRC & DST (6 bytes each) and
+ * VLAN/IEEE_802.1Q fields (4 bytes). */
+ ethertype = swap16 (bitstream_direct_read (buffer, (6 + 6 + 4) * 8,
+ 2 * 8));
+ }
+
+ /* If this is the expected ethertype. */
+ if (lib_seq_check_config.ethertype
+ && ethertype == lib_seq_check_config.ethertype)
+ {
+
+ /* Get sequence value. */
+ dbg_assert (lib_seq_check_config.seq_size == 16);
+ uint received_seq = swap16 (
+ bitstream_direct_read (buffer, lib_seq_check_config.seq_pos * 8,
+ lib_seq_check_config.seq_size));
+
+ /* Handle overflow. */
+ ctx->seq[seq_index] &= BITS_ONES (lib_seq_check_config.seq_size);
+
+ /* Check. */
+ if (ctx->seq[seq_index] != received_seq)
+ {
+ /* Call callback. */
+ dbg_assert (ctx->cb);
+ (*ctx->cb) (ctx->cb_user, seq_index, ctx->seq[seq_index],
+ received_seq);
+ /* Reset. */
+ ctx->seq[seq_index] = received_seq;
+ result = true;
+ }
+
+ /* Increment. */
+ ctx->seq[seq_index]++;
+ }
+
+ /* Return result. */
+ return result;
+}
diff --git a/cesar/lib/src/utils.c b/cesar/lib/src/utils.c
new file mode 100644
index 0000000000..4ca7b39654
--- /dev/null
+++ b/cesar/lib/src/utils.c
@@ -0,0 +1,42 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file lib/src/utils.c
+ * \brief Common utilities.
+ * \ingroup lib
+ */
+#include "common/std.h"
+
+/* See
+ * http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
+ */
+bool
+almost_eqf (float a, float b, int max_ulps)
+{
+ union
+ {
+ float f;
+ s32 i;
+ } aInt, bInt;
+ /* Make sure max_ulps is non-negative and small enough that the default
+ * NAN won't compare as equal to anything. */
+ dbg_assert (max_ulps > 0 && max_ulps < 4 * 1024 * 1024);
+ aInt.f = a;
+ /* Make aInt lexicographically ordered as a twos-complement int. */
+ if (aInt.i < 0)
+ aInt.i = 0x80000000 - aInt.i;
+ /* Make bInt lexicographically ordered as a twos-complement int. */
+ bInt.f = b;
+ if (bInt.i < 0)
+ bInt.i = 0x80000000 - bInt.i;
+ s32 intDiff = ABS (aInt.i - bInt.i);
+ if (intDiff <= max_ulps)
+ return true;
+ return false;
+}
+
diff --git a/cesar/lib/test/fixed/src/test_fixed.c b/cesar/lib/test/fixed/src/test_fixed.c
index 9b3ff3a8c8..15fe7ca3e0 100644
--- a/cesar/lib/test/fixed/src/test_fixed.c
+++ b/cesar/lib/test/fixed/src/test_fixed.c
@@ -36,30 +36,30 @@
void
asm_fixed_mul (void)
{
- volatile s32 a, b, r;
- volatile uint shift;
+ volatile s32 a = 0, b = 0, r;
+ volatile uint shift = 0;
r = fixed_mul (a, b, shift);
}
void
asm_fixed_mul_2 (void)
{
- volatile s32 a, b, r;
+ volatile s32 a = 0, b = 0, r;
r = fixed_mul (a, b, 24);
}
void
asm_fixed_div (void)
{
- volatile s32 a, b, r;
- volatile uint shift;
+ volatile s32 a = 0, b = 0, r;
+ volatile uint shift = 0;
r = fixed_div (a, b, shift);
}
void
asm_fixed_div_2 (void)
{
- volatile s32 a, b, r;
+ volatile s32 a = 0, b = 0, r;
r = fixed_div (a, b, 24);
}
diff --git a/cesar/lib/test/heap/src/test_heap.c b/cesar/lib/test/heap/src/test_heap.c
index 20e0d9ac14..b9be79feff 100644
--- a/cesar/lib/test/heap/src/test_heap.c
+++ b/cesar/lib/test/heap/src/test_heap.c
@@ -94,7 +94,9 @@ heap_check (test_t t, heap_t *heap)
static void
heap_stats (test_t t, heap_t *heap, uint *min, uint *max, unsigned long long *sum)
{
+#if CONFIG_HEAP_LEFTIST
test_within (t);
+#endif
heap_node_t *n;
uint path_length;
#if CONFIG_HEAP_LEFTIST
diff --git a/cesar/lib/test/mbox/src/mbox.c b/cesar/lib/test/mbox/src/mbox.c
index eea3155bd5..84fb090f1b 100644
--- a/cesar/lib/test/mbox/src/mbox.c
+++ b/cesar/lib/test/mbox/src/mbox.c
@@ -87,11 +87,11 @@ thread2_entry_function(cyg_addrword_t data)
mbox_nb = mbox_peek (&mbox);
mbox_uninit (&mbox);
- blk_print_memory ();
test_init (test, 0, NULL);
test_begin (test, "Mailbox")
{
+ test_fail_if (blk_check_memory() == false, "Memory not freed");
test_fail_unless (nb_msg == 10);
test_fail_unless (mbox_nb == 0);
}
diff --git a/cesar/lib/test/seq_check/Config b/cesar/lib/test/seq_check/Config
new file mode 100644
index 0000000000..aab2ba7dab
--- /dev/null
+++ b/cesar/lib/test/seq_check/Config
@@ -0,0 +1,2 @@
+CONFIG_SEQ_CHECK = y
+CONFIG_STATS = n
diff --git a/cesar/lib/test/seq_check/Makefile b/cesar/lib/test/seq_check/Makefile
new file mode 100644
index 0000000000..a74fa304d6
--- /dev/null
+++ b/cesar/lib/test/seq_check/Makefile
@@ -0,0 +1,8 @@
+BASE = ../../..
+
+HOST_PROGRAMS = test_seq_check
+
+test_seq_check_SOURCES = seq_check.c
+test_seq_check_MODULES = lib
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/lib/test/seq_check/src/seq_check.c b/cesar/lib/test/seq_check/src/seq_check.c
new file mode 100644
index 0000000000..574f98f017
--- /dev/null
+++ b/cesar/lib/test/seq_check/src/seq_check.c
@@ -0,0 +1,250 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file lib/test/seq_check/src/seq_check.c
+ * \brief Sequence check test
+ * \ingroup test
+ *
+ * Test sequencer check.
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/seq_check.h"
+#include "common/defs/ethernet.h"
+#include "lib/rnd.h"
+#include "lib/bitstream.h"
+#include "lib/swap.h"
+
+/* Test structure to use with the callback. */
+typedef struct test_seq_check_callback_t
+{
+ struct test_t *test;
+ bool cb_called;
+ uint vlan;
+ uint seq_expected;
+ uint seq_actual;
+} test_seq_check_callback_t;
+
+void
+test_seq_check_write_ethertype (u8 *p, u16 ethertype, bool vlan)
+{
+ /* Store ethertype. */
+ uint pos = 6 * 2 * 8;
+ if (vlan)
+ {
+ bitstream_direct_write (p, pos, swap16 (0x8100), 16);
+ pos += 4 * 8;
+ }
+ bitstream_direct_write (p, pos, swap16 (ethertype), 16);
+}
+
+void
+test_seq_check_cb (void *user, uint vlan, uint seq_expected, uint seq_actual)
+{
+ dbg_assert (user);
+ test_seq_check_callback_t *test_seq_check_callback_values
+ = (test_seq_check_callback_t *) user;
+
+ test_within (test_seq_check_callback_values->test);
+ test_fail_if (test_seq_check_callback_values->vlan != vlan);
+ test_fail_if (test_seq_check_callback_values->seq_expected !=
+ seq_expected);
+ test_fail_if (test_seq_check_callback_values->seq_actual != seq_actual);
+ test_seq_check_callback_values->cb_called = true;
+}
+
+void
+test_seq_check_packet (test_t t, lib_rnd_t *rnd, uint pos, u16 ethertype)
+{
+ lib_seq_check_t s;
+ uint i;
+ u32 p[ETH_PACKET_MAX_SIZE];
+ bool res;
+ test_seq_check_callback_t test_seq_check_callback_values;
+ test_seq_check_callback_values.test = t;
+
+ /* Set configuration. */
+ lib_seq_check_config_t conf;
+ lib_seq_check_config_get (&conf);
+ conf.seq_pos = pos;
+ conf.ethertype = ethertype;
+ lib_seq_check_config_set (&conf);
+
+ test_begin (t, "config")
+ {
+ lib_seq_check_config_get (&conf);
+ test_fail_if (conf.seq_pos != pos);
+ test_fail_if (conf.ethertype != ethertype);
+ } test_end;
+
+ test_begin (t, "init")
+ {
+ lib_seq_check_init (&s, test_seq_check_cb,
+ &test_seq_check_callback_values);
+
+ for (i = 0; i < CONFIG_SEQ_CHECK_VLAN_MAX; i++)
+ {
+ test_fail_if (s.seq[i] != 0);
+ }
+ } test_end;
+
+ test_begin (t, "good sequence")
+ {
+ /* Store ethertype. */
+ test_seq_check_write_ethertype ((u8 *) p, ethertype, false);
+ for (i = 0; i < 1 << 16; i++)
+ {
+ bitstream_direct_write (p, pos * 8, swap16 (i), 16);
+ test_seq_check_callback_values.cb_called = false;
+ lib_seq_check_packet (&s, (u8 *) p, ETH_PACKET_MAX_SIZE);
+ test_fail_if (test_seq_check_callback_values.cb_called == true);
+ }
+ } test_end;
+
+ test_begin (t, "good and bad sequence")
+ {
+ u16 seq, prev;
+
+ /* Re-init. */
+ lib_seq_check_init (&s, test_seq_check_cb,
+ &test_seq_check_callback_values);
+ /* Store ethertype. */
+ test_seq_check_write_ethertype ((u8 *) p, ethertype, false);
+ for (seq = 0, i = 0; i < 1 << 16; i++, seq++)
+ {
+ if (lib_rnd_uniform (rnd, 2))
+ res = true;
+ else
+ {
+ prev = seq;
+ seq = lib_rnd_uniform (rnd, 1 << 16);
+ if (seq == prev)
+ seq++;
+ test_seq_check_callback_values.vlan = 0;
+ test_seq_check_callback_values.seq_expected = prev;
+ test_seq_check_callback_values.seq_actual = seq;
+ res = false;
+ }
+ test_seq_check_callback_values.cb_called = false;
+ bitstream_direct_write (p, pos * 8, swap16 (seq), 16);
+ lib_seq_check_packet (&s, (u8 *) p, ETH_PACKET_MAX_SIZE);
+ test_fail_if (test_seq_check_callback_values.cb_called == res);
+ }
+ } test_end;
+
+ test_begin (t, "good sequence with VLAN")
+ {
+ u16 seq[CONFIG_SEQ_CHECK_VLAN_MAX];
+
+ /* Re-init. */
+ lib_seq_check_init (&s, test_seq_check_cb,
+ &test_seq_check_callback_values);
+ /* Store ethertype. */
+ test_seq_check_write_ethertype ((u8 *) p, ethertype, true);
+
+ for (i = 0; i < CONFIG_SEQ_CHECK_VLAN_MAX; i ++)
+ {
+ seq[i] = 0;
+ }
+
+ for (i = 0; i < (1 << 16) * CONFIG_SEQ_CHECK_VLAN_MAX ; i++)
+ {
+ /* Get a random VLAN. */
+ uint vlan = lib_rnd_uniform (rnd, CONFIG_SEQ_CHECK_VLAN_MAX);
+ /* Write VLAN. */
+ bitstream_direct_write ((u8 *) p, 6 * 2 * 8 + 16, swap16 (vlan),
+ 16);
+
+ test_seq_check_callback_values.cb_called = false;
+ bitstream_direct_write (p, pos * 8, swap16 (seq[vlan]), 16);
+ lib_seq_check_packet (&s, (u8 *) p, ETH_PACKET_MAX_SIZE);
+ test_fail_if (test_seq_check_callback_values.cb_called == true);
+ seq[vlan]++;
+ }
+ } test_end;
+
+ test_begin (t, "good and bad sequence with VLAN")
+ {
+ u16 seq[CONFIG_SEQ_CHECK_VLAN_MAX], prev;
+
+ /* Re-init. */
+ lib_seq_check_init (&s, test_seq_check_cb,
+ &test_seq_check_callback_values);
+ /* Store ethertype. */
+ test_seq_check_write_ethertype ((u8 *) p, ethertype, true);
+
+ for (i = 0; i < CONFIG_SEQ_CHECK_VLAN_MAX; i ++)
+ {
+ seq[i] = 0;
+ }
+
+ for (i = 0; i < (1 << 16) * CONFIG_SEQ_CHECK_VLAN_MAX ; i++)
+ {
+ /* Get a random VLAN. */
+ uint vlan = lib_rnd_uniform (rnd, CONFIG_SEQ_CHECK_VLAN_MAX);
+ /* Write VLAN. */
+ bitstream_direct_write ((u8 *) p, 6 * 2 * 8 + 16, swap16 (vlan),
+ 16);
+
+ if (lib_rnd_uniform (rnd, 2))
+ res = true;
+ else
+ {
+ prev = seq[vlan];
+ seq[vlan] = lib_rnd_uniform (rnd, 1 << 16);
+ if (seq[vlan] == prev)
+ seq[vlan]++;
+ test_seq_check_callback_values.vlan = vlan;
+ test_seq_check_callback_values.seq_expected = prev;
+ test_seq_check_callback_values.seq_actual = seq[vlan];
+ res = false;
+ }
+ test_seq_check_callback_values.cb_called = false;
+ bitstream_direct_write (p, pos * 8, swap16 (seq[vlan]), 16);
+ lib_seq_check_packet (&s, (u8 *) p, ETH_PACKET_MAX_SIZE);
+ test_fail_if (test_seq_check_callback_values.cb_called == res);
+ seq[vlan]++;
+ }
+ } test_end;
+}
+
+int
+main (int argc, char **argv)
+{
+ lib_rnd_t rnd;
+ test_t test;
+
+ lib_rnd_init (&rnd, 0x42);
+ test_init (test, argc, argv);
+
+ test_suite_begin (test, "sequence check");
+
+ lib_seq_check_config_init ();
+
+ test_begin (test, "default config")
+ {
+ lib_seq_check_config_t conf;
+ lib_seq_check_config_get (&conf);
+ test_fail_if (conf.seq_size != 16);
+ test_fail_if (conf.seq_pos != 44);
+ test_fail_if (conf.ethertype != 0x8000);
+ } test_end;
+
+ test_case_begin (test, "IPerf");
+ /* Iperf position is at 44 and we check only IP packet. */
+ test_seq_check_packet (test, &rnd, 44, 0x8000);
+
+ test_case_begin (test, "Other");
+ /* Iperf position is at 44 and we check only IP packet. */
+ test_seq_check_packet (test, &rnd, 50, 0x8042);
+
+ test_result (test);
+ return test_nb_failed (test);
+}
+
diff --git a/cesar/lib/test/utils/src/test_utils.c b/cesar/lib/test/utils/src/test_utils.c
index 8b7beab993..751a518b65 100644
--- a/cesar/lib/test/utils/src/test_utils.c
+++ b/cesar/lib/test/utils/src/test_utils.c
@@ -13,6 +13,55 @@
#include "common/std.h"
#include "lib/test.h"
+#include "float.h"
+#include "math.h"
+
+void
+eq_test_case (test_t t)
+{
+ test_case_begin (t, "eq");
+ test_begin (t, "almost_eqf basic")
+ {
+ test_fail_unless (almost_eqf (1.0f, 1.0f, 1));
+ test_fail_unless (!almost_eqf (1.0f, 2.0f, 1));
+ test_fail_unless (!almost_eqf (1000.0f, 2000.0f, 1));
+ /* FLT_EPSILON is the smallest number for which:
+ * 1.0f != 1.0f + FLT_EPSILON. */
+ test_fail_unless (almost_eqf (1.0f, 1.0f + FLT_EPSILON, 1));
+ test_fail_unless (!almost_eqf (1.0f, 1.0f + FLT_EPSILON * 2, 1));
+ test_fail_unless (almost_eqf (1.0f, 1.0f + FLT_EPSILON * 2, 2));
+ test_fail_unless (almost_eqf (512.f, 512.f + 512 * FLT_EPSILON, 1));
+ test_fail_unless (!almost_eqf (512.f, 512.f + 1024 * FLT_EPSILON, 1));
+ test_fail_unless (almost_eqf (512.f, 512.f + 1024 * FLT_EPSILON, 2));
+ } test_end;
+ test_begin (t, "almost_eqf zeroes")
+ {
+ /* IEEE floats are ordered. Compute the smallest non-zero positive and
+ * negative number. Those are subnormals. */
+ float ep = 0.0f;
+ s32 epb = *(s32 *)&ep + 1;
+ ep = *(float *) &epb;
+ float em = -0.0f;
+ s32 emb = *(s32 *)&em + 1;
+ em = *(float *) &emb;
+ /* Test around zero. */
+ test_fail_unless (almost_eqf (0.0f, -0.0f, 1));
+ test_fail_unless (almost_eqf (ep, em, 2));
+ test_fail_unless (!almost_eqf (ep, em, 1));
+ } test_end;
+ test_begin (t, "almost_eqf infinity")
+ {
+ /* Accepted complication. */
+ test_fail_unless (almost_eqf (INFINITY, FLT_MAX, 1));
+ test_fail_unless (almost_eqf (-INFINITY, -FLT_MAX, 1));
+ } test_end;
+ test_begin (t, "almost_eqf NaN")
+ {
+ test_fail_unless (!almost_eqf (NAN, 1.0f, 1));
+ /* Accepted complication. */
+ test_fail_unless (almost_eqf (NAN, NAN, 1));
+ } test_end;
+}
void
bits_test_case (test_t t)
@@ -229,6 +278,7 @@ void
utils_test_suite (test_t t)
{
test_suite_begin (t, "utils");
+ eq_test_case (t);
bits_test_case (t);
bf_test_case (t);
rot_test_case (t);
diff --git a/cesar/lib/utils.h b/cesar/lib/utils.h
index 5d0c237c37..c3229f27ce 100644
--- a/cesar/lib/utils.h
+++ b/cesar/lib/utils.h
@@ -341,4 +341,16 @@ distance_mod2p16 (u16 a, u16 b)
index = a_; \
} while (0)
+BEGIN_DECLS
+
+/** Compare floating point numbers, return true if they are almost equal.
+ * \param a first number to compare
+ * \param b second number to compare
+ * \param max_ulps maximum error as unit in the last place
+ */
+bool
+almost_eqf (float a, float b, int max_ulps);
+
+END_DECLS
+
#endif /* lib_utils_h */