Repository : ssh://git@open-mesh.org/batctl
On branch : master
>---------------------------------------------------------------
commit 3239dcdf46ca6ebf56d697971e2d7106bb794601
Author: montik <montik(a)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(a)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 */