Remove kernel datapath unit tests.

The tests haven't been seeing much love and are suffering from bit-rot at
this point.  We're removing them, since we have other ways to test at
this point.
This commit is contained in:
Justin Pettit committed 2008-09-26 14:58:33 -07:00
1 parent a3f9fd8581
commit 0fab7c69ae
15 files changed
+4 -1920

No files matched your search

-1
View File
@@ -72,7 +72,6 @@ utilities/Makefile
secchan/Makefile
switch/Makefile
tests/Makefile
datapath/tests/Makefile
third-party/Makefile
debian/Makefile
datapath/linux-2.6/Kbuild
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = tests
SUBDIRS =
if L26_ENABLED
SUBDIRS += linux-2.6
endif
+3 -11
View File
@@ -1,5 +1,5 @@
all_modules = $(dist_modules)
dist_modules = openflow unit
dist_modules = openflow
openflow_sources = \
chain.c \
@@ -10,8 +10,7 @@ openflow_sources = \
flow.c \
forward.c \
table-hash.c \
table-linear.c \
unit-exports.c
table-linear.c
openflow_headers = \
chain.h \
@@ -22,14 +21,7 @@ openflow_headers = \
flow.h \
forward.h \
snap.h \
table.h \
unit.h
unit_sources = \
crc_t.c \
forward_t.c \
table_t.c \
unit.c
table.h
dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
-47
View File
@@ -1,47 +0,0 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007, 2008 The Board of Trustees of The Leland
* Stanford Junior University
*/
#include <linux/string.h>
#include <linux/kernel.h>
#include "crc32.h"
#include "unit.h"
static void
print_error(unsigned int poly, char *data,
unsigned int expected, unsigned int calculated)
{
unit_fail("crc error: poly=%x data=%s expected=%x calculated=%x\n",
poly, data, expected, calculated);
}
void
run_crc_t(void)
{
struct crc32 crc;
unsigned int val, i, j;
char *data[3] = { "h3rei$@neX@mp13da7@sTr117G0fCH@r$",
"1324lkqasdf0-[LKJD0;asd,.cv;/asd0:\"'~`co29",
"6" };
unsigned int polys[2] = { 0x04C11DB7,
0x1EDC6F41 };
unsigned int crc_values[2][3] = {
{ 0xDE1040C3, 0x65343A0B, 0xCEB42022 },
{ 0x6C149FAE, 0x470A6B73, 0x4D3AA134 } };
for (i = 0; i < 2; i++) {
crc32_init(&crc, polys[i]);
for (j = 0; j < 3; j++) {
val = crc32_calculate(&crc, data[j], strlen(data[j]));
if (val != crc_values[i][j]) {
print_error(polys[i], data[j], crc_values[i][j], val);
}
}
}
}
-584
View File
@@ -1,584 +0,0 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007, 2008 The Board of Trustees of The Leland
* Stanford Junior University
*/
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/random.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include "forward.h"
#include "tests/forward_t.h"
#include "openflow.h"
#include "unit.h"
#include "flow.h"
/*
* Tests execute_settings() in forward.c to check that actions are
* appropriately taken on packets, meaning:
*
* 1. Checksums are correct.
* 2. Actions are only taken on compatible packets (IP action not taken on
* non-IP packet)
* 3. Other packet data remains untouched.
* forward_t.h contains static packet definitions. forward_t.h should be
* generated using gen_forward_t.c. This test is run on whatever packets are
* defined in forward_t.h.
*
* NOTE: Tests assume packets in forward_t.h are present in full and IP and
* transport checksums are correct. (Can prevent offloading of checksum
* computation using ethtool.
*/
/*
* Sets 'a->data'. If 'key' != NULL, sets 'data' to equal 'key's value for type
* specified by 'a->type'. If 'key' == NULL, sets data to a random value.
*/
static void
set_action_data(struct sk_buff *skb, struct sw_flow_key *key, struct ofp_action *a)
{
if (key != NULL) {
switch(ntohs(a->type)) {
case(OFPAT_SET_DL_SRC):
memcpy(a->arg.dl_addr, key->dl_src, sizeof key->dl_src);
break;
case(OFPAT_SET_DL_DST):
memcpy(a->arg.dl_addr, key->dl_dst, sizeof key->dl_dst);
break;
case(OFPAT_SET_NW_SRC):
if (key->dl_type == htons(ETH_P_IP))
a->arg.nw_addr = key->nw_src;
else
a->arg.nw_addr = random32();
break;
case(OFPAT_SET_NW_DST):
if (key->dl_type == htons(ETH_P_IP))
a->arg.nw_addr = key->nw_dst;
else
a->arg.nw_addr = random32();
break;
case(OFPAT_SET_TP_SRC):
if (key->nw_proto == IPPROTO_TCP || key->nw_proto == IPPROTO_UDP)
a->arg.tp = key->tp_src;
else
a->arg.tp = (uint16_t) random32();
break;
case(OFPAT_SET_TP_DST):
if (key->nw_proto == IPPROTO_TCP || key->nw_proto == IPPROTO_UDP)
a->arg.tp = key->tp_dst;
else
a->arg.tp = (uint16_t) random32();
break;
default:
BUG();
}
} else {
((uint32_t*)a->arg.dl_addr)[0] = random32();
((uint16_t*)a->arg.dl_addr)[2] = random32();
}
}
/*
* Checks the IP sum of an IP packet. Returns 0 if correct, else -1.
*/
static void
check_IP_csum(struct iphdr *ih)
{
uint16_t check, *data;
uint32_t n_bytes, sum;
check = ih->check;
ih->check = 0;
data = (uint16_t*) ih;
sum = 0;
n_bytes = ih->ihl * 4;
while (n_bytes > 1) {
sum += ntohs(*data);
sum = (sum >> 16) + (uint16_t)sum;
data++;
n_bytes -= 2;
}
if (n_bytes == 1) {
sum += *(uint8_t*)data;
sum = (sum >> 16) + (uint16_t)sum;
}
ih->check = htons((uint16_t)(~sum));
if (ih->check != check) {
unit_fail("IP checksum %hu does not match %hu",
ntohs(ih->check), ntohs(check));
}
}
/*
* Partially computes TCP checksum over 'n_bytes' pointed to by 'data'. Can be
* called multiple times if data csum is to be computed on is fragmented. If
* 'is_last' == 0, assumes will be called again on more data and returns the
* value that should be passed in as 'incr_sum' on the next call. Else if
* 'is_last' == 1, returns the final checksum. On the first call, 'incr_sum'
* should equal 0. If 'is_last' == 0, 'n_bytes' must be even. i.e. Should
* first be called on pseudo header fields that are multiples of two, and then
* on the TCP packet.
*/
static uint32_t
compute_transport_checksum(uint16_t *data, uint32_t n_bytes,
uint32_t incr_sum, uint8_t is_last)
{
uint8_t arr[2];
if (n_bytes % 2 != 0 && is_last == 0)
BUG();
while (n_bytes > 1) {
incr_sum += ntohs(*data);
incr_sum = (incr_sum >> 16) + (uint16_t)incr_sum;
data++;
n_bytes -= 2;
}
if (is_last == 0)
return incr_sum;
if(n_bytes == 1) {
arr[0] = *(uint8_t*)data;
arr[1] = 0;
incr_sum += ntohs(*((uint16_t*)arr));
incr_sum = (incr_sum >> 16) + (uint16_t)incr_sum;
}
return ~incr_sum;
}
/*
* Checks the transport layer's checksum of a packet. Returns '0' if correct,
* else '1'. 'ih' should point to the IP header of the packet, if TCP, 'th'
* should point the TCP header, and if UDP, 'uh' should point to the UDP
* header.
*/
static int
check_transport_csum(struct iphdr *ih, struct tcphdr *th,
struct udphdr *uh)
{
uint32_t tmp;
uint16_t len, check;
uint8_t arr[2];
tmp = compute_transport_checksum((uint16_t*)(&ih->saddr),
2 * sizeof ih->saddr, 0, 0);
arr[0] = 0;
arr[1] = ih->protocol;
tmp = compute_transport_checksum((uint16_t*)arr, 2, tmp, 0);
len = ntohs(ih->tot_len) - (ih->ihl * 4);
*((uint16_t*)arr) = htons(len);
tmp = compute_transport_checksum((uint16_t*)arr, 2, tmp, 0);
if (th != NULL) {
check = th->check;
th->check = 0;
th->check = htons((uint16_t)compute_transport_checksum((uint16_t*)th,
len, tmp, 1));
if (th->check != check) {
unit_fail("TCP checksum %hu does not match %hu",
ntohs(th->check), ntohs(check));
return -1;
}
} else if (uh != NULL) {
check = uh->check;
uh->check = 0;
uh->check = htons((uint16_t)compute_transport_checksum((uint16_t*)uh,
len, tmp, 1));
if (uh->check != check) {
unit_fail("UDP checksum %hu does not match %hu",
ntohs(uh->check), ntohs(check));
return -1;
}
}
return 0;
}
/*
* Compares 'pkt_len' bytes of 'data' to 'pkt'. excl_start and excl_end point
* together delineate areas of 'data' that are not supposed to match 'pkt'.
* 'num_excl' specify how many such areas exist. An 'excl_start' entry is
* ignored if it equals NULL. See 'check_packet()' for usage.
*/
static void
compare(uint8_t *data, uint8_t *pkt, uint32_t pkt_len,
uint8_t **excl_start, uint8_t **excl_end, uint32_t num_excl)
{
uint32_t i;
uint8_t *d, *p, *end;
int ret;
end = data + pkt_len;
d = data;
p = pkt;
ret = 0;
for (i = 0; i < num_excl; i++) {
if(*excl_start != NULL) {
if ((ret = memcmp(d, p, *excl_start - d)) != 0)
break;
p += (*excl_end - d);
d = *excl_end;
}
excl_start++;
excl_end++;
}
if (ret == 0)
ret = memcmp(d, p, end - d);
if (ret != 0) {
unit_fail("skb and packet comparison failed:");
for (i = 0; i < pkt_len; i++) {
if (data[i] != pkt[i]) {
unit_fail("skb[%u] = 0x%x != 0x%x",
i, data[i], pkt[i]);
}
}
}
}
/*
* Checks that a packet's data has remained consistent after an action has been
* applied. 'skb' is the modified packet, 'a' is the action that was taken on
* the packet, 'p' is a copy of the packet's data before action 'a' was taken.
* Checks that the action was in fact taken, that the checksums of the packet
* are correct, and that no other data in the packet was altered.
*/
static void
check_packet(struct sk_buff *skb, struct ofp_action *a, struct pkt *p)
{
struct ethhdr *eh;
struct iphdr *ih;
struct tcphdr *th;
struct udphdr *uh;
uint8_t *excl_start[5], *excl_end[5];
eh = eth_hdr(skb);
ih = NULL;
th = NULL;
uh = NULL;
memset(excl_start, 0, sizeof excl_start);
memset(excl_end, 0, sizeof excl_end);
if (eh->h_proto == htons(ETH_P_IP)) {
ih = ip_hdr(skb);
excl_start[1] = (uint8_t*)&ih->check;
excl_end[1] = (uint8_t*)(&ih->check + 1);
if (ih->protocol == IPPROTO_TCP) {
th = tcp_hdr(skb);
excl_start[4] = (uint8_t*)&th->check;
excl_end[4] = (uint8_t*)(&th->check + 1);
} else if (ih->protocol == IPPROTO_UDP) {
uh = udp_hdr(skb);
excl_start[4] = (uint8_t*)&uh->check;
excl_end[4] = (uint8_t*)(&uh->check + 1);
}
}
if (a != NULL) {
switch(ntohs(a->type)) {
case(OFPAT_SET_DL_SRC):
if (memcmp(a->arg.dl_addr, eh->h_source, sizeof eh->h_source) != 0) {
unit_fail("Source eth addr has not been set");
return;
}
excl_start[0] = (uint8_t*)(&eh->h_source);
excl_end[0] = (uint8_t*)(&eh->h_proto);
break;
case(OFPAT_SET_DL_DST):
if (memcmp(a->arg.dl_addr, eh->h_dest, sizeof eh->h_dest) != 0) {
unit_fail("Dest eth addr has not been set");
return;
}
excl_start[0] = (uint8_t*)(&eh->h_dest);
excl_end[0] = (uint8_t*)(&eh->h_source);
break;
case(OFPAT_SET_NW_SRC):
if (ih != NULL) {
if (a->arg.nw_addr != ih->saddr) {
unit_fail("Source IP addr has not been set");
return;
}
excl_start[2] = (uint8_t*)(&ih->saddr);
excl_end[2] = (uint8_t*)(&ih->saddr + 1);
}
break;
case(OFPAT_SET_NW_DST):
if (ih != NULL) {
if (a->arg.nw_addr != ih->daddr) {
unit_fail("Dest IP addr has not been set");
return;
}
excl_start[2] = (uint8_t*)(&ih->daddr);
excl_end[2] = (uint8_t*)(&ih->daddr + 1);
}
break;
case(OFPAT_SET_TP_SRC):
if (th != NULL) {
if (a->arg.tp != th->source) {
unit_fail("Source port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&th->source);
excl_end[3] = (uint8_t*)(&th->source + 1);
} else if (uh != NULL) {
if (a->arg.tp != uh->source) {
unit_fail("Source port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&uh->source);
excl_end[3] = (uint8_t*)(&uh->source + 1);
}
break;
case(OFPAT_SET_TP_DST):
if (th != NULL) {
if (a->arg.tp != th->dest) {
unit_fail("Dest port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&th->dest);
excl_end[3] = (uint8_t*)(&th->dest + 1);
} else if (uh != NULL) {
if (a->arg.tp != uh->dest) {
unit_fail("Dest port has not been set");
return;
}
excl_start[3] = (uint8_t*)(&uh->dest);
excl_end[3] = (uint8_t*)(&uh->dest + 1);
}
break;
default:
BUG();
}
}
compare(skb->data, p->data, p->len, excl_start, excl_end, 5);
if (unit_failed())
return;
if (ih == NULL)
return;
check_IP_csum(ih);
if (unit_failed())
return;
if (th == NULL && uh == NULL)
return;
check_transport_csum(ih, th, uh);
}
/*
* Layers 3 & 4 Tests: Given packets in forward_t.h, executes all actions
* with random data, checking for consistency described in check_packet().
*/
void
test_l3_l4(void)
{
struct ofp_action action;
uint16_t a_type;
struct sk_buff *skb;
struct sw_flow_key key;
unsigned int i, j;
uint16_t eth_proto;
int ret = 0;
for (i = 0; i < num_packets; i++) {
skb = alloc_skb(packets[i].len, GFP_KERNEL);
if (!skb) {
unit_fail("Couldn't allocate %uth skb", i);
return;
}
memcpy(skb_put(skb, packets[i].len), packets[i].data,
packets[i].len);
skb_set_mac_header(skb, 0);
flow_extract(skb, 0, &key);
eth_proto = ntohs(key.dl_type);
check_packet(skb, NULL, packets+i);
if (unit_failed())
return;
for (a_type = OFPAT_SET_DL_SRC;
a_type <= OFPAT_SET_TP_DST;
a_type++)
{
action.type = htons(a_type);
set_action_data(skb, NULL, &action);
for(j = 0; j < 2; j++) {
skb = execute_setter(skb, eth_proto, &key, &action);
check_packet(skb, &action, packets+i);
if (unit_failed()) {
unit_fail("Packet %u inconsistent "
"after setter on action "
"type %d, iteration %u",
i, action.type, j);
return;
}
set_action_data(skb, &key, &action);
}
}
kfree_skb(skb);
if (ret != 0)
break;
}
if (ret == 0)
printk("\nL3/L4 actions test passed.\n");
}
int
test_vlan(void)
{
struct ofp_action action;
struct sk_buff *skb;
struct sw_flow_key key;
unsigned int i;
uint16_t eth_proto;
int ret = 0;
struct vlan_ethhdr *vh;
struct ethhdr *eh;
struct net_device dev;
uint16_t new_id, orig_id;
memset((char *)&dev, '\0', sizeof(dev));
printk("Testing vlan\n");
for (i = 0; i < num_packets; i++) {
skb = alloc_skb(packets[i].len, GFP_KERNEL);
if (!skb) {
unit_fail("Couldn't allocate %uth skb", i);
return -ENOMEM;
}
memcpy(skb_put(skb, packets[i].len), packets[i].data,
packets[i].len);
skb->dev = &dev;
skb_set_mac_header(skb, 0);
flow_extract(skb, 0, &key);
eth_proto = ntohs(key.dl_type);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum unmodified",
i);
goto free_skb;
}
#endif
eh = eth_hdr(skb);
orig_id = eh->h_proto;
action.type = htons(OFPAT_SET_VLAN_VID);
// Add a random vlan tag
new_id = (uint16_t) random32() & VLAN_VID_MASK;
action.arg.vlan_vid = new_id;
skb = execute_setter(skb, eth_proto, &key, &action);
vh = vlan_eth_hdr(skb);
if (ntohs(vh->h_vlan_TCI) != new_id) {
unit_fail("add: vlan id doesn't match: %#x != %#x",
ntohs(vh->h_vlan_TCI), new_id);
return -1;
}
flow_extract(skb, 0, &key);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after adding vlan",
i);
goto free_skb;
}
#endif
// Modify the tag
new_id = (uint16_t) random32() & VLAN_VID_MASK;
action.arg.vlan_vid = new_id;
skb = execute_setter(skb, eth_proto, &key, &action);
vh = vlan_eth_hdr(skb);
if (ntohs(vh->h_vlan_TCI) != new_id) {
unit_fail("mod: vlan id doesn't match: %#x != %#x",
ntohs(vh->h_vlan_TCI), new_id);
return -1;
}
flow_extract(skb, 0, &key);
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after modifying vlan",
i);
goto free_skb;
}
#endif
// Remove the tag
action.type = htons(OFPAT_STRIP_VLAN);
skb = execute_setter(skb, eth_proto, &key, &action);
eh = eth_hdr(skb);
if (eh->h_proto != orig_id) {
unit_fail("del: vlan id doesn't match: %#x != %#x",
ntohs(eh->h_proto), ntohs(orig_id));
return -1;
}
#if 0
if ((ret = check_packet(skb, NULL, packets+i)) < 0) {
unit_fail("Packet %u has incorrect checksum after removing vlan",
i);
goto free_skb;
}
free_skb:
#endif
kfree_skb(skb);
if (ret != 0)
break;
}
if (ret == 0)
printk("\nVLAN actions test passed.\n");
return ret;
}
/*
* Actual test: Given packets in forward_t.h, executes all actions with random
* data, checking for consistency described in check_packet().
*/
void
run_forward_t(void)
{
test_vlan();
test_l3_l4();
}
-874
View File
@@ -1,874 +0,0 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007, 2008 The Board of Trustees of The Leland
* Stanford Junior University
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/random.h>
#include <linux/rcupdate.h>
#include "flow.h"
#include "table.h"
#include "openflow.h"
#include "unit.h"
static const char *
table_name(struct sw_table *table)
{
struct sw_table_stats stats;
table->stats(table, &stats);
return stats.name;
}
static unsigned long int
table_max_flows(struct sw_table *table)
{
struct sw_table_stats stats;
table->stats(table, &stats);
return stats.max_flows;
}
static struct sw_flow *flow_zalloc(int n_actions, gfp_t flags)
{
struct sw_flow *flow = flow_alloc(n_actions, flags);
if (flow) {
struct sw_flow_actions *sfa = flow->sf_acts;
memset(flow, 0, sizeof *flow);
flow->sf_acts = sfa;
}
return flow;
}
static void
simple_insert_delete(struct sw_table *swt, uint32_t wildcards)
{
struct sw_flow *a_flow = flow_zalloc(0, GFP_KERNEL);
struct sw_flow *b_flow = flow_zalloc(0, GFP_KERNEL);
struct sw_flow *found;
if (!swt) {
unit_fail("table creation failed");
return;
}
printk("simple_insert_delete: testing %s table\n", table_name(swt));
*((uint32_t*)a_flow->key.dl_src) = 0x12345678;
*((uint32_t*)b_flow->key.dl_src) = 0x87654321;
a_flow->key.nw_src = 0xdeadbeef;
b_flow->key.nw_src = 0x001dd0d0;
a_flow->key.wildcards = wildcards;
b_flow->key.wildcards = wildcards;
if (!(swt->insert(swt, a_flow)))
unit_fail("insert failed");
found = swt->lookup(swt, &a_flow->key);
if(found != a_flow)
unit_fail("%p != %p", found, a_flow);
if (swt->lookup(swt, &b_flow->key))
unit_fail("lookup should not succeed (1)");
swt->delete(swt, &a_flow->key, 0, 0);
if (swt->lookup(swt, &a_flow->key))
unit_fail("lookup should not succeed (3)");
flow_free(b_flow);
swt->destroy(swt);
}
static void
multiple_insert_destroy(struct sw_table *swt, int inserts, uint32_t wildcards,
int min_collisions, int max_collisions)
{
int i;
int col = 0;
if (!swt) {
unit_fail("table creation failed");
return;
}
printk("inserting %d flows into %s table with max %lu flows: ",
inserts, table_name(swt), table_max_flows(swt));
for(i = 0; i < inserts; ++i){
struct sw_flow *a_flow = flow_zalloc(0, GFP_KERNEL);
*((uint32_t*)&(a_flow->key.dl_src[0])) = random32();
a_flow->key.nw_src = random32();
a_flow->key.wildcards = wildcards;
if(!swt->insert(swt, a_flow)) {
col++;
flow_free(a_flow);
}
}
printk("%d failures\n", col);
if (min_collisions <= col && col <= max_collisions)
printk("\tmin = %d <= %d <= %d = max, OK.\n",
min_collisions, col, max_collisions);
else {
if (col < min_collisions)
unit_fail("too few collisions (%d < %d)",
col, min_collisions);
else if (col > max_collisions)
unit_fail("too many collisions (%d > %d)",
col, max_collisions);
printk("(This is statistically possible "
"but should not occur often.)\n");
}
swt->destroy(swt);
}
static void
set_random_key(struct sw_flow_key *key, uint32_t wildcards)
{
key->nw_src = random32();
key->nw_dst = random32();
key->in_port = (uint16_t) random32();
key->dl_vlan = (uint16_t) random32();
key->dl_type = (uint16_t) random32();
key->tp_src = (uint16_t) random32();
key->tp_dst = (uint16_t) random32();
key->wildcards = wildcards;
*((uint32_t*)key->dl_src) = random32();
*(((uint32_t*)key->dl_src) + 1) = random32();
*((uint32_t*)key->dl_dst) = random32();
*(((uint32_t*)key->dl_dst) + 1) = random32();
key->nw_proto = (uint8_t) random32();
}
struct flow_key_entry {
struct sw_flow_key key;
struct list_head node;
};
/*
* Allocates memory for 'n_keys' flow_key_entrys. Initializes the allocated
* keys with random values, setting their wildcard values to 'wildcards', and
* places them all in a list. Returns a pointer to a flow_key_entry that
* serves solely as the list's head (its key has not been set). If allocation
* fails, returns NULL. Returned pointer should be freed with vfree (which
* frees the memory associated with the keys as well.)
*/
static struct flow_key_entry *
allocate_random_keys(int n_keys, uint32_t wildcards)
{
struct flow_key_entry *entries, *pos;
struct list_head *keys;
if (n_keys < 0)
return NULL;
entries = vmalloc((n_keys+1) * sizeof *entries);
if (entries == NULL) {
unit_fail("cannot allocate memory for %u keys",
n_keys);
return NULL;
}
keys = &entries->node;
INIT_LIST_HEAD(keys);
for(pos = entries+1; pos < (entries + n_keys + 1); pos++) {
set_random_key(&pos->key, wildcards);
list_add(&pos->node, keys);
}
return entries;
}
/*
* Attempts to insert the first 'n_flows' flow keys in list 'keys' into table
* 'swt', where 'keys' is a list of flow_key_entrys. key_entrys that are
* inserted into the table are removed from the 'keys' list and placed in
* 'added' list. Returns -1 if flow memory allocation fails, else returns the
* number of flows that were actually inserted (some attempts might fail due to
* collisions).
*/
static int
insert_flows(struct sw_table *swt, struct list_head *keys, struct list_head *added, int n_flows)
{
struct flow_key_entry *pos, *next;
int cnt;
cnt = 0;
list_for_each_entry_safe (pos, next, keys, node) {
struct sw_flow *flow = flow_zalloc(0, GFP_KERNEL);
if (flow == NULL) {
unit_fail("Could only allocate %u flows", cnt);
return -1;
}
flow->key = pos->key;
if (!swt->insert(swt, flow)) {
flow_free(flow);
list_del(&pos->node);
} else {
list_del(&pos->node);
list_add(&pos->node, added);
cnt++;
if (n_flows != -1 && cnt == n_flows)
break;
}
}
return cnt;
}
/*
* Finds and returns the flow_key_entry in list 'keys' matching the passed in
* flow's key. If not found, returns NULL.
*/
static struct flow_key_entry *
find_flow(struct list_head *keys, struct sw_flow *flow)
{
struct flow_key_entry *pos;
list_for_each_entry(pos, keys, node) {
if(!memcmp(&pos->key, &flow->key, sizeof(struct sw_flow_key)))
return pos;
}
return NULL;
}
/*
* Checks that all flow_key_entrys in list 'keys' return successful lookups on
* the table 'swt'.
*/
static int
check_lookup(struct sw_table *swt, struct list_head *keys)
{
struct flow_key_entry *pos;
list_for_each_entry(pos, keys, node) {
if(swt->lookup(swt, &pos->key) == NULL)
return -1;
}
return 0;
}
/*
* Checks that all flow_key_entrys in list 'keys' DO NOT return successful
* lookups in the 'swt' table.
*/
static int
check_no_lookup(struct sw_table *swt, struct list_head *keys)
{
struct flow_key_entry *pos;
list_for_each_entry(pos, keys, node) {
if(swt->lookup(swt, &pos->key) != NULL)
return -1;
}
return 0;
}
struct check_iteration_state
{
int n_found;
struct list_head *to_find;
struct list_head *found;
};
static int
check_iteration_callback(struct sw_flow *flow, void *private)
{
struct check_iteration_state *s = private;
struct flow_key_entry *entry;
entry = find_flow(s->to_find, flow);
if (entry == NULL) {
unit_fail("UNKNOWN ITERATOR FLOW %p", flow);
rcu_read_unlock();
return 1;
}
s->n_found++;
list_del(&entry->node);
list_add(&entry->node, s->found);
return 0;
}
/*
* Compares an iterator's view of the 'swt' table to the list of
* flow_key_entrys in 'to_find'. flow_key_entrys that are matched are removed
* from the 'to_find' list and placed in the 'found' list. Returns -1 if the
* iterator cannot be initialized or it encounters a flow with a key not in
* 'to_find'. Else returns the number of flows found by the iterator
* (i.e. there might still be flow keys in the 'to_find' list that were not
* encountered by the iterator. it is up to the caller to determine if that is
* acceptable behavior)
*/
static int
check_iteration(struct sw_table *swt, struct list_head *to_find, struct list_head *found)
{
struct sw_flow_key key;
struct sw_table_position position;
struct check_iteration_state state;
memset(&key, 0, sizeof key);
key.wildcards = -1;
memset(&position, 0, sizeof position);
state.n_found = 0;
state.to_find = to_find;
state.found = found;
rcu_read_lock();
swt->iterate(swt, &key, &position, check_iteration_callback, &state);
rcu_read_unlock();
return state.n_found;
}
/*
* Deletes from table 'swt' keys from the list of flow_key_entrys 'keys'.
* Removes flow_key_entrys of deleted flows from 'keys' and places them in the
* 'deleted' list. If 'del_all' == 1, all flows in 'keys' will be deleted,
* else only every third key will be deleted. Returns the number flows deleted
* from the table.
*/
static int
delete_flows(struct sw_table *swt, struct list_head *keys,
struct list_head *deleted, uint8_t del_all)
{
struct flow_key_entry *pos, *next;
int i, n_del, total_del;
total_del = 0;
i = 0;
list_for_each_entry_safe (pos, next, keys, node) {
if (del_all == 1 || i % 3 == 0) {
n_del = swt->delete(swt, &pos->key, 0, 0);
if (n_del > 1) {
unit_fail("%d flows deleted for one entry", n_del);
unit_fail("\tfuture 'errors' could just be product duplicate flow_key_entries");
unit_fail("THIS IS VERY UNLIKELY...SHOULDN'T HAPPEN OFTEN");
}
total_del += n_del;
list_del(&pos->node);
list_add(&pos->node, deleted);
}
i++;
}
return total_del;
}
/*
* Checks that both iteration and lookups are consistent with the caller's view
* of the table. In particular, checks that all keys in flow_key_entry list
* 'deleted' do not show up in lookup or iteration, and keys in flow_key_entry
* list 'added' do show up. 'tmp' should be an empty list that can be used for
* iteration. References to list_head pointers are needed for 'added' and 'tmp'
* because iteration will cause the list_heads to change. Function thus
* switches 'added' to point to the list of added keys after the iteration.
*/
static int
check_lookup_and_iter(struct sw_table *swt, struct list_head *deleted,
struct list_head **added, struct list_head **tmp)
{
struct list_head *tmp2;
int ret;
if (check_no_lookup(swt, deleted) < 0) {
unit_fail("Uninserted flows returning lookup");
return -1;
}
if (check_lookup(swt, *added) < 0) {
unit_fail("Inserted flows not returning lookup");
return -1;
}
ret = check_iteration(swt, *added, *tmp);
tmp2 = *added;
*added = *tmp;
*tmp = tmp2;
if ((*tmp)->next != *tmp) {
unit_fail("WARNING: not all flows in 'added' found by iterator");
unit_fail("\tcould be a product of duplicate flow_key_entrys, though should be VERY rare.");
/* To avoid reoccurence */
(*tmp)->next = (*tmp)->prev = *tmp;
}
return ret;
}
/*
* Verifies iteration and lookup after inserting 'n_flows', then after deleting
* some flows, and once again after deleting all flows in table 'swt'.
*/
static int
iterator_test(struct sw_table *swt, int n_flows, uint32_t wildcards)
{
struct flow_key_entry *allocated, h1, h2;
struct list_head *added, *deleted, *tmp;
int ret, n_del, success;
INIT_LIST_HEAD(&h1.node);
INIT_LIST_HEAD(&h2.node);
success = -1;
allocated = allocate_random_keys(n_flows, wildcards);
if(allocated == NULL)
return success;
deleted = &allocated->node;
added = &h1.node;
tmp = &h2.node;
ret = insert_flows(swt, deleted, added, -1);
if (ret < 0)
goto iterator_test_destr;
n_flows = ret;
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after insertion");
goto iterator_test_destr;
} else if (ret != n_flows) {
unit_fail("Iterator only found %d of %d flows",
ret, n_flows);
goto iterator_test_destr;
}
n_del = delete_flows(swt, added, deleted, 0);
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after some deletion");
goto iterator_test_destr;
} else if (ret + n_del != n_flows) {
unit_fail("iterator after deletion inconsistent");
unit_fail("\tn_del = %d, n_found = %d, n_flows = %d",
n_del, ret, n_flows);
goto iterator_test_destr;
}
n_flows -= n_del;
n_del = delete_flows(swt, added, deleted, 1);
if (n_del != n_flows) {
unit_fail("Not all flows deleted - only %d of %d",
n_del, n_flows);
goto iterator_test_destr;
}
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after all deletion");
goto iterator_test_destr;
} else if (ret != 0) {
unit_fail("Empty table iterator failed. %d flows found",
ret);
goto iterator_test_destr;
}
success = 0;
iterator_test_destr:
allocated->key.wildcards = OFPFW_ALL;
swt->delete(swt, &allocated->key, 0, 0);
vfree(allocated);
return success;
}
/*
* Checks lookup and iteration consistency after adding one flow, adding the
* flow again, and then deleting the flow from table 'swt'.
*/
static int
add_test(struct sw_table *swt, uint32_t wildcards)
{
struct flow_key_entry *allocated, h1, h2;
struct list_head *added, *deleted, *tmp, *tmp2;
int ret, success = -1;
INIT_LIST_HEAD(&h1.node);
INIT_LIST_HEAD(&h2.node);
allocated = allocate_random_keys(2, wildcards);
if (allocated == NULL)
return success;
deleted = &allocated->node;
added = &h1.node;
tmp = &h2.node;
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup before table modification");
goto add_test_destr;
} else if (ret != 0) {
unit_fail("Iterator on empty table found %d flows",
ret);
goto add_test_destr;
}
if (insert_flows(swt, deleted, added, 1) != 1) {
unit_fail("Cannot add one flow to table");
goto add_test_destr;
}
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after single add");
goto add_test_destr;
} else if (ret != 1) {
unit_fail("Iterator on single add found %d flows",
ret);
goto add_test_destr;
}
/* Re-adding flow */
if (insert_flows(swt, added, tmp, 1) != 1) {
unit_fail("Cannot insert same flow twice");
goto add_test_destr;
}
tmp2 = added;
added = tmp;
tmp = tmp2;
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after double add");
goto add_test_destr;
} else if (ret != 1) {
unit_fail("Iterator on double add found %d flows",
ret);
goto add_test_destr;
}
ret = delete_flows(swt, added, deleted, 1);
if (ret != 1) {
unit_fail("Unexpected %d flows deleted", ret);
goto add_test_destr;
}
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after delete.");
goto add_test_destr;
} else if (ret != 0) {
unit_fail("unexpected %d flows found delete", ret);
goto add_test_destr;
}
success = 0;
add_test_destr:
allocated->key.wildcards = OFPFW_ALL;
swt->delete(swt, &allocated->key, 0, 0);
vfree(allocated);
return success;
}
/*
* Checks lookup and iteration consistency after each deleting a non-existent
* flow, adding and then deleting a flow, adding the flow again, and then
* deleting the flow twice in table 'swt'.
*/
static int
delete_test(struct sw_table *swt, uint32_t wildcards)
{
struct flow_key_entry *allocated, h1, h2;
struct list_head *added, *deleted, *tmp, *tmp2;
int i, ret, success = -1;
INIT_LIST_HEAD(&h1.node);
INIT_LIST_HEAD(&h2.node);
allocated = allocate_random_keys(2, wildcards);
if (allocated == NULL)
return success;
/* Not really added...*/
added = &allocated->node;
deleted = &h1.node;
tmp = &h2.node;
ret = delete_flows(swt, added, deleted, 1);
if (ret != 0) {
unit_fail("Deleting non-existent keys from table returned unexpected value %d",
ret);
goto delete_test_destr;
}
for (i = 0; i < 3; i++) {
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
if (i == 0)
unit_fail("Loop %d. Bad lookup before modification.", i);
else
unit_fail("Loop %d. Bad lookup after delete.", i);
goto delete_test_destr;
} else if (ret != 0) {
if(i == 0)
unit_fail("Loop %d. Unexpected %d flows found before modification",
i, ret);
else
unit_fail("Loop %d. Unexpected %d flows found after delete",
i, ret);
goto delete_test_destr;
}
if(i == 2)
break;
if (insert_flows(swt, deleted, added, 1) != 1) {
unit_fail("loop %d: cannot add flow to table", i);
goto delete_test_destr;
}
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("loop %d: bad lookup after single add.", i);
goto delete_test_destr;
} else if (ret != 1) {
unit_fail("loop %d: unexpected %d flows found after single add",
i, ret);
goto delete_test_destr;
}
ret = delete_flows(swt, added, deleted, 1);
if (ret != 1) {
unit_fail("loop %d: deleting inserted key from table returned unexpected value %d",
i, ret);
goto delete_test_destr;
}
}
ret = delete_flows(swt, deleted, tmp, 1);
tmp2 = deleted;
deleted = tmp2;
tmp = tmp2;
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup after double delete.");
goto delete_test_destr;
} else if (ret != 0) {
unit_fail("Unexpected %d flows found after double delete", ret);
goto delete_test_destr;
}
success = 0;
delete_test_destr:
allocated->key.wildcards = OFPFW_ALL;
swt->delete(swt, &allocated->key, 0, 0);
vfree(allocated);
return success;
}
/*
* Randomly adds and deletes from a set of size 'n_flows', looping for 'i'
* iterations.
*/
static int
complex_add_delete_test(struct sw_table *swt, int n_flows, int i, uint32_t wildcards)
{
struct flow_key_entry *allocated, h1, h2;
struct list_head *added, *deleted, *tmp;
int cnt, ret, n_added, n_deleted, success = -1;
uint8_t del_all;
INIT_LIST_HEAD(&h1.node);
INIT_LIST_HEAD(&h2.node);
allocated = allocate_random_keys(n_flows, wildcards);
if (allocated == NULL)
return success;
deleted = &allocated->node;
added = &h1.node;
tmp = &h2.node;
n_deleted = n_flows;
n_added = 0;
for (;i > 0; i--) {
if (n_deleted != 0 && random32() % 2 == 0) {
cnt = random32() % n_deleted;
cnt = insert_flows(swt, deleted, added, cnt);
if (cnt < 0)
goto complex_test_destr;
n_deleted -= cnt;
n_added += cnt;
} else {
if (random32() % 7 == 0)
del_all = 1;
else
del_all = 0;
cnt = delete_flows(swt, added, deleted, del_all);
n_deleted += cnt;
n_added -= cnt;
}
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup on iteration %d.", i);
goto complex_test_destr;
}
}
delete_flows(swt, added, deleted, 1);
ret = check_lookup_and_iter(swt, deleted, &added, &tmp);
if (ret < 0) {
unit_fail("Bad lookup on end deletion.");
goto complex_test_destr;
} else if (ret != 0) {
unit_fail("Unexpected %d flows found on end deletion", ret);
goto complex_test_destr;
}
success = 0;
complex_test_destr:
allocated->key.wildcards = OFPFW_ALL;
swt->delete(swt, &allocated->key, 0, 0);
vfree(allocated);
return success;
}
void run_table_t(void)
{
int linear_max, hash_buckets, hash2_buckets1;
int hash2_buckets2, num_flows, num_iterations;
int i;
struct sw_table *swt;
/* Most basic operations. */
simple_insert_delete(table_linear_create(2048), 0);
simple_insert_delete(table_hash_create(0x04C11DB7, 2048), 0);
simple_insert_delete(table_hash2_create(0x04C11DB7, 2048,
0x1EDC6F41, 2048), 0);
/* Linear table operations. */
multiple_insert_destroy(table_linear_create(2048), 1024, 0, 0, 0);
multiple_insert_destroy(table_linear_create(2048), 2048, 0, 0, 0);
multiple_insert_destroy(table_linear_create(2048), 8192, 0,
8192 - 2048, 8192 - 2048);
/* Hash table operations. */
multiple_insert_destroy(table_hash_create(0x04C11DB7, 2048), 1024, 0,
100, 300);
multiple_insert_destroy(table_hash_create(0x04C11DB7, 2048), 2048, 0,
500, 1000);
multiple_insert_destroy(table_hash_create(0x04C11DB7, 1 << 20), 8192, 0,
0, 50);
multiple_insert_destroy(table_hash_create(0x04C11DB7, 1 << 20), 65536, 0,
1500, 3000);
/* Hash table 2, two hash functions. */
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 2048,
0x1EDC6F41, 2048), 1024, 0, 0, 20);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 2048,
0x1EDC6F41, 2048), 2048, 0, 50, 200);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 1<<20,
0x1EDC6F41, 1<<20), 8192, 0, 0, 20);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 1<<20,
0x1EDC6F41, 1<<20), 65536, 0, 0, 20);
/* Hash table 2, one hash function. */
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 2048,
0x04C11DB7, 2048), 1024, 0, 0, 50);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 2048,
0x04C11DB7, 2048), 2048, 0, 100, 300);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 1<<20,
0x04C11DB7, 1<<20), 8192, 0, 0, 20);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 1<<20,
0x04C11DB7, 1<<20), 65536, 0, 0, 100);
multiple_insert_destroy(table_hash2_create(0x04C11DB7, 1<<20,
0x04C11DB7, 1<<20), 1<<16, 0, 0, 100);
linear_max = 2048;
hash_buckets = 2048;
hash2_buckets1 = 1024;
hash2_buckets2 = 1024;
num_flows = 2300;
num_iterations = 100;
printk("\nTesting on each table type:\n");
printk(" iteration_test on 0 flows\n");
printk(" iteration_test on %d flows\n", num_flows);
printk(" add_test\n");
printk(" delete_test\n");
printk(" complex_add_delete_test with %d flows and %d iterations\n\n",
num_flows, num_iterations);
for (i = 0; i < 3; i++) {
unsigned int mask = i == 0 ? : 0;
if (unit_failed())
return;
mask = 0;
switch (i) {
case 0:
swt = table_linear_create(linear_max);
break;
case 1:
swt = table_hash_create (0x04C11DB7, hash_buckets);
break;
case 2:
swt = table_hash2_create(0x04C11DB7, hash2_buckets1,
0x1EDC6F41, hash2_buckets2);
break;
default:
BUG();
return;
}
if (swt == NULL) {
unit_fail("failed to allocate table %d", i);
return;
}
printk("Testing %s table with %d buckets and %d max flows...\n",
table_name(swt), hash_buckets, num_flows);
iterator_test(swt, 0, mask);
iterator_test(swt, num_flows, mask);
add_test(swt, mask);
delete_test(swt, mask);
complex_add_delete_test(swt, num_flows, num_iterations, mask);
swt->destroy(swt);
}
}
-4
View File
@@ -1,4 +0,0 @@
/Makefile
/Makefile.in
/forward_t.h
/fwdhgen
-7
View File
@@ -1,7 +0,0 @@
noinst_HEADERS = forward_t.h
forward_t.h: gen_forward_t.pl example.pcap
perl $(srcdir)/gen_forward_t.pl $(srcdir)/example.pcap > forward_t.h.tmp
mv forward_t.h.tmp forward_t.h
EXTRA_DIST = gen_forward_t.pl example.pcap
Binary file not shown.
-80
View File
@@ -1,80 +0,0 @@
#! /usr/bin/perl
use warnings;
use strict;
if (@ARGV != 1) {
print "usage: $0 input.pcap > output.h\n";
print "where input.pcap is a packet capture in pcap format\n";
print "and output.c is a C header file containing the packets\n";
exit(1);
}
my ($in_file_name) = $ARGV[0];
open(INPUT, '<', $in_file_name) or die "$in_file_name: open: $!\n";
my ($file_header);
if (read(INPUT, $file_header, 24) != 24) {
die "$in_file_name: could not read pcap header\n";
}
my ($s, $l);
if (substr($file_header, 0, 4) eq pack('V', 0xa1b2c3d4)) {
($s, $l) = ('v', 'V');
} elsif (substr($file_header, 0, 4) eq pack('N', 0xa1b2c3d4)) {
($s, $l) = ('n', 'N');
} else {
die "$in_file_name: not a pcap file\n";
}
print <<'EOF';
#ifndef DP_TEST_PACKETS_H
#define DP_TEST_PACKETS_H 1
struct pkt {
unsigned char *data;
unsigned int len;
};
EOF
my ($n_packets) = 0;
for (;;) {
my ($pkt_hdr) = must_read(16);
last if $pkt_hdr eq '';
my ($ts_sec, $ts_usec, $incl_len, $orig_len) = unpack("${l}4", $pkt_hdr);
print STDERR "warning: captured less than len %u\n"
if $incl_len < $orig_len;
my ($pkt) = must_read($incl_len);
die "$in_file_name: unexpected end of file\n" if !$pkt;
print "\nstatic unsigned char p${n_packets}[] = {";
my ($line_bytes) = 0;
for my $c (map(ord($_), split(//, $pkt))) {
if ($line_bytes++ % 13 == 0) {
print "\n";
}
printf " 0x%02x,", $c;
}
print "\n};\n";
$n_packets++;
}
print "\nstatic int num_packets = $n_packets;\n";
print "\nstatic struct pkt packets[] = {\n";
for my $i (0..$n_packets - 1) {
print " { p$i, sizeof p$i },\n";
}
print "};\n";
print "\n#endif\n";
sub must_read {
my ($rq_bytes) = @_;
my ($data);
my ($nbytes) = read(INPUT, $data, $rq_bytes);
die "$in_file_name: read: $!\n" if !defined $nbytes;
die "$in_file_name: unexpected end of file\n"
if $nbytes && $nbytes != $rq_bytes;
return $data;
}
-97
View File
@@ -1,97 +0,0 @@
/* A cheap knock-off of the pcap library to remove that dependency. */
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include "ofp_pcap.h"
int
ofp_pcap_open(struct ofp_pcap *p, const char *fname, char *errbuf)
{
FILE *fp;
struct pcap_file_header hdr;
size_t amt_read;
fp = fopen(fname, "r");
memset((char *)p, 0, sizeof(*p));
amt_read = fread((char *)&hdr, 1, sizeof(hdr), fp);
if (amt_read != sizeof(hdr)) {
snprintf(errbuf, OFP_PCAP_ERRBUF_SIZE, "error reading dump file");
goto error;
}
if (hdr.magic != TCPDUMP_MAGIC) {
hdr.magic = SWAPLONG(hdr.magic);
hdr.version_major = SWAPSHORT(hdr.version_major);
hdr.version_minor = SWAPSHORT(hdr.version_minor);
hdr.thiszone = SWAPLONG(hdr.thiszone);
hdr.sigfigs = SWAPLONG(hdr.sigfigs);
hdr.snaplen = SWAPLONG(hdr.snaplen);
hdr.linktype = SWAPLONG(hdr.linktype);
p->swapped = 1;
}
p->fp = fp;
p->errbuf = errbuf;
p->bufsize = hdr.snaplen+sizeof(struct pcap_pkthdr);
p->buf = malloc(p->bufsize);
if (!p->buf) {
snprintf(errbuf, OFP_PCAP_ERRBUF_SIZE, "error allocating buffer");
goto error;
}
if (hdr.version_major < OFP_PCAP_VERSION_MAJOR) {
snprintf(errbuf, OFP_PCAP_ERRBUF_SIZE, "archaic file format");
goto error;
}
return 0;
error:
if (p->buf)
free(p->buf);
return 1;
}
char *
ofp_pcap_next(struct ofp_pcap *p, struct pcap_pkthdr *hdr)
{
size_t amt_read;
amt_read = fread(hdr, 1, sizeof(*hdr), p->fp);
if (amt_read != sizeof(*hdr)) {
snprintf(p->errbuf, OFP_PCAP_ERRBUF_SIZE, "error reading dump file");
return NULL;
}
if (p->swapped) {
hdr->caplen = SWAPLONG(hdr->caplen);
hdr->len = SWAPLONG(hdr->len);
hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
}
if (hdr->caplen > p->bufsize) {
snprintf(p->errbuf, OFP_PCAP_ERRBUF_SIZE, "error reading dump file");
return NULL;
}
amt_read = fread((char *)p->buf, 1, hdr->caplen, p->fp);
if (amt_read != hdr->caplen){
snprintf(p->errbuf, OFP_PCAP_ERRBUF_SIZE, "error reading dump file");
return NULL;
}
return p->buf;
}
void
ofp_pcap_close(struct ofp_pcap *p)
{
fclose(p->fp);
free(p->buf);
}
-64
View File
@@ -1,64 +0,0 @@
#ifndef OFP_PCAP_H
#define OFP_PCAP_H
#include <stdint.h>
#include <sys/time.h>
#include <stdio.h>
#define OFP_PCAP_VERSION_MAJOR 2
#define OFP_PCAP_VERSION_MINOR 4
#define TCPDUMP_MAGIC 0xa1b2c3d4
#define OFP_LINKTYPE_ETHERNET 1
#define OFP_PCAP_ERRBUF_SIZE 256
/* Swap the byte order regardless of the architecture */
#define SWAPLONG(x) \
((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)&0xff0000)>>8) | (((x)&0xff000000)>>24))
#define SWAPSHORT(x) \
((((x)&0xff)<<8) | (((x)&0xff00)>>8))
struct ofp_pcap {
FILE *fp; /* File pointer to currently processed file */
int swapped; /* Indicate whether endian-ness needs to change */
char *buf; /* Buffer to hold packet data */
size_t bufsize; /* Size of buffer */
char *errbuf; /* Pointer to buffer to hold error message */
};
struct pcap_file_header {
uint32_t magic; /* Magic number */
uint16_t version_major; /* Version number major */
uint16_t version_minor; /* Version number minor */
int32_t thiszone; /* Gmt to local correction */
uint32_t sigfigs; /* Accuracy of timestamps */
uint32_t snaplen; /* Max length saved portion of each pkt */
uint32_t linktype; /* Data link type (LINKTYPE_*) */
};
/*
* This is a timeval as stored in disk in a dumpfile.
* It has to use the same types everywhere, independent of the actual
* `struct timeval'
*/
struct pcap_timeval {
int32_t tv_sec; /* Seconds */
int32_t tv_usec; /* Microseconds */
};
/*
* How a `pcap_pkthdr' is actually stored in the dumpfile.
*/
struct pcap_pkthdr {
struct pcap_timeval ts; /* Time stamp */
uint32_t caplen; /* Length of portion present */
uint32_t len; /* Length this packet (off wire) */
};
int ofp_pcap_open(struct ofp_pcap *p, const char *fname, char *errbuf);
char *ofp_pcap_next(struct ofp_pcap *p, struct pcap_pkthdr *hdr);
void ofp_pcap_close(struct ofp_pcap *p);
#endif /* ofp_pcap.h */
-24
View File
@@ -1,24 +0,0 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007, 2008 The Board of Trustees of The Leland
* Stanford Junior University
*/
#include "table.h"
#include "flow.h"
#include "crc32.h"
#include "forward.h"
#include <linux/module.h>
EXPORT_SYMBOL(flow_alloc);
EXPORT_SYMBOL(flow_cache);
EXPORT_SYMBOL(table_hash_create);
EXPORT_SYMBOL(table_hash2_create);
EXPORT_SYMBOL(table_linear_create);
EXPORT_SYMBOL(crc32_init);
EXPORT_SYMBOL(crc32_calculate);
EXPORT_SYMBOL(flow_extract);
EXPORT_SYMBOL(execute_setter);
-105
View File
@@ -1,105 +0,0 @@
/*
* Distributed under the terms of the GNU GPL version 2.
* Copyright (c) 2007, 2008 The Board of Trustees of The Leland
* Stanford Junior University
*/
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/errno.h>
#include "unit.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static char run[1024];
module_param_string(run, run, sizeof run, 0);
MODULE_PARM_DESC(run_tests, "run=\"test1,[test2,...]\"\n");
#else
static char *run;
MODULE_PARM(run, "s");
#endif
static int test_failed;
static const char *test_name;
void unit_fail_function(const char *function, const char *msg, ...)
{
va_list args;
printk("%s: FAIL: %s: ", test_name, function);
va_start(args, msg);
vprintk(msg, args);
va_end(args);
printk("\n");
test_failed = 1;
}
int unit_failed(void)
{
return test_failed;
}
static int run_test(const char *name, size_t len)
{
static const struct test {
const char *name;
void (*func)(void);
} tests[] = {
#define UNIT_TEST(NAME) {#NAME, run_##NAME},
UNIT_TESTS
#undef UNIT_TEST
};
const struct test *p;
for (p = tests; p < &tests[ARRAY_SIZE(tests)]; p++)
if (len == strlen(p->name)
&& !memcmp(name, p->name, len)) {
test_name = p->name;
test_failed = 0;
p->func();
printk("%s: %s\n", test_name,
test_failed ? "FAIL" : "PASS");
return !test_failed;
}
printk("unknown unit test %.*s\n", (int) len, name);
return 0;
}
int unit_init(void)
{
int n_pass = 0, n_fail = 0;
char *p = run;
if (p == NULL) {
p = "";
}
for (;;) {
static const char white_space[] = " \t\r\n\v,";
int len;
p += strspn(p, white_space);
if (!*p)
break;
len = strcspn(p, white_space);
if (run_test(p, len))
n_pass++;
else
n_fail++;
p += len;
}
if (n_pass + n_fail == 0)
printk("no tests specified (use run=\"test1 [test2...]\")\n");
else
printk("%d tests passed, %d failed\n", n_pass, n_fail);
return -ENODEV;
}
module_init(unit_init);
MODULE_LICENSE("GPL");
-21
View File
@@ -1,21 +0,0 @@
#ifndef UNIT_H
#define UNIT_H 1
/* List of unit tests. */
#define UNIT_TESTS \
UNIT_TEST(table_t) \
UNIT_TEST(crc_t) \
UNIT_TEST(forward_t)
/* Prototype a function run_<NAME> for each of the unit tests. */
#define UNIT_TEST(NAME) void run_##NAME(void);
UNIT_TESTS
#undef UNIT_TEST
void unit_fail_function(const char *function, const char *msg, ...)
__attribute__((format(printf, 2, 3)));
#define unit_fail(...) unit_fail_function(__func__, __VA_ARGS__)
int unit_failed(void);
#endif /* unit.h */