public inbox for b.a.t.m.a.n@lists.open-mesh.org
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project
@ 2012-08-09 12:15 Edo Monticelli
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Edo Monticelli @ 2012-08-09 12:15 UTC (permalink / raw)
  To: b.a.t.m.a.n

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


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation
  2012-08-09 12:15 [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Edo Monticelli
@ 2012-08-09 12:15 ` Edo Monticelli
  2012-08-12 12:20   ` Sven Eckelmann
  2012-08-13  9:14   ` Sven Eckelmann
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 2/3] batman-adv: sender retransmission counter Edo Monticelli
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 8+ messages in thread
From: Edo Monticelli @ 2012-08-09 12:15 UTC (permalink / raw)
  To: b.a.t.m.a.n

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 {
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [B.A.T.M.A.N.] [RFC 2/3] batman-adv: sender retransmission counter
  2012-08-09 12:15 [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Edo Monticelli
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
@ 2012-08-09 12:15 ` Edo Monticelli
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 3/3] batman-adv: seqnumber is wrap around safe Edo Monticelli
  2012-08-10 13:44 ` [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Simon Wunderlich
  3 siblings, 0 replies; 8+ messages in thread
From: Edo Monticelli @ 2012-08-09 12:15 UTC (permalink / raw)
  To: b.a.t.m.a.n

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 {
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [B.A.T.M.A.N.] [RFC 3/3] batman-adv: seqnumber is wrap around safe
  2012-08-09 12:15 [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Edo Monticelli
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 2/3] batman-adv: sender retransmission counter Edo Monticelli
@ 2012-08-09 12:15 ` Edo Monticelli
  2012-08-10 13:44 ` [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Simon Wunderlich
  3 siblings, 0 replies; 8+ messages in thread
From: Edo Monticelli @ 2012-08-09 12:15 UTC (permalink / raw)
  To: b.a.t.m.a.n

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;
-- 
1.7.8.6


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project
  2012-08-09 12:15 [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Edo Monticelli
                   ` (2 preceding siblings ...)
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 3/3] batman-adv: seqnumber is wrap around safe Edo Monticelli
@ 2012-08-10 13:44 ` Simon Wunderlich
  3 siblings, 0 replies; 8+ messages in thread
From: Simon Wunderlich @ 2012-08-10 13:44 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

[-- Attachment #1: Type: text/plain, Size: 1542 bytes --]

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
> 
> 

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
@ 2012-08-12 12:20   ` Sven Eckelmann
  2012-08-13  9:07     ` Sven Eckelmann
  2012-08-13  9:14   ` Sven Eckelmann
  1 sibling, 1 reply; 8+ messages in thread
From: Sven Eckelmann @ 2012-08-12 12:20 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 2567 bytes --]

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

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation
  2012-08-12 12:20   ` Sven Eckelmann
@ 2012-08-13  9:07     ` Sven Eckelmann
  0 siblings, 0 replies; 8+ messages in thread
From: Sven Eckelmann @ 2012-08-13  9:07 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 493 bytes --]

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

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation
  2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
  2012-08-12 12:20   ` Sven Eckelmann
@ 2012-08-13  9:14   ` Sven Eckelmann
  1 sibling, 0 replies; 8+ messages in thread
From: Sven Eckelmann @ 2012-08-13  9:14 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

[-- Attachment #1: Type: text/plain, Size: 1189 bytes --]

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

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-08-13  9:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-09 12:15 [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Edo Monticelli
2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 1/3] batman-adv: bandwidth meter implementation Edo Monticelli
2012-08-12 12:20   ` Sven Eckelmann
2012-08-13  9:07     ` Sven Eckelmann
2012-08-13  9:14   ` Sven Eckelmann
2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 2/3] batman-adv: sender retransmission counter Edo Monticelli
2012-08-09 12:15 ` [B.A.T.M.A.N.] [RFC 3/3] batman-adv: seqnumber is wrap around safe Edo Monticelli
2012-08-10 13:44 ` [B.A.T.M.A.N.] [RFC 0/3] GSOC 2012: bandwidth meter project Simon Wunderlich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox