Repository : ssh://git@open-mesh.org/batctl
On branch : master
commit 3239dcdf46ca6ebf56d697971e2d7106bb794601 Author: montik montik@autistici.org Date: Fri Jul 6 12:57:19 2012 +0200
batctl: introduced support for bandwidth meter
Added the possibility to launch the bandwidth meter test. Bandwidth meter is a batman kernel space tool for bandwidth measurements. The syntax is:
batctl bw <MAC>
The test is interruptable with SIGINT or SIGTERM; once the test is over in case of success the throughput is printed to stdout, if a problem occured an error message is displayed (on stdout) accordingly.
Signed-off-by: Edo Monticelli montik@autistici.org
3239dcdf46ca6ebf56d697971e2d7106bb794601 Makefile | 2 +- bw_meter.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bw_meter.h | 1 + main.c | 6 +++ packet.h | 37 +++++++++++-- 5 files changed, 208 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile index 72cecde..059efc2 100755 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@
# batctl build BINARY_NAME = batctl -OBJ = main.o bat-hosts.o functions.o sys.o debug.o ping.o traceroute.o tcpdump.o list-batman.o hash.o vis.o debugfs.o bisect.o ioctl.o +OBJ = main.o bat-hosts.o functions.o sys.o debug.o ping.o traceroute.o tcpdump.o list-batman.o hash.o vis.o debugfs.o bisect.o ioctl.o bw_meter.o MANPAGE = man/batctl.8
# batctl flags and options diff --git a/bw_meter.c b/bw_meter.c new file mode 100644 index 0000000..2b870bf --- /dev/null +++ b/bw_meter.c @@ -0,0 +1,168 @@ +#include <netinet/in.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <signal.h> + +#include "main.h" +#include "functions.h" +#include "packet.h" +#include "bat-hosts.h" +#include "debugfs.h" + +struct ether_addr *dst_mac; +int bw_fd = -1; + +void bw_sig_handler(int sig) +{ + int write_bytes; + struct batadv_icmp_packet icmp_packet_out; + + switch (sig) { + case SIGINT: + case SIGTERM: + fflush(stdout); + memcpy(&icmp_packet_out.dst, dst_mac, ETH_ALEN); + icmp_packet_out.header.version = BATADV_COMPAT_VERSION; + icmp_packet_out.header.packet_type = BATADV_ICMP; + icmp_packet_out.msg_type = BATADV_BW_STOP; + icmp_packet_out.seqno = 0; + + write_bytes = write(bw_fd, (char *)&icmp_packet_out, + sizeof(struct batadv_icmp_packet)); + if (write_bytes < 0) { + printf("sig_handler can't write to fd for %d, %s\n", + write_bytes, strerror(write_bytes)); + } + break; + default: + break; + } +} + +int bw_meter(char *mesh_iface, int argc, char **argv) +{ + struct batadv_icmp_packet icmp_packet_out; + struct batadv_icmp_packet_rr icmp_packet_rr; + struct batadv_bw_result *result; + struct bat_host *bat_host; + fd_set read_socket; + unsigned long int throughput; + char *dst_string, *mac_string; + int ret = EXIT_FAILURE; + int write_error; + int found_args = 1, read_opt = USE_BAT_HOSTS; + char *debugfs_mnt; + char icmp_socket[MAX_PATH+1]; + + if (argc <= found_args) { + printf("Error - target mac address or bat-host name not specified\n"); + return EXIT_FAILURE; + } + + signal(SIGINT, bw_sig_handler); + signal(SIGTERM, bw_sig_handler); + + dst_string = argv[found_args]; + bat_hosts_init(read_opt); + bat_host = bat_hosts_find_by_name(dst_string); + + if (bat_host) + dst_mac = &bat_host->mac_addr; + + if (!dst_mac) { + dst_mac = ether_aton(dst_string); + + if (!dst_mac) { + printf("Error - the bwmeter destination is not a mac address or bat-host name: %s\n", + dst_string); + goto out; + } + } + + mac_string = ether_ntoa_long(dst_mac); + + debugfs_mnt = debugfs_mount(NULL); + if (!debugfs_mnt) { + printf("Error - can't mount or find debugfs\n"); + goto out; + } + + debugfs_make_path(SOCKET_PATH_FMT, mesh_iface, icmp_socket, + sizeof(icmp_socket)); + + bw_fd = open(icmp_socket, O_RDWR); + + if (bw_fd < 0) { + printf("Error - can't open a connection to the batman adv kernel module via the socket '%s': %s\n", + icmp_socket, strerror(errno)); + printf("Check whether the module is loaded and active.\n"); + goto out; + } + + memcpy(&icmp_packet_out.dst, dst_mac, ETH_ALEN); + icmp_packet_out.header.version = BATADV_COMPAT_VERSION; + icmp_packet_out.header.packet_type = BATADV_ICMP; + icmp_packet_out.msg_type = BATADV_BW_START; + icmp_packet_out.seqno = 0; + + printf("Bandwidth meter called towards %s\n", mac_string); + + write_error = write(bw_fd, (char *)&icmp_packet_out, + sizeof(struct batadv_icmp_packet)); + if (write_error < 0) { + printf("Can't write to fd for %s. %d, %s\n", icmp_socket, + write_error, strerror(write_error)); + goto out; + } + + FD_ZERO(&read_socket); + FD_SET(bw_fd, &read_socket); + + select(bw_fd + 1, &read_socket, NULL, NULL, NULL); + /* a size icmp_packet_rr is read, because that is written + * kernel function only handles such structure + */ + if (read(bw_fd, (char *)&icmp_packet_rr, sizeof(icmp_packet_rr))) { + result = (struct batadv_bw_result *)&icmp_packet_rr; + + switch (result->return_value) { + case BATADV_BW_DST_UNREACHABLE: + printf("Destination unreachable\n"); + goto out; + + case BATADV_BW_SIGINT: + printf("SIGINT received: test aborted\n"); + goto out; + + case BATADV_BW_RESEND_LIMIT: + printf("The number of retry for the same window exceeds the limit, test aborted\n"); + goto out; + + case BATADV_BW_ALREADY_ONGOING: + printf("Cannot run two test towards the same node\n"); + goto out; + + case BATADV_BW_MEMORY_ERROR: + printf("Kernel cannot allocate memory, aborted\n"); + goto out; + + case BATADV_BW_COMPLETE: + throughput = result->total_bytes / result->test_time + * 1000; + printf("Test over in %lu ms.\n\t sent %lu bytes.\nThroughput %lu Byte/s\n", + result->test_time, result->total_bytes, + throughput); + goto out; + } + printf ("Unrecognized return value %d\n", result->return_value); + } +out: + bat_hosts_free(); + if (bw_fd) + close(bw_fd); + return ret; +} diff --git a/bw_meter.h b/bw_meter.h new file mode 100644 index 0000000..44269f6 --- /dev/null +++ b/bw_meter.h @@ -0,0 +1 @@ +int bw_meter(char *mesh_iface, int argc, char **argv); diff --git a/main.c b/main.c index 1086f8e..3664958 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,7 @@ #include "sys.h" #include "debug.h" #include "ping.h" +#include "bw_meter.h" #include "traceroute.h" #include "tcpdump.h" #include "bisect.h" @@ -85,6 +86,7 @@ void print_usage(void) printf(" \tping|p <destination> \tping another batman adv host via layer 2\n"); printf(" \ttraceroute|tr <destination> \ttraceroute another batman adv host via layer 2\n"); printf(" \ttcpdump|td <interface> \ttcpdump layer 2 traffic on the given interface\n"); + printf(" \tbandwidthmeter|bw <destination> \tstart a bandwith measurement\n"); printf(" \tbisect <file1> .. <fileN>\tanalyze given log files for routing stability\n"); }
@@ -140,6 +142,10 @@ int main(int argc, char **argv)
ret = ping(mesh_iface, argc - 1, argv + 1);
+ } else if ((strcmp(argv[1], "bandwidthmeter") == 0) || (strcmp(argv[1], "bw") == 0)) { + + ret = bw_meter (mesh_iface, argc -1, argv + 1); + } else if ((strcmp(argv[1], "traceroute") == 0) || (strcmp(argv[1], "tr") == 0)) {
ret = traceroute(mesh_iface, argc - 1, argv + 1); diff --git a/packet.h b/packet.h index 2d23a14..d2804d8 100644 --- a/packet.h +++ b/packet.h @@ -21,6 +21,7 @@ #define _NET_BATMAN_ADV_PACKET_H_
#define BATADV_ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ +#define batadv_bw_is_error(n) ((uint8_t)n > 127 ? 1 : 0)
enum batadv_packettype { BATADV_IV_OGM = 0x01, @@ -44,12 +45,15 @@ enum batadv_iv_flags { };
/* ICMP message types */ -enum batadv_icmp_packettype { - BATADV_ECHO_REPLY = 0, +enum icmp_packettype { + BATADV_ECHO_REPLY = 0, BATADV_DESTINATION_UNREACHABLE = 3, - BATADV_ECHO_REQUEST = 8, - BATADV_TTL_EXCEEDED = 11, - BATADV_PARAMETER_PROBLEM = 12, + BATADV_ECHO_REQUEST = 8, + BATADV_TTL_EXCEEDED = 11, + BATADV_PARAMETER_PROBLEM = 12, + BATADV_BW_START = 15, + BATADV_BW_ACK = 16, + BATADV_BW_STOP = 17, };
/* vis defines */ @@ -155,6 +159,29 @@ struct batadv_icmp_packet_rr { uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; } __packed;
+enum batadv_bw_meter_status { + BATADV_BW_RECEIVER = 1, + BATADV_BW_SENDER = 2, + BATADV_BW_COMPLETE = 3, + BATADV_BW_LAST_WINDOW = 4, + /* error status >= 128 */ + BATADV_BW_SIGINT = 128, + BATADV_BW_DST_UNREACHABLE = 129, + BATADV_BW_RESEND_LIMIT = 130, + BATADV_BW_ALREADY_ONGOING = 131, + BATADV_BW_MEMORY_ERROR = 132, +}; + +/* structure returned to batctl */ +/* icmp_packet_rr used to keep socket_client's index, + * as function batadv_socket_receive_packet expects it + */ +struct batadv_bw_result { + unsigned long int test_time; + unsigned long int total_bytes; + uint8_t return_value; +}; + struct batadv_unicast_packet { struct batadv_header header; uint8_t ttvn; /* destination translation table version number */