From b5d3be9c859e24cd331e94b001a3d0e044c5c56b Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 10 Apr 2013 12:45:46 +0200 Subject: [PATCH] run: add nic driver performance test A run script which sends raw ethernet packets from the host machine to the target machine. Three tests are implemented: - The network_stat instrumented driver of usb_drv and net_drv are used to get the raw receive performance of the network driver. - A simple nic_session client is receiving from the un-instrumented network driver raw ethernet packets. - A bridge is added between driver and simple nic_session client. --- os/run/network_test_nic.inc | 262 ++++++++++++++++++ os/run/network_test_nic.run | 14 + os/run/network_test_nic_raw.run | 4 + os/run/network_test_nic_raw_bridge_client.run | 4 + os/run/network_test_nic_raw_client.run | 4 + os/src/lib/net/stat-client.cc | 190 +++++++++++++ 6 files changed, 478 insertions(+) create mode 100644 os/run/network_test_nic.inc create mode 100644 os/run/network_test_nic.run create mode 100644 os/run/network_test_nic_raw.run create mode 100644 os/run/network_test_nic_raw_bridge_client.run create mode 100644 os/run/network_test_nic_raw_client.run create mode 100644 os/src/lib/net/stat-client.cc diff --git a/os/run/network_test_nic.inc b/os/run/network_test_nic.inc new file mode 100644 index 0000000000..0f0ec6e019 --- /dev/null +++ b/os/run/network_test_nic.inc @@ -0,0 +1,262 @@ +# +# \brief Nic performance test +# \author Alexander Boettcher +# \date 2013-03-26 +# + +if {[have_spec linux]} { + puts "Run script does not support Linux."; exit 0 } + +# +# Build +# + +set build_components { + core init + drivers/pci drivers/timer drivers/nic +} + +lappend_if [expr [have_spec omap4] || [have_spec exynos5]] build_components drivers/usb +lappend_if [expr [have_spec omap4] || [have_spec exynos5]] build_components drivers/usb_net_stat +lappend_if [have_spec acpi] build_components drivers/acpi +lappend_if [have_spec pci] build_components drivers/pci/device_pd +lappend_if [have_spec x86] build_components drivers/nic_stat + +lappend_if $use_nic_client build_components test/nic_raw +lappend_if $use_nic_bridge build_components server/nic_bridge + +# +# Choose network driver +# +if {[expr $use_nic_client && ([have_spec omap4] || [have_spec exynos5])]} { + set network_driver "usb_drv" } +if {[expr !$use_nic_client && ([have_spec omap4] || [have_spec exynos5])]} { + set network_driver "usb_drv_net_stat" } +if {[expr $use_nic_client && ![have_spec omap4] && ![have_spec exynos5]]} { + set network_driver "nic_drv" } +if {[expr !$use_nic_client && ![have_spec omap4] && ![have_spec exynos5]]} { + set network_driver "nic_drv_stat" } + +build $build_components + +create_boot_directory + +# +# Generate config +# + +set config { + + + + + + + + + + + + + + + + + + + + + } + +append_if [expr [have_spec omap4] || [have_spec exynos5]] config " + + + + + + + + + " + +append_if [expr ![have_spec omap4] && ![have_spec exynos5]] config " + + + + " + +append_if $use_nic_bridge config { + + + + + } +append_if $use_nic_bridge config " + " +append_if $use_nic_bridge config { + + + + } + +append_if $use_nic_client config { + + + } +append_if [expr $use_nic_client && $use_nic_bridge] config { + } +append_if $use_nic_client config { + + + } + +append_if [have_spec acpi] config { + + + + + + + + + + + + } + +append_if [expr ![have_spec acpi] && [have_spec pci]] config { + + + + } + +append config { + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init timer +} + +lappend_if $use_nic_client boot_modules test-nic_raw +lappend_if $use_nic_bridge boot_modules nic_bridge + +# platform-specific modules +lappend_if [have_spec acpi] boot_modules acpi_drv +lappend_if [have_spec pci] boot_modules pci_drv +lappend_if [expr [have_spec omap4] || [have_spec exynos5]] boot_modules usb_drv +lappend_if [expr [have_spec omap4] || [have_spec exynos5]] boot_modules usb_drv_net_stat +lappend_if [expr ![have_spec omap4] && ![have_spec exynos5]] boot_modules nic_drv +lappend_if [expr ![have_spec omap4] && ![have_spec exynos5]] boot_modules nic_drv_stat +lappend_if [have_spec nova] boot_modules pci_device_pd + +build_boot_image $boot_modules + +# build the test client +set test_client_dir $genode_dir/os/src/lib/net +if {![file exists bin/nic_drv_test_client]} { + exec g++ -Wall -o bin/nic_drv_test_client $test_client_dir/stat-client.cc +} +# set appropriate rights to create raw sockets +set cap_rights [exec getcap bin/nic_drv_test_client] +if {![regexp cap_net_raw $cap_rights]} { + set sudo_command "sudo setcap cap_net_raw=ep bin/nic_drv_test_client" + puts "For sending raw packets cap_net_raw permission are required." + puts "Trying to execute: '$sudo_command'" + eval "exec $sudo_command" +} + +# +# Execute test case +# + +if {[expr [have_spec omap4] || [have_spec exynos5]]} { + run_genode_until {announces service "Nic"} 30 + set serial_id $spawn_id + + set match_string "Using configured mac: " + + sleep 10 +} else { + set match_string {--- get MAC address } + run_genode_until "$match_string.*\n" 30 + set serial_id $spawn_id + + sleep 2 + +} + +# remember output string, will be overwritten by next run_genode_until +set mac_string $output + +if {$use_nic_client} { + # wait until client become ready + if {![regexp {ready to receive packets} $output]} { + run_genode_until {ready to receive packets} 10 $serial_id + } +} + +if {$use_nic_bridge} { + set match_string "mac: " + if {![regexp "$match_string.*\n" $output]} { + run_genode_until "$match_string.*\n" 10 $serial_id + } +} + +grep_output $match_string +unify_output {[\r\n\t]+} "" +unify_output {[\033]\[0m} "" + +set pos [string first $match_string $mac_string] +set mac_addr [string replace $mac_string 0 [expr $pos + [string length $match_string] - 1]] + +# +# Start test with different packet size +# +set test_result "" +set packet_size_list [list 64 128 256 512 1024 1500] +foreach packet_size $packet_size_list { + set packet_count [expr 200 * 1024 * 1024 / $packet_size] + + set time_start [clock milliseconds] + spawn bin/nic_drv_test_client eth0 $mac_addr $packet_size $packet_count + set test_app_id $spawn_id + interact $test_app_id + + run_genode_until "packets dropped.*\n" 15 $serial_id + run_genode_until "packets dropped.*\n" 70 $serial_id + set time_end [clock milliseconds] + + set target_data [regexp -inline {[0-9]+ kiBytes} $output] + set target_data [regexp -inline {[0-9]+} $target_data] + + set match_string {[0-9]+ kBit/s \(raw [0-9]+ kBit/s\), runtime [0-9]+ ms} + set target_perf [regexp -inline $match_string $output] + set target_perf [regexp -all -inline {[0-9]+} $target_perf] + set target_runtime [lindex $target_perf 2] + set target_perf [lindex $target_perf 0] + + set host_data [expr $packet_count * $packet_size / 1024 ] +# set host_perf [expr $host_data * 1024 * 8 / ($time_end - $time_start)] + set host_perf [expr $target_data * 1024 * 8 / ($time_end - $time_start)] + + puts "host : data send - $host_data kiBytes" + puts "target: data received - $target_data kiBytes" + puts "host : runtime [expr $time_end - $time_start] ms $host_perf kBit/s" + puts "target: runtime $target_runtime ms $target_perf kBit/s" + puts "! PERF: rx_$packet_size [expr $host_perf / 1000] MBit/s ok" + set test_result "$test_result rx_$packet_size:$host_perf" +} +close -i $serial_id + +puts "" +puts "Test succeeded" + +# vi: set ft=tcl : diff --git a/os/run/network_test_nic.run b/os/run/network_test_nic.run new file mode 100644 index 0000000000..a32bbfdbf1 --- /dev/null +++ b/os/run/network_test_nic.run @@ -0,0 +1,14 @@ +source ${genode_dir}/os/run/network_test_nic_raw.run +set test_result_raw $test_result + +source ${genode_dir}/os/run/network_test_nic_raw_client.run +set test_result_raw_client $test_result + +source ${genode_dir}/os/run/network_test_nic_raw_bridge_client.run +set test_result_raw_bridge_client $test_result + +puts "\nTest results:\n" +puts "nic : $test_result_raw" +puts "nic+client : $test_result_raw_client" +puts "nic+bridge+client: $test_result_raw_bridge_client" +puts "" diff --git a/os/run/network_test_nic_raw.run b/os/run/network_test_nic_raw.run new file mode 100644 index 0000000000..72a6a83841 --- /dev/null +++ b/os/run/network_test_nic_raw.run @@ -0,0 +1,4 @@ +set use_nic_client 0 +set use_nic_bridge 0 + +source ${genode_dir}/os/run/network_test_nic.inc diff --git a/os/run/network_test_nic_raw_bridge_client.run b/os/run/network_test_nic_raw_bridge_client.run new file mode 100644 index 0000000000..53173d1b3b --- /dev/null +++ b/os/run/network_test_nic_raw_bridge_client.run @@ -0,0 +1,4 @@ +set use_nic_client 1 +set use_nic_bridge 1 + +source ${genode_dir}/os/run/network_test_nic.inc diff --git a/os/run/network_test_nic_raw_client.run b/os/run/network_test_nic_raw_client.run new file mode 100644 index 0000000000..6be00f6753 --- /dev/null +++ b/os/run/network_test_nic_raw_client.run @@ -0,0 +1,4 @@ +set use_nic_client 1 +set use_nic_bridge 0 + +source ${genode_dir}/os/run/network_test_nic.inc diff --git a/os/src/lib/net/stat-client.cc b/os/src/lib/net/stat-client.cc new file mode 100644 index 0000000000..5d6483b98f --- /dev/null +++ b/os/src/lib/net/stat-client.cc @@ -0,0 +1,190 @@ +/* + * \brief Send a raw Ethernet frame + * \author Alexander Boettcher + * \date 2013-04-02 + * + */ + +/* + * Copyright (C) 2013-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +enum { + FRAG_DONT = 0x40, + + IP_VERSION = 4, + IP_HEADER_LENGTH = 5, /* 5 * 4Bytes */ + + PROTOCOL_IP_UDP = 17, + + PACKET_BUFFER = 4096, + }; + +static unsigned short checksum(unsigned short * data, unsigned short count) { + unsigned short result = 0; + + for (unsigned i=0; i < count; i++) { + result += htons(data[i]); + } + + return ~result; +} + +int main(int argc, char **argv) +{ + const char * net_if_name = argv[1]; + const char * net_mac_dst = argv[2]; + struct ifreq net_if, net_mac_src; + + if (argc < 5 || strlen(net_mac_dst) < 17) { + printf("argument missing\n"); + printf("usage: ' '" + " - e.g. 'eth0 2e:60:90:0c:4e:01 256 65536'\n"); + return 1; + } + + unsigned long const packet_size = atol(argv[3]); + unsigned long const packet_count = atol(argv[4]); + + char packet[PACKET_BUFFER]; + memset(packet, 0, sizeof(packet)); + + if (packet_size < 64 || packet_size > sizeof(packet)) { + printf("packet size must be in the range of 64 - %lu\n", + sizeof(packet)); + return 1; + } + printf("sending %lu packets a %lu Bytes via %s network interface\n", + packet_count, packet_size, net_if_name); + + int const sock_fd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + if (sock_fd < 0) { + perror("socket d"); + return 2; + } + + /* get network interface */ + memset(&net_if, 0, sizeof(net_if)); + strncpy(net_if.ifr_name, net_if_name, strlen(net_if_name)); + if (ioctl(sock_fd, SIOCGIFINDEX, &net_if)) { + perror("ioctl SIOCGIFINDEX"); + return 3; + } + + /* get mac of network interface */ + memset(&net_mac_src, 0, sizeof(net_mac_src)); + strncpy(net_mac_src.ifr_name, net_if_name, strlen(net_if_name)); + if (ioctl(sock_fd, SIOCGIFHWADDR, &net_mac_src)) { + perror("ioctl SIOCGIFHWADDR"); + return 4; + } + + struct ether_header *eh = (struct ether_header *) packet; + + /* create ethernet frame */ + memcpy(eh->ether_shost, net_mac_src.ifr_hwaddr.sa_data, ETH_ALEN); + for (unsigned i=0; i < ETH_ALEN; i++) + eh->ether_dhost[i] = strtoul(&net_mac_dst[i*3], 0, 16); + eh->ether_type = htons(ETH_P_IP); + + /* debugging */ + if (true) { + printf("%02x", eh->ether_shost[0]); + for (unsigned i=1; i < ETH_ALEN; i++) + printf(":%02x", eh->ether_shost[i]); + + printf(" -> %02x", eh->ether_dhost[0]); + for (unsigned i=1; i < ETH_ALEN; i++) + printf(":%02x", eh->ether_dhost[i]); + printf("\n"); + } + + /* create IP frame */ + struct iphdr *ip = (struct iphdr *) (packet + sizeof(struct ether_header)); + + ip->version = IP_VERSION; + ip->ihl = IP_HEADER_LENGTH; + ip->protocol = PROTOCOL_IP_UDP; +/* + ip->daddr = (10U) | (65U << 24); + ip->saddr = (10U) | (22U << 24); +*/ + ip->tot_len = htons(packet_size - ((char *)ip - packet)); + ip->ttl = 10; + ip->frag_off = FRAG_DONT; + + ip->check = htons(checksum((unsigned short *)ip, + sizeof(*ip) / sizeof(unsigned short))); + + /* setup UDP header */ + struct udphdr *udp = (struct udphdr *) (ip + 1); + udp->source = htons(7321); + udp->dest = htons(7323); + + /* add UDP data */ + char * data = (char *) (udp + 1); + char txt_magic[] = "Hello world! Genode is greeting."; + memcpy(data, txt_magic, sizeof(txt_magic)); + + int len = data + sizeof(txt_magic) - packet; + udp->len = htons(len - ((char *)udp - packet)); + + if ((len + 0UL) > sizeof(packet)) { + printf("packet size larger then buffer %d > %lu\n", len, sizeof(packet)); + return 5; + } + + /* send packet */ + struct sockaddr_ll socket_address; + socket_address.sll_ifindex = net_if.ifr_ifindex; + socket_address.sll_halen = ETH_ALEN; + memcpy(socket_address.sll_addr, net_mac_dst, ETH_ALEN); + + int res = sendto(sock_fd, packet, len, 0, (struct sockaddr*)&socket_address, + sizeof(struct sockaddr_ll)); + if (res != len) { + perror("sending packet - start"); + return 6; + } + memset(data, 0, sizeof(txt_magic)); + + for (unsigned long j=0; j < packet_count;j++) + { + res = sendto(sock_fd, packet, packet_size, 0, + (struct sockaddr*)&socket_address, + sizeof(struct sockaddr_ll)); + } + + memcpy(data, txt_magic, sizeof(txt_magic)); + + usleep (5000); + res = sendto(sock_fd, packet, len, 0, (struct sockaddr*)&socket_address, + sizeof(struct sockaddr_ll)); + if (res != len) { + perror("sending packet - end"); + return 6; + } + + printf("send %lu packets a %lu Bytes = %lu kiBytes\n", + packet_count, packet_size, + packet_count / 1024 * packet_size); +}