Hi,
I have almost completed my Google Summer of Code project and I'd like to have a feedback from the batman community. The project is a kernel-space bandwidth meter, a lightweight tool to measure network performance between batman nodes. You can find a general project description in the project wiki page:
http://www.open-mesh.org/projects/batman-adv/wiki/GSOC2012_BW
Any advice is welcome, Edo Monticelli
Edo Monticelli (3): batman-adv: bandwidth meter implementation batman-adv: sender retransmission counter batman-adv: seqnumber is wrap around safe
Makefile | 2 +- Makefile.kbuild | 1 + bw_meter.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bw_meter.h | 7 + icmp_socket.c | 18 ++ main.c | 2 + packet.h | 22 ++- routing.c | 15 ++- soft-interface.c | 5 + types.h | 38 ++++ 10 files changed, 634 insertions(+), 7 deletions(-) create mode 100644 bw_meter.c create mode 100644 bw_meter.h
The bandwith meter module is a simple, kernel-space replacement for bandwith measurements tool like iperf and netper. It is intended to approximate TCP behaviour.
It is invoked through ``batctl bw": the protocol is connection oriented, with cumulative acknowledgment and sliding window. Sender keeps a timeout, which is checked by a worker function regoularly invoked through the workqueue mechanism. If the timeout is expired at the time worker is executed, the whole window is re-transmitted.
Struct bw_vars, one for each connection, are collected into a linked list. Thus access to them is protected with a spinlock.
Another spinlock prevents more than one instance of multiple_send to run concurrently. Ack code is mutually exclusive (two ack handler cannot run at the same time for differnent acks), but they are not mutually exclusive with send_remaining_window, that is to say the ack handler shifts the window ``while" send_remaining_window is running. Maybe some atomic variable (window_first) is needed to avoid problems.
When the test is over, the results are returned to batctl through a call to the function batadv_socket_receive_packet(), before freeing struct batadv_bw_vars.
The function only accepts struct batadv_icmp_packet_rr, so that structure is used and a cast is done to struct batadv_bw_result.
The test interruptable with CTRL-C. A receiver side timeout avoids unlimited waitings for sender packets: after one second of inactivity, the receiver abort the ongoing test.
Signed-off-by: Edo Monticelli montik@autistici.org --- Makefile | 2 +- Makefile.kbuild | 1 + bw_meter.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bw_meter.h | 7 + icmp_socket.c | 18 ++ main.c | 2 + packet.h | 22 ++- routing.c | 15 ++- soft-interface.c | 5 + types.h | 36 ++++ 10 files changed, 614 insertions(+), 7 deletions(-) create mode 100644 bw_meter.c create mode 100644 bw_meter.h
diff --git a/Makefile b/Makefile index bd8d30c..12aebe5 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@
# changing the CONFIG_* line to 'y' enables the related feature # B.A.T.M.A.N. debugging: -export CONFIG_BATMAN_ADV_DEBUG=n +export CONFIG_BATMAN_ADV_DEBUG=y # B.A.T.M.A.N. bridge loop avoidance: export CONFIG_BATMAN_ADV_BLA=y
diff --git a/Makefile.kbuild b/Makefile.kbuild index 8676d2b..8c08ff9 100644 --- a/Makefile.kbuild +++ b/Makefile.kbuild @@ -23,6 +23,7 @@ batman-adv-y += bat_iv_ogm.o batman-adv-y += bitarray.o batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o batman-adv-y += debugfs.o +batman-adv-y += bw_meter.o batman-adv-y += gateway_client.o batman-adv-y += gateway_common.o batman-adv-y += hard-interface.o diff --git a/bw_meter.c b/bw_meter.c new file mode 100644 index 0000000..b5a67d3 --- /dev/null +++ b/bw_meter.c @@ -0,0 +1,513 @@ +#include "main.h" +#include "send.h" +#include "hash.h" +#include "originator.h" +#include "hard-interface.h" +#include "bw_meter.h" +#include "icmp_socket.h" +#include "types.h" +#include "bw_meter.h" + +#define BATADV_BW_PACKET_LEN 1400 +#define BATADV_BW_WINDOW_SIZE 30 +#define BATADV_BW_CLEAN_RECEIVER_TIMEOUT 2000 +#define BATADV_BW_TIMEOUT 60 +#define BATADV_BW_WORKER_TIMEOUT 30 +#define BATADV_BW_RECV_TIMEOUT 1000 +#define BATADV_BW_TOTAL_TO_SEND 5000 +#define BATADV_BW_MAX_RETRY 3 + +static int batadv_bw_queue_sender_worker(struct batadv_bw_vars *bw_vars); +static int batadv_bw_queue_receiver_worker(struct batadv_bw_vars *bw_vars); + +static void batadv_bw_vars_free(struct batadv_bw_vars *bw_vars) +{ + spin_lock_bh(&bw_vars->bat_priv->bw_list_lock); + list_del(&bw_vars->list); + spin_unlock_bh(&bw_vars->bat_priv->bw_list_lock); + kfree(bw_vars); +} + +static int batadv_bw_icmp_send(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + struct batadv_hard_iface *primary_if = NULL; + struct batadv_orig_node *orig_node = NULL; + struct batadv_neigh_node *neigh_node = NULL; + struct batadv_icmp_packet *icmp_packet; + int ret = -1; + + icmp_packet = (struct batadv_icmp_packet *)skb->data; + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: no primary if\n"); + goto out; + } + if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: mesh inactive\n"); + goto dst_unreach; + } + + orig_node = batadv_orig_hash_find(bat_priv, + icmp_packet->dst); + if (!orig_node) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: no orig node\n"); + goto dst_unreach; + } + + neigh_node = batadv_orig_node_get_router(orig_node); + if (!neigh_node) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: no neigh node\n"); + goto dst_unreach; + } + + if (!neigh_node->if_incoming) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: no if incoming\n"); + goto dst_unreach; + } + + if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter:batadv_bw_icmp_send: status not IF_ACTIVE\n"); + goto dst_unreach; + } + + memcpy(icmp_packet->orig, + primary_if->net_dev->dev_addr, ETH_ALEN); + + batadv_send_skb_packet(skb, neigh_node->if_incoming, + neigh_node->addr); + ret = 0; + goto out; + +dst_unreach: + /* TODO not in .h + icmp_to_send->msg_type = DESTINATION_UNREACHABLE; + batadv_socket_add_packet(socket_client, icmp_to_send, packet_len); + */ + +out: + if (primary_if) + batadv_hardif_free_ref(primary_if); + if (neigh_node) + batadv_neigh_node_free_ref(neigh_node); + if (orig_node) + batadv_orig_node_free_ref(orig_node); + return ret; +} + +static struct batadv_bw_vars *batadv_bw_list_find(struct batadv_priv *bat_priv, + void *dst) +{ + struct batadv_bw_vars *pos = NULL, *tmp; + + list_for_each_entry_safe(pos, tmp, &bat_priv->bw_list, list) { + if (memcmp(&pos->other_end, dst, ETH_ALEN) == 0) + return pos; + } + + return NULL; +} + +static int batadv_bw_ack_send(struct batadv_socket_client *socket_client, + struct batadv_icmp_packet *icmp_packet, + uint16_t seq) +{ + struct sk_buff *skb; + struct batadv_icmp_packet *icmp_ack; + struct batadv_priv *bat_priv = socket_client->bat_priv; + int ret = -1; + + bat_priv = socket_client->bat_priv; + skb = dev_alloc_skb(sizeof(*skb) + ETH_HLEN); + if (!skb) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_send_bw_ack cannot allocate skb\n"); + goto out; + } + + skb_reserve(skb, ETH_HLEN); + icmp_ack = (struct batadv_icmp_packet *) + skb_put(skb, sizeof(*icmp_ack)); + icmp_ack->header.packet_type = BATADV_ICMP; + icmp_ack->header.version = BATADV_COMPAT_VERSION; + icmp_ack->header.ttl = 50; + icmp_ack->seqno = htons(seq); + icmp_ack->msg_type = BATADV_BW_ACK; + memcpy(icmp_ack->dst, icmp_packet->orig, ETH_ALEN); + icmp_ack->uid = socket_client->index; + + /* send the ack */ + if (batadv_bw_icmp_send(bat_priv, skb) < 0) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_send_bw_ack cannot send_icmp_packet\n"); + goto out; + } + ret = 0; +out: + return ret; +} + +void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) +{ + struct batadv_bw_vars *bw_vars; + struct batadv_icmp_packet *icmp_packet; + struct batadv_socket_client *socket_client; + uint16_t seqno; + socket_client = container_of(&bat_priv, + struct batadv_socket_client, bat_priv); + + icmp_packet = (struct batadv_icmp_packet *)skb->data; + + /* search/initialize bw_vars struct */ + spin_lock_bh(&bat_priv->bw_list_lock); + seqno = ntohs(icmp_packet->seqno); + bw_vars = batadv_bw_list_find(bat_priv, &icmp_packet->dst); + if (!bw_vars) { + if (seqno != 0) { + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: seq != 0 cannot initiate connection\n"); + goto out; + } + bw_vars = kmalloc(sizeof(*bw_vars), GFP_ATOMIC); + if (!bw_vars) { + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: meter_received cannot allocate bw_vars\n"); + goto out; + } + memcpy(&bw_vars->other_end, &icmp_packet->dst, ETH_ALEN); + bw_vars->status = RECEIVER; + bw_vars->window_first = 0; + bw_vars->bat_priv = bat_priv; + spin_lock_init(&bw_vars->bw_vars_lock); + list_add(&bw_vars->list, &bat_priv->bw_list); + + batadv_bw_queue_receiver_worker(bw_vars); + + } + + if (bw_vars->status != RECEIVER) { + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: dropping packet: connection is not expecting any\n"); + goto out; + } + spin_unlock_bh(&bat_priv->bw_list_lock); + + /* check if the packet belongs to window */ + spin_lock_bh(&bw_vars->bw_vars_lock); + if (seqno < bw_vars->window_first) { + spin_unlock_bh(&bw_vars->bw_vars_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: %d < window_first\n", icmp_packet->seqno); + goto out; /* TODO send an ack! */ + } + + if (seqno > bw_vars->window_first + BATADV_BW_WINDOW_SIZE) { + spin_unlock_bh(&bw_vars->bw_vars_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: unexpected packet received\n"); + goto out; /* TODO ?? */ + } + + /* packet does belong to the window */ + if (seqno == bw_vars->window_first) { + bw_vars->window_first++; + bw_vars->last_sent_time = jiffies; + spin_unlock_bh(&bw_vars->bw_vars_lock); + + batadv_bw_ack_send(socket_client, + (struct batadv_icmp_packet *)icmp_packet, + seqno); + + /* check for the last packet */ + if (skb->len < BATADV_BW_PACKET_LEN) { + bw_vars->status = COMPLETED; + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: succesfully completed test with node %02x:%02x:%02x:%02x:%02x:%02x\n", + icmp_packet->orig[0], icmp_packet->orig[1], + icmp_packet->orig[2], icmp_packet->orig[3], + icmp_packet->orig[4], icmp_packet->orig[5]); + } + } else { + spin_unlock_bh(&bw_vars->bw_vars_lock); + } +out: + return; +} + +/* Sends all packets that belongs to the window and have not been sent yet + * according to next_to_send and (window_first + BW_WINDOW_SIZE) + */ +static int batadv_bw_multiple_send(struct batadv_priv *bat_priv, + struct batadv_bw_vars *bw_vars) +{ + struct sk_buff *skb; + struct batadv_icmp_packet *icmp_to_send; + struct batadv_socket_client *socket_client; + int ret, bw_packet_len; + uint16_t window_default_end, window_end, next_to_send; + + ret = -1; + bw_packet_len = BATADV_BW_PACKET_LEN; + socket_client = container_of(&bat_priv, struct batadv_socket_client, + bat_priv); + + if (!spin_trylock_bh(&bw_vars->bw_send_lock)) + goto out; + + while (1) { + spin_lock_bh(&bw_vars->bw_window_first_lock); + window_default_end = bw_vars->window_first + + BATADV_BW_WINDOW_SIZE; + window_end = min(window_default_end, bw_vars->total_to_send); + + if (!batadv_seq_before(bw_vars->next_to_send, window_end)) { + spin_unlock_bh(&bw_vars->bw_send_lock); + spin_unlock_bh(&bw_vars->bw_window_first_lock); + break; + } + + next_to_send = bw_vars->next_to_send++; + bw_vars->last_sent_time = jiffies; + spin_unlock_bh(&bw_vars->bw_window_first_lock); + + if (bw_vars->next_to_send == bw_vars->total_to_send) + bw_packet_len -= 1; + + skb = dev_alloc_skb(bw_packet_len + ETH_HLEN); + if (!skb) { + spin_unlock_bh(&bw_vars->bw_send_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_bw_multiple_send() cannot allocate skb\n"); + goto out; + } + + /* TODO redefine BW_PACKET_LEN */ + skb_reserve(skb, ETH_HLEN); + icmp_to_send = (struct batadv_icmp_packet *) + skb_put(skb, bw_packet_len); + + /* fill the icmp header */ + memcpy(&icmp_to_send->dst, &bw_vars->other_end, ETH_ALEN); + icmp_to_send->header.version = BATADV_COMPAT_VERSION; + icmp_to_send->header.packet_type = BATADV_ICMP; + icmp_to_send->msg_type = BATADV_BW_START; + icmp_to_send->seqno = htons(next_to_send); + icmp_to_send->uid = socket_client->index; + + if (batadv_bw_icmp_send(bat_priv, skb) < 0) { + spin_unlock_bh(&bw_vars->bw_send_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_bw_multiple_send() cannot send_icmp_packet\n"); + goto out; + } + } + ret = 0; +out: + return ret; +} + +void batadv_bw_ack_received(struct batadv_priv *bat_priv, + struct sk_buff *skb) +{ + struct batadv_icmp_packet *icmp_packet; + struct batadv_bw_vars *bw_vars; + uint16_t window_end, seqno; + + icmp_packet = (struct batadv_icmp_packet *)skb->data; + + /* find the bw_vars */ + spin_lock_bh(&bat_priv->bw_list_lock); + bw_vars = batadv_bw_list_find(bat_priv, &icmp_packet->orig); + spin_unlock_bh(&bat_priv->bw_list_lock); + + if (!bw_vars) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: received an ack not related to an open connection\n"); + goto out; + } + + /* slide and send fresh packets */ + spin_lock_bh(&bw_vars->bw_window_first_lock); + seqno = ntohs(icmp_packet->seqno); + window_end = bw_vars->window_first + BATADV_BW_WINDOW_SIZE; + if (!batadv_seq_after(bw_vars->window_first, seqno) && + batadv_seq_before(seqno, bw_vars->next_to_send)) { + bw_vars->window_first = seqno + 1; + } else if (bw_vars->status != ABORTING) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: received unespected ack\n"); + } + + spin_unlock_bh(&bw_vars->bw_window_first_lock); + batadv_bw_multiple_send(bat_priv, bw_vars); +out: + return; +} + +static void batadv_bw_receiver_worker(struct work_struct *work) +{ + struct delayed_work *delayed_work; + struct batadv_bw_vars *bw_vars; + struct batadv_priv *bat_priv; + + delayed_work = container_of(work, struct delayed_work, work); + bw_vars = container_of(delayed_work, struct batadv_bw_vars, bw_work); + bat_priv = bw_vars->bat_priv; + + if (batadv_has_timed_out(bw_vars->last_sent_time, + BATADV_BW_RECV_TIMEOUT)) { + if (bw_vars->status != COMPLETED) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: more than %dms of inactivity: test will be aborted!\n", + BATADV_BW_RECV_TIMEOUT); + } + batadv_bw_vars_free(bw_vars); + } else { + batadv_bw_queue_receiver_worker(bw_vars); + } +} +static void batadv_bw_sender_worker(struct work_struct *work) +{ + struct delayed_work *delayed_work; + struct batadv_bw_vars *bw_vars; + struct batadv_priv *bat_priv; + struct batadv_bw_result *result; + struct batadv_icmp_packet_rr *icmp_packet_rr; + + delayed_work = container_of(work, struct delayed_work, work); + bw_vars = container_of(delayed_work, struct batadv_bw_vars, bw_work); + bat_priv = bw_vars->bat_priv; + + /* if timedout, resend whole window */ + if (batadv_has_timed_out(bw_vars->last_sent_time, BATADV_BW_TIMEOUT)) { + pr_info("RESENDING WHOLE WINDOW %d\n", bw_vars->window_first); + bw_vars->next_to_send = bw_vars->window_first; + batadv_bw_multiple_send(bat_priv, bw_vars); + } + + if (bw_vars->window_first < bw_vars->total_to_send) { + /* if not finished, re-enqueue worker */ + if (batadv_bw_queue_sender_worker(bw_vars) == 0) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_bw_start work already enqueued\n"); + } + + } else { + /* send the answer to batctl */ + icmp_packet_rr = kmalloc(sizeof(*icmp_packet_rr), GFP_ATOMIC); + icmp_packet_rr->uid = bw_vars->socket_client->index; + result = (struct batadv_bw_result *)icmp_packet_rr; + if (bw_vars->status == ABORTING) { + result->test_time = 0; + result->total_bytes = 0; + } else { + result->test_time = ((long)jiffies - + (long)bw_vars->start_time) * + (1000/HZ); + result->total_bytes = bw_vars->total_to_send * + BATADV_BW_PACKET_LEN; + } + batadv_socket_receive_packet(icmp_packet_rr, + sizeof(*icmp_packet_rr)); + batadv_bw_vars_free(bw_vars); + } +} + +static int batadv_bw_queue_sender_worker(struct batadv_bw_vars *bw_vars) +{ + int ret; + INIT_DELAYED_WORK(&bw_vars->bw_work, batadv_bw_sender_worker); + ret = queue_delayed_work(batadv_event_workqueue, &bw_vars->bw_work, + msecs_to_jiffies(BATADV_BW_WORKER_TIMEOUT)); + + return ret; +} + +static int batadv_bw_queue_receiver_worker(struct batadv_bw_vars *bw_vars) +{ + int ret; + INIT_DELAYED_WORK(&bw_vars->bw_work, batadv_bw_receiver_worker); + ret = queue_delayed_work(batadv_event_workqueue, &bw_vars->bw_work, + msecs_to_jiffies(BATADV_BW_RECV_TIMEOUT)); + + return ret; +} + +void batadv_bw_stop(struct batadv_priv *bat_priv, + struct batadv_icmp_packet *icmp_packet) +{ + struct batadv_bw_vars *bw_vars; + spin_lock_bh(&bat_priv->bw_list_lock); + bw_vars = batadv_bw_list_find(bat_priv, &icmp_packet->dst); + if (!bw_vars) { + /* TODO notify batctl */ + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: trying to interrupt an already over connection\n"); + return; + } + spin_unlock_bh(&bat_priv->bw_list_lock); + spin_lock_bh(&bw_vars->bw_window_first_lock); + bw_vars->window_first = BATADV_BW_TOTAL_TO_SEND; + bw_vars->status = ABORTING; + spin_unlock_bh(&bw_vars->bw_window_first_lock); +} + +void batadv_bw_start(struct batadv_socket_client *socket_client, + struct batadv_icmp_packet *icmp_packet) +{ + struct batadv_priv *bat_priv = socket_client->bat_priv; + struct batadv_bw_vars *bw_vars; + + /* find bw_vars */ + spin_lock_bh(&bat_priv->bw_list_lock); + bw_vars = batadv_bw_list_find(bat_priv, &icmp_packet->dst); + if (bw_vars) { + /* TODO notify batctl */ + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: test to or from the same node already ongoing, aborting\n"); + goto out; + } + + bw_vars = kmalloc(sizeof(*bw_vars), GFP_ATOMIC); + if (!bw_vars) { + spin_unlock_bh(&bat_priv->bw_list_lock); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_bw_start cannot allocate list elements\n"); + goto out; + } + + /* initialize bw_vars */ + memcpy(&bw_vars->other_end, &icmp_packet->dst, ETH_ALEN); + bw_vars->total_to_send = BATADV_BW_TOTAL_TO_SEND; + bw_vars->next_to_send = 0; + bw_vars->window_first = 0; + bw_vars->bat_priv = bat_priv; + bw_vars->socket_client = socket_client; + bw_vars->last_sent_time = jiffies; + bw_vars->start_time = jiffies; + spin_lock_init(&bw_vars->bw_window_first_lock); + spin_lock_init(&bw_vars->bw_send_lock); + list_add(&bw_vars->list, &bat_priv->bw_list); + spin_unlock_bh(&bat_priv->bw_list_lock); + + /* start worker */ + if (batadv_bw_queue_sender_worker(bw_vars) == 0) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Meter: batadv_bw_start work already enqueued\n"); + } + + batadv_bw_multiple_send(bat_priv, bw_vars); +out: + return; +} diff --git a/bw_meter.h b/bw_meter.h new file mode 100644 index 0000000..3c04521 --- /dev/null +++ b/bw_meter.h @@ -0,0 +1,7 @@ +void batadv_bw_start(struct batadv_socket_client *socket_client, + struct batadv_icmp_packet *icmp_packet_bw); +void batadv_bw_stop(struct batadv_priv *bat_priv, + struct batadv_icmp_packet *icmp_packet); +void batadv_bw_meter_received(struct batadv_priv *bat_priv, + struct sk_buff *skb); +void batadv_bw_ack_received(struct batadv_priv *bat_priv, struct sk_buff *skb); diff --git a/icmp_socket.c b/icmp_socket.c index bde3cf7..f9f6435 100644 --- a/icmp_socket.c +++ b/icmp_socket.c @@ -20,11 +20,13 @@ #include "main.h" #include <linux/debugfs.h> #include <linux/slab.h> + #include "icmp_socket.h" #include "send.h" #include "hash.h" #include "originator.h" #include "hard-interface.h" +#include "bw_meter.h"
static struct batadv_socket_client *batadv_socket_client_hash[256];
@@ -152,6 +154,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, struct batadv_hard_iface *primary_if = NULL; struct sk_buff *skb; struct batadv_icmp_packet_rr *icmp_packet; + struct batadv_icmp_packet icmp_packet_bw;
struct batadv_orig_node *orig_node = NULL; struct batadv_neigh_node *neigh_node = NULL; @@ -170,6 +173,21 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, goto out; }
+ if (copy_from_user(&icmp_packet_bw, buff, sizeof(icmp_packet_bw))) { + len = -EFAULT; + goto out; + } + + if (icmp_packet_bw.msg_type == BATADV_BW_START) { + batadv_bw_start(socket_client, &icmp_packet_bw); + goto out; + } + + if (icmp_packet_bw.msg_type == BATADV_BW_STOP) { + batadv_bw_stop(bat_priv, &icmp_packet_bw); + goto out; + } + if (len >= sizeof(struct batadv_icmp_packet_rr)) packet_len = sizeof(struct batadv_icmp_packet_rr);
diff --git a/main.c b/main.c index b4aa470..23a49e3 100644 --- a/main.c +++ b/main.c @@ -101,6 +101,7 @@ int batadv_mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->gw.list_lock); spin_lock_init(&bat_priv->vis.hash_lock); spin_lock_init(&bat_priv->vis.list_lock); + spin_lock_init(&bat_priv->bw_list_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); @@ -108,6 +109,7 @@ int batadv_mesh_init(struct net_device *soft_iface) INIT_LIST_HEAD(&bat_priv->tt.changes_list); INIT_LIST_HEAD(&bat_priv->tt.req_list); INIT_LIST_HEAD(&bat_priv->tt.roam_list); + INIT_LIST_HEAD(&bat_priv->bw_list);
ret = batadv_originator_init(bat_priv); if (ret < 0) diff --git a/packet.h b/packet.h index 2d23a14..1fd4e7f 100644 --- a/packet.h +++ b/packet.h @@ -44,12 +44,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 +158,15 @@ struct batadv_icmp_packet_rr { uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; } __packed;
+/* 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; +}; + struct batadv_unicast_packet { struct batadv_header header; uint8_t ttvn; /* destination translation table version number */ diff --git a/routing.c b/routing.c index 939fc01..f82751d 100644 --- a/routing.c +++ b/routing.c @@ -28,6 +28,7 @@ #include "vis.h" #include "unicast.h" #include "bridge_loop_avoidance.h" +#include "bw_meter.h"
static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if); @@ -290,6 +291,16 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
icmp_packet = (struct batadv_icmp_packet_rr *)skb->data;
+ if (icmp_packet->msg_type == BATADV_BW_START) { + batadv_bw_meter_received(bat_priv, skb); + goto out; + } + + if (icmp_packet->msg_type == BATADV_BW_ACK) { + batadv_bw_ack_received(bat_priv, skb); + goto out; + } + /* add data to device queue */ if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { batadv_socket_receive_packet(icmp_packet, icmp_len); @@ -427,7 +438,9 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
/* add record route information if not full */ if ((hdr_size == sizeof(struct batadv_icmp_packet_rr)) && - (icmp_packet->rr_cur < BATADV_RR_LEN)) { + (icmp_packet->rr_cur < BATADV_RR_LEN) && + (icmp_packet->msg_type != BATADV_BW_START) && + (icmp_packet->msg_type != BATADV_BW_ACK)) { memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), ethhdr->h_dest, ETH_ALEN); icmp_packet->rr_cur++; diff --git a/soft-interface.c b/soft-interface.c index 1aee7db..15077ac 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -438,6 +438,11 @@ struct net_device *batadv_softif_create(const char *name) bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0;
+ bat_priv->bat_counters = __alloc_percpu(sizeof(uint64_t) * BATADV_CNT_NUM, + __alignof__(uint64_t)); + if (!bat_priv->bat_counters) + goto unreg_soft_iface; + ret = batadv_algo_select(bat_priv, batadv_routing_algo); if (ret < 0) goto unreg_soft_iface; diff --git a/types.h b/types.h index 2ed82ca..813914c 100644 --- a/types.h +++ b/types.h @@ -226,6 +226,35 @@ struct batadv_priv_vis { struct batadv_vis_info *my_info; };
+enum bw_meter_status { + RECEIVER, + SENDER, + ABORTING, + COMPLETED, +}; + +struct batadv_bw_vars { + struct list_head list; + struct delayed_work bw_work; + struct batadv_priv *bat_priv; + struct batadv_socket_client *socket_client; + /* lock used in receiver */ + spinlock_t bw_vars_lock; + /* locks used in sender */ + spinlock_t bw_window_first_lock; + /* protects multiple_send calls */ + spinlock_t bw_send_lock; + /* total data to send OR window data received */ + uint16_t total_to_send; + /* offset of the first window packet */ + uint16_t next_to_send; + uint16_t window_first; + uint8_t other_end[ETH_ALEN]; + uint8_t status; /* see bm_meter_status */ + unsigned long start_time; + unsigned long last_sent_time; +}; + struct batadv_priv { atomic_t mesh_state; struct net_device_stats stats; @@ -251,18 +280,25 @@ struct batadv_priv { struct dentry *debug_dir; struct hlist_head forw_bat_list; struct hlist_head forw_bcast_list; + + struct list_head bw_list; struct batadv_hashtable *orig_hash; spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ spinlock_t forw_bcast_list_lock; /* protects */ struct delayed_work orig_work; struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ struct batadv_algo_ops *bat_algo_ops; + #ifdef CONFIG_BATMAN_ADV_BLA struct batadv_priv_bla bla; #endif struct batadv_priv_gw gw; struct batadv_priv_tt tt; struct batadv_priv_vis vis; + + struct delayed_work bw_work; + struct batadv_bw_vars *bw_vars; + spinlock_t bw_list_lock; /* protects bw_list */ };
struct batadv_socket_client {
On Thursday 09 August 2012 14:15:24 Edo Monticelli wrote:
The bandwith meter module is a simple, kernel-space replacement for bandwith measurements tool like iperf and netper. It is intended to approximate TCP behaviour.
It is invoked through ``batctl bw": the protocol is connection oriented, with cumulative acknowledgment and sliding window. Sender keeps a timeout, which is checked by a worker function regoularly invoked through the workqueue mechanism. If the timeout is expired at the time worker is executed, the whole window is re-transmitted.
Struct bw_vars, one for each connection, are collected into a linked list. Thus access to them is protected with a spinlock.
Another spinlock prevents more than one instance of multiple_send to run concurrently. Ack code is mutually exclusive (two ack handler cannot run at the same time for differnent acks), but they are not mutually exclusive with send_remaining_window, that is to say the ack handler shifts the window ``while" send_remaining_window is running. Maybe some atomic variable (window_first) is needed to avoid problems.
When the test is over, the results are returned to batctl through a call to the function batadv_socket_receive_packet(), before freeing struct batadv_bw_vars.
The function only accepts struct batadv_icmp_packet_rr, so that structure is used and a cast is done to struct batadv_bw_result.
The test interruptable with CTRL-C. A receiver side timeout avoids unlimited waitings for sender packets: after one second of inactivity, the receiver abort the ongoing test.
Signed-off-by: Edo Monticelli montik@autistici.org
Makefile | 2 +- Makefile.kbuild | 1 + bw_meter.c | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bw_meter.h | 7 + icmp_socket.c | 18 ++ main.c | 2 + packet.h | 22 ++- routing.c | 15 ++- soft-interface.c | 5 + types.h | 36 ++++ 10 files changed, 614 insertions(+), 7 deletions(-) create mode 100644 bw_meter.c create mode 100644 bw_meter.h
diff --git a/Makefile b/Makefile index bd8d30c..12aebe5 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@
# changing the CONFIG_* line to 'y' enables the related feature # B.A.T.M.A.N. debugging: -export CONFIG_BATMAN_ADV_DEBUG=n +export CONFIG_BATMAN_ADV_DEBUG=y # B.A.T.M.A.N. bridge loop avoidance: export CONFIG_BATMAN_ADV_BLA=y
Sry, disapproved.
Kind regards, Sven
On Sunday 12 August 2012 14:20:57 Sven Eckelmann wrote: [...]
Sry, disapproved.
And just because I just saw it in your git branch:
--- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ # B.A.T.M.A.N. debugging: export CONFIG_BATMAN_ADV_DEBUG=n # B.A.T.M.A.N. bridge loop avoidance: -export CONFIG_BATMAN_ADV_BLA=y +export CONFIG_BATMAN_ADV_BLA=n
PWD:=$(shell pwd) KERNELPATH ?= /lib/modules/$(shell uname -r)/build
This is also not acceptable.
Kind regards, Sven
On Thursday 09 August 2012 14:15:24 Edo Monticelli wrote: [...]
+dst_unreach:
- /* TODO not in .h
- icmp_to_send->msg_type = DESTINATION_UNREACHABLE;
- batadv_socket_add_packet(socket_client, icmp_to_send, packet_len);
*/
[...]
goto out; /* TODO send an ack! */
[...]
goto out; /* TODO ?? */
[...]
/* TODO redefine BW_PACKET_LEN */
skb_reserve(skb, ETH_HLEN);
icmp_to_send = (struct batadv_icmp_packet *)
skb_put(skb, bw_packet_len);
[...]
/* TODO notify batctl */
spin_unlock_bh(&bat_priv->bw_list_lock);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Meter: trying to interrupt an already over connection\n");
return;
- }
[...]
/* TODO notify batctl */
spin_unlock_bh(&bat_priv->bw_list_lock);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Meter: test to or from the same node already ongoing,
aborting\n");
goto out;
- }
Mh, Looks like some open tasks... ;)
Can you also convert (and of course add) the documentation of all new functions/structures to KernelDoc style. Example templates can be found at http://www.open-mesh.org/projects/batman-adv/wiki/KernelDoc
Kind regards, Sven
Added a sender-side counter of the number of retransmission of the *same window*, defaults to BATADV_BW_MAX_SENDER_RETRANSMISSIONS. After them, test is aborted.
Signed-off-by: Edo Monticelli montik@autistici.org --- bw_meter.c | 18 +++++++++++++++--- types.h | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/bw_meter.c b/bw_meter.c index b5a67d3..b582ab0 100644 --- a/bw_meter.c +++ b/bw_meter.c @@ -389,20 +389,31 @@ static void batadv_bw_sender_worker(struct work_struct *work)
/* if timedout, resend whole window */ if (batadv_has_timed_out(bw_vars->last_sent_time, BATADV_BW_TIMEOUT)) { + /* increase resend counters */ + if (bw_vars->window_first == bw_vars->last_resent_window) { + bw_vars->retry_number += 1; + if (bw_vars->retry_number > BATADV_BW_MAX_RETRY) { + bw_vars->window_first = BATADV_BW_TOTAL_TO_SEND; + bw_vars->status = ABORTING; + } + } else { + bw_vars->retry_number = 0; + } + pr_info("RESENDING WHOLE WINDOW %d\n", bw_vars->window_first); + bw_vars->last_resent_window = bw_vars->window_first; bw_vars->next_to_send = bw_vars->window_first; batadv_bw_multiple_send(bat_priv, bw_vars); }
+ /* if not finished, re-enqueue worker */ if (bw_vars->window_first < bw_vars->total_to_send) { - /* if not finished, re-enqueue worker */ if (batadv_bw_queue_sender_worker(bw_vars) == 0) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Meter: batadv_bw_start work already enqueued\n"); } - + /* send the answer to batctl */ } else { - /* send the answer to batctl */ icmp_packet_rr = kmalloc(sizeof(*icmp_packet_rr), GFP_ATOMIC); icmp_packet_rr->uid = bw_vars->socket_client->index; result = (struct batadv_bw_result *)icmp_packet_rr; @@ -492,6 +503,7 @@ void batadv_bw_start(struct batadv_socket_client *socket_client, bw_vars->total_to_send = BATADV_BW_TOTAL_TO_SEND; bw_vars->next_to_send = 0; bw_vars->window_first = 0; + bw_vars->last_resent_window = 0; bw_vars->bat_priv = bat_priv; bw_vars->socket_client = socket_client; bw_vars->last_sent_time = jiffies; diff --git a/types.h b/types.h index 813914c..e5ba150 100644 --- a/types.h +++ b/types.h @@ -253,6 +253,8 @@ struct batadv_bw_vars { uint8_t status; /* see bm_meter_status */ unsigned long start_time; unsigned long last_sent_time; + uint8_t retry_number; + uint16_t last_resent_window; };
struct batadv_priv {
Sequence number in packet header is 16 bit and is made wrap around safe. Two 32 bit counters, window_first and total_to_send are locally kept in the struct bw_vars. On packet or acks arrival batadv_seq_before()/after() are used to check seqno against 16bit version of these counters. BATADV_BW_FIRST_SEQ is the sequence number of the first packet. It is set to 65530 to generate a wrap-around. *Both sides must agree on this value*
Signed-off-by: Edo Monticelli montik@autistici.org --- bw_meter.c | 56 +++++++++++++++++++++++++++++++------------------------- types.h | 4 ++-- 2 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/bw_meter.c b/bw_meter.c index b582ab0..c636c53 100644 --- a/bw_meter.c +++ b/bw_meter.c @@ -16,6 +16,7 @@ #define BATADV_BW_RECV_TIMEOUT 1000 #define BATADV_BW_TOTAL_TO_SEND 5000 #define BATADV_BW_MAX_RETRY 3 +#define BATADV_BW_FIRST_SEQ 65530
static int batadv_bw_queue_sender_worker(struct batadv_bw_vars *bw_vars); static int batadv_bw_queue_receiver_worker(struct batadv_bw_vars *bw_vars); @@ -158,7 +159,7 @@ void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) struct batadv_bw_vars *bw_vars; struct batadv_icmp_packet *icmp_packet; struct batadv_socket_client *socket_client; - uint16_t seqno; + uint16_t seqno, window_first_16; socket_client = container_of(&bat_priv, struct batadv_socket_client, bat_priv);
@@ -169,7 +170,7 @@ void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) seqno = ntohs(icmp_packet->seqno); bw_vars = batadv_bw_list_find(bat_priv, &icmp_packet->dst); if (!bw_vars) { - if (seqno != 0) { + if (seqno != BATADV_BW_FIRST_SEQ) { spin_unlock_bh(&bat_priv->bw_list_lock); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Meter: seq != 0 cannot initiate connection\n"); @@ -184,7 +185,7 @@ void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) } memcpy(&bw_vars->other_end, &icmp_packet->dst, ETH_ALEN); bw_vars->status = RECEIVER; - bw_vars->window_first = 0; + bw_vars->window_first = BATADV_BW_FIRST_SEQ; bw_vars->bat_priv = bat_priv; spin_lock_init(&bw_vars->bw_vars_lock); list_add(&bw_vars->list, &bat_priv->bw_list); @@ -199,18 +200,20 @@ void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) "Meter: dropping packet: connection is not expecting any\n"); goto out; } + window_first_16 = (uint16_t) bw_vars->window_first; spin_unlock_bh(&bat_priv->bw_list_lock);
/* check if the packet belongs to window */ spin_lock_bh(&bw_vars->bw_vars_lock); - if (seqno < bw_vars->window_first) { + if (batadv_seq_before(seqno, window_first_16)) { spin_unlock_bh(&bw_vars->bw_vars_lock); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Meter: %d < window_first\n", icmp_packet->seqno); goto out; /* TODO send an ack! */ }
- if (seqno > bw_vars->window_first + BATADV_BW_WINDOW_SIZE) { + if (batadv_seq_after(seqno, (uint16_t) (window_first_16 + + BATADV_BW_WINDOW_SIZE))) { spin_unlock_bh(&bw_vars->bw_vars_lock); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Meter: unexpected packet received\n"); @@ -218,7 +221,7 @@ void batadv_bw_meter_received(struct batadv_priv *bat_priv, struct sk_buff *skb) }
/* packet does belong to the window */ - if (seqno == bw_vars->window_first) { + if (seqno == window_first_16) { bw_vars->window_first++; bw_vars->last_sent_time = jiffies; spin_unlock_bh(&bw_vars->bw_vars_lock); @@ -253,7 +256,7 @@ static int batadv_bw_multiple_send(struct batadv_priv *bat_priv, struct batadv_icmp_packet *icmp_to_send; struct batadv_socket_client *socket_client; int ret, bw_packet_len; - uint16_t window_default_end, window_end, next_to_send; + uint16_t window_end, next_to_send;
ret = -1; bw_packet_len = BATADV_BW_PACKET_LEN; @@ -265,9 +268,8 @@ static int batadv_bw_multiple_send(struct batadv_priv *bat_priv,
while (1) { spin_lock_bh(&bw_vars->bw_window_first_lock); - window_default_end = bw_vars->window_first + - BATADV_BW_WINDOW_SIZE; - window_end = min(window_default_end, bw_vars->total_to_send); + window_end = min(bw_vars->window_first + BATADV_BW_WINDOW_SIZE, + bw_vars->total_to_send);
if (!batadv_seq_before(bw_vars->next_to_send, window_end)) { spin_unlock_bh(&bw_vars->bw_send_lock); @@ -275,12 +277,15 @@ static int batadv_bw_multiple_send(struct batadv_priv *bat_priv, break; }
- next_to_send = bw_vars->next_to_send++; bw_vars->last_sent_time = jiffies; + next_to_send = bw_vars->next_to_send++; spin_unlock_bh(&bw_vars->bw_window_first_lock);
- if (bw_vars->next_to_send == bw_vars->total_to_send) + if ((bw_vars->window_first + BATADV_BW_WINDOW_SIZE >= + bw_vars->total_to_send) && + bw_vars->next_to_send == (uint16_t)bw_vars->total_to_send) { bw_packet_len -= 1; + }
skb = dev_alloc_skb(bw_packet_len + ETH_HLEN); if (!skb) { @@ -320,7 +325,7 @@ void batadv_bw_ack_received(struct batadv_priv *bat_priv, { struct batadv_icmp_packet *icmp_packet; struct batadv_bw_vars *bw_vars; - uint16_t window_end, seqno; + uint16_t seqno, window_end, window_first_16;
icmp_packet = (struct batadv_icmp_packet *)skb->data;
@@ -338,10 +343,11 @@ void batadv_bw_ack_received(struct batadv_priv *bat_priv, /* slide and send fresh packets */ spin_lock_bh(&bw_vars->bw_window_first_lock); seqno = ntohs(icmp_packet->seqno); - window_end = bw_vars->window_first + BATADV_BW_WINDOW_SIZE; - if (!batadv_seq_after(bw_vars->window_first, seqno) && + window_first_16 = (uint16_t) bw_vars->window_first; + window_end = window_first_16 + BATADV_BW_WINDOW_SIZE; + if (!batadv_seq_after(window_first_16, seqno) && batadv_seq_before(seqno, bw_vars->next_to_send)) { - bw_vars->window_first = seqno + 1; + bw_vars->window_first += seqno + 1 - window_first_16; } else if (bw_vars->status != ABORTING) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Meter: received unespected ack\n"); @@ -393,14 +399,15 @@ static void batadv_bw_sender_worker(struct work_struct *work) if (bw_vars->window_first == bw_vars->last_resent_window) { bw_vars->retry_number += 1; if (bw_vars->retry_number > BATADV_BW_MAX_RETRY) { - bw_vars->window_first = BATADV_BW_TOTAL_TO_SEND; + bw_vars->window_first = bw_vars->total_to_send; bw_vars->status = ABORTING; } } else { bw_vars->retry_number = 0; }
- pr_info("RESENDING WHOLE WINDOW %d\n", bw_vars->window_first); + pr_info("RESENDING WHOLE WINDOW %d\n", + (uint16_t)bw_vars->window_first); bw_vars->last_resent_window = bw_vars->window_first; bw_vars->next_to_send = bw_vars->window_first; batadv_bw_multiple_send(bat_priv, bw_vars); @@ -422,9 +429,8 @@ static void batadv_bw_sender_worker(struct work_struct *work) result->total_bytes = 0; } else { result->test_time = ((long)jiffies - - (long)bw_vars->start_time) * - (1000/HZ); - result->total_bytes = bw_vars->total_to_send * + (long)bw_vars->start_time); + result->total_bytes = BATADV_BW_TOTAL_TO_SEND * BATADV_BW_PACKET_LEN; } batadv_socket_receive_packet(icmp_packet_rr, @@ -468,7 +474,7 @@ void batadv_bw_stop(struct batadv_priv *bat_priv, } spin_unlock_bh(&bat_priv->bw_list_lock); spin_lock_bh(&bw_vars->bw_window_first_lock); - bw_vars->window_first = BATADV_BW_TOTAL_TO_SEND; + bw_vars->window_first = bw_vars->total_to_send; bw_vars->status = ABORTING; spin_unlock_bh(&bw_vars->bw_window_first_lock); } @@ -500,9 +506,9 @@ void batadv_bw_start(struct batadv_socket_client *socket_client,
/* initialize bw_vars */ memcpy(&bw_vars->other_end, &icmp_packet->dst, ETH_ALEN); - bw_vars->total_to_send = BATADV_BW_TOTAL_TO_SEND; - bw_vars->next_to_send = 0; - bw_vars->window_first = 0; + bw_vars->total_to_send = BATADV_BW_TOTAL_TO_SEND + BATADV_BW_FIRST_SEQ; + bw_vars->window_first = BATADV_BW_FIRST_SEQ; + bw_vars->next_to_send = BATADV_BW_FIRST_SEQ; bw_vars->last_resent_window = 0; bw_vars->bat_priv = bat_priv; bw_vars->socket_client = socket_client; diff --git a/types.h b/types.h index e5ba150..dd515e6 100644 --- a/types.h +++ b/types.h @@ -245,10 +245,10 @@ struct batadv_bw_vars { /* protects multiple_send calls */ spinlock_t bw_send_lock; /* total data to send OR window data received */ - uint16_t total_to_send; + uint32_t total_to_send; /* offset of the first window packet */ uint16_t next_to_send; - uint16_t window_first; + uint32_t window_first; uint8_t other_end[ETH_ALEN]; uint8_t status; /* see bm_meter_status */ unsigned long start_time;
Hello Edo,
as discussed already, some general remarks:
* please squash these patches to one - as far as I can see, the 2 others are mostly fixes to the first one * Don't turn on debugging in the Makefile - we don't want that by default * please also include the batctl patch, it is important for testing
Thanks Simon
On Thu, Aug 09, 2012 at 02:15:23PM +0200, Edo Monticelli wrote:
Hi,
I have almost completed my Google Summer of Code project and I'd like to have a feedback from the batman community. The project is a kernel-space bandwidth meter, a lightweight tool to measure network performance between batman nodes. You can find a general project description in the project wiki page:
http://www.open-mesh.org/projects/batman-adv/wiki/GSOC2012_BW
Any advice is welcome, Edo Monticelli
Edo Monticelli (3): batman-adv: bandwidth meter implementation batman-adv: sender retransmission counter batman-adv: seqnumber is wrap around safe
Makefile | 2 +- Makefile.kbuild | 1 + bw_meter.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bw_meter.h | 7 + icmp_socket.c | 18 ++ main.c | 2 + packet.h | 22 ++- routing.c | 15 ++- soft-interface.c | 5 + types.h | 38 ++++ 10 files changed, 634 insertions(+), 7 deletions(-) create mode 100644 bw_meter.c create mode 100644 bw_meter.h
-- 1.7.8.6
b.a.t.m.a.n@lists.open-mesh.org